/************************************************************************ * Member Functions of RRGraph * include mutators, accessors and utility functions ***********************************************************************/ #include #include #include #include #include "vtr_geometry.h" #include "vtr_vector_map.h" #include "vtr_log.h" #include "vtr_util.h" #include "vtr_assert.h" #include "rr_graph_obj.h" #include "rr_graph_obj_utils.h" /******************************************************************** * Constructors *******************************************************************/ RRGraph::RRGraph() : num_nodes_(0) , num_edges_(0) { //Pass } /******************************************************************** * Accessors *******************************************************************/ RRGraph::lazy_node_range RRGraph::nodes() const { return vtr::make_range(lazy_node_iterator(RRNodeId(0), invalid_node_ids_), lazy_node_iterator(RRNodeId(num_nodes_), invalid_node_ids_)); } RRGraph::lazy_edge_range RRGraph::edges() const { return vtr::make_range(lazy_edge_iterator(RREdgeId(0), invalid_edge_ids_), lazy_edge_iterator(RREdgeId(num_edges_), invalid_edge_ids_)); } RRGraph::switch_range RRGraph::switches() const { return vtr::make_range(switch_ids_.begin(), switch_ids_.end()); } RRGraph::segment_range RRGraph::segments() const { return vtr::make_range(segment_ids_.begin(), segment_ids_.end()); } //Node attributes t_rr_type RRGraph::node_type(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); return node_types_[node]; } size_t RRGraph::node_index(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); return size_t(node); } short RRGraph::node_xlow(const RRNodeId& node) const { return node_bounding_box(node).xmin(); } short RRGraph::node_ylow(const RRNodeId& node) const { return node_bounding_box(node).ymin(); } short RRGraph::node_xhigh(const RRNodeId& node) const { return node_bounding_box(node).xmax(); } short RRGraph::node_yhigh(const RRNodeId& node) const { return node_bounding_box(node).ymax(); } short RRGraph::node_length(const RRNodeId& node) const { return std::max(node_xhigh(node) - node_xlow(node), node_yhigh(node) - node_ylow(node)); } vtr::Rect RRGraph::node_bounding_box(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); return node_bounding_boxes_[node]; } /* Node starting and ending points */ /************************************************************************ * Get the coordinator of a starting point of a routing track * For routing tracks in INC_DIRECTION * (xlow, ylow) should be the starting point * * For routing tracks in DEC_DIRECTION * (xhigh, yhigh) should be the starting point * * For routing tracks in BI_DIRECTION * we always use (xhigh, yhigh) ***********************************************************************/ vtr::Point RRGraph::node_start_coordinate(const RRNodeId& node) const { /* Make sure we have CHANX or CHANY */ VTR_ASSERT((CHANX == node_type(node)) || (CHANY == node_type(node))); vtr::Point start_coordinate(node_xlow(node), node_ylow(node)); if (DEC_DIRECTION == node_direction(node)) { start_coordinate.set(node_xhigh(node), node_yhigh(node)); } return start_coordinate; } /************************************************************************ * Get the coordinator of a end point of a routing track * For routing tracks in INC_DIRECTION * (xhigh, yhigh) should be the ending point * * For routing tracks in DEC_DIRECTION * (xlow, ylow) should be the ending point * * For routing tracks in BI_DIRECTION * we always use (xhigh, yhigh) ***********************************************************************/ vtr::Point RRGraph::node_end_coordinate(const RRNodeId& node) const { /* Make sure we have CHANX or CHANY */ VTR_ASSERT((CHANX == node_type(node)) || (CHANY == node_type(node))); vtr::Point end_coordinate(node_xhigh(node), node_yhigh(node)); if (DEC_DIRECTION == node_direction(node)) { end_coordinate.set(node_xlow(node), node_ylow(node)); } return end_coordinate; } short RRGraph::node_fan_in(const RRNodeId& node) const { return node_num_in_edges_[node]; } short RRGraph::node_fan_out(const RRNodeId& node) const { return node_num_out_edges_[node]; } short RRGraph::node_capacity(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); return node_capacities_[node]; } short RRGraph::node_ptc_num(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); return node_ptc_nums_[node]; } short RRGraph::node_pin_num(const RRNodeId& node) const { VTR_ASSERT_MSG(node_type(node) == IPIN || node_type(node) == OPIN, "Pin number valid only for IPIN/OPIN RR nodes"); return node_ptc_num(node); } short RRGraph::node_track_num(const RRNodeId& node) const { VTR_ASSERT_MSG(node_type(node) == CHANX || node_type(node) == CHANY, "Track number valid only for CHANX/CHANY RR nodes"); return node_ptc_num(node); } short RRGraph::node_class_num(const RRNodeId& node) const { VTR_ASSERT_MSG(node_type(node) == SOURCE || node_type(node) == SINK, "Class number valid only for SOURCE/SINK RR nodes"); return node_ptc_num(node); } short RRGraph::node_cost_index(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); return node_cost_indices_[node]; } e_direction RRGraph::node_direction(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); VTR_ASSERT_MSG(node_type(node) == CHANX || node_type(node) == CHANY, "Direction valid only for CHANX/CHANY RR nodes"); return node_directions_[node]; } e_side RRGraph::node_side(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); VTR_ASSERT_MSG(node_type(node) == IPIN || node_type(node) == OPIN, "Side valid only for IPIN/OPIN RR nodes"); return node_sides_[node]; } /* Get the resistance of a node */ float RRGraph::node_R(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); return node_Rs_[node]; } /* Get the capacitance of a node */ float RRGraph::node_C(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); return node_Cs_[node]; } short RRGraph::node_rc_data_index(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); return node_rc_data_indices_[node]; } /* * Get a segment id of a node in rr_graph */ RRSegmentId RRGraph::node_segment(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); return node_segments_[node]; } RRGraph::edge_range RRGraph::node_edges(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); return vtr::make_range(node_edges_[node].get(), node_edges_[node].get() + node_num_in_edges_[node] + node_num_out_edges_[node]); } RRGraph::edge_range RRGraph::node_in_edges(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); return vtr::make_range(node_edges_[node].get(), node_edges_[node].get() + node_num_in_edges_[node]); } RRGraph::edge_range RRGraph::node_out_edges(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); return vtr::make_range((node_edges_[node].get() + node_num_in_edges_[node]), (node_edges_[node].get() + node_num_in_edges_[node]) + node_num_out_edges_[node]); } /* Get the list of configurable edges from the input edges of a given node * And return the range(iterators) of the list */ RRGraph::edge_range RRGraph::node_configurable_in_edges(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); return vtr::make_range(node_edges_[node].get(), node_edges_[node].get() + node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]); } /* Get the list of non configurable edges from the input edges of a given node * And return the range(iterators) of the list */ RRGraph::edge_range RRGraph::node_non_configurable_in_edges(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); return vtr::make_range(node_edges_[node].get() + node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node], node_edges_[node].get() + node_num_in_edges_[node]); } /* Get the list of configurable edges from the output edges of a given node * And return the range(iterators) of the list */ RRGraph::edge_range RRGraph::node_configurable_out_edges(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); return vtr::make_range((node_edges_[node].get() + node_num_in_edges_[node]), (node_edges_[node].get() + node_num_in_edges_[node]) + node_num_out_edges_[node] - node_num_non_configurable_out_edges_[node]); } /* Get the list of non configurable edges from the output edges of a given node * And return the range(iterators) of the list */ RRGraph::edge_range RRGraph::node_non_configurable_out_edges(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); return vtr::make_range((node_edges_[node].get() + node_num_in_edges_[node]) + node_num_out_edges_[node] - node_num_non_configurable_out_edges_[node], (node_edges_[node].get() + node_num_in_edges_[node]) + node_num_out_edges_[node]); } //Edge attributes size_t RRGraph::edge_index(const RREdgeId& edge) const { VTR_ASSERT_SAFE(valid_edge_id(edge)); return size_t(edge); } RRNodeId RRGraph::edge_src_node(const RREdgeId& edge) const { VTR_ASSERT_SAFE(valid_edge_id(edge)); return edge_src_nodes_[edge]; } RRNodeId RRGraph::edge_sink_node(const RREdgeId& edge) const { VTR_ASSERT_SAFE(valid_edge_id(edge)); return edge_sink_nodes_[edge]; } RRSwitchId RRGraph::edge_switch(const RREdgeId& edge) const { VTR_ASSERT_SAFE(valid_edge_id(edge)); return edge_switches_[edge]; } /* Check if the edge is a configurable edge (programmble) */ bool RRGraph::edge_is_configurable(const RREdgeId& edge) const { /* Make sure we have a valid edge id */ VTR_ASSERT_SAFE(valid_edge_id(edge)); auto iswitch = edge_switch(edge); return switches_[iswitch].configurable(); } /* Check if the edge is a non-configurable edge (hardwired) */ bool RRGraph::edge_is_non_configurable(const RREdgeId& edge) const { /* Make sure we have a valid edge id */ VTR_ASSERT_SAFE(valid_edge_id(edge)); return !edge_is_configurable(edge); } size_t RRGraph::switch_index(const RRSwitchId& switch_id) const { VTR_ASSERT_SAFE(valid_switch_id(switch_id)); return size_t(switch_id); } /* * Get a switch from the rr_switch list with a given id */ const t_rr_switch_inf& RRGraph::get_switch(const RRSwitchId& switch_id) const { VTR_ASSERT_SAFE(valid_switch_id(switch_id)); return switches_[switch_id]; } size_t RRGraph::segment_index(const RRSegmentId& segment_id) const { VTR_ASSERT_SAFE(valid_segment_id(segment_id)); return size_t(segment_id); } /* * Get a segment from the segment list with a given id */ const t_segment_inf& RRGraph::get_segment(const RRSegmentId& segment_id) const { VTR_ASSERT_SAFE(valid_segment_id(segment_id)); return segments_[segment_id]; } /************************************************************************ * Find all the edges interconnecting two nodes * Return a vector of the edge ids ***********************************************************************/ std::vector RRGraph::find_edges(const RRNodeId& src_node, const RRNodeId& sink_node) const { std::vector matching_edges; /* Iterate over the outgoing edges of the source node */ for (auto edge : node_out_edges(src_node)) { if (edge_sink_node(edge) == sink_node) { /* Update edge list to return */ matching_edges.push_back(edge); } } return matching_edges; } RRNodeId RRGraph::find_node(const short& x, const short& y, const t_rr_type& type, const int& ptc, const e_side& side) const { initialize_fast_node_lookup(); size_t itype = type; size_t iside = side; /* Check if x, y, type and ptc, side is valid */ if ((x < 0) /* See if x is smaller than the index of first element */ || (size_t(x) > node_lookup_.dim_size(0) - 1) /* See if x is large than the index of last element */ || (0 == node_lookup_.dim_size(0))) { /* See if x is large than the index of last element */ /* Return a zero range! */ return RRNodeId::INVALID(); } /* Check if x, y, type and ptc, side is valid */ if ((y < 0) /* See if y is smaller than the index of first element */ || (size_t(y) > node_lookup_.dim_size(1) - 1) /* See if y is large than the index of last element */ || (0 == node_lookup_.dim_size(1))) { /* See if y is large than the index of last element */ /* Return a zero range! */ return RRNodeId::INVALID(); } /* Check if x, y, type and ptc, side is valid */ /* itype is always larger than -1, we can skip checking */ if ( (itype > node_lookup_.dim_size(2) - 1) /* See if type is large than the index of last element */ || (0 == node_lookup_.dim_size(2))) { /* See if type is large than the index of last element */ /* Return a zero range! */ return RRNodeId::INVALID(); } /* Check if x, y, type and ptc, side is valid */ if ((ptc < 0) /* See if ptc is smaller than the index of first element */ || (size_t(ptc) > node_lookup_[x][y][type].size() - 1) /* See if ptc is large than the index of last element */ || (0 == node_lookup_[x][y][type].size())) { /* See if ptc is large than the index of last element */ /* Return a zero range! */ return RRNodeId::INVALID(); } /* Check if x, y, type and ptc, side is valid */ /* iside is always larger than -1, we can skip checking */ if ((iside > node_lookup_[x][y][type][ptc].size() - 1) /* See if side is large than the index of last element */ || (0 == node_lookup_[x][y][type][ptc].size()) ) { /* See if side is large than the index of last element */ /* Return a zero range! */ return RRNodeId::INVALID(); } return node_lookup_[x][y][itype][ptc][iside]; } /* Find the channel width (number of tracks) of a channel [x][y] */ short RRGraph::chan_num_tracks(const short& x, const short& y, const t_rr_type& type) const { /* Must be CHANX or CHANY */ VTR_ASSERT_MSG(CHANX == type || CHANY == type, "Required node_type to be CHANX or CHANY!"); initialize_fast_node_lookup(); /* Check if x, y, type and ptc is valid */ if ((x < 0) /* See if x is smaller than the index of first element */ || (size_t(x) > node_lookup_.dim_size(0) - 1)) { /* See if x is large than the index of last element */ /* Return a zero range! */ return 0; } /* Check if x, y, type and ptc is valid */ if ((y < 0) /* See if y is smaller than the index of first element */ || (size_t(y) > node_lookup_.dim_size(1) - 1)) { /* See if y is large than the index of last element */ /* Return a zero range! */ return 0; } /* Check if x, y, type and ptc is valid */ if ((size_t(type) > node_lookup_.dim_size(2) - 1)) { /* See if type is large than the index of last element */ /* Return a zero range! */ return 0; } const auto& matching_nodes = node_lookup_[x][y][type]; return vtr::make_range(matching_nodes.begin(), matching_nodes.end()).size(); } /* This function aims to print basic information about a node */ void RRGraph::print_node(const RRNodeId& node) const { VTR_LOG("Node id: %d\n", node_index(node)); VTR_LOG("Node type: %s\n", rr_node_typename[node_type(node)]); VTR_LOG("Node xlow: %d\n", node_xlow(node)); VTR_LOG("Node ylow: %d\n", node_ylow(node)); VTR_LOG("Node xhigh: %d\n", node_xhigh(node)); VTR_LOG("Node yhigh: %d\n", node_yhigh(node)); VTR_LOG("Node ptc: %d\n", node_ptc_num(node)); VTR_LOG("Node num in_edges: %d\n", node_in_edges(node).size()); VTR_LOG("Node num out_edges: %d\n", node_out_edges(node).size()); } /* Check if the segment id of a node is in range */ bool RRGraph::validate_node_segment(const RRNodeId& node) const { VTR_ASSERT_SAFE(valid_node_id(node)); /* Only CHANX and CHANY requires a valid segment id */ if ((CHANX == node_type(node)) || (CHANY == node_type(node))) { return valid_segment_id(node_segments_[node]); } else { return true; } } /* Check if the segment id of every node is in range */ bool RRGraph::validate_node_segments() const { bool all_valid = true; for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } if (true == validate_node_segment(RRNodeId(id))) { continue; } /* Reach here it means we find an invalid segment id */ all_valid = false; /* Print a warning! */ VTR_LOG_WARN("Node %d has an invalid segment id (%d)!\n", id, size_t(node_segment(RRNodeId(id)))); } return all_valid; } /* Check if the switch id of a edge is in range */ bool RRGraph::validate_edge_switch(const RREdgeId& edge) const { VTR_ASSERT_SAFE(valid_edge_id(edge)); return valid_switch_id(edge_switches_[edge]); } /* Check if the switch id of every edge is in range */ bool RRGraph::validate_edge_switches() const { bool all_valid = true; for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ if (!valid_edge_id(RREdgeId(id))) { /* Skip this id */ continue; } if (true == validate_edge_switch(RREdgeId(id))) { continue; } /* Reach here it means we find an invalid segment id */ all_valid = false; /* Print a warning! */ VTR_LOG_WARN("Edge %d has an invalid switch id (%d)!\n", id, size_t(edge_switch(RREdgeId(id)))); } return all_valid; } /* Check if a node is in the list of source_nodes of a edge */ bool RRGraph::validate_node_is_edge_src(const RRNodeId& node, const RREdgeId& edge) const { /* Assure a valid node id */ VTR_ASSERT_SAFE(valid_node_id(node)); /* assure a valid edge id */ VTR_ASSERT_SAFE(valid_edge_id(edge)); /* find if the node is the src */ if (node == edge_src_node(edge)) { return true; /* confirmed source node*/ } else { return false; /* not a source */ } } /* Check if a node is in the list of sink_nodes of a edge */ bool RRGraph::validate_node_is_edge_sink(const RRNodeId& node, const RREdgeId& edge) const { /* Assure a valid node id */ VTR_ASSERT_SAFE(valid_node_id(node)); /* assure a valid edge id */ VTR_ASSERT_SAFE(valid_edge_id(edge)); /* find if the node is the sink */ if (node == edge_sink_node(edge)) { return true; /* confirmed source node*/ } else { return false; /* not a source */ } } /* This function will check if a node has valid input edges * 1. Check the edge ids are valid * 2. Check the node is in the list of edge_sink_node */ bool RRGraph::validate_node_in_edges(const RRNodeId& node) const { bool all_valid = true; /* Assure a valid node id */ VTR_ASSERT_SAFE(valid_node_id(node)); /* Check each edge */ for (auto edge : node_in_edges(node)) { /* assure a valid edge id */ VTR_ASSERT_SAFE(valid_edge_id(edge)); /* check the node is in the list of edge_sink_node */ if (true == validate_node_is_edge_sink(node, edge)) { continue; } /* Reach here, it means there is something wrong! * Print a warning */ VTR_LOG_WARN("Edge %d is in the input edge list of node %d while the node is not in edge's sink node list!\n", size_t(edge), size_t(node)); all_valid = false; } return all_valid; } /* This function will check if a node has valid output edges * 1. Check the edge ids are valid * 2. Check the node is in the list of edge_source_node */ bool RRGraph::validate_node_out_edges(const RRNodeId& node) const { bool all_valid = true; /* Assure a valid node id */ VTR_ASSERT_SAFE(valid_node_id(node)); /* Check each edge */ for (auto edge : node_out_edges(node)) { /* assure a valid edge id */ VTR_ASSERT_SAFE(valid_edge_id(edge)); /* check the node is in the list of edge_sink_node */ if (true == validate_node_is_edge_src(node, edge)) { continue; } /* Reach here, it means there is something wrong! * Print a warning */ VTR_LOG_WARN("Edge %d is in the output edge list of node %d while the node is not in edge's source node list!\n", size_t(edge), size_t(node)); all_valid = false; } return all_valid; } /* check all the edges of a node */ bool RRGraph::validate_node_edges(const RRNodeId& node) const { bool all_valid = true; if (false == validate_node_in_edges(node)) { all_valid = false; } if (false == validate_node_out_edges(node)) { all_valid = false; } return all_valid; } /* check if all the nodes' input edges are valid */ bool RRGraph::validate_nodes_in_edges() const { bool all_valid = true; for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } if (true == validate_node_in_edges(RRNodeId(id))) { continue; } /* Reach here, it means there is something wrong! * Print a warning */ all_valid = false; } return all_valid; } /* check if all the nodes' output edges are valid */ bool RRGraph::validate_nodes_out_edges() const { bool all_valid = true; for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } if (true == validate_node_out_edges(RRNodeId(id))) { continue; } /* Reach here, it means there is something wrong! * Print a warning */ all_valid = false; } return all_valid; } /* check all the edges of every node */ bool RRGraph::validate_nodes_edges() const { bool all_valid = true; if (false == validate_nodes_in_edges()) { all_valid = false; } if (false == validate_nodes_out_edges()) { all_valid = false; } return all_valid; } /* Check if source node of a edge is valid */ bool RRGraph::validate_edge_src_node(const RREdgeId& edge) const { return valid_node_id(edge_src_node(edge)); } /* Check if sink node of a edge is valid */ bool RRGraph::validate_edge_sink_node(const RREdgeId& edge) const { return valid_node_id(edge_sink_node(edge)); } /* Check if source nodes of a edge are all valid */ bool RRGraph::validate_edge_src_nodes() const { bool all_valid = true; for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ if (!valid_edge_id(RREdgeId(id))) { /* Skip this id */ continue; } if (true == validate_edge_src_node(RREdgeId(id))) { continue; } /* Reach here, it means there is something wrong! * Print a warning */ VTR_LOG_WARN("Edge %d has a invalid source node %d!\n", id, size_t(edge_src_node(RREdgeId(id)))); all_valid = false; } return all_valid; } /* Check if source nodes of a edge are all valid */ bool RRGraph::validate_edge_sink_nodes() const { bool all_valid = true; for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ if (!valid_edge_id(RREdgeId(id))) { /* Skip this id */ continue; } if (true == validate_edge_sink_node(RREdgeId(id))) { continue; } /* Reach here, it means there is something wrong! * Print a warning */ VTR_LOG_WARN("Edge %d has a invalid sink node %d!\n", id, size_t(edge_sink_node(RREdgeId(id)))); all_valid = false; } return all_valid; } /* This function should be used when nodes, edges, switches and segments have been used after * We will build the fast_lookup, partition edges and check * This function run fundamental and optional checks on internal data * Errors are thrown if fundamental checking fails * Warnings are thrown if optional checking fails */ bool RRGraph::validate() const { size_t num_err = 0; initialize_fast_node_lookup(); /* Validate the sizes of nodes and node-related vectors * Validate the sizes of edges and edge-related vectors */ if (false == validate_sizes()) { VTR_LOG_WARN("Fail in validating node- and edge-related vector sizes!\n"); num_err++; } /* Fundamental check */ if (false == validate_nodes_edges()) { VTR_LOG_WARN("Fail in validating edges connected to each node!\n"); num_err++; } if (false == validate_node_segments()) { VTR_LOG_WARN("Fail in validating segment IDs of nodes !\n"); num_err++; } if (false == validate_edge_switches()) { VTR_LOG_WARN("Fail in validating switch IDs of edges !\n"); num_err++; } /* Error out if there is any fatal errors found */ if (0 < num_err) { VTR_LOG_ERROR("Routing Resource graph is not valid due to %d fatal errors !\n", num_err); } return (0 == num_err); } bool RRGraph::is_dirty() const { return dirty_; } void RRGraph::set_dirty() { dirty_ = true; } void RRGraph::clear_dirty() { dirty_ = false; } /* Reserve a list of nodes */ void RRGraph::reserve_nodes(const unsigned long& num_nodes) { /* Reserve the full set of vectors related to nodes */ /* Basic information */ this->node_types_.reserve(num_nodes); this->node_bounding_boxes_.reserve(num_nodes); this->node_capacities_.reserve(num_nodes); this->node_ptc_nums_.reserve(num_nodes); this->node_cost_indices_.reserve(num_nodes); this->node_directions_.reserve(num_nodes); this->node_sides_.reserve(num_nodes); this->node_Rs_.reserve(num_nodes); this->node_Cs_.reserve(num_nodes); this->node_rc_data_indices_.reserve(num_nodes); this->node_segments_.reserve(num_nodes); /* Edge-related vectors */ this->node_num_in_edges_.reserve(num_nodes); this->node_num_out_edges_.reserve(num_nodes); this->node_num_non_configurable_in_edges_.reserve(num_nodes); this->node_num_non_configurable_out_edges_.reserve(num_nodes); this->node_edges_.reserve(num_nodes); } /* Reserve a list of edges */ void RRGraph::reserve_edges(const unsigned long& num_edges) { /* Reserve the full set of vectors related to edges */ this->edge_src_nodes_.reserve(num_edges); this->edge_sink_nodes_.reserve(num_edges); this->edge_switches_.reserve(num_edges); } /* Reserve a list of switches */ void RRGraph::reserve_switches(const size_t& num_switches) { this->switch_ids_.reserve(num_switches); this->switches_.reserve(num_switches); } /* Reserve a list of segments */ void RRGraph::reserve_segments(const size_t& num_segments) { this->segment_ids_.reserve(num_segments); this->segments_.reserve(num_segments); } /* Mutators */ RRNodeId RRGraph::create_node(const t_rr_type& type) { /* Allocate an ID */ RRNodeId node_id = RRNodeId(num_nodes_); /* Expand range of node ids */ num_nodes_++; /* Initialize the attributes */ node_types_.push_back(type); node_bounding_boxes_.emplace_back(-1, -1, -1, -1); node_capacities_.push_back(-1); node_ptc_nums_.push_back(-1); node_cost_indices_.push_back(-1); node_directions_.push_back(NO_DIRECTION); node_sides_.push_back(NUM_SIDES); node_Rs_.push_back(0.); node_Cs_.push_back(0.); node_rc_data_indices_.push_back(-1); node_segments_.push_back(RRSegmentId::INVALID()); node_edges_.emplace_back(); //Initially empty node_num_in_edges_.emplace_back(0); node_num_out_edges_.emplace_back(0); node_num_non_configurable_in_edges_.emplace_back(0); node_num_non_configurable_out_edges_.emplace_back(0); invalidate_fast_node_lookup(); VTR_ASSERT(validate_sizes()); return node_id; } RREdgeId RRGraph::create_edge(const RRNodeId& source, const RRNodeId& sink, const RRSwitchId& switch_id, const bool& fake_switch) { VTR_ASSERT(valid_node_id(source)); VTR_ASSERT(valid_node_id(sink)); if (false == fake_switch) { VTR_ASSERT(valid_switch_id(switch_id)); } /* Allocate an ID */ RREdgeId edge_id = RREdgeId(num_edges_); /* Expand range of edge ids */ num_edges_++; /* Initialize the attributes */ edge_src_nodes_.push_back(source); edge_sink_nodes_.push_back(sink); edge_switches_.push_back(switch_id); //We do not create the entry in node_edges_ here! //For memory efficiency this is done when //rebuild_node_edges() is called (i.e. after all //edges have been created). VTR_ASSERT(validate_sizes()); return edge_id; } void RRGraph::set_edge_switch(const RREdgeId& edge, const RRSwitchId& switch_id) { VTR_ASSERT(valid_edge_id(edge)); VTR_ASSERT(valid_switch_id(switch_id)); edge_switches_[edge] = switch_id; } RRSwitchId RRGraph::create_switch(const t_rr_switch_inf& switch_info) { //Allocate an ID RRSwitchId switch_id = RRSwitchId(switch_ids_.size()); switch_ids_.push_back(switch_id); switches_.push_back(switch_info); return switch_id; } /* Create segment */ RRSegmentId RRGraph::create_segment(const t_segment_inf& segment_info) { //Allocate an ID RRSegmentId segment_id = RRSegmentId(segment_ids_.size()); segment_ids_.push_back(segment_id); segments_.push_back(segment_info); return segment_id; } /* This function just marks the node to be removed with an INVALID id * It also disconnects and mark the incoming and outcoming edges to be INVALID() * And then set the RRGraph as polluted (dirty_flag = true) * The compress() function should be called to physically remove the node */ void RRGraph::remove_node(const RRNodeId& node) { //Invalidate all connected edges // TODO: consider removal of self-loop edges? for (auto edge : node_in_edges(node)) { remove_edge(edge); } for (auto edge : node_out_edges(node)) { remove_edge(edge); } //Mark node invalid invalid_node_ids_.insert(node); //Invalidate the node look-up invalidate_fast_node_lookup(); set_dirty(); } /* This function just marks the edge to be removed with an INVALID id * And then set the RRGraph as polluted (dirty_flag = true) * The compress() function should be called to physically remove the edge */ void RRGraph::remove_edge(const RREdgeId& edge) { RRNodeId src_node = edge_src_node(edge); RRNodeId sink_node = edge_sink_node(edge); /* Invalidate node to edge references * TODO: consider making this optional (e.g. if called from remove_node) */ for (size_t i = 0; i < node_num_in_edges_[src_node]; ++i) { if (node_edges_[src_node][i] == edge) { node_edges_[src_node][i] = RREdgeId::INVALID(); break; } } for (size_t i = node_num_in_edges_[sink_node]; i < node_num_in_edges_[sink_node] + node_num_out_edges_[sink_node]; ++i) { if (node_edges_[sink_node][i] == edge) { node_edges_[sink_node][i] = RREdgeId::INVALID(); break; } } /* Mark edge invalid */ invalid_edge_ids_.insert(edge); set_dirty(); } void RRGraph::set_node_type(const RRNodeId& node, const t_rr_type& type) { VTR_ASSERT(valid_node_id(node)); node_types_[node] = type; } void RRGraph::set_node_xlow(const RRNodeId& node, const short& xlow) { VTR_ASSERT(valid_node_id(node)); node_bounding_boxes_[node].set_xmin(xlow); } void RRGraph::set_node_ylow(const RRNodeId& node, const short& ylow) { VTR_ASSERT(valid_node_id(node)); node_bounding_boxes_[node].set_ymin(ylow); } void RRGraph::set_node_xhigh(const RRNodeId& node, const short& xhigh) { VTR_ASSERT(valid_node_id(node)); node_bounding_boxes_[node].set_xmax(xhigh); } void RRGraph::set_node_yhigh(const RRNodeId& node, const short& yhigh) { VTR_ASSERT(valid_node_id(node)); node_bounding_boxes_[node].set_ymax(yhigh); } void RRGraph::set_node_bounding_box(const RRNodeId& node, const vtr::Rect& bb) { VTR_ASSERT(valid_node_id(node)); node_bounding_boxes_[node] = bb; } void RRGraph::set_node_capacity(const RRNodeId& node, const short& capacity) { VTR_ASSERT(valid_node_id(node)); node_capacities_[node] = capacity; } void RRGraph::set_node_ptc_num(const RRNodeId& node, const short& ptc) { VTR_ASSERT(valid_node_id(node)); node_ptc_nums_[node] = ptc; } void RRGraph::set_node_pin_num(const RRNodeId& node, const short& pin_id) { VTR_ASSERT(valid_node_id(node)); VTR_ASSERT_MSG(node_type(node) == IPIN || node_type(node) == OPIN, "Pin number valid only for IPIN/OPIN RR nodes"); set_node_ptc_num(node, pin_id); } void RRGraph::set_node_track_num(const RRNodeId& node, const short& track_id) { VTR_ASSERT(valid_node_id(node)); VTR_ASSERT_MSG(node_type(node) == CHANX || node_type(node) == CHANY, "Track number valid only for CHANX/CHANY RR nodes"); set_node_ptc_num(node, track_id); } void RRGraph::set_node_class_num(const RRNodeId& node, const short& class_id) { VTR_ASSERT(valid_node_id(node)); VTR_ASSERT_MSG(node_type(node) == SOURCE || node_type(node) == SINK, "Class number valid only for SOURCE/SINK RR nodes"); set_node_ptc_num(node, class_id); } void RRGraph::set_node_cost_index(const RRNodeId& node, const short& cost_index) { VTR_ASSERT(valid_node_id(node)); node_cost_indices_[node] = cost_index; } void RRGraph::set_node_direction(const RRNodeId& node, const e_direction& direction) { VTR_ASSERT(valid_node_id(node)); VTR_ASSERT_MSG(node_type(node) == CHANX || node_type(node) == CHANY, "Direct can only be specified on CHANX/CNAY rr nodes"); node_directions_[node] = direction; } void RRGraph::set_node_side(const RRNodeId& node, const e_side& side) { VTR_ASSERT(valid_node_id(node)); VTR_ASSERT_MSG(node_type(node) == IPIN || node_type(node) == OPIN, "Side can only be specified on IPIN/OPIN rr nodes"); node_sides_[node] = side; } void RRGraph::set_node_R(const RRNodeId& node, const float& R) { VTR_ASSERT(valid_node_id(node)); node_Rs_[node] = R; } void RRGraph::set_node_C(const RRNodeId& node, const float& C) { VTR_ASSERT(valid_node_id(node)); node_Cs_[node] = C; } void RRGraph::set_node_rc_data_index(const RRNodeId& node, const short& rc_data_index) { VTR_ASSERT(valid_node_id(node)); node_rc_data_indices_[node] = rc_data_index; } /* * Set a segment id for a node in rr_graph */ void RRGraph::set_node_segment(const RRNodeId& node, const RRSegmentId& segment_id) { VTR_ASSERT(valid_node_id(node)); /* Only CHANX and CHANY requires a valid segment id */ if ((CHANX == node_type(node)) || (CHANY == node_type(node))) { VTR_ASSERT(valid_segment_id(segment_id)); } node_segments_[node] = segment_id; } void RRGraph::rebuild_node_edges() { node_edges_.resize(nodes().size()); node_num_in_edges_.resize(nodes().size(), 0); node_num_out_edges_.resize(nodes().size(), 0); node_num_non_configurable_in_edges_.resize(nodes().size(), 0); node_num_non_configurable_out_edges_.resize(nodes().size(), 0); //Count the number of edges of each type for (RREdgeId edge : edges()) { if (!edge) continue; RRNodeId src_node = edge_src_node(edge); RRNodeId sink_node = edge_sink_node(edge); bool config = edge_is_configurable(edge); ++node_num_out_edges_[src_node]; ++node_num_in_edges_[sink_node]; if (!config) { ++node_num_non_configurable_out_edges_[src_node]; ++node_num_non_configurable_in_edges_[sink_node]; } } //Allocate precisely the correct space for each nodes edge list for (RRNodeId node : nodes()) { if (!node) continue; node_edges_[node] = std::make_unique(node_num_in_edges_[node] + node_num_out_edges_[node]); } //Insert the edges into the node lists { vtr::vector inserted_edge_cnt(nodes().size(), 0); for (RREdgeId edge : edges()) { RRNodeId src_node = edge_src_node(edge); RRNodeId sink_node = edge_sink_node(edge); node_edges_[src_node][inserted_edge_cnt[src_node]++] = edge; node_edges_[sink_node][inserted_edge_cnt[sink_node]++] = edge; } } #if 0 //TODO: Sanity Check remove! for (RRNodeId node : nodes()) { for (size_t iedge = 0; iedge < node_num_in_edges_[node] + node_num_out_edges_[node]; ++iedge) { RREdgeId edge = node_edges_[node][iedge]; VTR_ASSERT(edge_src_node(edge) == node || edge_sink_node(edge) == node); } } #endif //Partition each node's edge lists according to their type to line up with the counts auto is_configurable_edge = [&](const RREdgeId edge) { return edge_is_configurable(edge); }; for (RRNodeId node : nodes()) { if (!node) continue; //We partition the nodes first by incoming/outgoing: // // +---------------------------+-----------------------------+ // | in | out | // +---------------------------+-----------------------------+ // //and then the two subsets by configurability. So the final ordering is: // // +-----------+---------------+------------+----------------+ // | in_config | in_non_config | out_config | out_non_config | // +-----------+---------------+------------+----------------+ // //Partition first into incoming/outgoing auto is_incoming_edge = [&](const RREdgeId edge) { return edge_sink_node(edge) == node; }; /* Use stable_partition to keep the relative order, * This is mainly for comparing the RRGraph write with rr_node writer * so that it is easy to check consistency */ std::stable_partition(node_edges_[node].get(), node_edges_[node].get() + node_num_in_edges_[node] + node_num_out_edges_[node], is_incoming_edge); //Partition incoming by configurable/non-configurable std::stable_partition(node_edges_[node].get(), node_edges_[node].get() + node_num_in_edges_[node], is_configurable_edge); //Partition outgoing by configurable/non-configurable std::stable_partition(node_edges_[node].get() + node_num_in_edges_[node], node_edges_[node].get() + node_num_in_edges_[node] + node_num_out_edges_[node], is_configurable_edge); #if 0 //TODO: Sanity check remove! size_t nedges = node_num_in_edges_[node] + node_num_out_edges_[node]; for (size_t iedge = 0; iedge < nedges; ++iedge) { RREdgeId edge = node_edges_[node][iedge]; if (iedge < node_num_in_edges_[node]) { //Incoming VTR_ASSERT(edge_sink_node(edge) == node); if (iedge < node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]) { VTR_ASSERT(edge_is_configurable(edge)); } else { VTR_ASSERT(!edge_is_configurable(edge)); } } else { //Outgoing VTR_ASSERT(edge_src_node(edge) == node); if (iedge < node_num_in_edges_[node] + node_num_out_edges_[node] - node_num_non_configurable_out_edges_[node]) { VTR_ASSERT(edge_is_configurable(edge)); } else { VTR_ASSERT(!edge_is_configurable(edge)); } } } #endif } } void RRGraph::build_fast_node_lookup() const { /* Free the current fast node look-up, we will rebuild a new one here */ invalidate_fast_node_lookup(); /* Get the max (x,y) and then we can resize the ndmatrix */ vtr::Point max_coord(0, 0); for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } max_coord.set_x(std::max(max_coord.x(), std::max(node_bounding_boxes_[RRNodeId(id)].xmax(), node_bounding_boxes_[RRNodeId(id)].xmin()))); max_coord.set_y(std::max(max_coord.y(), std::max(node_bounding_boxes_[RRNodeId(id)].ymax(), node_bounding_boxes_[RRNodeId(id)].ymin()))); } node_lookup_.resize({(size_t)max_coord.x() + 1, (size_t)max_coord.y() + 1, NUM_RR_TYPES + 1}); for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } RRNodeId node = RRNodeId(id); /* Special for CHANX and CHANY, we should annotate in the look-up * for all the (x,y) upto (xhigh, yhigh) */ size_t x_start = std::min(node_xlow(node), node_xhigh(node)); size_t y_start = std::min(node_ylow(node), node_yhigh(node)); std::vector node_x(std::abs(node_xlow(node) - node_xhigh(node)) + 1); std::vector node_y(std::abs(node_ylow(node) - node_yhigh(node)) + 1); std::iota(node_x.begin(), node_x.end(), x_start); std::iota(node_y.begin(), node_y.end(), y_start); VTR_ASSERT(size_t(std::max(node_xlow(node), node_xhigh(node))) == node_x.back()); VTR_ASSERT(size_t(std::max(node_ylow(node), node_yhigh(node))) == node_y.back()); size_t itype = node_type(node); size_t ptc = node_ptc_num(node); for (const size_t& x : node_x) { for (const size_t& y : node_y) { if (ptc >= node_lookup_[x][y][itype].size()) { node_lookup_[x][y][itype].resize(ptc + 1); } size_t iside = -1; if (node_type(node) == OPIN || node_type(node) == IPIN) { iside = node_side(node); } else { iside = NUM_SIDES; } if (iside >= node_lookup_[x][y][itype][ptc].size()) { node_lookup_[x][y][itype][ptc].resize(iside + 1); } //Save node in lookup node_lookup_[x][y][itype][ptc][iside] = node; } } } } void RRGraph::invalidate_fast_node_lookup() const { node_lookup_.clear(); } bool RRGraph::valid_fast_node_lookup() const { return !node_lookup_.empty(); } void RRGraph::initialize_fast_node_lookup() const { if (!valid_fast_node_lookup()) { build_fast_node_lookup(); } } bool RRGraph::valid_node_id(const RRNodeId& node) const { return (size_t(node) < num_nodes_) && (!invalid_node_ids_.count(node)); } bool RRGraph::valid_edge_id(const RREdgeId& edge) const { return (size_t(edge) < num_edges_) && (!invalid_edge_ids_.count(edge)); } /* check if a given switch id is valid or not */ bool RRGraph::valid_switch_id(const RRSwitchId& switch_id) const { /* TODO: should we check the index of switch[id] matches ? */ return size_t(switch_id) < switches_.size(); } /* check if a given segment id is valid or not */ bool RRGraph::valid_segment_id(const RRSegmentId& segment_id) const { /* TODO: should we check the index of segment[id] matches ? */ return size_t(segment_id) < segments_.size(); } /** * Internal checking codes to ensure data consistency * If you add any internal data to RRGraph and update create_node/edge etc. * you need to update the validate_sizes() here to make sure these * internal vectors are aligned to the id vectors */ bool RRGraph::validate_sizes() const { return validate_node_sizes() && validate_edge_sizes() && validate_switch_sizes() && validate_segment_sizes(); } bool RRGraph::validate_node_sizes() const { return node_types_.size() == num_nodes_ && node_bounding_boxes_.size() == num_nodes_ && node_capacities_.size() == num_nodes_ && node_ptc_nums_.size() == num_nodes_ && node_cost_indices_.size() == num_nodes_ && node_directions_.size() == num_nodes_ && node_sides_.size() == num_nodes_ && node_Rs_.size() == num_nodes_ && node_Cs_.size() == num_nodes_ && node_segments_.size() == num_nodes_ && node_num_non_configurable_in_edges_.size() == num_nodes_ && node_num_non_configurable_out_edges_.size() == num_nodes_ && node_edges_.size() == num_nodes_; } bool RRGraph::validate_edge_sizes() const { return edge_src_nodes_.size() == num_edges_ && edge_sink_nodes_.size() == num_edges_ && edge_switches_.size() == num_edges_; } bool RRGraph::validate_switch_sizes() const { return switches_.size() == switch_ids_.size(); } bool RRGraph::validate_segment_sizes() const { return segments_.size() == segment_ids_.size(); } void RRGraph::compress() { vtr::vector node_id_map(num_nodes_); vtr::vector edge_id_map(num_edges_); build_id_maps(node_id_map, edge_id_map); clean_nodes(node_id_map); clean_edges(edge_id_map); rebuild_node_refs(edge_id_map); invalidate_fast_node_lookup(); /* Clear invalid node list */ invalid_node_ids_.clear(); /* Clear invalid edge list */ invalid_edge_ids_.clear(); clear_dirty(); } void RRGraph::build_id_maps(vtr::vector& node_id_map, vtr::vector& edge_id_map) { /* Build node ids including invalid ids and compress */ vtr::vector node_ids; for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (!valid_node_id(RRNodeId(id))) { /* Give and invalid id */ node_ids.push_back(RRNodeId::INVALID()); continue; } /* Reach here, this is a valid id, push to the edge list */ node_ids.push_back(RRNodeId(id)); } node_id_map = compress_ids(node_ids); /* Build edge ids including invalid ids and compress */ vtr::vector edge_ids; for (size_t id = 0; id < num_edges_; ++id) { /* Try to find if this is an invalid id or not */ if (!valid_edge_id(RREdgeId(id))) { /* Give and invalid id */ edge_ids.push_back(RREdgeId::INVALID()); continue; } /* Reach here, this is a valid id, push to the edge list */ edge_ids.push_back(RREdgeId(id)); } edge_id_map = compress_ids(edge_ids); } void RRGraph::clean_nodes(const vtr::vector& node_id_map) { num_nodes_ = node_id_map.size(); node_types_ = clean_and_reorder_values(node_types_, node_id_map); node_bounding_boxes_ = clean_and_reorder_values(node_bounding_boxes_, node_id_map); node_capacities_ = clean_and_reorder_values(node_capacities_, node_id_map); node_ptc_nums_ = clean_and_reorder_values(node_ptc_nums_, node_id_map); node_cost_indices_ = clean_and_reorder_values(node_cost_indices_, node_id_map); node_directions_ = clean_and_reorder_values(node_directions_, node_id_map); node_sides_ = clean_and_reorder_values(node_sides_, node_id_map); node_Rs_ = clean_and_reorder_values(node_Rs_, node_id_map); node_Cs_ = clean_and_reorder_values(node_Cs_, node_id_map); node_segments_ = clean_and_reorder_values(node_segments_, node_id_map); node_num_non_configurable_in_edges_ = clean_and_reorder_values(node_num_non_configurable_in_edges_, node_id_map); node_num_non_configurable_out_edges_ = clean_and_reorder_values(node_num_non_configurable_out_edges_, node_id_map); node_num_in_edges_ = clean_and_reorder_values(node_num_in_edges_, node_id_map); node_num_out_edges_ = clean_and_reorder_values(node_num_out_edges_, node_id_map); //node_edges_ = clean_and_reorder_values(node_edges_, node_id_map); VTR_ASSERT(validate_node_sizes()); } void RRGraph::clean_edges(const vtr::vector& edge_id_map) { num_edges_ = edge_id_map.size(); edge_src_nodes_ = clean_and_reorder_values(edge_src_nodes_, edge_id_map); edge_sink_nodes_ = clean_and_reorder_values(edge_sink_nodes_, edge_id_map); edge_switches_ = clean_and_reorder_values(edge_switches_, edge_id_map); VTR_ASSERT(validate_edge_sizes()); } void RRGraph::rebuild_node_refs(const vtr::vector& edge_id_map) { for (size_t id = 0; id < num_nodes_; ++id) { /* Try to find if this is an invalid id or not */ if (!valid_node_id(RRNodeId(id))) { /* Skip this id */ continue; } RRNodeId node = RRNodeId(id); auto begin = node_edges_[node].get(); auto end = begin + node_num_in_edges_[node] + node_num_out_edges_[node]; update_valid_refs(begin, end, edge_id_map); VTR_ASSERT_MSG(all_valid(begin, end), "All Ids should be valid"); } } /* Empty all the vectors related to nodes */ void RRGraph::clear_nodes() { num_nodes_ = 0; node_types_.clear(); node_bounding_boxes_.clear(); node_capacities_.clear(); node_ptc_nums_.clear(); node_cost_indices_.clear(); node_directions_.clear(); node_sides_.clear(); node_Rs_.clear(); node_Cs_.clear(); node_segments_.clear(); node_num_in_edges_.clear(); node_num_out_edges_.clear(); node_num_non_configurable_in_edges_.clear(); node_num_non_configurable_out_edges_.clear(); node_edges_.clear(); /* clean node_look_up */ node_lookup_.clear(); } /* Empty all the vectors related to edges */ void RRGraph::clear_edges() { num_edges_ = 0; edge_src_nodes_.clear(); edge_sink_nodes_.clear(); edge_switches_.clear(); } /* Empty all the vectors related to switches */ void RRGraph::clear_switches() { switch_ids_.clear(); switches_.clear(); } /* Empty all the vectors related to segments */ void RRGraph::clear_segments() { segment_ids_.clear(); segments_.clear(); } /* Clean the rr_graph */ void RRGraph::clear() { clear_nodes(); clear_edges(); clear_switches(); clear_segments(); }