diff --git a/vpr/src/device/rr_spatial_lookup.cpp b/vpr/src/device/rr_spatial_lookup.cpp index 0845e7a468c..f8e3e9050b1 100644 --- a/vpr/src/device/rr_spatial_lookup.cpp +++ b/vpr/src/device/rr_spatial_lookup.cpp @@ -80,8 +80,33 @@ void RRSpatialLookup::add_node(RRNodeId node, t_rr_type type, int ptc, e_side side) { + VTR_ASSERT(node); /* Must have a valid node id to be added */ VTR_ASSERT_SAFE(3 == rr_node_indices_[type].ndims()); + resize_nodes(x, y, type, side); + + if (size_t(ptc) >= rr_node_indices_[type][x][y][side].size()) { + /* Deposit invalid ids to newly allocated elements while original elements are untouched */ + rr_node_indices_[type][x][y][side].resize(ptc + 1, int(size_t(RRNodeId::INVALID()))); + } + + /* Resize on demand finished; Register the node */ + rr_node_indices_[type][x][y][side][ptc] = int(size_t(node)); +} + +void RRSpatialLookup::mirror_nodes(const vtr::Point& src_coord, + const vtr::Point& des_coord, + t_rr_type type, + e_side side) { + VTR_ASSERT(SOURCE == type || SINK == type); + resize_nodes(des_coord.x(), des_coord.y(), type, side); + rr_node_indices_[type][des_coord.x()][des_coord.y()][side] = rr_node_indices_[type][src_coord.x()][src_coord.y()][side]; +} + +void RRSpatialLookup::resize_nodes(int x, + int y, + t_rr_type type, + e_side side) { /* 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 @@ -97,11 +122,4 @@ void RRSpatialLookup::add_node(RRNodeId node, 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 index 44a413b5f90..1822bb073a5 100644 --- a/vpr/src/device/rr_spatial_lookup.h +++ b/vpr/src/device/rr_spatial_lookup.h @@ -1,6 +1,7 @@ #ifndef RR_SPATIAL_LOOKUP_H #define RR_SPATIAL_LOOKUP_H +#include "vtr_geometry.h" #include "vpr_types.h" /******************************************************************** @@ -29,7 +30,8 @@ class RRSpatialLookup { /* -- Accessors -- */ public: - /* Returns the index of the specified routing resource node. + /** + * 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). @@ -63,7 +65,8 @@ class RRSpatialLookup { /* -- Mutators -- */ public: - /* Register a node in the fast look-up + /** + * 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 @@ -89,7 +92,53 @@ class RRSpatialLookup { int ptc, e_side side); - /* TODO: Add an API remove_node() to unregister a node from the look-up */ + /** + * Mirror the last dimension of a look-up, i.e., a list of nodes, from a source coordinate to + * a destination coordinate. + * This function is mostly need by SOURCE and SINK nodes which are indexable in multiple locations. + * Considering a bounding box (x, y)->(x + width, y + height) of a multi-height and multi-width grid, + * SOURCE and SINK nodes are indexable in any location inside the boundry. + * + * An example of usage: + * + * // Create a empty lookup + * RRSpatialLookup rr_lookup; + * // Adding other nodes ... + * // Copy the nodes whose types are SOURCE at (1, 1) to (1, 2) + * rr_lookup.mirror_nodes(vtr::Point(1, 1), + * vtr::Point(1, 2), + * SOURCE, + * TOP); + * + * Note: currently this function only accepts SOURCE/SINK nodes. May unlock for the other types + * depending on needs + * + * TODO: Consider to make a high-level API to duplicate the nodes for large blocks. + * Then this API can become a private one + * For example, + * expand_nodes(source_coordinate, bounding_box_coordinate, type, side); + * Alternatively, we can rework the ``find_node()`` API so that we always search the lowest (x,y) + * corner when dealing with large blocks. But this may require the data structure to be dependent + * on DeviceGrid information (it needs to identify if a grid has height > 1 as well as width > 1) + */ + void mirror_nodes(const vtr::Point& src_coord, + const vtr::Point& des_coord, + t_rr_type type, + e_side side); + + /** + * Resize the given 3 dimensions (x, y, side) of the RRSpatialLookup data structure for the given type + * This function will keep any existing data + * + * Strongly recommend to use when the sizes of dimensions are deterministic + * + * TODO: should have a reserve function but vtd::ndmatrix does not have such API + * as a result, resize can be an internal one while reserve function is a public mutator + */ + void resize_nodes(int x, + int y, + t_rr_type type, + e_side side); /* -- Internal data storage -- */ private: diff --git a/vpr/src/route/rr_edge.h b/vpr/src/route/rr_edge.h new file mode 100644 index 00000000000..7033d2e1cce --- /dev/null +++ b/vpr/src/route/rr_edge.h @@ -0,0 +1,25 @@ +#ifndef RR_EDGE_H +#define RR_EDGE_H + +struct t_rr_edge_info { + t_rr_edge_info(int from, int to, short type) noexcept + : from_node(from) + , to_node(to) + , switch_type(type) {} + + int from_node = OPEN; + int to_node = OPEN; + short switch_type = OPEN; + + friend bool operator<(const t_rr_edge_info& lhs, const t_rr_edge_info& rhs) { + return std::tie(lhs.from_node, lhs.to_node, lhs.switch_type) < std::tie(rhs.from_node, rhs.to_node, rhs.switch_type); + } + + friend bool operator==(const t_rr_edge_info& lhs, const t_rr_edge_info& rhs) { + return std::tie(lhs.from_node, lhs.to_node, lhs.switch_type) == std::tie(rhs.from_node, rhs.to_node, rhs.switch_type); + } +}; + +typedef std::vector t_rr_edge_info_set; + +#endif /* RR_EDGE */ \ No newline at end of file diff --git a/vpr/src/route/rr_graph.cpp b/vpr/src/route/rr_graph.cpp index 109e001c051..d2e57d94799 100644 --- a/vpr/src/route/rr_graph.cpp +++ b/vpr/src/route/rr_graph.cpp @@ -573,7 +573,7 @@ static void build_rr_graph(const t_graph_type graph_type, /* Alloc node lookups, count nodes, alloc rr nodes */ int num_rr_nodes = 0; - alloc_and_load_rr_node_indices(device_ctx.rr_node_indices, + alloc_and_load_rr_node_indices(device_ctx.rr_graph_builder, max_chan_width, grid, &num_rr_nodes, chan_details_x, chan_details_y); diff --git a/vpr/src/route/rr_graph2.cpp b/vpr/src/route/rr_graph2.cpp index 6f5567b2443..5f6ec46c884 100644 --- a/vpr/src/route/rr_graph2.cpp +++ b/vpr/src/route/rr_graph2.cpp @@ -32,11 +32,10 @@ static void load_chan_rr_indices(const int max_chan_width, const int num_chans, const t_rr_type type, const t_chan_details& chan_details, - t_rr_node_indices& indices, + RRGraphBuilder& rr_graph_builder, int* index); static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder, - t_rr_node_indices& indices, const DeviceGrid& grid, int* index); @@ -928,19 +927,8 @@ static void load_chan_rr_indices(const int max_chan_width, const int num_chans, const t_rr_type type, const t_chan_details& chan_details, - t_rr_node_indices& indices, + RRGraphBuilder& rr_graph_builder, int* index) { - VTR_ASSERT(indices[type].dim_size(0) == size_t(num_chans)); - VTR_ASSERT(indices[type].dim_size(1) == size_t(chan_len)); - VTR_ASSERT(indices[type].dim_size(2) == NUM_SIDES); - for (int chan = 0; chan < num_chans - 1; ++chan) { - for (int seg = 1; seg < chan_len - 1; ++seg) { - /* Alloc the track inode lookup list */ - //Since channels have no side, we just use the first side - indices[type][chan][seg][0].resize(max_chan_width, OPEN); - } - } - for (int chan = 0; chan < num_chans - 1; ++chan) { for (int seg = 1; seg < chan_len - 1; ++seg) { /* Assign an inode to the starts of tracks */ @@ -948,24 +936,32 @@ static void load_chan_rr_indices(const int max_chan_width, int y = (type == CHANX ? chan : seg); const t_chan_seg_details* seg_details = chan_details[x][y].data(); - for (unsigned track = 0; track < indices[type][chan][seg][0].size(); ++track) { + for (int track = 0; track < max_chan_width; ++track) { + /* TODO: May let the length() == 0 case go through, to model muxes */ if (seg_details[track].length() <= 0) continue; int start = get_seg_start(seg_details, track, chan, seg); + /* TODO: Now we still use the (y, x) convention here for CHANX. Should rework later */ + int node_x = chan; + int node_y = start; + if (CHANX == type) { + std::swap(node_x, node_y); + } + /* If the start of the wire doesn't have a inode, * assign one to it. */ - int inode = indices[type][chan][start][0][track]; - if (OPEN == inode) { - inode = *index; + RRNodeId inode = rr_graph_builder.node_lookup().find_node(node_x, node_y, type, track, SIDES[0]); + if (!inode) { + inode = RRNodeId(*index); ++(*index); - indices[type][chan][start][0][track] = inode; + rr_graph_builder.node_lookup().add_node(inode, chan, start, type, track, SIDES[0]); } /* Assign inode of start of wire to current position */ - indices[type][chan][seg][0][track] = inode; + rr_graph_builder.node_lookup().add_node(inode, chan, seg, type, track, SIDES[0]); } } } @@ -975,7 +971,6 @@ static void load_chan_rr_indices(const int max_chan_width, * 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 @@ -991,16 +986,12 @@ static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder, auto class_type = type->class_inf[iclass].type; if (class_type == DRIVER) { 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); 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); } - VTR_ASSERT(indices[SOURCE][x][y][0].size() == type->class_inf.size()); - VTR_ASSERT(indices[SINK][x][y][0].size() == type->class_inf.size()); /* Limited sides for grids * The wanted side depends on the location of the grid. @@ -1068,18 +1059,13 @@ static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder, auto class_type = type->class_inf[iclass].type; if (class_type == DRIVER) { - indices[OPIN][x_tile][y_tile][side].push_back(*index); - indices[IPIN][x_tile][y_tile][side].push_back(OPEN); + rr_graph_builder.node_lookup().add_node(RRNodeId(*index), x_tile, y_tile, OPIN, ipin, side); assigned_to_rr_node = true; } else { VTR_ASSERT(class_type == RECEIVER); - indices[OPIN][x_tile][y_tile][side].push_back(OPEN); - indices[IPIN][x_tile][y_tile][side].push_back(*index); + rr_graph_builder.node_lookup().add_node(RRNodeId(*index), x_tile, y_tile, IPIN, ipin, side); assigned_to_rr_node = true; } - } else { - indices[IPIN][x_tile][y_tile][side].push_back(OPEN); - indices[OPIN][x_tile][y_tile][side].push_back(OPEN); } } } @@ -1099,25 +1085,6 @@ static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder, ++(*index); } } - - //Sanity check - for (int width_offset = 0; width_offset < type->width; ++width_offset) { - int x_tile = x + width_offset; - for (int height_offset = 0; height_offset < type->height; ++height_offset) { - int y_tile = y + height_offset; - for (e_side side : SIDES) { - //Note that the fast look-up stores all the indices for the pins on each side - //It has a fixed size (either 0 or the number of pins) - //Case 0 pins: the side is skipped as no pins are located on it - //Case number of pins: there are pins on this side - //and data query can be applied any pin id on this side - VTR_ASSERT((indices[IPIN][x_tile][y_tile][side].size() == size_t(type->num_pins)) - || (0 == indices[IPIN][x_tile][y_tile][side].size())); - VTR_ASSERT((indices[OPIN][x_tile][y_tile][side].size() == size_t(type->num_pins)) - || (0 == indices[OPIN][x_tile][y_tile][side].size())); - } - } - } } } } @@ -1132,8 +1099,14 @@ static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder, int root_x = x - width_offset; int root_y = y - height_offset; - indices[SOURCE][x][y][0] = indices[SOURCE][root_x][root_y][0]; - indices[SINK][x][y][0] = indices[SINK][root_x][root_y][0]; + rr_graph_builder.node_lookup().mirror_nodes(vtr::Point(root_x, root_y), + vtr::Point(x, y), + SOURCE, + SIDES[0]); + rr_graph_builder.node_lookup().mirror_nodes(vtr::Point(root_x, root_y), + vtr::Point(x, y), + SINK, + SIDES[0]); } } } @@ -1149,7 +1122,7 @@ static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder, * 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, +void alloc_and_load_rr_node_indices(RRGraphBuilder& rr_graph_builder, const int max_chan_width, const DeviceGrid& grid, int* index, @@ -1162,20 +1135,20 @@ void alloc_and_load_rr_node_indices(t_rr_node_indices& indices, /* Alloc the lookup table */ for (t_rr_type rr_type : RR_TYPES) { if (rr_type == CHANX) { - indices[rr_type].resize({grid.height(), grid.width(), NUM_SIDES}); + rr_graph_builder.node_lookup().resize_nodes(grid.height(), grid.width(), rr_type, NUM_SIDES); } else { - indices[rr_type].resize({grid.width(), grid.height(), NUM_SIDES}); + rr_graph_builder.node_lookup().resize_nodes(grid.width(), grid.height(), rr_type, NUM_SIDES); } } /* Assign indices for block nodes */ - load_block_rr_indices(g_vpr_ctx.mutable_device().rr_graph_builder, indices, grid, index); + load_block_rr_indices(rr_graph_builder, 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); + CHANX, chan_details_x, rr_graph_builder, index); load_chan_rr_indices(max_chan_width, grid.height(), grid.width(), - CHANY, chan_details_y, indices, index); + CHANY, chan_details_y, rr_graph_builder, index); } 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 09467afcdd3..04cbcc1c86c 100644 --- a/vpr/src/route/rr_graph2.h +++ b/vpr/src/route/rr_graph2.h @@ -5,6 +5,7 @@ #include "build_switchblocks.h" #include "rr_graph_fwd.h" #include "rr_graph_util.h" +#include "rr_graph_builder.h" #include "rr_types.h" #include "device_grid.h" @@ -15,27 +16,6 @@ enum e_seg_details_type { SEG_DETAILS_Y }; -struct t_rr_edge_info { - t_rr_edge_info(int from, int to, short type) noexcept - : from_node(from) - , to_node(to) - , switch_type(type) {} - - int from_node = OPEN; - int to_node = OPEN; - short switch_type = OPEN; - - friend bool operator<(const t_rr_edge_info& lhs, const t_rr_edge_info& rhs) { - return std::tie(lhs.from_node, lhs.to_node, lhs.switch_type) < std::tie(rhs.from_node, rhs.to_node, rhs.switch_type); - } - - friend bool operator==(const t_rr_edge_info& lhs, const t_rr_edge_info& rhs) { - return std::tie(lhs.from_node, lhs.to_node, lhs.switch_type) == std::tie(rhs.from_node, rhs.to_node, rhs.switch_type); - } -}; - -typedef std::vector t_rr_edge_info_set; - typedef vtr::NdMatrix t_sblock_pattern; struct t_opin_connections_scratchpad { @@ -44,7 +24,7 @@ struct t_opin_connections_scratchpad { /******************* Subroutines exported by rr_graph2.c *********************/ -void alloc_and_load_rr_node_indices(t_rr_node_indices& indices, +void alloc_and_load_rr_node_indices(RRGraphBuilder& rr_graph_builder, const int max_chan_width, const DeviceGrid& grid, int* index, diff --git a/vpr/src/route/rr_graph_storage.h b/vpr/src/route/rr_graph_storage.h index b3a72d3a8a6..a73bfe233d7 100644 --- a/vpr/src/route/rr_graph_storage.h +++ b/vpr/src/route/rr_graph_storage.h @@ -6,7 +6,7 @@ #include "rr_graph_fwd.h" #include "rr_node_fwd.h" -#include "rr_graph2.h" +#include "rr_edge.h" #include "vtr_log.h" #include "vtr_memory.h" #include "vpr_utils.h"