From 302efd4f4f776daab7aca1f09f95342037c8420b Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Thu, 15 May 2025 13:56:10 -0400 Subject: [PATCH 01/10] add rr_graph_genearion directory --- vpr/src/route/{ => rr_graph_generation}/build_switchblocks.cpp | 0 vpr/src/route/{ => rr_graph_generation}/build_switchblocks.h | 0 vpr/src/route/{ => rr_graph_generation}/cb_metrics.cpp | 0 vpr/src/route/{ => rr_graph_generation}/cb_metrics.h | 0 .../{ => rr_graph_generation}/clock_connection_builders.cpp | 0 .../{ => rr_graph_generation}/clock_connection_builders.h | 0 vpr/src/route/{ => rr_graph_generation}/clock_fwd.h | 0 .../route/{ => rr_graph_generation}/clock_network_builders.cpp | 0 .../route/{ => rr_graph_generation}/clock_network_builders.h | 0 vpr/src/route/{ => rr_graph_generation}/rr_graph.cpp | 0 vpr/src/route/{ => rr_graph_generation}/rr_graph.h | 0 vpr/src/route/{ => rr_graph_generation}/rr_graph2.cpp | 0 vpr/src/route/{ => rr_graph_generation}/rr_graph2.h | 0 vpr/src/route/{ => rr_graph_generation}/rr_graph_area.cpp | 0 vpr/src/route/{ => rr_graph_generation}/rr_graph_area.h | 0 vpr/src/route/{ => rr_graph_generation}/rr_graph_clock.cpp | 0 vpr/src/route/{ => rr_graph_generation}/rr_graph_clock.h | 0 .../route/{ => rr_graph_generation}/rr_graph_indexed_data.cpp | 0 .../route/{ => rr_graph_generation}/rr_graph_indexed_data.h | 0 vpr/src/route/{ => rr_graph_generation}/rr_graph_sbox.cpp | 0 vpr/src/route/{ => rr_graph_generation}/rr_graph_sbox.h | 0 .../route/{ => rr_graph_generation}/rr_graph_timing_params.cpp | 0 .../route/{ => rr_graph_generation}/rr_graph_timing_params.h | 0 vpr/src/route/{ => rr_graph_generation}/rr_types.h | 3 ++- 24 files changed, 2 insertions(+), 1 deletion(-) rename vpr/src/route/{ => rr_graph_generation}/build_switchblocks.cpp (100%) rename vpr/src/route/{ => rr_graph_generation}/build_switchblocks.h (100%) rename vpr/src/route/{ => rr_graph_generation}/cb_metrics.cpp (100%) rename vpr/src/route/{ => rr_graph_generation}/cb_metrics.h (100%) rename vpr/src/route/{ => rr_graph_generation}/clock_connection_builders.cpp (100%) rename vpr/src/route/{ => rr_graph_generation}/clock_connection_builders.h (100%) rename vpr/src/route/{ => rr_graph_generation}/clock_fwd.h (100%) rename vpr/src/route/{ => rr_graph_generation}/clock_network_builders.cpp (100%) rename vpr/src/route/{ => rr_graph_generation}/clock_network_builders.h (100%) rename vpr/src/route/{ => rr_graph_generation}/rr_graph.cpp (100%) rename vpr/src/route/{ => rr_graph_generation}/rr_graph.h (100%) rename vpr/src/route/{ => rr_graph_generation}/rr_graph2.cpp (100%) rename vpr/src/route/{ => rr_graph_generation}/rr_graph2.h (100%) rename vpr/src/route/{ => rr_graph_generation}/rr_graph_area.cpp (100%) rename vpr/src/route/{ => rr_graph_generation}/rr_graph_area.h (100%) rename vpr/src/route/{ => rr_graph_generation}/rr_graph_clock.cpp (100%) rename vpr/src/route/{ => rr_graph_generation}/rr_graph_clock.h (100%) rename vpr/src/route/{ => rr_graph_generation}/rr_graph_indexed_data.cpp (100%) rename vpr/src/route/{ => rr_graph_generation}/rr_graph_indexed_data.h (100%) rename vpr/src/route/{ => rr_graph_generation}/rr_graph_sbox.cpp (100%) rename vpr/src/route/{ => rr_graph_generation}/rr_graph_sbox.h (100%) rename vpr/src/route/{ => rr_graph_generation}/rr_graph_timing_params.cpp (100%) rename vpr/src/route/{ => rr_graph_generation}/rr_graph_timing_params.h (100%) rename vpr/src/route/{ => rr_graph_generation}/rr_types.h (99%) diff --git a/vpr/src/route/build_switchblocks.cpp b/vpr/src/route/rr_graph_generation/build_switchblocks.cpp similarity index 100% rename from vpr/src/route/build_switchblocks.cpp rename to vpr/src/route/rr_graph_generation/build_switchblocks.cpp diff --git a/vpr/src/route/build_switchblocks.h b/vpr/src/route/rr_graph_generation/build_switchblocks.h similarity index 100% rename from vpr/src/route/build_switchblocks.h rename to vpr/src/route/rr_graph_generation/build_switchblocks.h diff --git a/vpr/src/route/cb_metrics.cpp b/vpr/src/route/rr_graph_generation/cb_metrics.cpp similarity index 100% rename from vpr/src/route/cb_metrics.cpp rename to vpr/src/route/rr_graph_generation/cb_metrics.cpp diff --git a/vpr/src/route/cb_metrics.h b/vpr/src/route/rr_graph_generation/cb_metrics.h similarity index 100% rename from vpr/src/route/cb_metrics.h rename to vpr/src/route/rr_graph_generation/cb_metrics.h diff --git a/vpr/src/route/clock_connection_builders.cpp b/vpr/src/route/rr_graph_generation/clock_connection_builders.cpp similarity index 100% rename from vpr/src/route/clock_connection_builders.cpp rename to vpr/src/route/rr_graph_generation/clock_connection_builders.cpp diff --git a/vpr/src/route/clock_connection_builders.h b/vpr/src/route/rr_graph_generation/clock_connection_builders.h similarity index 100% rename from vpr/src/route/clock_connection_builders.h rename to vpr/src/route/rr_graph_generation/clock_connection_builders.h diff --git a/vpr/src/route/clock_fwd.h b/vpr/src/route/rr_graph_generation/clock_fwd.h similarity index 100% rename from vpr/src/route/clock_fwd.h rename to vpr/src/route/rr_graph_generation/clock_fwd.h diff --git a/vpr/src/route/clock_network_builders.cpp b/vpr/src/route/rr_graph_generation/clock_network_builders.cpp similarity index 100% rename from vpr/src/route/clock_network_builders.cpp rename to vpr/src/route/rr_graph_generation/clock_network_builders.cpp diff --git a/vpr/src/route/clock_network_builders.h b/vpr/src/route/rr_graph_generation/clock_network_builders.h similarity index 100% rename from vpr/src/route/clock_network_builders.h rename to vpr/src/route/rr_graph_generation/clock_network_builders.h diff --git a/vpr/src/route/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp similarity index 100% rename from vpr/src/route/rr_graph.cpp rename to vpr/src/route/rr_graph_generation/rr_graph.cpp diff --git a/vpr/src/route/rr_graph.h b/vpr/src/route/rr_graph_generation/rr_graph.h similarity index 100% rename from vpr/src/route/rr_graph.h rename to vpr/src/route/rr_graph_generation/rr_graph.h diff --git a/vpr/src/route/rr_graph2.cpp b/vpr/src/route/rr_graph_generation/rr_graph2.cpp similarity index 100% rename from vpr/src/route/rr_graph2.cpp rename to vpr/src/route/rr_graph_generation/rr_graph2.cpp diff --git a/vpr/src/route/rr_graph2.h b/vpr/src/route/rr_graph_generation/rr_graph2.h similarity index 100% rename from vpr/src/route/rr_graph2.h rename to vpr/src/route/rr_graph_generation/rr_graph2.h diff --git a/vpr/src/route/rr_graph_area.cpp b/vpr/src/route/rr_graph_generation/rr_graph_area.cpp similarity index 100% rename from vpr/src/route/rr_graph_area.cpp rename to vpr/src/route/rr_graph_generation/rr_graph_area.cpp diff --git a/vpr/src/route/rr_graph_area.h b/vpr/src/route/rr_graph_generation/rr_graph_area.h similarity index 100% rename from vpr/src/route/rr_graph_area.h rename to vpr/src/route/rr_graph_generation/rr_graph_area.h diff --git a/vpr/src/route/rr_graph_clock.cpp b/vpr/src/route/rr_graph_generation/rr_graph_clock.cpp similarity index 100% rename from vpr/src/route/rr_graph_clock.cpp rename to vpr/src/route/rr_graph_generation/rr_graph_clock.cpp diff --git a/vpr/src/route/rr_graph_clock.h b/vpr/src/route/rr_graph_generation/rr_graph_clock.h similarity index 100% rename from vpr/src/route/rr_graph_clock.h rename to vpr/src/route/rr_graph_generation/rr_graph_clock.h diff --git a/vpr/src/route/rr_graph_indexed_data.cpp b/vpr/src/route/rr_graph_generation/rr_graph_indexed_data.cpp similarity index 100% rename from vpr/src/route/rr_graph_indexed_data.cpp rename to vpr/src/route/rr_graph_generation/rr_graph_indexed_data.cpp diff --git a/vpr/src/route/rr_graph_indexed_data.h b/vpr/src/route/rr_graph_generation/rr_graph_indexed_data.h similarity index 100% rename from vpr/src/route/rr_graph_indexed_data.h rename to vpr/src/route/rr_graph_generation/rr_graph_indexed_data.h diff --git a/vpr/src/route/rr_graph_sbox.cpp b/vpr/src/route/rr_graph_generation/rr_graph_sbox.cpp similarity index 100% rename from vpr/src/route/rr_graph_sbox.cpp rename to vpr/src/route/rr_graph_generation/rr_graph_sbox.cpp diff --git a/vpr/src/route/rr_graph_sbox.h b/vpr/src/route/rr_graph_generation/rr_graph_sbox.h similarity index 100% rename from vpr/src/route/rr_graph_sbox.h rename to vpr/src/route/rr_graph_generation/rr_graph_sbox.h diff --git a/vpr/src/route/rr_graph_timing_params.cpp b/vpr/src/route/rr_graph_generation/rr_graph_timing_params.cpp similarity index 100% rename from vpr/src/route/rr_graph_timing_params.cpp rename to vpr/src/route/rr_graph_generation/rr_graph_timing_params.cpp diff --git a/vpr/src/route/rr_graph_timing_params.h b/vpr/src/route/rr_graph_generation/rr_graph_timing_params.h similarity index 100% rename from vpr/src/route/rr_graph_timing_params.h rename to vpr/src/route/rr_graph_generation/rr_graph_timing_params.h diff --git a/vpr/src/route/rr_types.h b/vpr/src/route/rr_graph_generation/rr_types.h similarity index 99% rename from vpr/src/route/rr_types.h rename to vpr/src/route/rr_graph_generation/rr_types.h index 8e093faca75..620427a2d11 100644 --- a/vpr/src/route/rr_types.h +++ b/vpr/src/route/rr_graph_generation/rr_types.h @@ -1,5 +1,6 @@ #ifndef RR_TYPES_H #define RR_TYPES_H + #include #include "vtr_ndmatrix.h" @@ -14,7 +15,7 @@ typedef std::vector, 5>> t_pin_to_track_lookup; -/* AA: t_pin_to_track_lookup is alloacted first and is then converted to t_track_to_pin lookup by simply redefining the accessing order. +/* AA: t_pin_to_track_lookup is alloacted first and is then converted to t_track_to_pin lookup by simply redefining the accessing order. * As a result, the matrix should be accessed as follow as a result after allocation in rr_graph.cpp: alloc_track_to_pin_lookup (used by unidir and bidir) * [0..device_ctx.physical_tile_types.size()-1][0..max_chan_width-1][0..width][0..height][0..layer-1][0..3] * From 0cb4c48f5e3e580c724b8ff0b906255a10150cba Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Thu, 15 May 2025 14:34:36 -0400 Subject: [PATCH 02/10] add rr_node_indices.cpp/.h --- .../route/rr_graph_generation/rr_graph.cpp | 1 + .../route/rr_graph_generation/rr_graph2.cpp | 598 +---------------- vpr/src/route/rr_graph_generation/rr_graph2.h | 56 -- .../rr_graph_generation/rr_node_indices.cpp | 600 ++++++++++++++++++ .../rr_graph_generation/rr_node_indices.h | 66 ++ 5 files changed, 669 insertions(+), 652 deletions(-) create mode 100644 vpr/src/route/rr_graph_generation/rr_node_indices.cpp create mode 100644 vpr/src/route/rr_graph_generation/rr_node_indices.h diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index 3f77949d96b..b993ed7ded5 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -33,6 +33,7 @@ #include "edge_groups.h" #include "rr_graph_builder.h" #include "rr_types.h" +#include "rr_node_indices.h" //#define VERBOSE //used for getting the exact count of each edge type and printing it to std out. diff --git a/vpr/src/route/rr_graph_generation/rr_graph2.cpp b/vpr/src/route/rr_graph_generation/rr_graph2.cpp index 7bc71b57a78..a703bad0418 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph2.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph2.cpp @@ -1,6 +1,5 @@ #include -#include "describe_rr_node.h" #include "physical_types_util.h" #include "vtr_util.h" #include "vtr_assert.h" @@ -24,52 +23,8 @@ static void get_switch_type(bool is_from_sb, const int switch_override, short switch_types[2]); -static void load_chan_rr_indices(const int max_chan_width, - const DeviceGrid& grid, - const int chan_len, - const int num_chans, - const e_rr_type type, - const t_chan_details& chan_details, - RRGraphBuilder& rr_graph_builder, - int* index); - -/** - * @brief Assigns and loads rr_node indices for block-level routing resources (SOURCE, SINK, IPIN, OPIN). - * - * This function walks through the device grid and assigns unique rr_node indices to the routing resources - * associated with each block (tiles). - * - * For SINKs and SOURCEs, it uses side 0 by convention (since they have no geometric side). For IPINs and OPINs, - * it determines the correct sides based on the tile's position in the grid, following special rules for - * edge and corner tiles. - * - * The index counter is passed and updated as rr_nodes are added. - */ -static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder, - const DeviceGrid& grid, - int* index); - -static void add_pins_spatial_lookup(RRGraphBuilder& rr_graph_builder, - t_physical_tile_type_ptr physical_type_ptr, - const std::vector& pin_num_vec, - int layer, - int root_x, - int root_y, - int* index, - const std::vector& wanted_sides); - -static void add_classes_spatial_lookup(RRGraphBuilder& rr_graph_builder, - t_physical_tile_type_ptr physical_type_ptr, - const std::vector& class_num_vec, - int layer, - int x, - int y, - int block_width, - int block_height, - int* index); - static int get_bidir_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, - const std::vector conn_tracks, + const std::vector& conn_tracks, const int layer, const int to_chan, const int to_seg, @@ -1091,57 +1046,6 @@ void dump_track_to_pin_map(t_track_to_pin_lookup& track_to_pin_map, } } -static void load_chan_rr_indices(const int max_chan_width, - const DeviceGrid& grid, - const int chan_len, - const int num_chans, - const e_rr_type type, - const t_chan_details& chan_details, - RRGraphBuilder& rr_graph_builder, - int* index) { - const auto& device_ctx = g_vpr_ctx.device(); - - for (int layer = 0; layer < grid.get_num_layers(); layer++) { - // Skip the current die if architecture file specifies that it doesn't require global resource routing - if (!device_ctx.inter_cluster_prog_routing_resources.at(layer)) { - continue; - } - - 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 - const int x = (type == e_rr_type::CHANX) ? seg : chan; - const int y = (type == e_rr_type::CHANX) ? chan : seg; - const t_chan_seg_details* seg_details = chan_details[x][y].data(); - - // Reserve nodes in lookup to save memory - rr_graph_builder.node_lookup().reserve_nodes(layer, x, y, type, max_chan_width); - - 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); - int node_start_x = (type == e_rr_type::CHANX) ? start : chan; - int node_start_y = (type == e_rr_type::CHANX) ? chan : start; - - // If the start of the wire doesn't have an RRNodeId, assign one to it. - RRNodeId inode = rr_graph_builder.node_lookup().find_node(layer, node_start_x, node_start_y, type, track); - if (!inode) { - inode = RRNodeId(*index); - ++(*index); - rr_graph_builder.node_lookup().add_node(inode, layer, node_start_x, node_start_y, type, track); - } - - // Assign RRNodeId of start of wire to current position - rr_graph_builder.node_lookup().add_node(inode, layer, x, y, type, track); - } - } - } - } -} - static bool is_sb_conn_layer_crossing(enum e_side src_side, enum e_side dest_side) { if (src_side < NUM_2D_SIDES && dest_side < NUM_2D_SIDES) { return false; @@ -1212,471 +1116,6 @@ vtr::NdMatrix get_number_track_to_track_inter_die_conn(t_sb_connection_m return extra_nodes_per_switchblocks; } -void alloc_and_load_inter_die_rr_node_indices(RRGraphBuilder& rr_graph_builder, - const t_chan_width& nodes_per_chan, - const DeviceGrid& grid, - const vtr::NdMatrix& extra_nodes_per_switchblock, - int* index) { - /* - * In case of multi-die FPGAs, we add extra nodes (could have used either CHANX or CHANY; we chose to use all CHANX) to - * support inter-die communication coming from switch blocks (connection between two tracks in different layers) - * The extra nodes have the following attribute: - * 1) type = CHANX - * 2) length = 0 (xhigh = xlow, yhigh = ylow) - * 3) ptc = [max_chanx_width:max_chanx_width+number_of_connection-1] - * 4) direction = NONE - */ - const auto& device_ctx = g_vpr_ctx.device(); - - for (int layer = 0; layer < grid.get_num_layers(); layer++) { - /* Skip the current die if architecture file specifies that it doesn't have global resource routing */ - if (!device_ctx.inter_cluster_prog_routing_resources.at(layer)) { - continue; - } - - for (size_t y = 0; y < grid.height() - 1; ++y) { - for (size_t x = 1; x < grid.width() - 1; ++x) { - // count how many track-to-track connection go from current layer to other layers - int conn_count = extra_nodes_per_switchblock[x][y]; - - // skip if no connection is required - if (conn_count == 0) { - continue; - } - - // reserve extra nodes for inter-die track-to-track connection - rr_graph_builder.node_lookup().reserve_nodes(layer, x, y, e_rr_type::CHANX, conn_count + nodes_per_chan.max); - for (int rr_node_offset = 0; rr_node_offset < conn_count; rr_node_offset++) { - RRNodeId inode = rr_graph_builder.node_lookup().find_node(layer, x, y, e_rr_type::CHANX, nodes_per_chan.max + rr_node_offset); - if (!inode) { - inode = RRNodeId(*index); - ++(*index); - rr_graph_builder.node_lookup().add_node(inode, layer, x, y, e_rr_type::CHANX, nodes_per_chan.max + rr_node_offset); - } - } - } - } - } -} - -/* 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, - const DeviceGrid& grid, - int* index) { - //Walk through the grid assigning indices to SOURCE/SINK IPIN/OPIN - for (int layer = 0; layer < grid.get_num_layers(); layer++) { - for (int x = 0; x < (int)grid.width(); x++) { - for (int y = 0; y < (int)grid.height(); y++) { - //Process each block from its root location - if (grid.is_root_location({x, y, layer})) { - t_physical_tile_type_ptr physical_type = grid.get_physical_type({x, y, layer}); - - //Assign indices for SINKs and SOURCEs - // Note that SINKS/SOURCES have no side, so we always use side 0 - std::vector class_num_vec = get_tile_root_classes(physical_type); - std::vector pin_num_vec = get_tile_root_pins(physical_type); - - add_classes_spatial_lookup(rr_graph_builder, - physical_type, - class_num_vec, - layer, - x, - y, - physical_type->width, - physical_type->height, - index); - - /* Limited sides for grids - * The wanted side depends on the location of the grid. - * In particular for perimeter grid, - * ------------------------------------------------------- - * Grid location | IPIN side - * ------------------------------------------------------- - * TOP | BOTTOM - * ------------------------------------------------------- - * RIGHT | LEFT - * ------------------------------------------------------- - * BOTTOM | TOP - * ------------------------------------------------------- - * LEFT | RIGHT - * ------------------------------------------------------- - * TOP-LEFT | BOTTOM & RIGHT - * ------------------------------------------------------- - * TOP-RIGHT | BOTTOM & LEFT - * ------------------------------------------------------- - * BOTTOM-LEFT | TOP & RIGHT - * ------------------------------------------------------- - * BOTTOM-RIGHT | TOP & LEFT - * ------------------------------------------------------- - * Other | First come first fit - * ------------------------------------------------------- - * - * Special for IPINs: - * If there are multiple wanted sides, first come first fit is applied - * This guarantee that there is only a unique rr_node - * for the same input pin on multiple sides, and thus avoid multiple driver problems - */ - std::vector wanted_sides; - if ((int)grid.height() - 1 == y) { /* TOP side */ - wanted_sides.push_back(BOTTOM); - } - if ((int)grid.width() - 1 == x) { /* RIGHT side */ - wanted_sides.push_back(LEFT); - } - if (0 == y) { /* BOTTOM side */ - wanted_sides.push_back(TOP); - } - if (0 == x) { /* LEFT side */ - wanted_sides.push_back(RIGHT); - } - - /* If wanted sides is empty still, this block does not have specific wanted sides, - * Deposit all the sides - */ - if (wanted_sides.empty()) { - for (e_side side : TOTAL_2D_SIDES) { - wanted_sides.push_back(side); - } - } - - add_pins_spatial_lookup(rr_graph_builder, - physical_type, - pin_num_vec, - layer, - x, - y, - index, - wanted_sides); - } - } - } - } -} - -static void add_pins_spatial_lookup(RRGraphBuilder& rr_graph_builder, - t_physical_tile_type_ptr physical_type_ptr, - const std::vector& pin_num_vec, - int layer, - int root_x, - int root_y, - int* index, - const std::vector& wanted_sides) { - for (e_side side : wanted_sides) { - for (int width_offset = 0; width_offset < physical_type_ptr->width; ++width_offset) { - int x_tile = root_x + width_offset; - for (int height_offset = 0; height_offset < physical_type_ptr->height; ++height_offset) { - int y_tile = root_y + height_offset; - //only nodes on the tile may be located in a location other than the root-location - rr_graph_builder.node_lookup().reserve_nodes(layer, x_tile, y_tile, e_rr_type::OPIN, physical_type_ptr->num_pins, side); - rr_graph_builder.node_lookup().reserve_nodes(layer, x_tile, y_tile, e_rr_type::IPIN, physical_type_ptr->num_pins, side); - } - } - } - - for (const int pin_num : pin_num_vec) { - bool assigned_to_rr_node = false; - const auto [x_offset, y_offset, pin_sides] = get_pin_coordinates(physical_type_ptr, pin_num, wanted_sides); - e_pin_type pin_type = get_pin_type_from_pin_physical_num(physical_type_ptr, pin_num); - for (int pin_coord_idx = 0; pin_coord_idx < (int)pin_sides.size(); pin_coord_idx++) { - int x_tile = root_x + x_offset[pin_coord_idx]; - int y_tile = root_y + y_offset[pin_coord_idx]; - e_side side = pin_sides[pin_coord_idx]; - if (pin_type == DRIVER) { - rr_graph_builder.node_lookup().add_node(RRNodeId(*index), layer, x_tile, y_tile, e_rr_type::OPIN, pin_num, side); - assigned_to_rr_node = true; - } else { - VTR_ASSERT(pin_type == RECEIVER); - rr_graph_builder.node_lookup().add_node(RRNodeId(*index), layer, x_tile, y_tile, e_rr_type::IPIN, pin_num, side); - assigned_to_rr_node = true; - } - } - /* A pin may locate on multiple sides of a tile. - * Instead of allocating multiple rr_nodes for the pin, - * we just create a rr_node and make it indexable on these sides - * As such, we can avoid redundant rr_node to be allocated - * and multiple nets to be mapped to the pin - * - * Considering that some pin could be just dangling, we do not need - * to create a void rr_node for it. - * As such, we only allocate a rr node when the pin is indeed located - * on at least one side - */ - if (assigned_to_rr_node) { - ++(*index); - } - } -} - -static void add_classes_spatial_lookup(RRGraphBuilder& rr_graph_builder, - t_physical_tile_type_ptr physical_type_ptr, - const std::vector& class_num_vec, - int layer, - int root_x, - int root_y, - int block_width, - int block_height, - int* index) { - for (int x_tile = root_x; x_tile < (root_x + block_width); x_tile++) { - for (int y_tile = root_y; y_tile < (root_y + block_height); y_tile++) { - rr_graph_builder.node_lookup().reserve_nodes(layer, x_tile, y_tile, e_rr_type::SOURCE, class_num_vec.size(), TOTAL_2D_SIDES[0]); - rr_graph_builder.node_lookup().reserve_nodes(layer, x_tile, y_tile, e_rr_type::SINK, class_num_vec.size(), TOTAL_2D_SIDES[0]); - } - } - - for (const int class_num : class_num_vec) { - e_pin_type class_type = get_class_type_from_class_physical_num(physical_type_ptr, class_num); - e_rr_type node_type = e_rr_type::SINK; - if (class_type == DRIVER) { - node_type = e_rr_type::SOURCE; - } else { - VTR_ASSERT(class_type == RECEIVER); - } - - for (int x_offset = 0; x_offset < block_width; x_offset++) { - for (int y_offset = 0; y_offset < block_height; y_offset++) { - int curr_x = root_x + x_offset; - int curr_y = root_y + y_offset; - - rr_graph_builder.node_lookup().add_node(RRNodeId(*index), layer, curr_x, curr_y, node_type, class_num); - } - } - - ++(*index); - } -} - -void alloc_and_load_rr_node_indices(RRGraphBuilder& rr_graph_builder, - const t_chan_width& nodes_per_chan, - const DeviceGrid& grid, - int* index, - const t_chan_details& chan_details_x, - const t_chan_details& chan_details_y) { - /* Alloc the lookup table */ - for (e_rr_type rr_type : RR_TYPES) { - rr_graph_builder.node_lookup().resize_nodes(grid.get_num_layers(), grid.width(), grid.height(), rr_type, NUM_2D_SIDES); - } - - /* Assign indices for block nodes */ - load_block_rr_indices(rr_graph_builder, grid, index); - - /* Load the data for x and y channels */ - load_chan_rr_indices(nodes_per_chan.x_max, grid, grid.width(), grid.height(), - e_rr_type::CHANX, chan_details_x, rr_graph_builder, index); - load_chan_rr_indices(nodes_per_chan.y_max, grid, grid.height(), grid.width(), - e_rr_type::CHANY, chan_details_y, rr_graph_builder, index); -} - -void alloc_and_load_intra_cluster_rr_node_indices(RRGraphBuilder& rr_graph_builder, - const DeviceGrid& grid, - const vtr::vector& pin_chains, - const vtr::vector>& pin_chains_num, - int* index) { - for (int layer = 0; layer < grid.get_num_layers(); layer++) { - for (int x = 0; x < (int)grid.width(); x++) { - for (int y = 0; y < (int)grid.height(); y++) { - //Process each block from its root location - if (grid.is_root_location({x, y, layer})) { - t_physical_tile_type_ptr physical_type = grid.get_physical_type({x, y, layer}); - //Assign indices for SINKs and SOURCEs - // Note that SINKS/SOURCES have no side, so we always use side 0 - std::vector class_num_vec; - std::vector pin_num_vec; - class_num_vec = get_cluster_netlist_intra_tile_classes_at_loc(layer, x, y, physical_type); - pin_num_vec = get_cluster_netlist_intra_tile_pins_at_loc(layer, - x, - y, - pin_chains, - pin_chains_num, - physical_type); - add_classes_spatial_lookup(rr_graph_builder, - physical_type, - class_num_vec, - layer, - x, - y, - physical_type->width, - physical_type->height, - index); - - std::vector wanted_sides; - wanted_sides.push_back(e_side::TOP); - add_pins_spatial_lookup(rr_graph_builder, - physical_type, - pin_num_vec, - layer, - x, - y, - index, - wanted_sides); - } - } - } - } -} - -bool verify_rr_node_indices(const DeviceGrid& grid, - const RRGraphView& rr_graph, - const vtr::vector& rr_indexed_data, - const t_rr_graph_storage& rr_nodes, - bool is_flat) { - std::unordered_map rr_node_counts; - - int width = grid.width(); - int height = grid.height(); - int layer = grid.get_num_layers(); - - for (int l = 0; l < layer; ++l) { - for (int x = 0; x < width; ++x) { - for (int y = 0; y < height; ++y) { - for (e_rr_type rr_type : RR_TYPES) { - /* Get the list of nodes at a specific location (x, y) */ - std::vector nodes_from_lookup; - if (rr_type == e_rr_type::CHANX || rr_type == e_rr_type::CHANY) { - nodes_from_lookup = rr_graph.node_lookup().find_channel_nodes(l, x, y, rr_type); - } else { - nodes_from_lookup = rr_graph.node_lookup().find_grid_nodes_at_all_sides(l, x, y, rr_type); - } - - for (RRNodeId inode : nodes_from_lookup) { - rr_node_counts[inode]++; - - if (rr_graph.node_type(inode) != rr_type) { - VPR_ERROR(VPR_ERROR_ROUTE, "RR node type does not match between rr_nodes and rr_node_indices (%s/%s): %s", - rr_node_typename[rr_graph.node_type(inode)], - rr_node_typename[rr_type], - describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); - } - - if (rr_graph.node_type(inode) == e_rr_type::CHANX) { - VTR_ASSERT_MSG(rr_graph.node_ylow(inode) == rr_graph.node_yhigh(inode), "CHANX should be horizontal"); - if (y != rr_graph.node_ylow(inode)) { - VPR_ERROR(VPR_ERROR_ROUTE, "RR node y position does not agree between rr_nodes (%d) and rr_node_indices (%d): %s", - rr_graph.node_ylow(inode), - y, - describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); - } - - if (!rr_graph.x_in_node_range(x, inode)) { - VPR_ERROR(VPR_ERROR_ROUTE, "RR node x positions do not agree between rr_nodes (%d <-> %d) and rr_node_indices (%d): %s", - rr_graph.node_xlow(inode), - rr_graph.node_xlow(inode), - x, - describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); - } - } else if (rr_graph.node_type(inode) == e_rr_type::CHANY) { - VTR_ASSERT_MSG(rr_graph.node_xlow(inode) == rr_graph.node_xhigh(inode), "CHANY should be vertical"); - - if (x != rr_graph.node_xlow(inode)) { - VPR_ERROR(VPR_ERROR_ROUTE, "RR node x position does not agree between rr_nodes (%d) and rr_node_indices (%d): %s", - rr_graph.node_xlow(inode), - x, - describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); - } - - if (!rr_graph.y_in_node_range(y, inode)) { - VPR_ERROR(VPR_ERROR_ROUTE, "RR node y positions do not agree between rr_nodes (%d <-> %d) and rr_node_indices (%d): %s", - rr_graph.node_ylow(inode), - rr_graph.node_ylow(inode), - y, - describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); - } - } else if (rr_graph.node_type(inode) == e_rr_type::SOURCE || rr_graph.node_type(inode) == e_rr_type::SINK) { - // Sources have co-ordinates covering the entire block they are in, but not sinks - if (!rr_graph.x_in_node_range(x, inode)) { - VPR_ERROR(VPR_ERROR_ROUTE, "RR node x positions do not agree between rr_nodes (%d <-> %d) and rr_node_indices (%d): %s", - rr_graph.node_xlow(inode), - rr_graph.node_xlow(inode), - x, - describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); - } - - if (!rr_graph.y_in_node_range(y, inode)) { - VPR_ERROR(VPR_ERROR_ROUTE, "RR node y positions do not agree between rr_nodes (%d <-> %d) and rr_node_indices (%d): %s", - rr_graph.node_ylow(inode), - rr_graph.node_ylow(inode), - y, - describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); - } - } else { - VTR_ASSERT(rr_graph.node_type(inode) == e_rr_type::IPIN || rr_graph.node_type(inode) == e_rr_type::OPIN); - /* As we allow a pin to be indexable on multiple sides, - * This check code should be invalid - * if (rr_node.xlow() != x) { - * VPR_ERROR(VPR_ERROR_ROUTE, "RR node xlow does not match between rr_nodes and rr_node_indices (%d/%d): %s", - * rr_node.xlow(), - * x, - * describe_rr_node(rr_graph, grid, rr_indexed_data, inode).c_str()); - * } - * - * if (rr_node.ylow() != y) { - * VPR_ERROR(VPR_ERROR_ROUTE, "RR node ylow does not match between rr_nodes and rr_node_indices (%d/%d): %s", - * rr_node.ylow(), - * y, - * describe_rr_node(rr_graph, grid, rr_indexed_data, inode).c_str()); - * } - */ - } - - if (rr_type == e_rr_type::IPIN || rr_type == e_rr_type::OPIN) { - /* As we allow a pin to be indexable on multiple sides, - * This check code should be invalid - * if (rr_node.side() != side) { - * VPR_ERROR(VPR_ERROR_ROUTE, "RR node xlow does not match between rr_nodes and rr_node_indices (%s/%s): %s", - * TOTAL_2D_SIDE_STRINGS[rr_node.side()], - * TOTAL_2D_SIDE_STRINGS[side], - * describe_rr_node(rr_graph, grid, rr_indexed_data, inode).c_str()); - * } else { - * VTR_ASSERT(rr_node.side() == side); - * } - */ - } - } - } - } - } - } - - if (rr_node_counts.size() != rr_nodes.size()) { - VPR_ERROR(VPR_ERROR_ROUTE, "Mismatch in number of unique RR nodes in rr_nodes (%zu) and rr_node_indices (%zu)", - rr_nodes.size(), - rr_node_counts.size()); - } - - for (auto kv : rr_node_counts) { - RRNodeId inode = kv.first; - int count = kv.second; - - auto& rr_node = rr_nodes[size_t(inode)]; - - if (rr_graph.node_type(inode) == e_rr_type::SOURCE || rr_graph.node_type(inode) == e_rr_type::SINK) { - int rr_width = (rr_graph.node_xhigh(rr_node.id()) - rr_graph.node_xlow(rr_node.id()) + 1); - int rr_height = (rr_graph.node_yhigh(rr_node.id()) - rr_graph.node_ylow(rr_node.id()) + 1); - int rr_area = rr_width * rr_height; - if (count != rr_area) { - VPR_ERROR(VPR_ERROR_ROUTE, "Mismatch between RR node size (%d) and count within rr_node_indices (%d): %s", - rr_area, - rr_node.length(), - count, - describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); - } - /* As we allow a pin to be indexable on multiple sides, - * This check code should not be applied to input and output pins - */ - } else if ((e_rr_type::OPIN != rr_graph.node_type(inode)) && (e_rr_type::IPIN != rr_graph.node_type(inode))) { - if (count != rr_node.length() + 1) { - VPR_ERROR(VPR_ERROR_ROUTE, "Mismatch between RR node length (%d) and count within rr_node_indices (%d, should be length + 1): %s", - rr_node.length(), - count, - describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); - } - } - } - - return true; -} - int get_track_to_pins(RRGraphBuilder& rr_graph_builder, int layer, int seg, @@ -2007,41 +1446,8 @@ int get_track_to_tracks(RRGraphBuilder& rr_graph_builder, return num_conn; } -void alloc_and_load_tile_rr_node_indices(RRGraphBuilder& rr_graph_builder, - t_physical_tile_type_ptr physical_tile, - int layer, - int x, - int y, - int* num_rr_nodes) { - std::vector wanted_sides{TOP, BOTTOM, LEFT, RIGHT}; - auto class_num_range = get_flat_tile_primitive_classes(physical_tile); - auto pin_num_vec = get_flat_tile_pins(physical_tile); - - std::vector class_num_vec(class_num_range.total_num()); - std::iota(class_num_vec.begin(), class_num_vec.end(), class_num_range.low); - - add_classes_spatial_lookup(rr_graph_builder, - physical_tile, - class_num_vec, - layer, - x, - y, - physical_tile->width, - physical_tile->height, - num_rr_nodes); - - add_pins_spatial_lookup(rr_graph_builder, - physical_tile, - pin_num_vec, - layer, - x, - y, - num_rr_nodes, - wanted_sides); -} - static int get_bidir_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, - const std::vector conn_tracks, + const std::vector& conn_tracks, const int layer, const int to_chan, const int to_seg, diff --git a/vpr/src/route/rr_graph_generation/rr_graph2.h b/vpr/src/route/rr_graph_generation/rr_graph2.h index 05e723470e4..c4b24569993 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph2.h +++ b/vpr/src/route/rr_graph_generation/rr_graph2.h @@ -14,62 +14,6 @@ /******************* Subroutines exported by rr_graph2.c *********************/ -/** - * @brief Allocates and populates data structures for efficient rr_node index lookups. - * - * This function sets up the `rr_node_indices` structure, which maps a physical location - * and type to the index of the first corresponding rr_node. - */ -void alloc_and_load_rr_node_indices(RRGraphBuilder& rr_graph_builder, - const t_chan_width& nodes_per_chan, - const DeviceGrid& grid, - int* index, - const t_chan_details& chan_details_x, - const t_chan_details& chan_details_y); - -/** - * @brief Allocates extra nodes within the RR graph to support 3D custom switch blocks for multi-die FPGAs - * - * @param rr_graph_builder RRGraphBuilder data structure which allows data modification on a routing resource graph - * @param nodes_per_chan number of tracks per channel (x, y) - * @param grid device grid - * @param extra_nodes_per_switchblock keeps how many extra length-0 CHANX node is required for each unique (x,y) location within the grid. - * Number of these extra nodes are exactly the same for all layers. Hence, we only keep it for one layer. ([0..grid.width-1][0..grid.height-1) - * @param index RRNodeId that should be assigned to add a new RR node to the RR graph - */ -void alloc_and_load_inter_die_rr_node_indices(RRGraphBuilder& rr_graph_builder, - const t_chan_width& nodes_per_chan, - const DeviceGrid& grid, - const vtr::NdMatrix& extra_nodes_per_switchblock, - int* index); - -void alloc_and_load_tile_rr_node_indices(RRGraphBuilder& rr_graph_builder, - t_physical_tile_type_ptr physical_tile, - int layer, - int x, - int y, - int* num_rr_nodes); - -void alloc_and_load_intra_cluster_rr_node_indices(RRGraphBuilder& rr_graph_builder, - const DeviceGrid& grid, - const vtr::vector& pin_chains, - const vtr::vector>& pin_chains_num, - int* index); - -/** - * Validate the node look-up matches all the node-level information - * in the storage of a routing resource graph - * This function will check the following aspects: - * - The type of each node matches its type that is indexed in the node look-up - * - For bounding box (xlow, ylow, xhigh, yhigh) of each node is indexable in the node look-up - * - The number of unique indexable nodes in the node look up matches the number of nodes in the storage - * This ensures that every node in the storage is indexable and there are no hidden nodes in the look-up - */ -bool verify_rr_node_indices(const DeviceGrid& grid, - const RRGraphView& rr_graph, - const vtr::vector& rr_indexed_data, - const t_rr_graph_storage& rr_nodes, - bool is_flat); /** * @brief goes through 3D custom switch blocks and counts how many connections are crossing dice for each switch block. * diff --git a/vpr/src/route/rr_graph_generation/rr_node_indices.cpp b/vpr/src/route/rr_graph_generation/rr_node_indices.cpp new file mode 100644 index 00000000000..5012b2d67c0 --- /dev/null +++ b/vpr/src/route/rr_graph_generation/rr_node_indices.cpp @@ -0,0 +1,600 @@ + +#include "rr_node_indices.h" + +#include "describe_rr_node.h" +#include "globals.h" +#include "physical_types_util.h" + + +/** + * @brief Assigns and loads rr_node indices for block-level routing resources (SOURCE, SINK, IPIN, OPIN). + * + * This function walks through the device grid and assigns unique rr_node indices to the routing resources + * associated with each block (tiles). + * + * For SINKs and SOURCEs, it uses side 0 by convention (since they have no geometric side). For IPINs and OPINs, + * it determines the correct sides based on the tile's position in the grid, following special rules for + * edge and corner tiles. + * + * The index counter is passed and updated as rr_nodes are added. + */ +static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder, + const DeviceGrid& grid, + int* index); + +static void load_chan_rr_indices(const int max_chan_width, + const DeviceGrid& grid, + const int chan_len, + const int num_chans, + const e_rr_type type, + const t_chan_details& chan_details, + RRGraphBuilder& rr_graph_builder, + int* index); + +static void add_classes_spatial_lookup(RRGraphBuilder& rr_graph_builder, + t_physical_tile_type_ptr physical_type_ptr, + const std::vector& class_num_vec, + int layer, + int x, + int y, + int block_width, + int block_height, + int* index); + +static void add_pins_spatial_lookup(RRGraphBuilder& rr_graph_builder, + t_physical_tile_type_ptr physical_type_ptr, + const std::vector& pin_num_vec, + int layer, + int root_x, + int root_y, + int* index, + const std::vector& wanted_sides); + +/* 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, + const DeviceGrid& grid, + int* index) { + //Walk through the grid assigning indices to SOURCE/SINK IPIN/OPIN + for (int layer = 0; layer < grid.get_num_layers(); layer++) { + for (int x = 0; x < (int)grid.width(); x++) { + for (int y = 0; y < (int)grid.height(); y++) { + //Process each block from its root location + if (grid.is_root_location({x, y, layer})) { + t_physical_tile_type_ptr physical_type = grid.get_physical_type({x, y, layer}); + + //Assign indices for SINKs and SOURCEs + // Note that SINKS/SOURCES have no side, so we always use side 0 + std::vector class_num_vec = get_tile_root_classes(physical_type); + std::vector pin_num_vec = get_tile_root_pins(physical_type); + + add_classes_spatial_lookup(rr_graph_builder, + physical_type, + class_num_vec, + layer, + x, + y, + physical_type->width, + physical_type->height, + index); + + /* Limited sides for grids + * The wanted side depends on the location of the grid. + * In particular for perimeter grid, + * ------------------------------------------------------- + * Grid location | IPIN side + * ------------------------------------------------------- + * TOP | BOTTOM + * ------------------------------------------------------- + * RIGHT | LEFT + * ------------------------------------------------------- + * BOTTOM | TOP + * ------------------------------------------------------- + * LEFT | RIGHT + * ------------------------------------------------------- + * TOP-LEFT | BOTTOM & RIGHT + * ------------------------------------------------------- + * TOP-RIGHT | BOTTOM & LEFT + * ------------------------------------------------------- + * BOTTOM-LEFT | TOP & RIGHT + * ------------------------------------------------------- + * BOTTOM-RIGHT | TOP & LEFT + * ------------------------------------------------------- + * Other | First come first fit + * ------------------------------------------------------- + * + * Special for IPINs: + * If there are multiple wanted sides, first come first fit is applied + * This guarantee that there is only a unique rr_node + * for the same input pin on multiple sides, and thus avoid multiple driver problems + */ + std::vector wanted_sides; + if ((int)grid.height() - 1 == y) { /* TOP side */ + wanted_sides.push_back(BOTTOM); + } + if ((int)grid.width() - 1 == x) { /* RIGHT side */ + wanted_sides.push_back(LEFT); + } + if (0 == y) { /* BOTTOM side */ + wanted_sides.push_back(TOP); + } + if (0 == x) { /* LEFT side */ + wanted_sides.push_back(RIGHT); + } + + /* If wanted sides is empty still, this block does not have specific wanted sides, + * Deposit all the sides + */ + if (wanted_sides.empty()) { + for (e_side side : TOTAL_2D_SIDES) { + wanted_sides.push_back(side); + } + } + + add_pins_spatial_lookup(rr_graph_builder, + physical_type, + pin_num_vec, + layer, + x, + y, + index, + wanted_sides); + } + } + } + } +} + +static void load_chan_rr_indices(const int max_chan_width, + const DeviceGrid& grid, + const int chan_len, + const int num_chans, + const e_rr_type type, + const t_chan_details& chan_details, + RRGraphBuilder& rr_graph_builder, + int* index) { + const auto& device_ctx = g_vpr_ctx.device(); + + for (int layer = 0; layer < grid.get_num_layers(); layer++) { + // Skip the current die if architecture file specifies that it doesn't require global resource routing + if (!device_ctx.inter_cluster_prog_routing_resources.at(layer)) { + continue; + } + + 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 + const int x = (type == e_rr_type::CHANX) ? seg : chan; + const int y = (type == e_rr_type::CHANX) ? chan : seg; + const t_chan_seg_details* seg_details = chan_details[x][y].data(); + + // Reserve nodes in lookup to save memory + rr_graph_builder.node_lookup().reserve_nodes(layer, x, y, type, max_chan_width); + + 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); + int node_start_x = (type == e_rr_type::CHANX) ? start : chan; + int node_start_y = (type == e_rr_type::CHANX) ? chan : start; + + // If the start of the wire doesn't have an RRNodeId, assign one to it. + RRNodeId inode = rr_graph_builder.node_lookup().find_node(layer, node_start_x, node_start_y, type, track); + if (!inode) { + inode = RRNodeId(*index); + ++(*index); + rr_graph_builder.node_lookup().add_node(inode, layer, node_start_x, node_start_y, type, track); + } + + // Assign RRNodeId of start of wire to current position + rr_graph_builder.node_lookup().add_node(inode, layer, x, y, type, track); + } + } + } + } +} + +static void add_classes_spatial_lookup(RRGraphBuilder& rr_graph_builder, + t_physical_tile_type_ptr physical_type_ptr, + const std::vector& class_num_vec, + int layer, + int root_x, + int root_y, + int block_width, + int block_height, + int* index) { + for (int x_tile = root_x; x_tile < (root_x + block_width); x_tile++) { + for (int y_tile = root_y; y_tile < (root_y + block_height); y_tile++) { + rr_graph_builder.node_lookup().reserve_nodes(layer, x_tile, y_tile, e_rr_type::SOURCE, class_num_vec.size(), TOTAL_2D_SIDES[0]); + rr_graph_builder.node_lookup().reserve_nodes(layer, x_tile, y_tile, e_rr_type::SINK, class_num_vec.size(), TOTAL_2D_SIDES[0]); + } + } + + for (const int class_num : class_num_vec) { + e_pin_type class_type = get_class_type_from_class_physical_num(physical_type_ptr, class_num); + e_rr_type node_type = e_rr_type::SINK; + if (class_type == DRIVER) { + node_type = e_rr_type::SOURCE; + } else { + VTR_ASSERT(class_type == RECEIVER); + } + + for (int x_offset = 0; x_offset < block_width; x_offset++) { + for (int y_offset = 0; y_offset < block_height; y_offset++) { + int curr_x = root_x + x_offset; + int curr_y = root_y + y_offset; + + rr_graph_builder.node_lookup().add_node(RRNodeId(*index), layer, curr_x, curr_y, node_type, class_num); + } + } + + ++(*index); + } +} + +static void add_pins_spatial_lookup(RRGraphBuilder& rr_graph_builder, + t_physical_tile_type_ptr physical_type_ptr, + const std::vector& pin_num_vec, + int layer, + int root_x, + int root_y, + int* index, + const std::vector& wanted_sides) { + for (e_side side : wanted_sides) { + for (int width_offset = 0; width_offset < physical_type_ptr->width; ++width_offset) { + int x_tile = root_x + width_offset; + for (int height_offset = 0; height_offset < physical_type_ptr->height; ++height_offset) { + int y_tile = root_y + height_offset; + //only nodes on the tile may be located in a location other than the root-location + rr_graph_builder.node_lookup().reserve_nodes(layer, x_tile, y_tile, e_rr_type::OPIN, physical_type_ptr->num_pins, side); + rr_graph_builder.node_lookup().reserve_nodes(layer, x_tile, y_tile, e_rr_type::IPIN, physical_type_ptr->num_pins, side); + } + } + } + + for (const int pin_num : pin_num_vec) { + bool assigned_to_rr_node = false; + const auto [x_offset, y_offset, pin_sides] = get_pin_coordinates(physical_type_ptr, pin_num, wanted_sides); + e_pin_type pin_type = get_pin_type_from_pin_physical_num(physical_type_ptr, pin_num); + for (int pin_coord_idx = 0; pin_coord_idx < (int)pin_sides.size(); pin_coord_idx++) { + int x_tile = root_x + x_offset[pin_coord_idx]; + int y_tile = root_y + y_offset[pin_coord_idx]; + e_side side = pin_sides[pin_coord_idx]; + if (pin_type == DRIVER) { + rr_graph_builder.node_lookup().add_node(RRNodeId(*index), layer, x_tile, y_tile, e_rr_type::OPIN, pin_num, side); + assigned_to_rr_node = true; + } else { + VTR_ASSERT(pin_type == RECEIVER); + rr_graph_builder.node_lookup().add_node(RRNodeId(*index), layer, x_tile, y_tile, e_rr_type::IPIN, pin_num, side); + assigned_to_rr_node = true; + } + } + /* A pin may locate on multiple sides of a tile. + * Instead of allocating multiple rr_nodes for the pin, + * we just create a rr_node and make it indexable on these sides + * As such, we can avoid redundant rr_node to be allocated + * and multiple nets to be mapped to the pin + * + * Considering that some pin could be just dangling, we do not need + * to create a void rr_node for it. + * As such, we only allocate a rr node when the pin is indeed located + * on at least one side + */ + if (assigned_to_rr_node) { + ++(*index); + } + } +} + +void alloc_and_load_rr_node_indices(RRGraphBuilder& rr_graph_builder, + const t_chan_width& nodes_per_chan, + const DeviceGrid& grid, + int* index, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y) { + /* Alloc the lookup table */ + for (e_rr_type rr_type : RR_TYPES) { + rr_graph_builder.node_lookup().resize_nodes(grid.get_num_layers(), grid.width(), grid.height(), rr_type, NUM_2D_SIDES); + } + + /* Assign indices for block nodes */ + load_block_rr_indices(rr_graph_builder, grid, index); + + /* Load the data for x and y channels */ + load_chan_rr_indices(nodes_per_chan.x_max, grid, grid.width(), grid.height(), + e_rr_type::CHANX, chan_details_x, rr_graph_builder, index); + load_chan_rr_indices(nodes_per_chan.y_max, grid, grid.height(), grid.width(), + e_rr_type::CHANY, chan_details_y, rr_graph_builder, index); +} + +void alloc_and_load_inter_die_rr_node_indices(RRGraphBuilder& rr_graph_builder, + const t_chan_width& nodes_per_chan, + const DeviceGrid& grid, + const vtr::NdMatrix& extra_nodes_per_switchblock, + int* index) { + /* + * In case of multi-die FPGAs, we add extra nodes (could have used either CHANX or CHANY; we chose to use all CHANX) to + * support inter-die communication coming from switch blocks (connection between two tracks in different layers) + * The extra nodes have the following attribute: + * 1) type = CHANX + * 2) length = 0 (xhigh = xlow, yhigh = ylow) + * 3) ptc = [max_chanx_width:max_chanx_width+number_of_connection-1] + * 4) direction = NONE + */ + const auto& device_ctx = g_vpr_ctx.device(); + + for (int layer = 0; layer < grid.get_num_layers(); layer++) { + /* Skip the current die if architecture file specifies that it doesn't have global resource routing */ + if (!device_ctx.inter_cluster_prog_routing_resources.at(layer)) { + continue; + } + + for (size_t y = 0; y < grid.height() - 1; ++y) { + for (size_t x = 1; x < grid.width() - 1; ++x) { + // count how many track-to-track connection go from current layer to other layers + int conn_count = extra_nodes_per_switchblock[x][y]; + + // skip if no connection is required + if (conn_count == 0) { + continue; + } + + // reserve extra nodes for inter-die track-to-track connection + rr_graph_builder.node_lookup().reserve_nodes(layer, x, y, e_rr_type::CHANX, conn_count + nodes_per_chan.max); + for (int rr_node_offset = 0; rr_node_offset < conn_count; rr_node_offset++) { + RRNodeId inode = rr_graph_builder.node_lookup().find_node(layer, x, y, e_rr_type::CHANX, nodes_per_chan.max + rr_node_offset); + if (!inode) { + inode = RRNodeId(*index); + ++(*index); + rr_graph_builder.node_lookup().add_node(inode, layer, x, y, e_rr_type::CHANX, nodes_per_chan.max + rr_node_offset); + } + } + } + } + } +} + +void alloc_and_load_tile_rr_node_indices(RRGraphBuilder& rr_graph_builder, + t_physical_tile_type_ptr physical_tile, + int layer, + int x, + int y, + int* num_rr_nodes) { + std::vector wanted_sides{TOP, BOTTOM, LEFT, RIGHT}; + auto class_num_range = get_flat_tile_primitive_classes(physical_tile); + auto pin_num_vec = get_flat_tile_pins(physical_tile); + + std::vector class_num_vec(class_num_range.total_num()); + std::iota(class_num_vec.begin(), class_num_vec.end(), class_num_range.low); + + add_classes_spatial_lookup(rr_graph_builder, + physical_tile, + class_num_vec, + layer, + x, + y, + physical_tile->width, + physical_tile->height, + num_rr_nodes); + + add_pins_spatial_lookup(rr_graph_builder, + physical_tile, + pin_num_vec, + layer, + x, + y, + num_rr_nodes, + wanted_sides); +} + +void alloc_and_load_intra_cluster_rr_node_indices(RRGraphBuilder& rr_graph_builder, + const DeviceGrid& grid, + const vtr::vector& pin_chains, + const vtr::vector>& pin_chains_num, + int* index) { + for (int layer = 0; layer < grid.get_num_layers(); layer++) { + for (int x = 0; x < (int)grid.width(); x++) { + for (int y = 0; y < (int)grid.height(); y++) { + //Process each block from its root location + if (grid.is_root_location({x, y, layer})) { + t_physical_tile_type_ptr physical_type = grid.get_physical_type({x, y, layer}); + //Assign indices for SINKs and SOURCEs + // Note that SINKS/SOURCES have no side, so we always use side 0 + std::vector class_num_vec; + std::vector pin_num_vec; + class_num_vec = get_cluster_netlist_intra_tile_classes_at_loc(layer, x, y, physical_type); + pin_num_vec = get_cluster_netlist_intra_tile_pins_at_loc(layer, + x, + y, + pin_chains, + pin_chains_num, + physical_type); + add_classes_spatial_lookup(rr_graph_builder, + physical_type, + class_num_vec, + layer, + x, + y, + physical_type->width, + physical_type->height, + index); + + std::vector wanted_sides; + wanted_sides.push_back(e_side::TOP); + add_pins_spatial_lookup(rr_graph_builder, + physical_type, + pin_num_vec, + layer, + x, + y, + index, + wanted_sides); + } + } + } + } +} + +bool verify_rr_node_indices(const DeviceGrid& grid, + const RRGraphView& rr_graph, + const vtr::vector& rr_indexed_data, + const t_rr_graph_storage& rr_nodes, + bool is_flat) { + std::unordered_map rr_node_counts; + + int width = grid.width(); + int height = grid.height(); + int layer = grid.get_num_layers(); + + for (int l = 0; l < layer; ++l) { + for (int x = 0; x < width; ++x) { + for (int y = 0; y < height; ++y) { + for (e_rr_type rr_type : RR_TYPES) { + /* Get the list of nodes at a specific location (x, y) */ + std::vector nodes_from_lookup; + if (rr_type == e_rr_type::CHANX || rr_type == e_rr_type::CHANY) { + nodes_from_lookup = rr_graph.node_lookup().find_channel_nodes(l, x, y, rr_type); + } else { + nodes_from_lookup = rr_graph.node_lookup().find_grid_nodes_at_all_sides(l, x, y, rr_type); + } + + for (RRNodeId inode : nodes_from_lookup) { + rr_node_counts[inode]++; + + if (rr_graph.node_type(inode) != rr_type) { + VPR_ERROR(VPR_ERROR_ROUTE, "RR node type does not match between rr_nodes and rr_node_indices (%s/%s): %s", + rr_node_typename[rr_graph.node_type(inode)], + rr_node_typename[rr_type], + describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); + } + + if (rr_graph.node_type(inode) == e_rr_type::CHANX) { + VTR_ASSERT_MSG(rr_graph.node_ylow(inode) == rr_graph.node_yhigh(inode), "CHANX should be horizontal"); + if (y != rr_graph.node_ylow(inode)) { + VPR_ERROR(VPR_ERROR_ROUTE, "RR node y position does not agree between rr_nodes (%d) and rr_node_indices (%d): %s", + rr_graph.node_ylow(inode), + y, + describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); + } + + if (!rr_graph.x_in_node_range(x, inode)) { + VPR_ERROR(VPR_ERROR_ROUTE, "RR node x positions do not agree between rr_nodes (%d <-> %d) and rr_node_indices (%d): %s", + rr_graph.node_xlow(inode), + rr_graph.node_xlow(inode), + x, + describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); + } + } else if (rr_graph.node_type(inode) == e_rr_type::CHANY) { + VTR_ASSERT_MSG(rr_graph.node_xlow(inode) == rr_graph.node_xhigh(inode), "CHANY should be vertical"); + + if (x != rr_graph.node_xlow(inode)) { + VPR_ERROR(VPR_ERROR_ROUTE, "RR node x position does not agree between rr_nodes (%d) and rr_node_indices (%d): %s", + rr_graph.node_xlow(inode), + x, + describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); + } + + if (!rr_graph.y_in_node_range(y, inode)) { + VPR_ERROR(VPR_ERROR_ROUTE, "RR node y positions do not agree between rr_nodes (%d <-> %d) and rr_node_indices (%d): %s", + rr_graph.node_ylow(inode), + rr_graph.node_ylow(inode), + y, + describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); + } + } else if (rr_graph.node_type(inode) == e_rr_type::SOURCE || rr_graph.node_type(inode) == e_rr_type::SINK) { + // Sources have co-ordinates covering the entire block they are in, but not sinks + if (!rr_graph.x_in_node_range(x, inode)) { + VPR_ERROR(VPR_ERROR_ROUTE, "RR node x positions do not agree between rr_nodes (%d <-> %d) and rr_node_indices (%d): %s", + rr_graph.node_xlow(inode), + rr_graph.node_xlow(inode), + x, + describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); + } + + if (!rr_graph.y_in_node_range(y, inode)) { + VPR_ERROR(VPR_ERROR_ROUTE, "RR node y positions do not agree between rr_nodes (%d <-> %d) and rr_node_indices (%d): %s", + rr_graph.node_ylow(inode), + rr_graph.node_ylow(inode), + y, + describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); + } + } else { + VTR_ASSERT(rr_graph.node_type(inode) == e_rr_type::IPIN || rr_graph.node_type(inode) == e_rr_type::OPIN); + /* As we allow a pin to be indexable on multiple sides, + * This check code should be invalid + * if (rr_node.xlow() != x) { + * VPR_ERROR(VPR_ERROR_ROUTE, "RR node xlow does not match between rr_nodes and rr_node_indices (%d/%d): %s", + * rr_node.xlow(), + * x, + * describe_rr_node(rr_graph, grid, rr_indexed_data, inode).c_str()); + * } + * + * if (rr_node.ylow() != y) { + * VPR_ERROR(VPR_ERROR_ROUTE, "RR node ylow does not match between rr_nodes and rr_node_indices (%d/%d): %s", + * rr_node.ylow(), + * y, + * describe_rr_node(rr_graph, grid, rr_indexed_data, inode).c_str()); + * } + */ + } + + if (rr_type == e_rr_type::IPIN || rr_type == e_rr_type::OPIN) { + /* As we allow a pin to be indexable on multiple sides, + * This check code should be invalid + * if (rr_node.side() != side) { + * VPR_ERROR(VPR_ERROR_ROUTE, "RR node xlow does not match between rr_nodes and rr_node_indices (%s/%s): %s", + * TOTAL_2D_SIDE_STRINGS[rr_node.side()], + * TOTAL_2D_SIDE_STRINGS[side], + * describe_rr_node(rr_graph, grid, rr_indexed_data, inode).c_str()); + * } else { + * VTR_ASSERT(rr_node.side() == side); + * } + */ + } + } + } + } + } + } + + if (rr_node_counts.size() != rr_nodes.size()) { + VPR_ERROR(VPR_ERROR_ROUTE, "Mismatch in number of unique RR nodes in rr_nodes (%zu) and rr_node_indices (%zu)", + rr_nodes.size(), + rr_node_counts.size()); + } + + for (auto kv : rr_node_counts) { + RRNodeId inode = kv.first; + int count = kv.second; + + auto& rr_node = rr_nodes[size_t(inode)]; + + if (rr_graph.node_type(inode) == e_rr_type::SOURCE || rr_graph.node_type(inode) == e_rr_type::SINK) { + int rr_width = (rr_graph.node_xhigh(rr_node.id()) - rr_graph.node_xlow(rr_node.id()) + 1); + int rr_height = (rr_graph.node_yhigh(rr_node.id()) - rr_graph.node_ylow(rr_node.id()) + 1); + int rr_area = rr_width * rr_height; + if (count != rr_area) { + VPR_ERROR(VPR_ERROR_ROUTE, "Mismatch between RR node size (%d) and count within rr_node_indices (%d): %s", + rr_area, + rr_node.length(), + count, + describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); + } + /* As we allow a pin to be indexable on multiple sides, + * This check code should not be applied to input and output pins + */ + } else if ((e_rr_type::OPIN != rr_graph.node_type(inode)) && (e_rr_type::IPIN != rr_graph.node_type(inode))) { + if (count != rr_node.length() + 1) { + VPR_ERROR(VPR_ERROR_ROUTE, "Mismatch between RR node length (%d) and count within rr_node_indices (%d, should be length + 1): %s", + rr_node.length(), + count, + describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); + } + } + } + + return true; +} \ No newline at end of file diff --git a/vpr/src/route/rr_graph_generation/rr_node_indices.h b/vpr/src/route/rr_graph_generation/rr_node_indices.h new file mode 100644 index 00000000000..0be90e07c6a --- /dev/null +++ b/vpr/src/route/rr_graph_generation/rr_node_indices.h @@ -0,0 +1,66 @@ +#pragma once + +#include "rr_graph_builder.h" +#include "rr_graph_view.h" +#include "device_grid.h" +#include "rr_types.h" +#include "rr_graph_type.h" +#include "rr_graph_utils.h" +#include "clustered_netlist_fwd.h" + +/** + * @brief Allocates and populates data structures for efficient rr_node index lookups. + * + * This function sets up the `rr_node_indices` structure, which maps a physical location + * and type to the index of the first corresponding rr_node. + */ +void alloc_and_load_rr_node_indices(RRGraphBuilder& rr_graph_builder, + const t_chan_width& nodes_per_chan, + const DeviceGrid& grid, + int* index, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y); + +/** + * @brief Allocates extra nodes within the RR graph to support 3D custom switch blocks for multi-die FPGAs + * + * @param rr_graph_builder RRGraphBuilder data structure which allows data modification on a routing resource graph + * @param nodes_per_chan number of tracks per channel (x, y) + * @param grid device grid + * @param extra_nodes_per_switchblock keeps how many extra length-0 CHANX node is required for each unique (x,y) location within the grid. + * Number of these extra nodes are exactly the same for all layers. Hence, we only keep it for one layer. ([0..grid.width-1][0..grid.height-1) + * @param index RRNodeId that should be assigned to add a new RR node to the RR graph + */ +void alloc_and_load_inter_die_rr_node_indices(RRGraphBuilder& rr_graph_builder, + const t_chan_width& nodes_per_chan, + const DeviceGrid& grid, + const vtr::NdMatrix& extra_nodes_per_switchblock, + int* index); + +void alloc_and_load_tile_rr_node_indices(RRGraphBuilder& rr_graph_builder, + t_physical_tile_type_ptr physical_tile, + int layer, + int x, + int y, + int* num_rr_nodes); + +void alloc_and_load_intra_cluster_rr_node_indices(RRGraphBuilder& rr_graph_builder, + const DeviceGrid& grid, + const vtr::vector& pin_chains, + const vtr::vector>& pin_chains_num, + int* index); + +/** + * Validate the node look-up matches all the node-level information + * in the storage of a routing resource graph + * This function will check the following aspects: + * - The type of each node matches its type that is indexed in the node look-up + * - For bounding box (xlow, ylow, xhigh, yhigh) of each node is indexable in the node look-up + * - The number of unique indexable nodes in the node look up matches the number of nodes in the storage + * This ensures that every node in the storage is indexable and there are no hidden nodes in the look-up + */ +bool verify_rr_node_indices(const DeviceGrid& grid, + const RRGraphView& rr_graph, + const vtr::vector& rr_indexed_data, + const t_rr_graph_storage& rr_nodes, + bool is_flat); From 7b9c22627b3117705d80120f2239bc57bb53c490 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Thu, 15 May 2025 14:42:05 -0400 Subject: [PATCH 03/10] add doxygen comment for load_chan_rr_indices() --- .../rr_graph_generation/rr_node_indices.cpp | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/vpr/src/route/rr_graph_generation/rr_node_indices.cpp b/vpr/src/route/rr_graph_generation/rr_node_indices.cpp index 5012b2d67c0..062b4e79b90 100644 --- a/vpr/src/route/rr_graph_generation/rr_node_indices.cpp +++ b/vpr/src/route/rr_graph_generation/rr_node_indices.cpp @@ -5,7 +5,6 @@ #include "globals.h" #include "physical_types_util.h" - /** * @brief Assigns and loads rr_node indices for block-level routing resources (SOURCE, SINK, IPIN, OPIN). * @@ -22,13 +21,28 @@ static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder, const DeviceGrid& grid, int* index); +/** + * @brief Populates the lookup indices for channel (CHANX or CHANY) RR nodes. + * + * This function builds part of the RR spatial lookup structure, specifically + * the RR nodes associated with routing channels (CHANX or CHANY). + * + * @param max_chan_width Maximum channel width (number of tracks). + * @param grid Device grid layout. + * @param chan_len Length of the channel being processed. + * @param num_chans Total number of channels in the direction being processed. + * @param type RR node type: should be CHANX or CHANY. + * @param chan_details Channel details used to determine segment and track information. + * @param node_lookup Spatial RR node lookup to be filled by this function. + * @param index The next available RR node index. + */ static void load_chan_rr_indices(const int max_chan_width, const DeviceGrid& grid, const int chan_len, const int num_chans, const e_rr_type type, const t_chan_details& chan_details, - RRGraphBuilder& rr_graph_builder, + RRSpatialLookup& node_lookup, int* index); static void add_classes_spatial_lookup(RRGraphBuilder& rr_graph_builder, @@ -152,7 +166,7 @@ static void load_chan_rr_indices(const int max_chan_width, const int num_chans, const e_rr_type type, const t_chan_details& chan_details, - RRGraphBuilder& rr_graph_builder, + RRSpatialLookup& node_lookup, int* index) { const auto& device_ctx = g_vpr_ctx.device(); @@ -170,7 +184,7 @@ static void load_chan_rr_indices(const int max_chan_width, const t_chan_seg_details* seg_details = chan_details[x][y].data(); // Reserve nodes in lookup to save memory - rr_graph_builder.node_lookup().reserve_nodes(layer, x, y, type, max_chan_width); + node_lookup.reserve_nodes(layer, x, y, type, max_chan_width); for (int track = 0; track < max_chan_width; ++track) { /* TODO: May let the length() == 0 case go through, to model muxes */ @@ -182,15 +196,15 @@ static void load_chan_rr_indices(const int max_chan_width, int node_start_y = (type == e_rr_type::CHANX) ? chan : start; // If the start of the wire doesn't have an RRNodeId, assign one to it. - RRNodeId inode = rr_graph_builder.node_lookup().find_node(layer, node_start_x, node_start_y, type, track); + RRNodeId inode = node_lookup.find_node(layer, node_start_x, node_start_y, type, track); if (!inode) { inode = RRNodeId(*index); ++(*index); - rr_graph_builder.node_lookup().add_node(inode, layer, node_start_x, node_start_y, type, track); + node_lookup.add_node(inode, layer, node_start_x, node_start_y, type, track); } // Assign RRNodeId of start of wire to current position - rr_graph_builder.node_lookup().add_node(inode, layer, x, y, type, track); + node_lookup.add_node(inode, layer, x, y, type, track); } } } @@ -305,9 +319,9 @@ void alloc_and_load_rr_node_indices(RRGraphBuilder& rr_graph_builder, /* Load the data for x and y channels */ load_chan_rr_indices(nodes_per_chan.x_max, grid, grid.width(), grid.height(), - e_rr_type::CHANX, chan_details_x, rr_graph_builder, index); + e_rr_type::CHANX, chan_details_x, rr_graph_builder.node_lookup(), index); load_chan_rr_indices(nodes_per_chan.y_max, grid, grid.height(), grid.width(), - e_rr_type::CHANY, chan_details_y, rr_graph_builder, index); + e_rr_type::CHANY, chan_details_y, rr_graph_builder.node_lookup(), index); } void alloc_and_load_inter_die_rr_node_indices(RRGraphBuilder& rr_graph_builder, @@ -597,4 +611,4 @@ bool verify_rr_node_indices(const DeviceGrid& grid, } return true; -} \ No newline at end of file +} From c12350d73032f3a61ef7cd0f775dc003b1d0c447 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Mon, 19 May 2025 14:22:26 -0400 Subject: [PATCH 04/10] make is_io_type() a member function of t_physical_tile_type --- libs/libarchfpga/src/physical_types.cpp | 4 ++++ libs/libarchfpga/src/physical_types.h | 3 +++ libs/libarchfpga/src/physical_types_util.cpp | 15 --------------- libs/libarchfpga/src/physical_types_util.h | 7 ------- vpr/src/util/vpr_utils.h | 5 +---- 5 files changed, 8 insertions(+), 26 deletions(-) diff --git a/libs/libarchfpga/src/physical_types.cpp b/libs/libarchfpga/src/physical_types.cpp index 9b72cb95758..fa83dfecc86 100644 --- a/libs/libarchfpga/src/physical_types.cpp +++ b/libs/libarchfpga/src/physical_types.cpp @@ -172,6 +172,10 @@ bool t_physical_tile_type::is_empty() const { return name == std::string(EMPTY_BLOCK_NAME); } +bool t_physical_tile_type::is_io_type() const { + return is_input_type || is_output_type; +} + int t_physical_tile_type::find_pin(std::string_view port_name, int pin_index_in_port) const { int ipin = OPEN; int port_base_ipin = 0; diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index c2459721d93..62224dcbcb5 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -725,6 +725,9 @@ struct t_physical_tile_type { ///@brief Is this t_physical_tile_type an empty type? bool is_empty() const; + ///@brief Returns true if the physical tile type can implement either a .input or .output block type + bool is_io_type() const; + ///@brief Returns the relative pin index within a sub tile that corresponds to the pin within the given port and its index in the port int find_pin(std::string_view port_name, int pin_index_in_port) const; diff --git a/libs/libarchfpga/src/physical_types_util.cpp b/libs/libarchfpga/src/physical_types_util.cpp index 2ecc7fbd41c..74ad3aa6f1e 100644 --- a/libs/libarchfpga/src/physical_types_util.cpp +++ b/libs/libarchfpga/src/physical_types_util.cpp @@ -637,21 +637,6 @@ bool is_pin_conencted_to_layer(t_physical_tile_type_ptr type, int ipin, int from return false; } -// TODO: Remove is_input_type / is_output_type / is_io_type as part of -// https://github.com/verilog-to-routing/vtr-verilog-to-routing/issues/1193 -bool is_input_type(t_physical_tile_type_ptr type) { - return type->is_input_type; -} - -bool is_output_type(t_physical_tile_type_ptr type) { - return type->is_output_type; -} - -bool is_io_type(t_physical_tile_type_ptr type) { - return is_input_type(type) - || is_output_type(type); -} - std::string block_type_pin_index_to_name(t_physical_tile_type_ptr type, int pin_physical_num, bool is_flat) { int max_ptc = get_tile_pin_max_ptc(type, is_flat); VTR_ASSERT(pin_physical_num < max_ptc); diff --git a/libs/libarchfpga/src/physical_types_util.h b/libs/libarchfpga/src/physical_types_util.h index a081683faeb..84cad62a845 100644 --- a/libs/libarchfpga/src/physical_types_util.h +++ b/libs/libarchfpga/src/physical_types_util.h @@ -120,13 +120,6 @@ bool is_opin(int ipin, t_physical_tile_type_ptr type); ///@brief Returns true if the specified pin is located at "from_layer" and it is connected to "to_layer" bool is_pin_conencted_to_layer(t_physical_tile_type_ptr type, int ipin, int from_layer, int to_layer, int num_of_avail_layer); -///@brief Returns true if the given physical tile type can implement a .input block type -bool is_input_type(t_physical_tile_type_ptr type); -///@brief Returns true if the given physical tile type can implement a .output block type -bool is_output_type(t_physical_tile_type_ptr type); -///@brief Returns true if the given physical tile type can implement either a .input or .output block type -bool is_io_type(t_physical_tile_type_ptr type); - /** * @brief Returns the corresponding physical pin based on the input parameters: * diff --git a/vpr/src/util/vpr_utils.h b/vpr/src/util/vpr_utils.h index 762efd36c5d..d9f279a47a3 100644 --- a/vpr/src/util/vpr_utils.h +++ b/vpr/src/util/vpr_utils.h @@ -1,5 +1,4 @@ -#ifndef VPR_UTILS_H -#define VPR_UTILS_H +#pragma once #include "arch_util.h" #include "atom_netlist.h" @@ -362,5 +361,3 @@ class PortPinToBlockPinConverter { */ std::vector>>> blk_pin_from_port_pin_; }; - -#endif From 490740eca9262285d2b583c4ba7fe32efe898dd0 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Mon, 19 May 2025 14:40:52 -0400 Subject: [PATCH 05/10] replace calls to is_io_type() with t_physical_tile_type::is_io() --- libs/libarchfpga/src/physical_types.cpp | 2 +- libs/libarchfpga/src/physical_types.h | 2 +- vpr/src/base/ShowSetup.cpp | 2 +- vpr/src/base/check_netlist.cpp | 3 +- vpr/src/base/read_route.cpp | 15 ++++--- vpr/src/base/stats.cpp | 9 ++-- vpr/src/pack/appack_max_dist_th_manager.cpp | 2 +- vpr/src/place/initial_placement.cpp | 8 ++-- vpr/src/route/route_common.cpp | 2 +- .../rr_graph_generation/rr_node_indices.cpp | 41 +++++++++---------- vpr/src/util/vpr_utils.h | 7 ---- 11 files changed, 42 insertions(+), 51 deletions(-) diff --git a/libs/libarchfpga/src/physical_types.cpp b/libs/libarchfpga/src/physical_types.cpp index fa83dfecc86..f3934f34de6 100644 --- a/libs/libarchfpga/src/physical_types.cpp +++ b/libs/libarchfpga/src/physical_types.cpp @@ -172,7 +172,7 @@ bool t_physical_tile_type::is_empty() const { return name == std::string(EMPTY_BLOCK_NAME); } -bool t_physical_tile_type::is_io_type() const { +bool t_physical_tile_type::is_io() const { return is_input_type || is_output_type; } diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index 62224dcbcb5..db1f9193030 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -726,7 +726,7 @@ struct t_physical_tile_type { bool is_empty() const; ///@brief Returns true if the physical tile type can implement either a .input or .output block type - bool is_io_type() const; + bool is_io() const; ///@brief Returns the relative pin index within a sub tile that corresponds to the pin within the given port and its index in the port int find_pin(std::string_view port_name, int pin_index_in_port) const; diff --git a/vpr/src/base/ShowSetup.cpp b/vpr/src/base/ShowSetup.cpp index fa81fa9f1ac..ccf900f8ef8 100644 --- a/vpr/src/base/ShowSetup.cpp +++ b/vpr/src/base/ShowSetup.cpp @@ -135,7 +135,7 @@ ClusteredNetlistStats::ClusteredNetlistStats() { auto logical_block = cluster_ctx.clb_nlist.block_type(blk_id); auto physical_tile = pick_physical_type(logical_block); num_blocks_type[logical_block->index]++; - if (is_io_type(physical_tile)) { + if (physical_tile->is_io()) { for (int j = 0; j < logical_block->pb_type->num_pins; j++) { int physical_pin = get_physical_pin(physical_tile, logical_block, j); diff --git a/vpr/src/base/check_netlist.cpp b/vpr/src/base/check_netlist.cpp index 3d777f3ec4b..d8ad7fab6f6 100644 --- a/vpr/src/base/check_netlist.cpp +++ b/vpr/src/base/check_netlist.cpp @@ -110,8 +110,7 @@ static int check_connections_to_global_clb_pins(ClusterNetId net_id, int verbosi int log_index = cluster_ctx.clb_nlist.pin_logical_index(pin_id); int pin_index = get_physical_pin(physical_type, logical_type, log_index); - if (physical_type->is_ignored_pin[pin_index] != net_is_ignored - && !is_io_type(physical_type)) { + if (physical_type->is_ignored_pin[pin_index] != net_is_ignored && !physical_type->is_io()) { VTR_LOGV_WARN(verbosity > 2, "Global net '%s' connects to non-global architecture pin '%s' (netlist pin '%s')\n", cluster_ctx.clb_nlist.net_name(net_id).c_str(), diff --git a/vpr/src/base/read_route.cpp b/vpr/src/base/read_route.cpp index 0b8231925e7..be2c4aa18bc 100644 --- a/vpr/src/base/read_route.cpp +++ b/vpr/src/base/read_route.cpp @@ -296,7 +296,7 @@ static void process_nodes(const Netlist<>& net_list, std::ifstream& fp, ClusterN /* Verify types and ptc*/ if (tokens[2] == "SOURCE" || tokens[2] == "SINK" || tokens[2] == "OPIN" || tokens[2] == "IPIN") { const auto& type = device_ctx.grid.get_physical_type({x, y, layer_num}); - if (tokens[4 + offset] == "Pad:" && !is_io_type(type)) { + if (tokens[4 + offset] == "Pad:" && !type->is_io()) { vpr_throw(VPR_ERROR_ROUTE, filename, lineno, "Node %d is of the wrong type", inode); } @@ -319,7 +319,7 @@ static void process_nodes(const Netlist<>& net_list, std::ifstream& fp, ClusterN if (tokens[6 + offset] != "Switch:") { /*This is an opin or ipin, process its pin nums*/ auto type = device_ctx.grid.get_physical_type({x, y, layer_num}); - if (!is_io_type(type) && (tokens[2] == "IPIN" || tokens[2] == "OPIN")) { + if (!type->is_io() && (tokens[2] == "IPIN" || tokens[2] == "OPIN")) { int pin_num = rr_graph.node_pin_num(RRNodeId(inode)); int width_offset = device_ctx.grid.get_width_offset({x, y, layer_num}); int height_offset = device_ctx.grid.get_height_offset({x, y, layer_num}); @@ -592,10 +592,13 @@ void print_route(const Netlist<>& net_list, fprintf(fp, "to (%d,%d,%d) ", rr_graph.node_xhigh(inode), rr_graph.node_yhigh(inode), layer_num); + t_physical_tile_type_ptr physical_tile = device_ctx.grid.get_physical_type({ilow, jlow, layer_num}); + switch (rr_type) { case e_rr_type::IPIN: case e_rr_type::OPIN: - if (is_io_type(device_ctx.grid.get_physical_type({ilow, jlow, layer_num}))) { + + if (physical_tile->is_io()) { fprintf(fp, " Pad: "); } else { /* IO Pad. */ fprintf(fp, " Pin: "); @@ -609,7 +612,7 @@ void print_route(const Netlist<>& net_list, case e_rr_type::SOURCE: case e_rr_type::SINK: - if (is_io_type(device_ctx.grid.get_physical_type({ilow, jlow, layer_num}))) { + if (physical_tile->is_io()) { fprintf(fp, " Pad: "); } else { /* IO Pad. */ fprintf(fp, " Class: "); @@ -625,8 +628,8 @@ void print_route(const Netlist<>& net_list, fprintf(fp, "%d ", rr_graph.node_ptc_num(inode)); - auto physical_tile = device_ctx.grid.get_physical_type({ilow, jlow, layer_num}); - if (!is_io_type(physical_tile) && (rr_type == e_rr_type::IPIN || rr_type == e_rr_type::OPIN)) { + + if (!physical_tile->is_io() && (rr_type == e_rr_type::IPIN || rr_type == e_rr_type::OPIN)) { int pin_num = rr_graph.node_pin_num(inode); int xoffset = device_ctx.grid.get_width_offset({ilow, jlow, layer_num}); int yoffset = device_ctx.grid.get_height_offset({ilow, jlow, layer_num}); diff --git a/vpr/src/base/stats.cpp b/vpr/src/base/stats.cpp index 109147e337b..08927b500ea 100644 --- a/vpr/src/base/stats.cpp +++ b/vpr/src/base/stats.cpp @@ -91,10 +91,7 @@ void routing_stats(const Netlist<>& net_list, auto type = device_ctx.grid.get_physical_type({i, j, layer_num}); int width_offset = device_ctx.grid.get_width_offset({i, j, layer_num}); int height_offset = device_ctx.grid.get_height_offset({i, j, layer_num}); - if (width_offset == 0 - && height_offset == 0 - && !is_io_type(type) - && type != device_ctx.EMPTY_PHYSICAL_TILE_TYPE) { + if (width_offset == 0 && height_offset == 0 && !type->is_io() && !type->is_empty()) { if (type->area == UNDEFINED) { area += grid_logic_tile_area * type->width * type->height; } else { @@ -111,7 +108,7 @@ void routing_stats(const Netlist<>& net_list, for (ClusterBlockId blk_id : cluster_ctx.clb_nlist.blocks()) { t_pl_loc block_loc = block_locs[blk_id].loc; auto type = physical_tile_type(block_loc); - if (!is_io_type(type)) { + if (!type->is_io()) { if (type->area == UNDEFINED) { used_area += grid_logic_tile_area * type->width * type->height; } else { @@ -473,7 +470,7 @@ void print_lambda() { t_pl_loc block_loc = block_locs[blk_id].loc; auto type = physical_tile_type(block_loc); VTR_ASSERT(type != nullptr); - if (!is_io_type(type)) { + if (!type->is_io()) { for (int ipin = 0; ipin < type->num_pins; ipin++) { if (get_pin_type_from_pin_physical_num(type, ipin) == RECEIVER) { ClusterNetId net_id = cluster_ctx.clb_nlist.block_net(blk_id, ipin); diff --git a/vpr/src/pack/appack_max_dist_th_manager.cpp b/vpr/src/pack/appack_max_dist_th_manager.cpp index 9f9a39815a7..c5c9b685b73 100644 --- a/vpr/src/pack/appack_max_dist_th_manager.cpp +++ b/vpr/src/pack/appack_max_dist_th_manager.cpp @@ -100,7 +100,7 @@ void APPackMaxDistThManager::auto_set_max_distance_thresholds(const std::vector< // Find which type(s) this logical block type looks like. bool has_memory = has_memory_pbs(lb_ty.pb_type); bool is_logic_block_type = (lb_ty.index == logic_block_type->index); - bool is_io_block = is_io_type(pick_physical_type(&lb_ty)); + bool is_io_block = pick_physical_type(&lb_ty)->is_io(); // Update the max distance threshold based on the type. If the logical // block type looks like many block types at the same time (for example diff --git a/vpr/src/place/initial_placement.cpp b/vpr/src/place/initial_placement.cpp index 3dc8650a3e2..bcf6e3b7094 100644 --- a/vpr/src/place/initial_placement.cpp +++ b/vpr/src/place/initial_placement.cpp @@ -1012,10 +1012,10 @@ static inline void fix_IO_block_types(const t_pl_macro& pl_macro, vtr::vector_map& block_locs) { const auto& device_ctx = g_vpr_ctx.device(); - //If the user marked the IO block pad_loc_type as RANDOM, that means it should be randomly - //placed and then stay fixed to that location, which is why the macro members are marked as fixed. - const auto& type = device_ctx.grid.get_physical_type({loc.x, loc.y, loc.layer}); - if (is_io_type(type) && pad_loc_type == e_pad_loc_type::RANDOM) { + // If the user marked the IO block pad_loc_type as RANDOM, that means it should be randomly + // placed and then stay fixed to that location, which is why the macro members are marked as fixed. + const t_physical_tile_type_ptr type = device_ctx.grid.get_physical_type({loc.x, loc.y, loc.layer}); + if (type->is_io() && pad_loc_type == e_pad_loc_type::RANDOM) { for (const t_pl_macro_member& pl_macro_member : pl_macro.members) { block_locs[pl_macro_member.blk_index].is_fixed = true; } diff --git a/vpr/src/route/route_common.cpp b/vpr/src/route/route_common.cpp index 43501cd04aa..3f6d574b601 100644 --- a/vpr/src/route/route_common.cpp +++ b/vpr/src/route/route_common.cpp @@ -358,7 +358,7 @@ static t_clb_opins_used alloc_and_load_clb_opins_used_locally() { clb_opins_used_locally[blk_id].resize((int)type->class_inf.size()); - if (is_io_type(type)) continue; + if (type->is_io()) continue; const auto [pin_low, pin_high] = get_pin_range_for_block(blk_id); diff --git a/vpr/src/route/rr_graph_generation/rr_node_indices.cpp b/vpr/src/route/rr_graph_generation/rr_node_indices.cpp index 062b4e79b90..99c1a729e6c 100644 --- a/vpr/src/route/rr_graph_generation/rr_node_indices.cpp +++ b/vpr/src/route/rr_graph_generation/rr_node_indices.cpp @@ -4,6 +4,7 @@ #include "describe_rr_node.h" #include "globals.h" #include "physical_types_util.h" +#include "vpr_utils.h" /** * @brief Assigns and loads rr_node indices for block-level routing resources (SOURCE, SINK, IPIN, OPIN). @@ -70,7 +71,7 @@ static void add_pins_spatial_lookup(RRGraphBuilder& rr_graph_builder, static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder, const DeviceGrid& grid, int* index) { - //Walk through the grid assigning indices to SOURCE/SINK IPIN/OPIN + // Walk through the grid assigning indices to SOURCE/SINK IPIN/OPIN for (int layer = 0; layer < grid.get_num_layers(); layer++) { for (int x = 0; x < (int)grid.width(); x++) { for (int y = 0; y < (int)grid.height(); y++) { @@ -78,7 +79,7 @@ static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder, if (grid.is_root_location({x, y, layer})) { t_physical_tile_type_ptr physical_type = grid.get_physical_type({x, y, layer}); - //Assign indices for SINKs and SOURCEs + // Assign indices for SINKs and SOURCEs // Note that SINKS/SOURCES have no side, so we always use side 0 std::vector class_num_vec = get_tile_root_classes(physical_type); std::vector pin_num_vec = get_tile_root_pins(physical_type); @@ -124,22 +125,20 @@ static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder, * for the same input pin on multiple sides, and thus avoid multiple driver problems */ std::vector wanted_sides; - if ((int)grid.height() - 1 == y) { /* TOP side */ + if ((int)grid.height() - 1 == y) { // TOP side wanted_sides.push_back(BOTTOM); } - if ((int)grid.width() - 1 == x) { /* RIGHT side */ + if ((int)grid.width() - 1 == x) { // RIGHT side wanted_sides.push_back(LEFT); } - if (0 == y) { /* BOTTOM side */ + if (0 == y) { // BOTTOM side wanted_sides.push_back(TOP); } - if (0 == x) { /* LEFT side */ + if (0 == x) { // LEFT side wanted_sides.push_back(RIGHT); } - /* If wanted sides is empty still, this block does not have specific wanted sides, - * Deposit all the sides - */ + // If wanted sides is empty still, this block does not have specific wanted sides, Deposit all the sides if (wanted_sides.empty()) { for (e_side side : TOTAL_2D_SIDES) { wanted_sides.push_back(side); @@ -262,7 +261,7 @@ static void add_pins_spatial_lookup(RRGraphBuilder& rr_graph_builder, int x_tile = root_x + width_offset; for (int height_offset = 0; height_offset < physical_type_ptr->height; ++height_offset) { int y_tile = root_y + height_offset; - //only nodes on the tile may be located in a location other than the root-location + // only nodes on the tile may be located in a location other than the root-location rr_graph_builder.node_lookup().reserve_nodes(layer, x_tile, y_tile, e_rr_type::OPIN, physical_type_ptr->num_pins, side); rr_graph_builder.node_lookup().reserve_nodes(layer, x_tile, y_tile, e_rr_type::IPIN, physical_type_ptr->num_pins, side); } @@ -309,15 +308,15 @@ void alloc_and_load_rr_node_indices(RRGraphBuilder& rr_graph_builder, int* index, const t_chan_details& chan_details_x, const t_chan_details& chan_details_y) { - /* Alloc the lookup table */ + // Alloc the lookup table for (e_rr_type rr_type : RR_TYPES) { rr_graph_builder.node_lookup().resize_nodes(grid.get_num_layers(), grid.width(), grid.height(), rr_type, NUM_2D_SIDES); } - /* Assign indices for block nodes */ + // Assign indices for block nodes load_block_rr_indices(rr_graph_builder, grid, index); - /* Load the data for x and y channels */ + // Load the data for x and y channels load_chan_rr_indices(nodes_per_chan.x_max, grid, grid.width(), grid.height(), e_rr_type::CHANX, chan_details_x, rr_graph_builder.node_lookup(), index); load_chan_rr_indices(nodes_per_chan.y_max, grid, grid.height(), grid.width(), @@ -341,7 +340,7 @@ void alloc_and_load_inter_die_rr_node_indices(RRGraphBuilder& rr_graph_builder, const auto& device_ctx = g_vpr_ctx.device(); for (int layer = 0; layer < grid.get_num_layers(); layer++) { - /* Skip the current die if architecture file specifies that it doesn't have global resource routing */ + // Skip the current die if architecture file specifies that it doesn't have global resource routing if (!device_ctx.inter_cluster_prog_routing_resources.at(layer)) { continue; } @@ -412,10 +411,10 @@ void alloc_and_load_intra_cluster_rr_node_indices(RRGraphBuilder& rr_graph_build for (int layer = 0; layer < grid.get_num_layers(); layer++) { for (int x = 0; x < (int)grid.width(); x++) { for (int y = 0; y < (int)grid.height(); y++) { - //Process each block from its root location + // Process each block from its root location if (grid.is_root_location({x, y, layer})) { t_physical_tile_type_ptr physical_type = grid.get_physical_type({x, y, layer}); - //Assign indices for SINKs and SOURCEs + // Assign indices for SINKs and SOURCEs // Note that SINKS/SOURCES have no side, so we always use side 0 std::vector class_num_vec; std::vector pin_num_vec; @@ -467,7 +466,7 @@ bool verify_rr_node_indices(const DeviceGrid& grid, for (int x = 0; x < width; ++x) { for (int y = 0; y < height; ++y) { for (e_rr_type rr_type : RR_TYPES) { - /* Get the list of nodes at a specific location (x, y) */ + // Get the list of nodes at a specific location (x, y) std::vector nodes_from_lookup; if (rr_type == e_rr_type::CHANX || rr_type == e_rr_type::CHANY) { nodes_from_lookup = rr_graph.node_lookup().find_channel_nodes(l, x, y, rr_type); @@ -584,7 +583,7 @@ bool verify_rr_node_indices(const DeviceGrid& grid, RRNodeId inode = kv.first; int count = kv.second; - auto& rr_node = rr_nodes[size_t(inode)]; + const t_rr_node& rr_node = rr_nodes[size_t(inode)]; if (rr_graph.node_type(inode) == e_rr_type::SOURCE || rr_graph.node_type(inode) == e_rr_type::SINK) { int rr_width = (rr_graph.node_xhigh(rr_node.id()) - rr_graph.node_xlow(rr_node.id()) + 1); @@ -597,9 +596,9 @@ bool verify_rr_node_indices(const DeviceGrid& grid, count, describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); } - /* As we allow a pin to be indexable on multiple sides, - * This check code should not be applied to input and output pins - */ + // As we allow a pin to be indexable on multiple sides, + // This check code should not be applied to input and output pins + } else if ((e_rr_type::OPIN != rr_graph.node_type(inode)) && (e_rr_type::IPIN != rr_graph.node_type(inode))) { if (count != rr_node.length() + 1) { VPR_ERROR(VPR_ERROR_ROUTE, "Mismatch between RR node length (%d) and count within rr_node_indices (%d, should be length + 1): %s", diff --git a/vpr/src/util/vpr_utils.h b/vpr/src/util/vpr_utils.h index d9f279a47a3..842b18fef47 100644 --- a/vpr/src/util/vpr_utils.h +++ b/vpr/src/util/vpr_utils.h @@ -286,13 +286,6 @@ std::vector get_cluster_netlist_intra_tile_classes_at_loc(int layer, /** * @brief Returns the list of pins inside the tile located at (layer, i, j), except for the ones which are on a chain - * @param layer - * @param i - * @param j - * @param pin_chains - * @param pin_chains_num - * @param physical_type - * @return */ std::vector get_cluster_netlist_intra_tile_pins_at_loc(const int layer, const int i, From 236515018ed37c8954ad51f608bfc289a9e8d5fe Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Mon, 19 May 2025 14:41:53 -0400 Subject: [PATCH 06/10] make format --- vpr/src/base/read_route.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/vpr/src/base/read_route.cpp b/vpr/src/base/read_route.cpp index be2c4aa18bc..3ede11a9f98 100644 --- a/vpr/src/base/read_route.cpp +++ b/vpr/src/base/read_route.cpp @@ -628,7 +628,6 @@ void print_route(const Netlist<>& net_list, fprintf(fp, "%d ", rr_graph.node_ptc_num(inode)); - if (!physical_tile->is_io() && (rr_type == e_rr_type::IPIN || rr_type == e_rr_type::OPIN)) { int pin_num = rr_graph.node_pin_num(inode); int xoffset = device_ctx.grid.get_width_offset({ilow, jlow, layer_num}); From ee82313bae78c3bef6f698017d7d117ba378243b Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Mon, 19 May 2025 17:15:14 -0400 Subject: [PATCH 07/10] inline t_physical_tile_type::is_io() --- libs/libarchfpga/src/physical_types.cpp | 4 ---- libs/libarchfpga/src/physical_types.h | 4 +++- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/libs/libarchfpga/src/physical_types.cpp b/libs/libarchfpga/src/physical_types.cpp index f3934f34de6..9b72cb95758 100644 --- a/libs/libarchfpga/src/physical_types.cpp +++ b/libs/libarchfpga/src/physical_types.cpp @@ -172,10 +172,6 @@ bool t_physical_tile_type::is_empty() const { return name == std::string(EMPTY_BLOCK_NAME); } -bool t_physical_tile_type::is_io() const { - return is_input_type || is_output_type; -} - int t_physical_tile_type::find_pin(std::string_view port_name, int pin_index_in_port) const { int ipin = OPEN; int port_base_ipin = 0; diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index db1f9193030..94e486afd51 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -726,7 +726,9 @@ struct t_physical_tile_type { bool is_empty() const; ///@brief Returns true if the physical tile type can implement either a .input or .output block type - bool is_io() const; + inline bool is_io() const { + return is_input_type || is_output_type; + } ///@brief Returns the relative pin index within a sub tile that corresponds to the pin within the given port and its index in the port int find_pin(std::string_view port_name, int pin_index_in_port) const; From d83b07cd747b56c7e5283f250336480ad0520a5a Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Mon, 19 May 2025 17:25:25 -0400 Subject: [PATCH 08/10] add doxygen comments for alloc_and_load_tile_rr_node_indices() --- vpr/src/route/router_lookahead_map.cpp | 2 +- .../route/rr_graph_generation/rr_node_indices.h | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/vpr/src/route/router_lookahead_map.cpp b/vpr/src/route/router_lookahead_map.cpp index b8782a45c5a..b9dde54cd95 100644 --- a/vpr/src/route/router_lookahead_map.cpp +++ b/vpr/src/route/router_lookahead_map.cpp @@ -89,7 +89,7 @@ static void compute_tiles_lookahead(std::unordered_map cost * @param physical_tile * @param det_routing_arch diff --git a/vpr/src/route/rr_graph_generation/rr_node_indices.h b/vpr/src/route/rr_graph_generation/rr_node_indices.h index 0be90e07c6a..00c555416bc 100644 --- a/vpr/src/route/rr_graph_generation/rr_node_indices.h +++ b/vpr/src/route/rr_graph_generation/rr_node_indices.h @@ -37,6 +37,21 @@ void alloc_and_load_inter_die_rr_node_indices(RRGraphBuilder& rr_graph_builder, const vtr::NdMatrix& extra_nodes_per_switchblock, int* index); +/** + * @brief Allocates and loads RR node indices for a specific tile. + * + * This function assigns RR node IDs to all classes (SOURCE/SINK) and pins (IPIN/OPIN) + * associated with a given physical tile at a specific grid location and layer. + * It is primarily used in scenarios where a standalone tile's routing resources + * need to be initialized independently. + * + * @param rr_graph_builder Reference to the RR graph builder with spatial lookup. + * @param physical_tile Pointer to the physical tile type being processed. + * @param layer Layer index of the tile in the device grid. + * @param x X-coordinate of the tile's root position in the grid. + * @param y Y-coordinate of the tile's root position in the grid. + * @param num_rr_nodes Pointer to the global RR node index counter (will be incremented). + */ void alloc_and_load_tile_rr_node_indices(RRGraphBuilder& rr_graph_builder, t_physical_tile_type_ptr physical_tile, int layer, From 2c47c52a3cb21b5ef7e96aa78adf9ea7e4e99147 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Mon, 19 May 2025 17:32:45 -0400 Subject: [PATCH 09/10] document alloc_and_load_rr_node_indices() arguments --- .../rr_graph_generation/rr_node_indices.h | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/vpr/src/route/rr_graph_generation/rr_node_indices.h b/vpr/src/route/rr_graph_generation/rr_node_indices.h index 00c555416bc..76373c1cc70 100644 --- a/vpr/src/route/rr_graph_generation/rr_node_indices.h +++ b/vpr/src/route/rr_graph_generation/rr_node_indices.h @@ -13,6 +13,13 @@ * * This function sets up the `rr_node_indices` structure, which maps a physical location * and type to the index of the first corresponding rr_node. + * + * @param rr_graph_builder Reference to the RRGraphBuilder used to construct and populate RR node spatial lookups. + * @param nodes_per_chan Specifies the maximum number of routing tracks per channel in the x and y directions. + * @param grid The device grid representing the physical layout of tiles in the FPGA fabric. + * @param index Pointer to the global RR node index counter; incremented as new RR nodes are assigned. + * @param chan_details_x Channel details describing segment and track properties for CHANX (horizontal) routing tracks. + * @param chan_details_y Channel details describing segment and track properties for CHANY (vertical) routing tracks. */ void alloc_and_load_rr_node_indices(RRGraphBuilder& rr_graph_builder, const t_chan_width& nodes_per_chan, @@ -24,12 +31,12 @@ void alloc_and_load_rr_node_indices(RRGraphBuilder& rr_graph_builder, /** * @brief Allocates extra nodes within the RR graph to support 3D custom switch blocks for multi-die FPGAs * - * @param rr_graph_builder RRGraphBuilder data structure which allows data modification on a routing resource graph - * @param nodes_per_chan number of tracks per channel (x, y) - * @param grid device grid - * @param extra_nodes_per_switchblock keeps how many extra length-0 CHANX node is required for each unique (x,y) location within the grid. - * Number of these extra nodes are exactly the same for all layers. Hence, we only keep it for one layer. ([0..grid.width-1][0..grid.height-1) - * @param index RRNodeId that should be assigned to add a new RR node to the RR graph + * @param rr_graph_builder RRGraphBuilder data structure which allows data modification on a routing resource graph + * @param nodes_per_chan number of tracks per channel (x, y) + * @param grid The device grid representing the physical layout of tiles in the FPGA fabric. + * @param extra_nodes_per_switchblock keeps how many extra length-0 CHANX node is required for each unique (x,y) location within the grid. + * Number of these extra nodes are exactly the same for all layers. Hence, we only keep it for one layer. ([0..grid.width-1][0..grid.height-1) + * @param index Pointer to the global RR node index counter; incremented as new RR nodes are assigned. */ void alloc_and_load_inter_die_rr_node_indices(RRGraphBuilder& rr_graph_builder, const t_chan_width& nodes_per_chan, From 1681fa1ac2d67a7153b0c78e4df80838ebe0d03c Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Mon, 19 May 2025 17:47:37 -0400 Subject: [PATCH 10/10] made a few function operating on t_pb_type its member functions --- libs/libarchfpga/src/physical_types.cpp | 66 ++++++++++++++++++++++++- libs/libarchfpga/src/physical_types.h | 4 ++ vpr/src/util/vpr_utils.cpp | 60 ---------------------- vpr/src/util/vpr_utils.h | 3 -- 4 files changed, 69 insertions(+), 64 deletions(-) diff --git a/libs/libarchfpga/src/physical_types.cpp b/libs/libarchfpga/src/physical_types.cpp index 9b72cb95758..6032bcb6d26 100644 --- a/libs/libarchfpga/src/physical_types.cpp +++ b/libs/libarchfpga/src/physical_types.cpp @@ -252,7 +252,71 @@ const t_port* t_logical_block_type::get_port_by_pin(int pin) const { return nullptr; } -/** +/* + * t_pb_type + */ + +int t_pb_type::get_max_primitives() const { + int max_size; + + if (modes == nullptr) { + max_size = 1; + } else { + max_size = 0; + int temp_size = 0; + for (int i = 0; i < num_modes; i++) { + for (int j = 0; j < modes[i].num_pb_type_children; j++) { + temp_size += modes[i].pb_type_children[j].num_pb * modes[i].pb_type_children[j].get_max_primitives(); + } + if (temp_size > max_size) { + max_size = temp_size; + } + } + } + + return max_size; +} + +/* finds maximum number of nets that can be contained in pb_type, this is bounded by the number of driving pins */ +int t_pb_type::get_max_nets() const { + int max_nets; + if (modes == nullptr) { + max_nets = num_output_pins; + } else { + max_nets = 0; + + for (int i = 0; i < num_modes; i++) { + int temp_nets = 0; + for (int j = 0; j < modes[i].num_pb_type_children; j++) { + temp_nets += modes[i].pb_type_children[j].num_pb * modes[i].pb_type_children[j].get_max_nets(); + } + + if (temp_nets > max_nets) { + max_nets = temp_nets; + } + } + } + + if (is_root()) { + max_nets += num_input_pins + num_output_pins + num_clock_pins; + } + + return max_nets; +} + +int t_pb_type::get_max_depth() const { + int max_depth = depth; + + for (int i = 0; i < num_modes; i++) { + for (int j = 0; j < modes[i].num_pb_type_children; j++) { + int temp_depth = modes[i].pb_type_children[j].get_max_depth(); + max_depth = std::max(max_depth, temp_depth); + } + } + return max_depth; +} + +/* * t_pb_graph_node */ diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index 94e486afd51..27b787f7c6b 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -1092,6 +1092,10 @@ struct t_pb_type { inline bool is_primitive() const { return num_modes == 0; } + + int get_max_primitives() const; + int get_max_depth() const; + int get_max_nets() const; }; /** Describes an operational mode of a clustered logic block diff --git a/vpr/src/util/vpr_utils.cpp b/vpr/src/util/vpr_utils.cpp index 34c2156b98f..82b019676f9 100644 --- a/vpr/src/util/vpr_utils.cpp +++ b/vpr/src/util/vpr_utils.cpp @@ -729,66 +729,6 @@ static bool pb_type_contains_blif_model(const t_pb_type* pb_type, const std::reg return false; } -int get_max_primitives_in_pb_type(t_pb_type* pb_type) { - int max_size; - if (pb_type->modes == nullptr) { - max_size = 1; - } else { - max_size = 0; - int temp_size = 0; - for (int i = 0; i < pb_type->num_modes; i++) { - for (int j = 0; j < pb_type->modes[i].num_pb_type_children; j++) { - temp_size += pb_type->modes[i].pb_type_children[j].num_pb - * get_max_primitives_in_pb_type( - &pb_type->modes[i].pb_type_children[j]); - } - if (temp_size > max_size) { - max_size = temp_size; - } - } - } - return max_size; -} - -/* finds maximum number of nets that can be contained in pb_type, this is bounded by the number of driving pins */ -int get_max_nets_in_pb_type(const t_pb_type* pb_type) { - int max_nets; - if (pb_type->modes == nullptr) { - max_nets = pb_type->num_output_pins; - } else { - max_nets = 0; - for (int i = 0; i < pb_type->num_modes; i++) { - int temp_nets = 0; - for (int j = 0; j < pb_type->modes[i].num_pb_type_children; j++) { - temp_nets += pb_type->modes[i].pb_type_children[j].num_pb - * get_max_nets_in_pb_type( - &pb_type->modes[i].pb_type_children[j]); - } - if (temp_nets > max_nets) { - max_nets = temp_nets; - } - } - } - if (pb_type->is_root()) { - max_nets += pb_type->num_input_pins + pb_type->num_output_pins - + pb_type->num_clock_pins; - } - return max_nets; -} - -int get_max_depth_of_pb_type(t_pb_type* pb_type) { - int max_depth = pb_type->depth; - for (int i = 0; i < pb_type->num_modes; i++) { - for (int j = 0; j < pb_type->modes[i].num_pb_type_children; j++) { - int temp_depth = get_max_depth_of_pb_type(&pb_type->modes[i].pb_type_children[j]); - if (temp_depth > max_depth) { - max_depth = temp_depth; - } - } - } - return max_depth; -} - /** * given an atom block and physical primitive type, is the mapping legal */ diff --git a/vpr/src/util/vpr_utils.h b/vpr/src/util/vpr_utils.h index 842b18fef47..b6828859bd9 100644 --- a/vpr/src/util/vpr_utils.h +++ b/vpr/src/util/vpr_utils.h @@ -180,9 +180,6 @@ InstPort parse_inst_port(const std::string& str); //Returns the block type which is most likely the logic block t_logical_block_type_ptr infer_logic_block_type(const DeviceGrid& grid); -int get_max_primitives_in_pb_type(t_pb_type* pb_type); -int get_max_depth_of_pb_type(t_pb_type* pb_type); -int get_max_nets_in_pb_type(const t_pb_type* pb_type); bool primitive_type_feasible(AtomBlockId blk_id, const t_pb_type* cur_pb_type); t_pb_graph_pin* get_pb_graph_node_pin_from_model_port_pin(const t_model_ports* model_port, const int model_pin, const t_pb_graph_node* pb_graph_node); /// @brief Gets the pb_graph_node pin at the given pin index for the given