diff --git a/vpr/src/base/vpr_context.h b/vpr/src/base/vpr_context.h index 8128b6244a3..c85aeb05245 100644 --- a/vpr/src/base/vpr_context.h +++ b/vpr/src/base/vpr_context.h @@ -9,7 +9,9 @@ #include "vtr_vector.h" #include "atom_netlist.h" #include "clustered_netlist.h" +#include "rr_graph_view.h" #include "rr_graph_storage.h" +#include "rr_graph_builder.h" #include "rr_node.h" #include "rr_rc_data.h" #include "tatum/TimingGraph.hpp" @@ -145,7 +147,6 @@ struct DeviceContext : public Context { /* * Structures to define the routing architecture of the FPGA. */ - t_rr_graph_storage rr_nodes; // autogenerated in build_rr_graph std::vector rr_indexed_data; // [0 .. num_rr_indexed_data-1] @@ -162,6 +163,24 @@ struct DeviceContext : public Context { ///@brief The indicies of rr nodes of a given type at a specific x,y grid location t_rr_node_indices rr_node_indices; // [0..NUM_RR_TYPES-1][0..grid.width()-1][0..grid.width()-1][0..size-1] + /* TODO: remove this interface from device_context once the code refactoring is completed + * because it should be part of the rr_graph view + * TODO: Currently, we use reference pointers to ensure that the rr_spatial_lookup is always + * synchronized with the rr_node_indices but this causes a lot of confusion for developers + * The temporary fix should be patched as soon as possible. + */ + RRSpatialLookup rr_spatial_lookup{rr_node_indices}; + + /* A read-only view of routing resource graph to be the ONLY database + * for client functions: GUI, placer, router, timing analyzer etc. + */ + RRGraphView rr_graph{rr_nodes, rr_spatial_lookup}; + + /* A writeable view of routing resource graph to be the ONLY database + * for routing resource graph builder functions. + */ + RRGraphBuilder rr_graph_builder{&rr_nodes, &rr_spatial_lookup}; + ///@brief Autogenerated in build_rr_graph based on switch fan-in. [0..(num_rr_switches-1)] std::vector rr_switch_inf; diff --git a/vpr/src/device/rr_graph_builder.cpp b/vpr/src/device/rr_graph_builder.cpp new file mode 100644 index 00000000000..6279177570f --- /dev/null +++ b/vpr/src/device/rr_graph_builder.cpp @@ -0,0 +1,15 @@ +#include "rr_graph_builder.h" + +RRGraphBuilder::RRGraphBuilder(t_rr_graph_storage* node_storage, + RRSpatialLookup* node_lookup) + : node_storage_(*node_storage) + , node_lookup_(*node_lookup) { +} + +t_rr_graph_storage& RRGraphBuilder::node_storage() { + return node_storage_; +} + +RRSpatialLookup& RRGraphBuilder::node_lookup() { + return node_lookup_; +} diff --git a/vpr/src/device/rr_graph_builder.h b/vpr/src/device/rr_graph_builder.h new file mode 100644 index 00000000000..594beef45df --- /dev/null +++ b/vpr/src/device/rr_graph_builder.h @@ -0,0 +1,58 @@ +#ifndef RR_GRAPH_BUILDER_H +#define RR_GRAPH_BUILDER_H + +#include "rr_graph_storage.h" +#include "rr_spatial_lookup.h" + +/* A data structure allows data modification on a routing resource graph + * + * Note that the builder does not own the storage + * It serves a virtual protocol for + * - node_storage: store the node list + * - node_lookup: store a fast look-up for the nodes + * + * Note: + * - This is the only data structre allowed to modify a routing resource graph + * + */ +class RRGraphBuilder { + /* -- Constructors -- */ + public: + /* See detailed comments about the data structures in the internal data storage section of this file */ + RRGraphBuilder(t_rr_graph_storage* node_storage, + RRSpatialLookup* node_lookup); + + /* Disable copy constructors and copy assignment operator + * This is to avoid accidental copy because it could be an expensive operation considering that the + * memory footprint of the data structure could ~ Gb + * Using the following syntax, we prohibit accidental 'pass-by-value' which can be immediately caught + * by compiler + */ + RRGraphBuilder(const RRGraphBuilder&) = delete; + void operator=(const RRGraphBuilder&) = delete; + + /* -- Mutators -- */ + public: + /* Return a writable object for rr_nodes */ + t_rr_graph_storage& node_storage(); + /* Return a writable object for update the fast look-up of rr_node */ + RRSpatialLookup& node_lookup(); + + /* -- Internal data storage -- */ + private: + /* TODO: When the refactoring effort finishes, + * the builder data structure will be the owner of the data storages. + * That is why the reference to storage/lookup is used here. + * It can avoid a lot of code changes once the refactoring is finished + * (there is no function get data directly through the node_storage in DeviceContext). + * If pointers are used, it may cause many codes in client functions + * or inside the data structures to be changed later. + * That explains why the reference is used here temporarily + */ + /* node-level storage including edge storages */ + t_rr_graph_storage& node_storage_; + /* Fast look-up for rr nodes */ + RRSpatialLookup& node_lookup_; +}; + +#endif diff --git a/vpr/src/device/rr_graph_view.cpp b/vpr/src/device/rr_graph_view.cpp new file mode 100644 index 00000000000..b6fb8941297 --- /dev/null +++ b/vpr/src/device/rr_graph_view.cpp @@ -0,0 +1,15 @@ +#include "rr_graph_view.h" + +RRGraphView::RRGraphView(const t_rr_graph_storage& node_storage, + const RRSpatialLookup& node_lookup) + : node_storage_(node_storage) + , node_lookup_(node_lookup) { +} + +t_rr_type RRGraphView::node_type(RRNodeId node) const { + return node_storage_.node_type(node); +} + +const RRSpatialLookup& RRGraphView::node_lookup() const { + return node_lookup_; +} diff --git a/vpr/src/device/rr_graph_view.h b/vpr/src/device/rr_graph_view.h new file mode 100644 index 00000000000..7d0853634e6 --- /dev/null +++ b/vpr/src/device/rr_graph_view.h @@ -0,0 +1,70 @@ +#ifndef RR_GRAPH_VIEW_H +#define RR_GRAPH_VIEW_H + +#include "rr_graph_storage.h" +#include "rr_spatial_lookup.h" + +/* An read-only routing resource graph + * which is an unified object including pointors to + * - node storage + * - TODO: edge_storage + * - TODO: node_ptc_storage + * - TODO: node_fan_in_storage + * - rr_node_indices + * + * Note that the RRGraphView does not own the storage + * It serves a virtual read-only protocol for + * - placer + * - router + * - timing analyzer + * - GUI + * + * Note that each client of rr_graph may get a frame view of the object + * The RRGraphView is the complete frame view of the routing resource graph + * - This helps to reduce the memory footprint for each client + * - This avoids massive changes for each client on using the APIs + * as each frame view provides adhoc APIs for each client + * + * TODO: more compact frame views will be created, e.g., + * - a mini frame view: contains only node and edges, representing the connectivity of the graph + * - a geometry frame view: an extended mini frame view with node-level attributes, + * in particular geometry information (type, x, y etc). + * + */ +class RRGraphView { + /* -- Constructors -- */ + public: + /* See detailed comments about the data structures in the internal data storage section of this file */ + RRGraphView(const t_rr_graph_storage& node_storage, + const RRSpatialLookup& node_lookup); + + /* Disable copy constructors and copy assignment operator + * This is to avoid accidental copy because it could be an expensive operation considering that the + * memory footprint of the data structure could ~ Gb + * Using the following syntax, we prohibit accidental 'pass-by-value' which can be immediately caught + * by compiler + */ + RRGraphView(const RRGraphView&) = delete; + void operator=(const RRGraphView&) = delete; + + /* -- Accessors -- */ + /* TODO: The accessors may be turned into private later if they are replacable by 'questionin' + * kind of accessors + */ + public: + /* Get the type of a routing resource node */ + t_rr_type node_type(RRNodeId node) const; + + /* Return the fast look-up data structure for queries from client functions */ + const RRSpatialLookup& node_lookup() const; + + /* -- Internal data storage -- */ + /* Note: only read-only object or data structures are allowed!!! */ + private: + /* node-level storage including edge storages */ + const t_rr_graph_storage& node_storage_; + /* Fast look-up for rr nodes */ + const RRSpatialLookup& node_lookup_; +}; + +#endif diff --git a/vpr/src/device/rr_spatial_lookup.cpp b/vpr/src/device/rr_spatial_lookup.cpp new file mode 100644 index 00000000000..0845e7a468c --- /dev/null +++ b/vpr/src/device/rr_spatial_lookup.cpp @@ -0,0 +1,107 @@ +#include "vtr_assert.h" +#include "rr_spatial_lookup.h" + +RRSpatialLookup::RRSpatialLookup(t_rr_node_indices& rr_node_indices) + : rr_node_indices_(rr_node_indices) { +} + +RRNodeId RRSpatialLookup::find_node(int x, + int y, + t_rr_type type, + int ptc, + e_side side) const { + /* Find actual side to be used + * - For the node which are input/outputs of a grid, there must be a specific side for them. + * Because they should have a specific pin location on the perimeter of a grid. + * - For other types of nodes, there is no need to define a side. However, a default value + * is needed when store the node in the fast look-up data structure. + * Here we just arbitrary use the first side of the SIDE vector as the default value. + * We may consider to use NUM_SIDES as the default value but it will cause an increase + * in the dimension of the fast look-up data structure. + * Please note that in the add_node function, we should keep the SAME convention! + */ + e_side node_side = side; + if (type == IPIN || type == OPIN) { + VTR_ASSERT_MSG(side != NUM_SIDES, "IPIN/OPIN must specify desired side (can not be default NUM_SIDES)"); + } else { + VTR_ASSERT_SAFE(type != IPIN && type != OPIN); + node_side = SIDES[0]; + } + + /* Pre-check: the x, y, side and ptc should be non negative numbers! Otherwise, return an invalid id */ + if ((0 > x) || (0 > y) || (NUM_SIDES == node_side) || (0 > ptc)) { + return RRNodeId::INVALID(); + } + + /* Currently need to swap x and y for CHANX because of chan, seg convention + * This is due to that the fast look-up builders uses (y, x) coordinate when + * registering a CHANX node in the look-up + * TODO: Once the builders is reworked for use consistent (x, y) convention, + * the following swapping can be removed + */ + size_t node_x = x; + size_t node_y = y; + if (CHANX == type) { + std::swap(node_x, node_y); + } + + VTR_ASSERT_SAFE(3 == rr_node_indices_[type].ndims()); + + /* Sanity check to ensure the x, y, side and ptc are in range + * - Return an valid id by searching in look-up when all the parameters are in range + * - Return an invalid id if any out-of-range is detected + */ + if (size_t(type) >= rr_node_indices_.size()) { + return RRNodeId::INVALID(); + } + + if (node_x >= rr_node_indices_[type].dim_size(0)) { + return RRNodeId::INVALID(); + } + + if (node_y >= rr_node_indices_[type].dim_size(1)) { + return RRNodeId::INVALID(); + } + + if (node_side >= rr_node_indices_[type].dim_size(2)) { + return RRNodeId::INVALID(); + } + + if (size_t(ptc) >= rr_node_indices_[type][node_x][node_y][node_side].size()) { + return RRNodeId::INVALID(); + } + + return RRNodeId(rr_node_indices_[type][node_x][node_y][node_side][ptc]); +} + +void RRSpatialLookup::add_node(RRNodeId node, + int x, + int y, + t_rr_type type, + int ptc, + e_side side) { + VTR_ASSERT_SAFE(3 == rr_node_indices_[type].ndims()); + + /* Expand the fast look-up if the new node is out-of-range + * This may seldom happen because the rr_graph building function + * should ensure the fast look-up well organized + */ + VTR_ASSERT(type < rr_node_indices_.size()); + VTR_ASSERT(0 <= x); + VTR_ASSERT(0 <= y); + + if ((x >= int(rr_node_indices_[type].dim_size(0))) + || (y >= int(rr_node_indices_[type].dim_size(1))) + || (size_t(side) >= rr_node_indices_[type].dim_size(2))) { + rr_node_indices_[type].resize({std::max(rr_node_indices_[type].dim_size(0), size_t(x) + 1), + std::max(rr_node_indices_[type].dim_size(1), size_t(y) + 1), + std::max(rr_node_indices_[type].dim_size(2), size_t(side) + 1)}); + } + + if (size_t(ptc) >= rr_node_indices_[type][x][y][side].size()) { + rr_node_indices_[type][x][y][side].resize(ptc + 1); + } + + /* Resize on demand finished; Register the node */ + rr_node_indices_[type][x][y][side][ptc] = int(size_t(node)); +} diff --git a/vpr/src/device/rr_spatial_lookup.h b/vpr/src/device/rr_spatial_lookup.h new file mode 100644 index 00000000000..44a413b5f90 --- /dev/null +++ b/vpr/src/device/rr_spatial_lookup.h @@ -0,0 +1,109 @@ +#ifndef RR_SPATIAL_LOOKUP_H +#define RR_SPATIAL_LOOKUP_H + +#include "vpr_types.h" + +/******************************************************************** + * A data structure built to find the id of an routing resource node + * (rr_node) given information about its physical position and type. + * The data structure is mostly needed during rr_graph building + * + * The data structure allows users to + * - Update the look-up with new nodes + * - Find the id of a node with given information, e.g., x, y, type etc. + ********************************************************************/ +class RRSpatialLookup { + /* -- Constructors -- */ + public: + /* Explicitly define the only way to create an object */ + explicit RRSpatialLookup(t_rr_node_indices& rr_node_indices); + + /* Disable copy constructors and copy assignment operator + * This is to avoid accidental copy because it could be an expensive operation considering that the + * memory footprint of the data structure could ~ Gb + * Using the following syntax, we prohibit accidental 'pass-by-value' which can be immediately caught + * by compiler + */ + RRSpatialLookup(const RRSpatialLookup&) = delete; + void operator=(const RRSpatialLookup&) = delete; + + /* -- Accessors -- */ + public: + /* Returns the index of the specified routing resource node. + * - (x, y) are the grid location within the FPGA + * - rr_type specifies the type of resource, + * - ptc gives a unique number of resources of that type (e.g. CHANX) at that (x,y). + * All ptcs start at 0 and are positive. + * Depending on what type of resource this is, ptc can be + * - the class number of a common SINK/SOURCE node of grid, + * starting at 0 and go up to class_inf size - 1 of SOURCEs + SINKs in a grid + * - pin number of an input/output pin of a grid. They would normally start at 0 + * and go to the number of pins on a block at that (x, y) location + * - track number of a routing wire in a channel. They would normally go from 0 + * to channel_width - 1 at that (x,y) + * + * An invalid id will be returned if the node does not exist + * + * Note that for segments (CHANX and CHANY) of length > 1, the segment is + * given an rr_index based on the (x,y) location at which it starts (i.e. + * lowest (x,y) location at which this segment exists). + * + * The 'side' argument only applies to IPIN/OPIN types, and specifies which + * side of the grid tile the node should be located on. The value is ignored + * for non-IPIN/OPIN types + * + * This routine also performs error checking to make sure the node in + * question exists. + */ + RRNodeId find_node(int x, + int y, + t_rr_type type, + int ptc, + e_side side = NUM_SIDES) const; + + /* -- Mutators -- */ + public: + /* Register a node in the fast look-up + * - You must have a valid node id to register the node in the lookup + * - (x, y) are the coordinate of the node to be indexable in the fast look-up + * - type is the type of a node + * - ptc is a feature number of a node, which can be + * - the class number of a common SINK/SOURCE node of grid, + * - pin index in a tile when type is OPIN/IPIN + * - track index in a routing channel when type is CHANX/CHANY + * - side is the side of node on the tile, applicable to OPIN/IPIN + * + * Note that a node added with this call will not create a node in the rr_graph_storage node list + * You MUST add the node in the rr_graph_storage so that the node is valid + * + * TODO: Consider to try to return a reference to *this so that we can do chain calls + * - .add_node(...) + * - .add_node(...) + * - .add_node(...) + * As such, multiple node addition could be efficiently implemented + */ + void add_node(RRNodeId node, + int x, + int y, + t_rr_type type, + int ptc, + e_side side); + + /* TODO: Add an API remove_node() to unregister a node from the look-up */ + + /* -- Internal data storage -- */ + private: + /* TODO: When the refactoring effort finishes, + * the data structure will be the owner of the data storages. + * That is why the reference is used here. + * It can avoid a lot of code changes once the refactoring is finished + * (there is no function get data directly through the rr_node_indices in DeviceContext). + * If pointers are used, it may cause many codes in client functions + * or inside the data structures to be changed later. + * That explains why the reference is used here temporarily + */ + /* Fast look-up */ + t_rr_node_indices& rr_node_indices_; +}; + +#endif diff --git a/vpr/src/place/timing_place_lookup.cpp b/vpr/src/place/timing_place_lookup.cpp index 65e3156b006..102e5dd0f4f 100644 --- a/vpr/src/place/timing_place_lookup.cpp +++ b/vpr/src/place/timing_place_lookup.cpp @@ -350,25 +350,25 @@ static float route_connection_delay( for (int driver_ptc : best_driver_ptcs) { VTR_ASSERT(driver_ptc != OPEN); - int source_rr_node = get_rr_node_index(device_ctx.rr_node_indices, source_x, source_y, SOURCE, driver_ptc); + RRNodeId source_rr_node = device_ctx.rr_graph.node_lookup().find_node(source_x, source_y, SOURCE, driver_ptc); - VTR_ASSERT(source_rr_node != OPEN); + VTR_ASSERT(source_rr_node != RRNodeId::INVALID()); for (int sink_ptc : best_sink_ptcs) { VTR_ASSERT(sink_ptc != OPEN); - int sink_rr_node = get_rr_node_index(device_ctx.rr_node_indices, sink_x, sink_y, SINK, sink_ptc); + RRNodeId sink_rr_node = device_ctx.rr_graph.node_lookup().find_node(sink_x, sink_y, SINK, sink_ptc); - VTR_ASSERT(sink_rr_node != OPEN); + VTR_ASSERT(sink_rr_node != RRNodeId::INVALID()); - if (!measure_directconnect && directconnect_exists(source_rr_node, sink_rr_node)) { + if (!measure_directconnect && directconnect_exists(size_t(source_rr_node), size_t(sink_rr_node))) { //Skip if we shouldn't measure direct connects and a direct connect exists continue; } { successfully_routed = route_profiler.calculate_delay( - source_rr_node, sink_rr_node, + size_t(source_rr_node), size_t(sink_rr_node), router_opts, &net_delay_value); } @@ -444,10 +444,10 @@ static void generic_compute_matrix_dijkstra_expansion( auto best_driver_ptcs = get_best_classes(DRIVER, device_ctx.grid[source_x][source_y].type); for (int driver_ptc : best_driver_ptcs) { VTR_ASSERT(driver_ptc != OPEN); - int source_rr_node = get_rr_node_index(device_ctx.rr_node_indices, source_x, source_y, SOURCE, driver_ptc); + RRNodeId source_rr_node = device_ctx.rr_graph.node_lookup().find_node(source_x, source_y, SOURCE, driver_ptc); - VTR_ASSERT(source_rr_node != OPEN); - auto delays = calculate_all_path_delays_from_rr_node(source_rr_node, router_opts); + VTR_ASSERT(source_rr_node != RRNodeId::INVALID()); + auto delays = calculate_all_path_delays_from_rr_node(size_t(source_rr_node), router_opts); bool path_to_all_sinks = true; for (int sink_x = start_x; sink_x <= end_x; sink_x++) { @@ -479,16 +479,16 @@ static void generic_compute_matrix_dijkstra_expansion( for (int sink_ptc : best_sink_ptcs) { VTR_ASSERT(sink_ptc != OPEN); - int sink_rr_node = get_rr_node_index(device_ctx.rr_node_indices, sink_x, sink_y, SINK, sink_ptc); + RRNodeId sink_rr_node = device_ctx.rr_graph.node_lookup().find_node(sink_x, sink_y, SINK, sink_ptc); - VTR_ASSERT(sink_rr_node != OPEN); + VTR_ASSERT(sink_rr_node != RRNodeId::INVALID()); - if (!measure_directconnect && directconnect_exists(source_rr_node, sink_rr_node)) { + if (!measure_directconnect && directconnect_exists(size_t(source_rr_node), size_t(sink_rr_node))) { //Skip if we shouldn't measure direct connects and a direct connect exists continue; } - if (std::isnan(delays[sink_rr_node])) { + if (std::isnan(delays[size_t(sink_rr_node)])) { // This sink was not found continue; } @@ -502,7 +502,7 @@ static void generic_compute_matrix_dijkstra_expansion( #endif found_matrix[delta_x][delta_y] = true; - add_delay_to_matrix(&matrix, delta_x, delta_y, delays[sink_rr_node]); + add_delay_to_matrix(&matrix, delta_x, delta_y, delays[size_t(sink_rr_node)]); found_a_sink = true; break; @@ -979,8 +979,8 @@ static bool find_direct_connect_sample_locations(const t_direct_inf* direct, //(with multi-width/height blocks pins may not exist at all locations) bool from_pin_found = false; if (direct->from_side != NUM_SIDES) { - int from_pin_rr = get_rr_node_index(device_ctx.rr_node_indices, from_x, from_y, OPIN, from_pin, direct->from_side); - from_pin_found = (from_pin_rr != OPEN); + RRNodeId from_pin_rr = device_ctx.rr_graph.node_lookup().find_node(from_x, from_y, OPIN, from_pin, direct->from_side); + from_pin_found = (from_pin_rr != RRNodeId::INVALID()); } else { std::vector& from_pin_rrs = *scratch; get_rr_node_indices(device_ctx.rr_node_indices, from_x, from_y, OPIN, from_pin, &from_pin_rrs); @@ -997,8 +997,8 @@ static bool find_direct_connect_sample_locations(const t_direct_inf* direct, //(with multi-width/height blocks pins may not exist at all locations) bool to_pin_found = false; if (direct->to_side != NUM_SIDES) { - int to_pin_rr = get_rr_node_index(device_ctx.rr_node_indices, to_x, to_y, IPIN, to_pin, direct->to_side); - to_pin_found = (to_pin_rr != OPEN); + RRNodeId to_pin_rr = device_ctx.rr_graph.node_lookup().find_node(to_x, to_y, IPIN, to_pin, direct->to_side); + to_pin_found = (to_pin_rr != RRNodeId::INVALID()); } else { std::vector& to_pin_rrs = *scratch; get_rr_node_indices(device_ctx.rr_node_indices, to_x, to_y, IPIN, to_pin, &to_pin_rrs); diff --git a/vpr/src/route/check_rr_graph.cpp b/vpr/src/route/check_rr_graph.cpp index 933caf25c91..4cd05937cce 100644 --- a/vpr/src/route/check_rr_graph.cpp +++ b/vpr/src/route/check_rr_graph.cpp @@ -205,7 +205,7 @@ void check_rr_graph(const t_graph_type graph_type, bool is_fringe_warning_sent = false; for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) { - t_rr_type rr_type = device_ctx.rr_nodes[inode].type(); + t_rr_type rr_type = device_ctx.rr_nodes.node_type(RRNodeId(inode)); if (rr_type != SOURCE) { if (total_edges_to_node[inode] < 1 && !rr_node_is_global_clb_ipin(inode)) { @@ -224,16 +224,17 @@ void check_rr_graph(const t_graph_type graph_type, } const auto& node = device_ctx.rr_nodes[inode]; + const auto& rr_graph = device_ctx.rr_graph; bool is_fringe = ((device_ctx.rr_nodes[inode].xlow() == 1) || (device_ctx.rr_nodes[inode].ylow() == 1) || (device_ctx.rr_nodes[inode].xhigh() == int(grid.width()) - 2) || (device_ctx.rr_nodes[inode].yhigh() == int(grid.height()) - 2)); - bool is_wire = (device_ctx.rr_nodes[inode].type() == CHANX - || device_ctx.rr_nodes[inode].type() == CHANY); + bool is_wire = (rr_graph.node_type(RRNodeId(inode)) == CHANX + || rr_graph.node_type(RRNodeId(inode)) == CHANY); if (!is_chain && !is_fringe && !is_wire) { - if (node.type() == IPIN || node.type() == OPIN) { + if (rr_graph.node_type(RRNodeId(inode)) == IPIN || rr_graph.node_type(RRNodeId(inode)) == OPIN) { if (has_adjacent_channel(node, device_ctx.grid)) { auto block_type = device_ctx.grid[node.xlow()][node.ylow()].type; std::string pin_name = block_type_pin_index_to_name(block_type, node.pin_num()); @@ -579,6 +580,9 @@ static void check_unbuffered_edges(int from_node) { } static bool has_adjacent_channel(const t_rr_node& node, const DeviceGrid& grid) { + /* TODO: this function should be reworked later to adapt RRGraphView interface + * once xlow(), ylow(), side() APIs are implemented + */ VTR_ASSERT(node.type() == IPIN || node.type() == OPIN); if ((node.xlow() == 0 && !node.is_node_on_specific_side(RIGHT)) //left device edge connects only along block's right side diff --git a/vpr/src/route/rr_graph.cpp b/vpr/src/route/rr_graph.cpp index 75c18fcd3cc..109e001c051 100644 --- a/vpr/src/route/rr_graph.cpp +++ b/vpr/src/route/rr_graph.cpp @@ -332,6 +332,7 @@ void create_rr_graph(const t_graph_type graph_type, det_routing_arch->read_rr_graph_filename.c_str(), router_opts.read_rr_edge_metadata, router_opts.do_check_rr_graph); + reorder_rr_graph_nodes(router_opts); } } else { @@ -572,8 +573,10 @@ static void build_rr_graph(const t_graph_type graph_type, /* Alloc node lookups, count nodes, alloc rr nodes */ int num_rr_nodes = 0; - device_ctx.rr_node_indices = alloc_and_load_rr_node_indices(max_chan_width, grid, - &num_rr_nodes, chan_details_x, chan_details_y); + alloc_and_load_rr_node_indices(device_ctx.rr_node_indices, + max_chan_width, grid, + &num_rr_nodes, chan_details_x, chan_details_y); + size_t expected_node_count = num_rr_nodes; if (clock_modeling == DEDICATED_NETWORK) { expected_node_count += ClockRRGraphBuilder::estimate_additional_nodes(grid); diff --git a/vpr/src/route/rr_graph2.cpp b/vpr/src/route/rr_graph2.cpp index 330ede4b6fd..6f5567b2443 100644 --- a/vpr/src/route/rr_graph2.cpp +++ b/vpr/src/route/rr_graph2.cpp @@ -35,8 +35,9 @@ static void load_chan_rr_indices(const int max_chan_width, t_rr_node_indices& indices, int* index); -static void load_block_rr_indices(const DeviceGrid& grid, +static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder, t_rr_node_indices& indices, + const DeviceGrid& grid, int* index); static int get_bidir_track_to_chan_seg(const std::vector conn_tracks, @@ -970,8 +971,12 @@ static void load_chan_rr_indices(const int max_chan_width, } } -static void load_block_rr_indices(const DeviceGrid& grid, +/* As the rr_indices builders modify a local copy of indices, use the local copy in the builder + * TODO: these building functions should only talk to a RRGraphBuilder object + */ +static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder, t_rr_node_indices& indices, + const DeviceGrid& grid, int* index) { //Walk through the grid assigning indices to SOURCE/SINK IPIN/OPIN for (size_t x = 0; x < grid.width(); x++) { @@ -982,15 +987,15 @@ static void load_block_rr_indices(const DeviceGrid& grid, //Assign indices for SINKs and SOURCEs // Note that SINKS/SOURCES have no side, so we always use side 0 - for (const auto& class_inf : type->class_inf) { - auto class_type = class_inf.type; + for (size_t iclass = 0; iclass < type->class_inf.size(); ++iclass) { + auto class_type = type->class_inf[iclass].type; if (class_type == DRIVER) { - indices[SOURCE][x][y][0].push_back(*index); - indices[SINK][x][y][0].push_back(OPEN); + rr_graph_builder.node_lookup().add_node(RRNodeId(*index), x, y, SOURCE, iclass, SIDES[0]); + rr_graph_builder.node_lookup().add_node(RRNodeId::INVALID(), x, y, SINK, iclass, SIDES[0]); } else { VTR_ASSERT(class_type == RECEIVER); - indices[SINK][x][y][0].push_back(*index); - indices[SOURCE][x][y][0].push_back(OPEN); + rr_graph_builder.node_lookup().add_node(RRNodeId(*index), x, y, SINK, iclass, SIDES[0]); + rr_graph_builder.node_lookup().add_node(RRNodeId::INVALID(), x, y, SOURCE, iclass, SIDES[0]); } ++(*index); } @@ -1134,17 +1139,26 @@ static void load_block_rr_indices(const DeviceGrid& grid, } } -t_rr_node_indices alloc_and_load_rr_node_indices(const int max_chan_width, - const DeviceGrid& grid, - int* index, - const t_chan_details& chan_details_x, - const t_chan_details& chan_details_y) { +/* As the rr_indices builders modify a local copy of indices, use the local copy in the builder + * TODO: these building functions should only talk to a RRGraphBuilder object + * The biggest and fatal issue is + * - the rr_graph2.h is included in the rr_graph_storage.h, + * which is included in the rr_graph_builder.h + * If we include rr_graph_builder.h in rr_graph2.h, this creates a loop + * for C++ compiler to identify data structures, which cannot be solved!!! + * This will block us when putting the RRGraphBuilder object as an input arguement + * of this function + */ +void alloc_and_load_rr_node_indices(t_rr_node_indices& indices, + const int max_chan_width, + const DeviceGrid& grid, + int* index, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y) { /* Allocates and loads all the structures needed for fast lookups of the * * index of an rr_node. rr_node_indices is a matrix containing the index * * of the *first* rr_node at a given (i,j) location. */ - t_rr_node_indices indices; - /* Alloc the lookup table */ for (t_rr_type rr_type : RR_TYPES) { if (rr_type == CHANX) { @@ -1155,15 +1169,13 @@ t_rr_node_indices alloc_and_load_rr_node_indices(const int max_chan_width, } /* Assign indices for block nodes */ - load_block_rr_indices(grid, indices, index); + load_block_rr_indices(g_vpr_ctx.mutable_device().rr_graph_builder, indices, grid, index); /* Load the data for x and y channels */ load_chan_rr_indices(max_chan_width, grid.width(), grid.height(), CHANX, chan_details_x, indices, index); load_chan_rr_indices(max_chan_width, grid.height(), grid.width(), CHANY, chan_details_y, indices, index); - - return indices; } bool verify_rr_node_indices(const DeviceGrid& grid, const t_rr_node_indices& rr_node_indices, const t_rr_graph_storage& rr_nodes) { diff --git a/vpr/src/route/rr_graph2.h b/vpr/src/route/rr_graph2.h index 2b3bd22de25..09467afcdd3 100644 --- a/vpr/src/route/rr_graph2.h +++ b/vpr/src/route/rr_graph2.h @@ -44,11 +44,12 @@ struct t_opin_connections_scratchpad { /******************* Subroutines exported by rr_graph2.c *********************/ -t_rr_node_indices alloc_and_load_rr_node_indices(const int max_chan_width, - const DeviceGrid& grid, - int* index, - const t_chan_details& chan_details_x, - const t_chan_details& chan_details_y); +void alloc_and_load_rr_node_indices(t_rr_node_indices& indices, + const int max_chan_width, + const DeviceGrid& grid, + int* index, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y); bool verify_rr_node_indices(const DeviceGrid& grid, const t_rr_node_indices& rr_node_indices, const t_rr_graph_storage& rr_nodes); diff --git a/vpr/src/route/rr_graph_uxsdcxx_serializer.h b/vpr/src/route/rr_graph_uxsdcxx_serializer.h index cd67a9d6ff5..75e9baaa3e9 100644 --- a/vpr/src/route/rr_graph_uxsdcxx_serializer.h +++ b/vpr/src/route/rr_graph_uxsdcxx_serializer.h @@ -1962,6 +1962,7 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { // Output for loads, and constant data for writes. int* wire_to_rr_ipin_switch_; t_chan_width* chan_width_; + RRGraphView* rr_graph_; t_rr_graph_storage* rr_nodes_; std::vector* rr_switch_inf_; std::vector* rr_indexed_data_;