diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index 153fd981e..c72a57378 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -163,9 +163,10 @@ enum e_interconnect { COMPLETE_INTERC = 1, DIRECT_INTERC = 2, MUX_INTERC = 3, - NUM_INTERC_TYPES + NUM_INTERC_TYPES /* Xifan Tang - Invalid types for interconnect */ }; -constexpr std::array INTERCONNECT_TYPE_STRING = {{"complete", "direct", "mux"}}; //String versions of interconnection type +/* Xifan Tang - String versions of interconnection type */ +constexpr std::array INTERCONNECT_TYPE_STRING = {{"complete", "direct", "mux"}}; /* Orientations. */ enum e_side : unsigned char { diff --git a/libs/libvtrutil/src/vtr_geometry.tpp b/libs/libvtrutil/src/vtr_geometry.tpp index 608b09c4c..f0151df2a 100644 --- a/libs/libvtrutil/src/vtr_geometry.tpp +++ b/libs/libvtrutil/src/vtr_geometry.tpp @@ -79,6 +79,12 @@ Rect::Rect(Point bottom_left_val, Point top_right_val) //pass } +template +Rect::Rect() { + //pass +} + + template T Rect::xmin() const { return bottom_left_.x(); diff --git a/libs/libvtrutil/stWnhl1a b/libs/libvtrutil/stWnhl1a deleted file mode 100644 index e69de29bb..000000000 diff --git a/openfpga/test_script/s298_k6_frac.openfpga b/openfpga/test_script/s298_k6_frac.openfpga index 22e74cdb1..fa3dcf993 100644 --- a/openfpga/test_script/s298_k6_frac.openfpga +++ b/openfpga/test_script/s298_k6_frac.openfpga @@ -1,5 +1,5 @@ # Run VPR for the s298 design -vpr ./test_vpr_arch/k6_frac_N10_40nm.xml ./test_blif/s298.blif +vpr ./test_vpr_arch/k6_frac_N10_40nm.xml ./test_blif/s298.blif --write_rr_graph example_rr_graph.xml # Read OpenFPGA architecture definition read_openfpga_arch -f ./test_openfpga_arch/k6_frac_N10_40nm_openfpga.xml diff --git a/vpr/src/base/vpr_context.h b/vpr/src/base/vpr_context.h index b6a1f9859..2a99e9351 100644 --- a/vpr/src/base/vpr_context.h +++ b/vpr/src/base/vpr_context.h @@ -22,6 +22,8 @@ #include "place_macro.h" #include "compressed_grid.h" +#include "rr_graph_obj.h" + //A Context is collection of state relating to a particular part of VPR // //This is a base class who's only purpose is to disable copying of contexts. @@ -143,6 +145,9 @@ struct DeviceContext : public Context { /* chan_width is for x|y-directed channels; i.e. between rows */ t_chan_width chan_width; + /* RRGraph object */ + RRGraph rr_graph; + /* Structures to define the routing architecture of the FPGA. */ std::vector rr_nodes; /* autogenerated in build_rr_graph */ diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index e6c010f73..cb38f75ee 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -40,6 +40,9 @@ #include "vtr_flat_map.h" #include "vtr_cache.h" +/* Header for rr_graph related definition */ +#include "rr_graph_types.h" + /******************************************************************************* * Global data types and constants ******************************************************************************/ @@ -1011,15 +1014,6 @@ struct t_det_routing_arch { std::string write_rr_graph_filename; }; -enum e_direction : unsigned char { - INC_DIRECTION = 0, - DEC_DIRECTION = 1, - BI_DIRECTION = 2, - NO_DIRECTION = 3, - NUM_DIRECTIONS -}; - -constexpr std::array DIRECTION_STRING = {{"INC_DIRECTION", "DEC_DIRECTION", "BI_DIRECTION", "NO_DIRECTION"}}; /* Lists detailed information about segmentation. [0 .. W-1]. * * length: length of segment. * @@ -1132,26 +1126,6 @@ struct t_linked_f_pointer { typedef std::vector>>>> t_rr_node_indices; //[0..num_rr_types-1][0..grid_width-1][0..grid_height-1][0..NUM_SIDES-1][0..max_ptc-1] -/* Type of a routing resource node. x-directed channel segment, * - * y-directed channel segment, input pin to a clb to pad, output * - * from a clb or pad (i.e. output pin of a net) and: * - * SOURCE: A dummy node that is a logical output within a block * - * -- i.e., the gate that generates a signal. * - * SINK: A dummy node that is a logical input within a block * - * -- i.e. the gate that needs a signal. */ -typedef enum e_rr_type : unsigned char { - SOURCE = 0, - SINK, - IPIN, - OPIN, - CHANX, - CHANY, - NUM_RR_TYPES -} t_rr_type; - -constexpr std::array RR_TYPES = {{SOURCE, SINK, IPIN, OPIN, CHANX, CHANY}}; -constexpr std::array rr_node_typename{{"SOURCE", "SINK", "IPIN", "OPIN", "CHANX", "CHANY"}}; - /* Basic element used to store the traceback (routing) of each net. * * index: Array index (ID) of this routing resource node. * * iswitch: Index of the switch type used to go from this rr_node to * diff --git a/vpr/src/device/check_rr_graph_obj.cpp b/vpr/src/device/check_rr_graph_obj.cpp index 253092fb7..69c772fcb 100644 --- a/vpr/src/device/check_rr_graph_obj.cpp +++ b/vpr/src/device/check_rr_graph_obj.cpp @@ -107,7 +107,7 @@ static bool check_rr_graph_source_nodes(const RRGraph& rr_graph) { } } - return invalid_sources; + return !invalid_sources; } /*********************************************************************** @@ -136,7 +136,7 @@ static bool check_rr_graph_sink_nodes(const RRGraph& rr_graph) { } } - return invalid_sinks; + return !invalid_sinks; } /*********************************************************************** @@ -153,48 +153,43 @@ static bool check_rr_graph_sink_nodes(const RRGraph& rr_graph) { * will work properly. **********************************************************************/ bool check_rr_graph(const RRGraph& rr_graph) { - bool check_flag = true; size_t num_err = 0; if (false == check_rr_graph_duplicated_edges(rr_graph)) { VTR_LOG_WARN("Fail in checking duplicated edges !\n"); - check_flag = false; num_err++; } if (false == check_rr_graph_dangling_nodes(rr_graph)) { VTR_LOG_WARN("Fail in checking dangling nodes !\n"); - check_flag = false; num_err++; } if (false == check_rr_graph_source_nodes(rr_graph)) { VTR_LOG_WARN("Fail in checking source nodes!\n"); - check_flag = false; num_err++; } if (false == check_rr_graph_sink_nodes(rr_graph)) { VTR_LOG_WARN("Fail in checking sink nodes!\n"); - check_flag = false; num_err++; } if (false == check_rr_graph_source_nodes(rr_graph)) { VTR_LOG_WARN("Fail in checking source nodes!\n"); - check_flag = false; num_err++; } if (false == check_rr_graph_sink_nodes(rr_graph)) { VTR_LOG_WARN("Fail in checking sink nodes!\n"); - check_flag = false; num_err++; } /* Error out if there is any fatal errors found */ - VTR_LOG_WARN("Checked Routing Resource graph with %d errors !\n", - num_err); + if (0 < num_err) { + VTR_LOG_WARN("Checked Routing Resource graph with %d errors !\n", + num_err); + } - return check_flag; + return (0 == num_err); } diff --git a/vpr/src/device/create_rr_graph.cpp b/vpr/src/device/create_rr_graph.cpp new file mode 100644 index 000000000..4ec054a52 --- /dev/null +++ b/vpr/src/device/create_rr_graph.cpp @@ -0,0 +1,138 @@ +/* Standard header files required go first */ +#include + +/* EXTERNAL library header files go second*/ +#include "vtr_assert.h" +#include "vtr_time.h" +#include "vtr_memory.h" + +/* VPR header files go then */ +#include "vpr_types.h" +#include "rr_graph_obj.h" +#include "check_rr_graph_obj.h" +#include "create_rr_graph.h" + +/* Finally we include global variables */ +#include "globals.h" + +/******************************************************************** + * TODO: remove when this conversion (from traditional to new data structure) + * is no longer needed + * This function will convert an existing rr_graph in device_ctx to the RRGraph + *object + * This function is used to test our RRGraph if it is acceptable in downstream + *routers + ********************************************************************/ +void convert_rr_graph(std::vector& vpr_segments) { + /* Release freed memory before start building rr_graph */ + vtr::malloc_trim(0); + + vtr::ScopedStartFinishTimer timer("Conversion to routing resource graph object"); + + /* IMPORTANT: to build clock tree, + * vpr added segments to the original arch segments + * This is why to use vpr_segments as an inputs!!! + */ + auto& device_ctx = g_vpr_ctx.mutable_device(); + + /* The number of switches are in general small, + * reserve switches may not bring significant memory efficiency + * So, we just use create_switch to push_back each time + */ + device_ctx.rr_graph.reserve_switches(device_ctx.rr_switch_inf.size()); + // Create the switches + for (size_t iswitch = 0; iswitch < device_ctx.rr_switch_inf.size(); ++iswitch) { + device_ctx.rr_graph.create_switch(device_ctx.rr_switch_inf[iswitch]); + } + + /* The number of segments are in general small, reserve segments may not bring + * significant memory efficiency */ + device_ctx.rr_graph.reserve_segments(vpr_segments.size()); + // Create the segments + for (size_t iseg = 0; iseg < vpr_segments.size(); ++iseg) { + device_ctx.rr_graph.create_segment(vpr_segments[iseg]); + } + + /* Reserve list of nodes to be memory efficient */ + device_ctx.rr_graph.reserve_nodes((unsigned long)device_ctx.rr_nodes.size()); + + // Create the nodes + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { + auto& node = device_ctx.rr_nodes[inode]; + RRNodeId rr_node = device_ctx.rr_graph.create_node(node.type()); + + device_ctx.rr_graph.set_node_xlow(rr_node, node.xlow()); + device_ctx.rr_graph.set_node_ylow(rr_node, node.ylow()); + device_ctx.rr_graph.set_node_xhigh(rr_node, node.xhigh()); + device_ctx.rr_graph.set_node_yhigh(rr_node, node.yhigh()); + + device_ctx.rr_graph.set_node_capacity(rr_node, node.capacity()); + + device_ctx.rr_graph.set_node_ptc_num(rr_node, node.ptc_num()); + + device_ctx.rr_graph.set_node_cost_index(rr_node, node.cost_index()); + + if (CHANX == node.type() || CHANY == node.type()) { + device_ctx.rr_graph.set_node_direction(rr_node, node.direction()); + } + if (IPIN == node.type() || OPIN == node.type()) { + device_ctx.rr_graph.set_node_side(rr_node, node.side()); + } + device_ctx.rr_graph.set_node_R(rr_node, node.R()); + device_ctx.rr_graph.set_node_C(rr_node, node.C()); + + /* Set up segment id */ + short irc_data = node.cost_index(); + short iseg = device_ctx.rr_indexed_data[irc_data].seg_index; + device_ctx.rr_graph.set_node_segment(rr_node, RRSegmentId(iseg)); + } + + /* Reserve list of edges to be memory efficient */ + unsigned long num_edges_to_reserve = 0; + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { + const auto& node = device_ctx.rr_nodes[inode]; + num_edges_to_reserve += node.num_edges(); + } + device_ctx.rr_graph.reserve_edges(num_edges_to_reserve); + + /* Add edges for each node */ + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { + const auto& node = device_ctx.rr_nodes[inode]; + for (int iedge = 0; iedge < node.num_edges(); ++iedge) { + size_t isink_node = node.edge_sink_node(iedge); + int iswitch = node.edge_switch(iedge); + + device_ctx.rr_graph.create_edge(RRNodeId(inode), + RRNodeId(isink_node), + RRSwitchId(iswitch)); + } + } + + /* Ensure that we reserved what we want */ + VTR_ASSERT(num_edges_to_reserve == (unsigned long)device_ctx.rr_graph.edges().size()); + + /* Partition edges to be two class: configurable (1st part) and + * non-configurable (2nd part) + * See how the router will use the edges and determine the strategy + * if we want to partition the edges first or depends on the routing needs + */ + device_ctx.rr_graph.rebuild_node_edges(); + + /* Essential check for rr_graph, build look-up and */ + if (false == device_ctx.rr_graph.validate()) { + /* Error out if built-in validator of rr_graph fails */ + vpr_throw(VPR_ERROR_ROUTE, + __FILE__, + __LINE__, + "Fundamental errors occurred when validating rr_graph object!\n"); + } + + /* Error out if advanced checker of rr_graph fails */ + if (false == check_rr_graph(device_ctx.rr_graph)) { + vpr_throw(VPR_ERROR_ROUTE, + __FILE__, + __LINE__, + "Advanced checking rr_graph object fails! Routing may still work " + "but not smooth\n"); + } +} diff --git a/vpr/src/device/create_rr_graph.h b/vpr/src/device/create_rr_graph.h new file mode 100644 index 000000000..5cc57ec92 --- /dev/null +++ b/vpr/src/device/create_rr_graph.h @@ -0,0 +1,17 @@ +#ifndef CREATE_RR_GRAPH_H +#define CREATE_RR_GRAPH_H + +/* + * Notes in include header files in a head file + * Only include the neccessary header files + * that is required by the data types in the function/class declarations! + */ +#include "rr_graph_obj.h" + +/* IMPORTANT: to build clock tree, + * vpr added segments to the original arch segments + * This is why to use vpr_segments as an inputs!!! + */ +void convert_rr_graph(std::vector& vpr_segments); + +#endif diff --git a/vpr/src/device/rr_graph_obj.cpp b/vpr/src/device/rr_graph_obj.cpp index 0cd9c49e8..316bc6e87 100644 --- a/vpr/src/device/rr_graph_obj.cpp +++ b/vpr/src/device/rr_graph_obj.cpp @@ -7,6 +7,7 @@ #include #include +#include "vtr_geometry.h" #include "vtr_vector_map.h" #include "vtr_log.h" #include "vtr_util.h" @@ -14,13 +15,26 @@ #include "rr_graph_obj.h" #include "rr_graph_obj_utils.h" -//Accessors -RRGraph::node_range RRGraph::nodes() const { - return vtr::make_range(node_ids_.begin(), node_ids_.end()); +/******************************************************************** + * Constructors + *******************************************************************/ +RRGraph::RRGraph() + : num_nodes_(0) + , num_edges_(0) { + //Pass } -RRGraph::edge_range RRGraph::edges() const { - return vtr::make_range(edge_ids_.begin(), edge_ids_.end()); +/******************************************************************** + * 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 { @@ -117,11 +131,11 @@ vtr::Point RRGraph::node_end_coordinate(const RRNodeId& node) const { } short RRGraph::node_fan_in(const RRNodeId& node) const { - return node_in_edges(node).size(); + return node_num_in_edges_[node]; } short RRGraph::node_fan_out(const RRNodeId& node) const { - return node_out_edges(node).size(); + return node_num_out_edges_[node]; } short RRGraph::node_capacity(const RRNodeId& node) const { @@ -189,118 +203,65 @@ RRSegmentId RRGraph::node_segment(const RRNodeId& node) const { return node_segments_[node]; } -/* - * Get the number of configurable input edges of a node - * TODO: we would use the node_num_configurable_in_edges() - * when the rr_graph edges have been partitioned - * This can avoid unneccessary walkthrough - */ -short RRGraph::node_num_configurable_in_edges(const RRNodeId& node) const { - return node_configurable_in_edges(node).size(); +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]); } -/* - * Get the number of configurable output edges of a node - * TODO: we would use the node_num_configurable_out_edges() - * when the rr_graph edges have been partitioned - * This can avoid unneccessary walkthrough - */ -short RRGraph::node_num_configurable_out_edges(const RRNodeId& node) const { - return node_configurable_out_edges(node).size(); +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]); } -/* - * Get the number of non-configurable input edges of a node - * TODO: we would use the node_num_configurable_in_edges() - * when the rr_graph edges have been partitioned - * This can avoid unneccessary walkthrough - */ -short RRGraph::node_num_non_configurable_in_edges(const RRNodeId& node) const { - return node_non_configurable_in_edges(node).size(); -} +RRGraph::edge_range RRGraph::node_out_edges(const RRNodeId& node) const { + VTR_ASSERT_SAFE(valid_node_id(node)); -/* - * Get the number of non-configurable output edges of a node - * TODO: we would use the node_num_configurable_out_edges() - * when the rr_graph edges have been partitioned - * This can avoid unneccessary walkthrough - */ -short RRGraph::node_num_non_configurable_out_edges(const RRNodeId& node) const { - return node_non_configurable_out_edges(node).size(); + 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 { - /* Make sure we will access a valid node */ VTR_ASSERT_SAFE(valid_node_id(node)); - /* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */ - auto begin = node_in_edges(node).begin(); - - /* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */ - auto end = node_in_edges(node).end() - node_num_non_configurable_in_edges_[node]; - - return vtr::make_range(begin, end); + 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 configurable edges from the input edges of a given 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 { - /* Make sure we will access a valid node */ VTR_ASSERT_SAFE(valid_node_id(node)); - /* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */ - auto begin = node_in_edges(node).end() - node_num_non_configurable_in_edges_[node]; - - /* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */ - auto end = node_in_edges(node).end(); - - return vtr::make_range(begin, end); + 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 input edges of a given 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 { - /* Make sure we will access a valid node */ VTR_ASSERT_SAFE(valid_node_id(node)); - /* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */ - auto begin = node_out_edges(node).begin(); - - /* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */ - auto end = node_out_edges(node).end() - node_num_non_configurable_out_edges_[node]; - - return vtr::make_range(begin, end); + 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 configurable edges from the input edges of a given 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 { - /* Make sure we will access a valid node */ VTR_ASSERT_SAFE(valid_node_id(node)); - /* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */ - auto begin = node_out_edges(node).end() - node_num_non_configurable_out_edges_[node]; - - /* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */ - auto end = node_out_edges(node).end(); - - return vtr::make_range(begin, end); -} - -RRGraph::edge_range RRGraph::node_out_edges(const RRNodeId& node) const { - VTR_ASSERT_SAFE(valid_node_id(node)); - return vtr::make_range(node_out_edges_[node].begin(), node_out_edges_[node].end()); -} - -RRGraph::edge_range RRGraph::node_in_edges(const RRNodeId& node) const { - VTR_ASSERT_SAFE(valid_node_id(node)); - return vtr::make_range(node_in_edges_[node].begin(), node_in_edges_[node].end()); + 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 @@ -391,22 +352,22 @@ RRNodeId RRGraph::find_node(const short& x, const short& y, const t_rr_type& typ 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_.size() - 1)) { /* See if x is large than the index of last element */ + 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_[x].size() - 1)) { /* See if y is large than the index of last element */ + 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_[x][y].size() - 1) { /* See if type is large than the index of last element */ + 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(); } @@ -436,21 +397,21 @@ short RRGraph::chan_num_tracks(const short& x, const short& y, const t_rr_type& 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_.size() - 1)) { /* See if x is large than the index of last element */ + 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_[x].size() - 1)) { /* See if y is large than the index of last element */ + 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_[x][y].size() - 1)) { /* See if type is large than the index of last element */ + 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; } @@ -488,15 +449,20 @@ bool RRGraph::validate_node_segment(const RRNodeId& node) const { /* Check if the segment id of every node is in range */ bool RRGraph::validate_node_segments() const { bool all_valid = true; - for (auto node : nodes()) { - if (true == validate_node_segment(node)) { + 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", - size_t(node), size_t(node_segment(node))); + id, size_t(node_segment(RRNodeId(id)))); } return all_valid; } @@ -510,15 +476,20 @@ bool RRGraph::validate_edge_switch(const RREdgeId& edge) const { /* Check if the switch id of every edge is in range */ bool RRGraph::validate_edge_switches() const { bool all_valid = true; - for (auto edge : edges()) { - if (true == validate_edge_switch(edge)) { + 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", - size_t(edge), size_t(edge_switch(edge))); + id, size_t(edge_switch(RREdgeId(id)))); } return all_valid; } @@ -622,8 +593,13 @@ bool RRGraph::validate_node_edges(const RRNodeId& node) const { /* check if all the nodes' input edges are valid */ bool RRGraph::validate_nodes_in_edges() const { bool all_valid = true; - for (auto node : nodes()) { - if (true == validate_node_in_edges(node)) { + 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! @@ -637,8 +613,13 @@ bool RRGraph::validate_nodes_in_edges() const { /* check if all the nodes' output edges are valid */ bool RRGraph::validate_nodes_out_edges() const { bool all_valid = true; - for (auto node : nodes()) { - if (true == validate_node_out_edges(node)) { + 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! @@ -676,15 +657,20 @@ bool RRGraph::validate_edge_sink_node(const RREdgeId& edge) const { /* Check if source nodes of a edge are all valid */ bool RRGraph::validate_edge_src_nodes() const { bool all_valid = true; - for (auto edge : edges()) { - if (true == validate_edge_src_node(edge)) { + 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", - size_t(edge), size_t(edge_src_node(edge))); + id, size_t(edge_src_node(RREdgeId(id)))); all_valid = false; } return all_valid; @@ -693,15 +679,20 @@ bool RRGraph::validate_edge_src_nodes() const { /* Check if source nodes of a edge are all valid */ bool RRGraph::validate_edge_sink_nodes() const { bool all_valid = true; - for (auto edge : edges()) { - if (true == validate_edge_sink_node(edge)) { + 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", - size_t(edge), size_t(edge_sink_node(edge))); + id, size_t(edge_sink_node(RREdgeId(id)))); all_valid = false; } return all_valid; @@ -714,7 +705,6 @@ bool RRGraph::validate_edge_sink_nodes() const { * Warnings are thrown if optional checking fails */ bool RRGraph::validate() const { - bool check_flag = true; size_t num_err = 0; initialize_fast_node_lookup(); @@ -724,34 +714,32 @@ bool RRGraph::validate() const { */ if (false == validate_sizes()) { VTR_LOG_WARN("Fail in validating node- and edge-related vector sizes!\n"); - check_flag = false; num_err++; } /* Fundamental check */ if (false == validate_nodes_edges()) { VTR_LOG_WARN("Fail in validating edges connected to each node!\n"); - check_flag = false; num_err++; } if (false == validate_node_segments()) { VTR_LOG_WARN("Fail in validating segment IDs of nodes !\n"); - check_flag = false; num_err++; } if (false == validate_edge_switches()) { VTR_LOG_WARN("Fail in validating switch IDs of edges !\n"); - check_flag = false; num_err++; } /* Error out if there is any fatal errors found */ - VTR_LOG_ERROR("Routing Resource graph is not valid due to %d fatal errors !\n", - num_err); + if (0 < num_err) { + VTR_LOG_ERROR("Routing Resource graph is not valid due to %d fatal errors !\n", + num_err); + } - return check_flag; + return (0 == num_err); } bool RRGraph::is_dirty() const { @@ -767,55 +755,58 @@ void RRGraph::clear_dirty() { } /* Reserve a list of nodes */ -void RRGraph::reserve_nodes(const int& num_nodes) { +void RRGraph::reserve_nodes(const unsigned long& num_nodes) { /* Reserve the full set of vectors related to nodes */ /* Basic information */ - this->node_ids_.reserve(num_nodes); 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_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); - - /* Edge-relate vectors */ - this->node_in_edges_.reserve(num_nodes); - this->node_out_edges_.reserve(num_nodes); + this->node_edges_.reserve(num_nodes); } /* Reserve a list of edges */ -void RRGraph::reserve_edges(const int& num_edges) { +void RRGraph::reserve_edges(const unsigned long& num_edges) { /* Reserve the full set of vectors related to edges */ - this->edge_ids_.reserve(num_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 int& num_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 int& num_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(node_ids_.size()); + /* Allocate an ID */ + RRNodeId node_id = RRNodeId(num_nodes_); + /* Expand range of node ids */ + num_nodes_++; - //Initialize the attributes - node_ids_.push_back(node_id); + /* Initialize the attributes */ node_types_.push_back(type); node_bounding_boxes_.emplace_back(-1, -1, -1, -1); @@ -827,12 +818,14 @@ RRNodeId RRGraph::create_node(const t_rr_type& type) { node_sides_.push_back(NUM_SIDES); node_Rs_.push_back(0.); node_Cs_.push_back(0.); + node_segments_.push_back(RRSegmentId::INVALID()); - node_in_edges_.emplace_back(); //Initially empty - node_out_edges_.emplace_back(); //Initially empty + node_edges_.emplace_back(); //Initially empty - node_num_non_configurable_in_edges_.emplace_back(); //Initially empty - node_num_non_configurable_out_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(); @@ -846,19 +839,20 @@ RREdgeId RRGraph::create_edge(const RRNodeId& source, const RRNodeId& sink, cons VTR_ASSERT(valid_node_id(sink)); VTR_ASSERT(valid_switch_id(switch_id)); - //Allocate an ID - RREdgeId edge_id = RREdgeId(edge_ids_.size()); - - //Initialize the attributes - edge_ids_.push_back(edge_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); - //Add the edge to the nodes - node_out_edges_[source].push_back(edge_id); - node_in_edges_[sink].push_back(edge_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()); @@ -902,7 +896,7 @@ void RRGraph::remove_node(const RRNodeId& node) { } //Mark node invalid - node_ids_[node] = RRNodeId::INVALID(); + invalid_node_ids_.insert(node); //Invalidate the node look-up invalidate_fast_node_lookup(); @@ -918,23 +912,24 @@ 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_out_edges_[src_node].size(); ++i) { - if (node_out_edges_[src_node][i] == edge) { - node_out_edges_[src_node][i] = RREdgeId::INVALID(); + /* 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 = 0; i < node_in_edges_[sink_node].size(); ++i) { - if (node_in_edges_[sink_node][i] == edge) { - node_in_edges_[sink_node][i] = RREdgeId::INVALID(); + 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 - edge_ids_[edge] = RREdgeId::INVALID(); + /* Mark edge invalid */ + invalid_edge_ids_.insert(edge); set_dirty(); } @@ -1047,94 +1042,154 @@ void RRGraph::set_node_segment(const RRNodeId& node, const RRSegmentId& segment_ 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); -/* For a given node in a rr_graph - * classify the edges of each node to be configurable (1st part) and non-configurable (2nd part) - */ -void RRGraph::partition_node_in_edges(const RRNodeId& node) { - //Partition the edges so the first set of edges are all configurable, and the later are not - auto first_non_config_edge = std::partition(node_in_edges_[node].begin(), node_in_edges_[node].end(), - [&](const RREdgeId edge) { return edge_is_configurable(edge); }); /* Condition to partition edges */ + //Count the number of edges of each type + for (RREdgeId edge : edges()) { + if (!edge) continue; - size_t num_conf_edges = std::distance(node_in_edges_[node].begin(), first_non_config_edge); - size_t num_non_conf_edges = node_in_edges_[node].size() - num_conf_edges; //Note we calculate using the size_t to get full range + RRNodeId src_node = edge_src_node(edge); + RRNodeId sink_node = edge_sink_node(edge); + bool config = edge_is_configurable(edge); - /* Check that within allowable range (no overflow when stored as num_non_configurable_edges_ - */ - VTR_ASSERT_MSG(num_non_conf_edges <= node_in_edges_[node].size(), - "Exceeded RR node maximum number of non-configurable input edges"); - - node_num_non_configurable_in_edges_[node] = num_non_conf_edges; //Narrowing -} - -/* For a given node in a rr_graph - * classify the edges of each node to be configurable (1st part) and non-configurable (2nd part) - */ -void RRGraph::partition_node_out_edges(const RRNodeId& node) { - //Partition the edges so the first set of edges are all configurable, and the later are not - auto first_non_config_edge = std::partition(node_out_edges_[node].begin(), node_out_edges_[node].end(), - [&](const RREdgeId edge) { return edge_is_configurable(edge); }); /* Condition to partition edges */ - - size_t num_conf_edges = std::distance(node_out_edges_[node].begin(), first_non_config_edge); - size_t num_non_conf_edges = node_out_edges_[node].size() - num_conf_edges; //Note we calculate using the size_t to get full range - - /* Check that within allowable range (no overflow when stored as num_non_configurable_edges_ - */ - VTR_ASSERT_MSG(num_non_conf_edges <= node_out_edges_[node].size(), - "Exceeded RR node maximum number of non-configurable output edges"); - - node_num_non_configurable_out_edges_[node] = num_non_conf_edges; //Narrowing -} - -/* For all nodes in a rr_graph - * classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) - */ -void RRGraph::partition_in_edges() { - /* For each node */ - for (auto node : nodes()) { - this->partition_node_in_edges(node); + ++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]; + } } -} -/* For all nodes in a rr_graph - * classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) - */ -void RRGraph::partition_out_edges() { - /* For each node */ - for (auto node : nodes()) { - this->partition_node_out_edges(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]); } -} -/* For all nodes in a rr_graph - * classify both input and output edges of each node - * to be configurable (1st part) and non-configurable (2nd part) - */ -void RRGraph::partition_edges() { - /* Partition input edges */ - this->partition_in_edges(); - /* Partition output edges */ - this->partition_out_edges(); + //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(); - for (auto node : nodes()) { + /* 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(), node_xlow(RRNodeId(id)))); + max_coord.set_y(std::max(max_coord.y(), node_ylow(RRNodeId(id)))); + } + 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); size_t x = node_xlow(node); - if (x >= node_lookup_.size()) { - node_lookup_.resize(x + 1); - } - size_t y = node_ylow(node); - if (y >= node_lookup_[x].size()) { - node_lookup_[x].resize(y + 1); - } - size_t itype = node_type(node); - if (itype >= node_lookup_[x][y].size()) { - node_lookup_[x][y].resize(itype + 1); - } size_t ptc = node_ptc_num(node); if (ptc >= node_lookup_[x][y][itype].size()) { @@ -1172,11 +1227,13 @@ void RRGraph::initialize_fast_node_lookup() const { } bool RRGraph::valid_node_id(const RRNodeId& node) const { - return size_t(node) < node_ids_.size() && node_ids_[node] == node; + return (size_t(node) < num_nodes_) + && (!invalid_node_ids_.count(node)); } bool RRGraph::valid_edge_id(const RREdgeId& edge) const { - return size_t(edge) < edge_ids_.size() && edge_ids_[edge] == edge; + return (size_t(edge) < num_edges_) + && (!invalid_edge_ids_.count(edge)); } /* check if a given switch id is valid or not */ @@ -1205,26 +1262,25 @@ bool RRGraph::validate_sizes() const { } bool RRGraph::validate_node_sizes() const { - return node_types_.size() == node_ids_.size() - && node_bounding_boxes_.size() == node_ids_.size() - && node_capacities_.size() == node_ids_.size() - && node_ptc_nums_.size() == node_ids_.size() - && node_cost_indices_.size() == node_ids_.size() - && node_directions_.size() == node_ids_.size() - && node_sides_.size() == node_ids_.size() - && node_Rs_.size() == node_ids_.size() - && node_Cs_.size() == node_ids_.size() - && node_segments_.size() == node_ids_.size() - && node_num_non_configurable_in_edges_.size() == node_ids_.size() - && node_num_non_configurable_out_edges_.size() == node_ids_.size() - && node_in_edges_.size() == node_ids_.size() - && node_out_edges_.size() == node_ids_.size(); + 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() == edge_ids_.size() - && edge_sink_nodes_.size() == edge_ids_.size() - && edge_switches_.size() == edge_ids_.size(); + return edge_src_nodes_.size() == num_edges_ + && edge_sink_nodes_.size() == num_edges_ + && edge_switches_.size() == num_edges_; } bool RRGraph::validate_switch_sizes() const { @@ -1236,8 +1292,8 @@ bool RRGraph::validate_segment_sizes() const { } void RRGraph::compress() { - vtr::vector node_id_map(node_ids_.size()); - vtr::vector edge_id_map(edge_ids_.size()); + vtr::vector node_id_map(num_nodes_); + vtr::vector edge_id_map(num_edges_); build_id_maps(node_id_map, edge_id_map); @@ -1248,17 +1304,48 @@ void RRGraph::compress() { 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) { - node_id_map = compress_ids(node_ids_); - edge_id_map = compress_ids(edge_ids_); + /* 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) { - node_ids_ = clean_and_reorder_ids(node_id_map); + num_nodes_ = node_id_map.size(); node_types_ = clean_and_reorder_values(node_types_, node_id_map); @@ -1272,39 +1359,46 @@ void RRGraph::clean_nodes(const vtr::vector& 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); - VTR_ASSERT(validate_node_sizes()); + 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_MSG(are_contiguous(node_ids_), "Ids should be contiguous"); - VTR_ASSERT_MSG(all_valid(node_ids_), "All Ids should be valid"); + VTR_ASSERT(validate_node_sizes()); } void RRGraph::clean_edges(const vtr::vector& edge_id_map) { - edge_ids_ = clean_and_reorder_ids(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()); - - VTR_ASSERT_MSG(are_contiguous(edge_ids_), "Ids should be contiguous"); - VTR_ASSERT_MSG(all_valid(edge_ids_), "All Ids should be valid"); } void RRGraph::rebuild_node_refs(const vtr::vector& edge_id_map) { - for (const auto& node : nodes()) { - node_in_edges_[node] = update_valid_refs(node_in_edges_[node], edge_id_map); - node_out_edges_[node] = update_valid_refs(node_out_edges_[node], 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); - VTR_ASSERT_MSG(all_valid(node_in_edges_[node]), "All Ids should be valid"); - VTR_ASSERT_MSG(all_valid(node_out_edges_[node]), "All Ids should be valid"); + 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() { - node_ids_.clear(); - + num_nodes_ = 0; node_types_.clear(); node_bounding_boxes_.clear(); @@ -1317,11 +1411,12 @@ void RRGraph::clear_nodes() { 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_in_edges_.clear(); - node_out_edges_.clear(); + node_edges_.clear(); /* clean node_look_up */ node_lookup_.clear(); @@ -1329,7 +1424,7 @@ void RRGraph::clear_nodes() { /* Empty all the vectors related to edges */ void RRGraph::clear_edges() { - edge_ids_.clear(); + num_edges_ = 0; edge_src_nodes_.clear(); edge_sink_nodes_.clear(); edge_switches_.clear(); diff --git a/vpr/src/device/rr_graph_obj.h b/vpr/src/device/rr_graph_obj.h index f34b11162..85bf7de4b 100644 --- a/vpr/src/device/rr_graph_obj.h +++ b/vpr/src/device/rr_graph_obj.h @@ -198,30 +198,44 @@ /* Standard header files required go first */ #include #include +#include +#include /* EXTERNAL library header files go second*/ +#include "vtr_ndmatrix.h" #include "vtr_vector.h" #include "vtr_range.h" #include "vtr_geometry.h" #include "arch_types.h" /* VPR header files go third */ -#include "vpr_types.h" +#include "rr_graph_types.h" #include "rr_graph_fwd.h" class RRGraph { public: /* Types */ + //Lazy iterator utility forward declaration + template + class lazy_id_iterator; + /* Iterators used to create iterator-based loop for nodes/edges/switches/segments */ typedef vtr::vector::const_iterator node_iterator; typedef vtr::vector::const_iterator edge_iterator; typedef vtr::vector::const_iterator switch_iterator; typedef vtr::vector::const_iterator segment_iterator; + typedef lazy_id_iterator lazy_node_iterator; + typedef lazy_id_iterator lazy_edge_iterator; /* Ranges used to create range-based loop for nodes/edges/switches/segments */ typedef vtr::Range node_range; - typedef vtr::Range edge_range; + typedef vtr::Range edge_range; typedef vtr::Range switch_range; typedef vtr::Range segment_range; + typedef vtr::Range lazy_node_range; + typedef vtr::Range lazy_edge_range; + + public: /* Constructors */ + RRGraph(); public: /* Accessors */ /* Aggregates: create range-based loops for nodes/edges/switches/segments @@ -247,8 +261,8 @@ class RRGraph { * // Do something with each segment * } */ - node_range nodes() const; - edge_range edges() const; + lazy_node_range nodes() const; + lazy_edge_range edges() const; switch_range switches() const; segment_range segments() const; @@ -445,23 +459,9 @@ class RRGraph { */ RRSegmentId node_segment(const RRNodeId& node) const; - /* Get the number of non-configurable incoming edges to a node */ - short node_num_configurable_in_edges(const RRNodeId& node) const; - - /* Get the number of non-configurable outgoing edges from a node */ - short node_num_non_configurable_in_edges(const RRNodeId& node) const; - - /* Get the number of configurable output edges of a node */ - short node_num_configurable_out_edges(const RRNodeId& node) const; - - /* Get the number of non-configurable output edges of a node */ - short node_num_non_configurable_out_edges(const RRNodeId& node) const; - - /* Get the range (list) of edges related to a given node */ - edge_range node_configurable_in_edges(const RRNodeId& node) const; - edge_range node_non_configurable_in_edges(const RRNodeId& node) const; - edge_range node_configurable_out_edges(const RRNodeId& node) const; - edge_range node_non_configurable_out_edges(const RRNodeId& node) const; + //Returns an iterable range of all edges (incoming & outgoing) for + //the specified node + edge_range node_edges(const RRNodeId& node) const; /* Get a list of edge ids, which are incoming edges to a node */ edge_range node_in_edges(const RRNodeId& node) const; @@ -469,6 +469,12 @@ class RRGraph { /* Get a list of edge ids, which are outgoing edges from a node */ edge_range node_out_edges(const RRNodeId& node) const; + /* Get the range (list) of edges related to a given node */ + edge_range node_configurable_in_edges(const RRNodeId& node) const; + edge_range node_non_configurable_in_edges(const RRNodeId& node) const; + edge_range node_configurable_out_edges(const RRNodeId& node) const; + edge_range node_non_configurable_out_edges(const RRNodeId& node) const; + /* Edge-related attributes * An example to explain the terminology used in RRGraph * edgeA @@ -583,10 +589,10 @@ class RRGraph { * rr_graph.create_node(CHANX); * } */ - void reserve_nodes(const int& num_nodes); - void reserve_edges(const int& num_edges); - void reserve_switches(const int& num_switches); - void reserve_segments(const int& num_segments); + void reserve_nodes(const unsigned long& num_nodes); + void reserve_edges(const unsigned long& num_edges); + void reserve_switches(const size_t& num_switches); + void reserve_segments(const size_t& num_segments); /* Add new elements (node, edge, switch, etc.) to RRGraph */ /* Add a node to the RRGraph with a deposited type @@ -596,6 +602,7 @@ class RRGraph { * set_node_xlow(node, 0); */ RRNodeId create_node(const t_rr_type& type); + /* Add a edge to the RRGraph, by providing the source and sink node * This function will automatically create a node and * configure the nodes and edges in connection @@ -690,15 +697,14 @@ class RRGraph { /* Set the routing segment linked to a node, only applicable to CHANX and CHANY */ void set_node_segment(const RRNodeId& node, const RRSegmentId& segment_index); - /* Edge partitioning is performed for efficiency, - * so we can store configurable and non-configurable edge lists for a node in one vector, - * and efficiently iterate over all edges, or only the configurable or non-configurable subsets. - * This function will re-organize the incoming and outgoing edges of each node, - * i.e., node_in_edges() and node_out_edges(): - * 1. configurable edges (1st part of the vectors) - * 2. non-configurable edges (2nd part of the vectors) + /* + * Build the node to edge references to allow iteration through + * a node's in/out edges. + * + * Must be called before any node_*_in_edges() or node_*_out_edges() member + * functions can be called. */ - void partition_edges(); + void rebuild_node_edges(); /* Graph-level Clean-up, remove invalid nodes/edges etc. * This will clear the dirty flag (query by is_dirty()) of RRGraph object, if it was set @@ -708,18 +714,52 @@ class RRGraph { /* top-level function to free, should be called when to delete a RRGraph */ void clear(); - private: /* Internal Mutators to perform edge partitioning */ - /* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */ - void partition_node_in_edges(const RRNodeId& node); + public: /* Type implementations */ + /* + * This class (forward delcared above) is a template used to represent a lazily calculated + * iterator of the specified ID type. The key assumption made is that the ID space is + * contiguous and can be walked by incrementing the underlying ID value. To account for + * invalid IDs, it keeps a reference to the invalid ID set and returns ID::INVALID() for + * ID values in the set. + * + * It is used to lazily create an iteration range (e.g. as returned by RRGraph::edges() RRGraph::nodes()) + * just based on the count of allocated elements (i.e. RRGraph::num_nodes_ or RRGraph::num_edges_), + * and the set of any invalid IDs (i.e. RRGraph::invalid_node_ids_, RRGraph::invalid_edge_ids_). + */ + template + class lazy_id_iterator : public std::iterator { + public: + //Since we pass ID as a template to std::iterator we need to use an explicit 'typename' + //to bring the value_type and iterator names into scope + typedef typename std::iterator::value_type value_type; + typedef typename std::iterator::iterator iterator; - /* classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) */ - void partition_node_out_edges(const RRNodeId& node); + lazy_id_iterator(value_type init, const std::unordered_set& invalid_ids) + : value_(init) + , invalid_ids_(invalid_ids) {} - /* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */ - void partition_in_edges(); + //Advance to the next ID value + iterator operator++() { + value_ = ID(size_t(value_) + 1); + return *this; + } - /* classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) */ - void partition_out_edges(); + //Advance to the previous ID value + iterator operator--() { + value_ = ID(size_t(value_) - 1); + return *this; + } + + //Dereference the iterator + value_type operator*() const { return (invalid_ids_.count(value_)) ? ID::INVALID() : value_; } + + friend bool operator==(const lazy_id_iterator lhs, const lazy_id_iterator rhs) { return lhs.value_ == rhs.value_; } + friend bool operator!=(const lazy_id_iterator lhs, const lazy_id_iterator rhs) { return !(lhs == rhs); } + + private: + value_type value_; + const std::unordered_set& invalid_ids_; + }; private: /* Internal free functions */ void clear_nodes(); @@ -787,7 +827,9 @@ class RRGraph { private: /* Internal Data */ /* Node related data */ - vtr::vector node_ids_; /* Unique identifiers for the nodes */ + size_t num_nodes_; /* Range of node ids */ + std::unordered_set invalid_node_ids_; /* Invalid edge ids */ + vtr::vector node_types_; vtr::vector> node_bounding_boxes_; @@ -800,15 +842,44 @@ class RRGraph { vtr::vector node_Rs_; vtr::vector node_Cs_; vtr::vector node_segments_; /* Segment ids for each node */ - /* Record the dividing point between configurable and non-configurable edges for each node */ - vtr::vector node_num_non_configurable_in_edges_; - vtr::vector node_num_non_configurable_out_edges_; - vtr::vector> node_in_edges_; - vtr::vector> node_out_edges_; + /* + * We store the edges assoicated with each node in a single array per node (for memory efficiency). + * + * The array of edges is sorted into sub-ranges to allow for easy iteration (with node_in_edges(), + * node_non_configurable_out_edges() etc.). + * + * For a particular 'node' we store the sizes of the various sub-ranges in the node_num_* members, + * from which the delimiters for each sub-range can be calculated. + * + * + * node_edges_[node]: + * + * + * node_num_non_configurable_in_edges_[node] node_num_non_configurable_out_edges_[node] + * <-------------------> <--------------------> + * + * +------------------+---------------------+------------------+----------------------+ + * | in_edges_config | in_edges_non_config | out_edges_config | out_edges_non_config | + * +------------------+---------------------+------------------+----------------------+ + * + * <--------------------------------------> <---------------------------------------> + * node_num_in_edges_[node] node_num_out_edges_[node] + * + * All elements of node_edges_ should be initialized after all edges have been created (with create_edge()), + * by calling rebuild_node_edges(), which will allocate node_edges_, add the relevant edges and partition + * each node's arrays into the appropriate. rebuild_node_edges() also initializes all the node_num_* members + * based on the edges (created with create_edge()) in the edge_* members. + */ + vtr::vector node_num_in_edges_; + vtr::vector node_num_out_edges_; + vtr::vector node_num_non_configurable_in_edges_; + vtr::vector node_num_non_configurable_out_edges_; + vtr::vector> node_edges_; /* Edge related data */ - vtr::vector edge_ids_; /* unique identifiers for edges */ + size_t num_edges_; /* Range of edge ids */ + std::unordered_set invalid_edge_ids_; /* Invalid edge ids */ vtr::vector edge_src_nodes_; vtr::vector edge_sink_nodes_; vtr::vector edge_switches_; @@ -836,7 +907,7 @@ class RRGraph { /* Fast look-up to search a node by its type, coordinator and ptc_num * Indexing of fast look-up: [0..xmax][0..ymax][0..NUM_TYPES-1][0..ptc_max][0..NUM_SIDES-1] */ - typedef std::vector>>>> NodeLookup; + typedef vtr::NdMatrix>, 3> NodeLookup; mutable NodeLookup node_lookup_; }; diff --git a/vpr/src/device/rr_graph_obj_utils.h b/vpr/src/device/rr_graph_obj_utils.h index 910b0ce3a..5c3a8f6d6 100644 --- a/vpr/src/device/rr_graph_obj_utils.h +++ b/vpr/src/device/rr_graph_obj_utils.h @@ -38,6 +38,16 @@ bool all_valid(const Container& values) { return true; } +template +bool all_valid(Iterator begin, Iterator end) { + for (auto itr = begin; itr != end; ++itr) { + if (!*itr) { + return false; + } + } + return true; +} + //Builds a mapping from old to new ids by skipping values marked invalid template Container compress_ids(const Container& ids) { @@ -162,4 +172,20 @@ ValueContainer update_valid_refs(const ValueContainer& values, const IdContainer return updated; } +template +void update_valid_refs(Iterator begin, Iterator end, const IdContainer& id_map) { + for (auto itr = begin; itr != end; ++itr) { + auto orig_val = *itr; + if (orig_val) { + //Original item valid + + auto new_val = id_map[orig_val]; + if (new_val) { + //The original item exists in the new mapping + *itr = new_val; + } + } + } +} + #endif diff --git a/vpr/src/device/rr_graph_types.h b/vpr/src/device/rr_graph_types.h new file mode 100644 index 000000000..51cf3a0dd --- /dev/null +++ b/vpr/src/device/rr_graph_types.h @@ -0,0 +1,43 @@ +#ifndef RR_GRAPH_TYPES +#define RR_GRAPH_TYPES + +/******************************************************************** + * Data types required by routing resource graph (RRGraph) definition + *******************************************************************/ + +/******************************************************************** + * Directionality of a routing track (node type CHANX and CHANY) in + * a routing resource graph + *******************************************************************/ +enum e_direction : unsigned char { + INC_DIRECTION = 0, + DEC_DIRECTION = 1, + BI_DIRECTION = 2, + NO_DIRECTION = 3, + NUM_DIRECTIONS +}; + +constexpr std::array DIRECTION_STRING = {{"INC_DIRECTION", "DEC_DIRECTION", "BI_DIRECTION", "NO_DIRECTION"}}; + +/* Type of a routing resource node. x-directed channel segment, * + * y-directed channel segment, input pin to a clb to pad, output * + * from a clb or pad (i.e. output pin of a net) and: * + * SOURCE: A dummy node that is a logical output within a block * + * -- i.e., the gate that generates a signal. * + * SINK: A dummy node that is a logical input within a block * + * -- i.e. the gate that needs a signal. */ +typedef enum e_rr_type : unsigned char { + SOURCE = 0, + SINK, + IPIN, + OPIN, + CHANX, + CHANY, + NUM_RR_TYPES +} t_rr_type; + +constexpr std::array RR_TYPES = {{SOURCE, SINK, IPIN, OPIN, CHANX, CHANY}}; +constexpr std::array rr_node_typename{{"SOURCE", "SINK", "IPIN", "OPIN", "CHANX", "CHANY"}}; + + +#endif diff --git a/vpr/src/device/write_xml_rr_graph_obj.cpp b/vpr/src/device/write_xml_rr_graph_obj.cpp new file mode 100644 index 000000000..a329b7bc0 --- /dev/null +++ b/vpr/src/device/write_xml_rr_graph_obj.cpp @@ -0,0 +1,239 @@ +/********************************************************************* + * This file defines the writing rr graph function in XML format. + * The rr graph is separated into channels, nodes, switches, + * grids, edges, block types, and segments. Each tag has several + * children tags such as timing, location, or some general + * details. Each tag has attributes to describe them + ********************************************************************/ + +#include +#include +#include +#include +#include +#include "vpr_error.h" +#include "globals.h" +#include "read_xml_arch_file.h" +#include "vtr_version.h" +#include "rr_graph_obj.h" +#include "write_xml_rr_graph_obj.h" + +using namespace std; + +/* All values are printed with this precision value. The higher the + * value, the more accurate the read in rr graph is. Using numeric_limits + * max_digits10 guarentees that no values change during a sequence of + * float -> string -> float conversions */ +constexpr int FLOAT_PRECISION = std::numeric_limits::max_digits10; + +/*********************** External Subroutines to this module *******************/ +void write_rr_channel(fstream &fp); +void write_rr_grid(fstream &fp); +void write_rr_block_types(fstream &fp); + +/************************ Subroutine definitions ****************************/ +static +void add_metadata_to_xml(std::fstream& fp, const char* tab_prefix, const t_metadata_dict& meta) { + fp << tab_prefix << "" << std::endl; + + for (const auto& meta_elem : meta) { + const std::string& key = meta_elem.first; + const std::vector& values = meta_elem.second; + for (const auto& value : values) { + fp << tab_prefix << "\t" << value.as_string() << "" << std::endl; + } + } + fp << tab_prefix << "" << std::endl; +} + +/* All relevant rr node info is written out to the graph. + * This includes location, timing, and segment info + */ +static +void write_rr_graph_node(fstream &fp, const RRGraph& rr_graph) { + /* TODO: we should make it function full independent from device_ctx !!! */ + auto& device_ctx = g_vpr_ctx.device(); + + std::array DIRECTION_STRING_WRITE_XML = {{"INC_DIR", "DEC_DIR", "BI_DIR", "NO_DIR"}}; + + fp << "\t" << endl; + + for (auto node : rr_graph.nodes()) { + fp << "\t\t" << endl; + fp << "\t\t\t" << endl; + fp << "\t\t\t" << endl; + + if (RRSegmentId::INVALID() != rr_graph.node_segment(node)) { + fp << "\t\t\t" << endl; + } + + const auto iter = device_ctx.rr_node_metadata.find(rr_graph.node_index(node)); + if(iter != device_ctx.rr_node_metadata.end()) { + const t_metadata_dict & meta = iter->second; + add_metadata_to_xml(fp, "\t\t\t", meta); + } + + fp << "\t\t" << endl; + } + + fp << "\t" << endl << endl; + + return; +} + +/* Segment information in the t_segment_inf data structure is written out. + * Information includes segment id, name, and optional timing parameters + */ +static +void write_rr_graph_segments(fstream &fp, const RRGraph& rr_graph) { + fp << "\t" << endl; + + for (auto seg : rr_graph.segments()) { + fp << "\t\t" << endl; + fp << "\t\t\t" << endl; + fp << "\t\t" << endl; + } + fp << "\t" << endl << endl; + + return; +} + +/* Switch info is written out into xml format. This includes + * general, sizing, and optional timing information + */ +static +void write_rr_graph_switches(fstream &fp, const RRGraph& rr_graph) { + fp << "\t" << endl; + + for (auto rr_switch : rr_graph.switches()) { + fp << "\t\t" << endl; + + fp << "\t\t\t" << endl; + fp << "\t\t\t" << endl; + fp << "\t\t" << endl; + } + fp << "\t" << endl << endl; + + return; +} + +/* Edges connecting to each rr node is printed out. The two nodes + * it connects to are also printed + */ +static +void write_rr_graph_edges(fstream &fp, const RRGraph& rr_graph) { + auto& device_ctx = g_vpr_ctx.device(); + fp << "\t" << endl; + + for (auto node : rr_graph.nodes()) { + /* Sort the edges by the ids of sink nodes */ + std::vector sorted_out_edge_ids; + for (auto edge: rr_graph.node_out_edges(node)) { + fp << "\t\t" << endl; + + const t_metadata_dict & meta = iter->second; + add_metadata_to_xml(fp, "\t\t\t", meta); + wrote_edge_metadata = true; + } + + if(wrote_edge_metadata == false) { + fp << "/>" << endl; + } else { + fp << "\t\t" << endl; + } + } + } + fp << "\t" << endl << endl; +} + +/* This function is used to write the rr_graph into xml format into a a file with name: file_name */ +void write_xml_rr_graph_obj(const char *file_name, const RRGraph& rr_graph) { + fstream fp; + fp.open(file_name, fstream::out | fstream::trunc); + + /* Prints out general info for easy error checking*/ + if (!fp.is_open() || !fp.good()) { + vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, + "couldn't open file \"%s\" for generating RR graph file\n", file_name); + } + cout << "Writing RR graph" << endl; + fp << "" << endl; + + /* Write out each individual component + * Use existing write_rr_* functions as much as possible + * 1. For those using external data structures outside RRGraph, + * leave as it is. + * 2. For those using RRGraph internal data, + * write new functions + */ + write_rr_channel(fp); + write_rr_graph_switches(fp, rr_graph); + write_rr_graph_segments(fp, rr_graph); + write_rr_block_types(fp); + write_rr_grid(fp); + write_rr_graph_node(fp, rr_graph); + write_rr_graph_edges(fp, rr_graph); + fp << ""; + + fp.close(); + + cout << "Finished generating RR graph file named " << file_name << endl << endl; +} + diff --git a/vpr/src/device/write_xml_rr_graph_obj.h b/vpr/src/device/write_xml_rr_graph_obj.h new file mode 100644 index 000000000..7337ff958 --- /dev/null +++ b/vpr/src/device/write_xml_rr_graph_obj.h @@ -0,0 +1,12 @@ +/********************************************************************* + * This function writes the RR_graph generated by VPR into a file in XML format + * Information included in the file includes rr nodes, rr switches, + * the grid, block info, node indices + ********************************************************************/ + +#ifndef WRITE_XML_RR_GRAPH_OBJ_H +#define WRITE_XML_RR_GRAPH_OBJ_H + +void write_xml_rr_graph_obj(const char *file_name, const RRGraph& rr_graph); + +#endif diff --git a/vpr/src/route/rr_graph.cpp b/vpr/src/route/rr_graph.cpp index df1bb8b09..6bb9892ed 100644 --- a/vpr/src/route/rr_graph.cpp +++ b/vpr/src/route/rr_graph.cpp @@ -36,6 +36,9 @@ #include "rr_types.h" +#include "create_rr_graph.h" +#include "write_xml_rr_graph_obj.h" + //#define VERBOSE struct t_mux { @@ -331,6 +334,9 @@ void create_rr_graph(const t_graph_type graph_type, base_cost_type, &det_routing_arch->wire_to_rr_ipin_switch, det_routing_arch->read_rr_graph_filename.c_str()); + + /* Xifan Tang - Create rr_graph object: load rr_nodes to the object */ + convert_rr_graph(segment_inf); } } else { if (channel_widths_unchanged(device_ctx.chan_width, nodes_per_chan) && !device_ctx.rr_nodes.empty()) { @@ -369,6 +375,9 @@ void create_rr_graph(const t_graph_type graph_type, det_routing_arch->wire_to_rr_ipin_switch, base_cost_type); } + + /* Xifan Tang - Create rr_graph object: load rr_nodes to the object */ + convert_rr_graph(segment_inf); } process_non_config_sets(); @@ -378,6 +387,11 @@ void create_rr_graph(const t_graph_type graph_type, //Write out rr graph file if needed if (!det_routing_arch->write_rr_graph_filename.empty()) { write_rr_graph(det_routing_arch->write_rr_graph_filename.c_str(), segment_inf); + + /* Just to test the writer of rr_graph_obj, give a filename in a fixed style*/ + std::string rr_graph_obj_filename(det_routing_arch->write_rr_graph_filename); + rr_graph_obj_filename += std::string(".obj"); + write_xml_rr_graph_obj(rr_graph_obj_filename.c_str(), device_ctx.rr_graph); } } @@ -1391,6 +1405,9 @@ void free_rr_graph() { device_ctx.rr_edge_metadata.clear(); invalidate_router_lookahead_cache(); + + /* Xifan Tang - Clear the rr_graph object */ + device_ctx.rr_graph.clear(); } static void build_rr_sinks_sources(const int i,