OpenFPGA/vpr/src/device/rr_graph_obj.cpp

1507 lines
51 KiB
C++
Raw Normal View History

/************************************************************************
* Member Functions of RRGraph
* include mutators, accessors and utility functions
***********************************************************************/
#include <cmath>
#include <algorithm>
#include <map>
#include <limits>
#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 {
2020-02-03 15:40:04 -06:00
/* Special for SOURCE and SINK node, we always return the xlow
* This is due to the convention in creating RRGraph
* so that we can guarantee unique SOURCE/SINK nodes searching
*/
if ( (SOURCE == node_type(node))
|| (SINK == node_type(node)) ) {
2020-02-03 15:40:04 -06:00
return node_bounding_box(node).xmin();
}
return node_bounding_box(node).xmax();
}
short RRGraph::node_yhigh(const RRNodeId& node) const {
if ( (SOURCE == node_type(node))
|| (SINK == node_type(node)) ) {
2020-02-03 15:40:04 -06:00
return node_bounding_box(node).ymin();
}
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<short> 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<short> 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<short> 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<short> 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<short> 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<RREdgeId> RRGraph::find_edges(const RRNodeId& src_node, const RRNodeId& sink_node) const {
std::vector<RREdgeId> 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 */
/* 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 */
/* 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 */
/* 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 */
/* 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) {
VTR_ASSERT(valid_node_id(source));
VTR_ASSERT(valid_node_id(sink));
//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));
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_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<short>& 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<RREdgeId[]>(node_num_in_edges_[node] + node_num_out_edges_[node]);
}
//Insert the edges into the node lists
{
vtr::vector<RRNodeId, int> 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<short> 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);
2020-02-03 15:40:04 -06:00
/* Special for SOURCE and SINK, we should annotate in the look-up
* for all the (x,y) upto (xhigh, yhigh)
*/
std::vector<size_t> xlows;
std::vector<size_t> ylows;
if ( (SOURCE == node_type(node))
|| (SINK == node_type(node))
|| (CHANX == node_type(node))
|| (CHANY == node_type(node)) ) {
2020-02-03 15:40:04 -06:00
xlows.resize(node_bounding_boxes_[node].xmax() - node_bounding_boxes_[node].xmin() + 1);
ylows.resize(node_bounding_boxes_[node].ymax() - node_bounding_boxes_[node].ymin() + 1);
std::iota(xlows.begin(), xlows.end(), node_xlow(node));
std::iota(ylows.begin(), ylows.end(), node_ylow(node));
/* Sanity check */
VTR_ASSERT(size_t(node_bounding_boxes_[node].xmax()) == xlows.back());
VTR_ASSERT(size_t(node_bounding_boxes_[node].ymax()) == ylows.back());
2020-02-03 15:40:04 -06:00
} else {
xlows.push_back(node_xlow(node));
ylows.push_back(node_ylow(node));
}
2020-02-03 15:40:04 -06:00
for (size_t x : xlows) {
for (size_t y : ylows) {
size_t itype = node_type(node);
2020-02-03 15:40:04 -06:00
size_t ptc = node_ptc_num(node);
if (ptc >= node_lookup_[x][y][itype].size()) {
node_lookup_[x][y][itype].resize(ptc + 1);
}
2020-02-03 15:40:04 -06:00
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<RRNodeId, RRNodeId> node_id_map(num_nodes_);
vtr::vector<RREdgeId, RREdgeId> 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<RRNodeId, RRNodeId>& node_id_map,
vtr::vector<RREdgeId, RREdgeId>& edge_id_map) {
/* Build node ids including invalid ids and compress */
vtr::vector<RRNodeId, RRNodeId> 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<RREdgeId, RREdgeId> 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<RRNodeId, RRNodeId>& 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<RREdgeId, RREdgeId>& 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<RREdgeId, RREdgeId>& 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();
}