From c3ea108dbb6972a4aba346b9727680ab1f5594bc Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Fri, 10 Oct 2025 15:13:28 -0400 Subject: [PATCH 01/32] clean some comments --- .../route/rr_graph_generation/rr_graph.cpp | 62 +++++++------------ 1 file changed, 22 insertions(+), 40 deletions(-) diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index 7671a72e91..f006a83438 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -2549,10 +2549,6 @@ static void load_uniform_connection_block_pattern(vtr::NdMatrix& tracks_ } } -/*AA: Will need to modify this perhaps to acount for the type of the segment that we're loading the cb for. - * waiting for reply from VB if yes, sides that are perpendicular to the channel don't connect to it. We look - * at the side we are at and only distribute those connections in the two sides that work. - */ static void load_perturbed_connection_block_pattern(vtr::NdMatrix& tracks_connected_to_pin, const std::vector& pin_locations, const int x_chan_width, @@ -2697,7 +2693,7 @@ static vtr::NdMatrix, 5> alloc_and_load_track_to_pin_lookup(vtr /* get number of tracks to which this pin connects */ int num_tracks = 0; for (int iseg = 0; iseg < num_seg_types; iseg++) { - num_tracks += Fc[pin][seg_inf[iseg].seg_index]; // AA: Fc_in and Fc_out matrices are unified for all segments so need to map index. + num_tracks += Fc[pin][seg_inf[iseg].seg_index]; // Fc_in and Fc_out matrices are unified for all segments so need to map index. } for (int connected_layer : get_layers_pin_is_connected_to(tile_type, type_layer_index, pin)) { if (!pin_to_track_map[pin][width][height][connected_layer][side].empty()) { @@ -2720,19 +2716,6 @@ static vtr::NdMatrix, 5> alloc_and_load_track_to_pin_lookup(vtr return track_to_pin_lookup; } -/*AA: - * So I need to update this cause the Fc_xofs and Fc_yofs are size of - * X and Y segment counts. When going through the side of the logic block, - * need to consider what segments to build Fc nodes for. More on this: - * I may have to update the Fc_out[][][] structure allocator because we have - * different segments for horizontal and vertical channels. Now we are giving the - * fc_specs in the architecture file, which refers to a segment by name and a port - * for a tile (block type). If we figure out [as done in previous routine - * get actual_fc ?] we need distribute them properly with consideration to the - * type of the segment they're giving specifications for. So say for uniform, we - * distribute them evenly across TOP and BOTTOM for a y-parallel channel and - * LEFT and RIGHT for x-parallel channel. - */ static void build_unidir_rr_opins(RRGraphBuilder& rr_graph_builder, const RRGraphView& rr_graph, const int layer, @@ -2761,37 +2744,34 @@ static void build_unidir_rr_opins(RRGraphBuilder& rr_graph_builder, int width_offset = grid.get_width_offset({i, j, layer}); int height_offset = grid.get_height_offset({i, j, layer}); - /* Go through each pin and find its fanout. */ + // Go through each pin and find its fanout. for (int pin_index = 0; pin_index < type->num_pins; ++pin_index) { - /* Skip global pins and pins that are not of DRIVER type */ e_pin_type pin_type = get_pin_type_from_pin_physical_num(type, pin_index); - if (pin_type != e_pin_type::DRIVER) { - continue; - } - if (type->is_ignored_pin[pin_index]) { + + // Skip global pins and pins that are not of DRIVER type + if (pin_type != e_pin_type::DRIVER || type->is_ignored_pin[pin_index]) { continue; } RRNodeId opin_node_index = rr_graph_builder.node_lookup().find_node(layer, i, j, e_rr_type::OPIN, pin_index, side); - if (!opin_node_index) continue; //No valid from node + if (!opin_node_index) { + continue; // No valid from node + } for (int iseg = 0; iseg < num_seg_types; iseg++) { - /* get Fc for this segment type */ + // Fc for this segment type int seg_type_Fc = Fc_out[type->index][pin_index][iseg]; VTR_ASSERT(seg_type_Fc >= 0); - if (seg_type_Fc == 0) { - continue; - } - /* Can't do anything if pin isn't at this location */ - if (0 == type->pinloc[width_offset][height_offset][side][pin_index]) { + // Skip if the pin is not at this location or is not connected + if (seg_type_Fc == 0 || !type->pinloc[width_offset][height_offset][side][pin_index]) { continue; } - /* Figure out the chan seg at that side. - * side is the side of the logic or io block. */ - bool vert = ((side == TOP) || (side == BOTTOM)); - bool pos_dir = ((side == TOP) || (side == RIGHT)); + // Figure out the chan seg at that side. + // side is the side of the logic or io block. + bool vert = (side == TOP) || (side == BOTTOM); + bool pos_dir = (side == TOP) || (side == RIGHT); e_rr_type chan_type = (vert ? e_rr_type::CHANX : e_rr_type::CHANY); int chan = (vert ? (j) : (i)); int seg = (vert ? (i) : (j)); @@ -2800,15 +2780,16 @@ static void build_unidir_rr_opins(RRGraphBuilder& rr_graph_builder, int seg_index = get_parallel_seg_index(iseg, seg_index_map, wanted_axis); // The segment at index iseg doesn't have the proper adjacency so skip building Fc_out connections for it. - if (seg_index < 0) + if (seg_index < 0) { continue; + } vtr::NdMatrix& Fc_ofs = (vert ? Fc_xofs : Fc_yofs); if (false == pos_dir) { --chan; } - /* Skip the location if there is no channel. */ + // Skip the location if there is no channel. if (chan < 0) { continue; } @@ -2824,10 +2805,11 @@ static void build_unidir_rr_opins(RRGraphBuilder& rr_graph_builder, const t_chan_seg_details* seg_details = (chan_type == e_rr_type::CHANX ? chan_details_x[seg][chan] : chan_details_y[chan][seg]).data(); - if (seg_details[0].length() == 0) + if (seg_details[0].length() == 0) { continue; + } - /* Get the list of opin to mux connections for that chan seg. */ + // Get the list of opin to mux connections for that chan seg. bool clipped; for (int connected_layer : get_layers_pin_is_connected_to(type, layer, pin_index)) { @@ -2845,7 +2827,7 @@ static void build_unidir_rr_opins(RRGraphBuilder& rr_graph_builder, } } - /* Add in direct connections */ + // Add in direct connections get_opin_direct_connections(rr_graph_builder, rr_graph, layer, i, j, side, pin_index, opin_node_index, rr_edges_to_create, directs, clb_to_clb_directs); } From cd680d757c19547cb06489209af28bc102764006 Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Fri, 10 Oct 2025 15:29:29 -0400 Subject: [PATCH 02/32] clean get_track_to_pins a bit --- .../route/rr_graph_generation/rr_graph2.cpp | 31 ++++++++----------- vpr/src/route/rr_graph_generation/rr_graph2.h | 1 + 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/vpr/src/route/rr_graph_generation/rr_graph2.cpp b/vpr/src/route/rr_graph_generation/rr_graph2.cpp index 22d3bd4140..c1a37d1a9d 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph2.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph2.cpp @@ -1005,24 +1005,18 @@ int get_track_to_pins(RRGraphBuilder& rr_graph_builder, int wire_to_ipin_switch, int wire_to_pin_between_dice_switch, e_directionality directionality) { - /* - * Adds the fan-out edges from wire segment at (chan, seg, track) to adjacent - * blocks along the wire's length - */ - - int j, pass, iconn, phy_track, end, max_conn, ipin, x, y, num_conn; - - auto& device_ctx = g_vpr_ctx.device(); + const DeviceContext& device_ctx = g_vpr_ctx.device(); - /* End of this wire */ - end = get_seg_end(seg_details, track, seg, chan, chan_length); + // End of this wire + int end = get_seg_end(seg_details, track, seg, chan, chan_length); - num_conn = 0; + int num_conn = 0; - for (j = seg; j <= end; j++) { + for (int j = seg; j <= end; j++) { if (is_cblock(chan, j, track, seg_details)) { - for (pass = 0; pass < 2; ++pass) { //pass == 0 => TOP/RIGHT, pass == 1 => BOTTOM/LEFT + for (int pass = 0; pass < 2; ++pass) { //pass == 0 => TOP/RIGHT, pass == 1 => BOTTOM/LEFT e_side side; + int x, y; if (e_rr_type::CHANX == chan_type) { x = j; y = chan + pass; @@ -1044,7 +1038,7 @@ int get_track_to_pins(RRGraphBuilder& rr_graph_builder, * - algorithm assigns ipin connections to same physical track index * so that the logical track gets distributed uniformly */ - phy_track = vpr_to_phy_track(track, chan, j, seg_details, directionality); + int phy_track = vpr_to_phy_track(track, chan, j, seg_details, directionality); phy_track %= tracks_per_chan; /* We need the type to find the ipin map for this type */ @@ -1052,9 +1046,9 @@ int get_track_to_pins(RRGraphBuilder& rr_graph_builder, int width_offset = device_ctx.grid.get_width_offset({x, y, layer_index}); int height_offset = device_ctx.grid.get_height_offset({x, y, layer_index}); - max_conn = track_to_pin_lookup[type->index][phy_track][width_offset][height_offset][layer][side].size(); - for (iconn = 0; iconn < max_conn; iconn++) { - ipin = track_to_pin_lookup[type->index][phy_track][width_offset][height_offset][layer][side][iconn]; + const int max_conn = track_to_pin_lookup[type->index][phy_track][width_offset][height_offset][layer][side].size(); + for (int iconn = 0; iconn < max_conn; iconn++) { + const int ipin = track_to_pin_lookup[type->index][phy_track][width_offset][height_offset][layer][side][iconn]; if (!is_pin_conencted_to_layer(type, ipin, layer_index, layer, device_ctx.grid.get_num_layers())) { continue; } @@ -1071,7 +1065,8 @@ int get_track_to_pins(RRGraphBuilder& rr_graph_builder, } } } - return (num_conn); + + return num_conn; } /* diff --git a/vpr/src/route/rr_graph_generation/rr_graph2.h b/vpr/src/route/rr_graph_generation/rr_graph2.h index 45bebc65f4..1d32978733 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph2.h +++ b/vpr/src/route/rr_graph_generation/rr_graph2.h @@ -91,6 +91,7 @@ int get_unidir_opin_connections(RRGraphBuilder& rr_graph_builder, const t_chan_width& nodes_per_chan, bool* Fc_clipped); +/// Adds the fan-out edges from wire segment at (chan, seg, track) to adjacent blocks along the wire's length int get_track_to_pins(RRGraphBuilder& rr_graph_builder, int layer, int seg, From 8294d2d7f89bff675309feb8e281c1fe575b04f4 Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Fri, 10 Oct 2025 16:13:39 -0400 Subject: [PATCH 03/32] remove direct pin to other layer's track connectivity --- libs/libarchfpga/src/physical_types_util.cpp | 18 --- libs/libarchfpga/src/physical_types_util.h | 3 - .../route/rr_graph_generation/rr_graph.cpp | 144 ++++++------------ .../route/rr_graph_generation/rr_graph2.cpp | 137 +++++++---------- vpr/src/route/rr_graph_generation/rr_graph2.h | 7 +- vpr/src/route/rr_graph_generation/rr_types.h | 4 +- 6 files changed, 113 insertions(+), 200 deletions(-) diff --git a/libs/libarchfpga/src/physical_types_util.cpp b/libs/libarchfpga/src/physical_types_util.cpp index 3792a8a046..6242287af1 100644 --- a/libs/libarchfpga/src/physical_types_util.cpp +++ b/libs/libarchfpga/src/physical_types_util.cpp @@ -609,24 +609,6 @@ bool is_opin(int ipin, t_physical_tile_type_ptr type) { return false; } -bool is_pin_conencted_to_layer(t_physical_tile_type_ptr type, int ipin, int from_layer, int to_layer, unsigned num_of_avail_layer) { - // if type is empty, there is no pins - if (type->is_empty()) { - return false; - } - - // ipin should be a valid pin in physical type - VTR_ASSERT(ipin < type->num_pins); - unsigned pin_layer = from_layer + type->pin_layer_offset[ipin]; - // if pin_offset specifies a layer that doesn't exist in arch file, we do a wrap around - pin_layer = (pin_layer < num_of_avail_layer) ? pin_layer : pin_layer % num_of_avail_layer; - if (from_layer == to_layer || int(pin_layer) == to_layer) { - return true; - } - - return false; -} - 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 8786da0f92..3bbedf924e 100644 --- a/libs/libarchfpga/src/physical_types_util.h +++ b/libs/libarchfpga/src/physical_types_util.h @@ -115,9 +115,6 @@ ///@brief Returns true if the absolute physical pin index is an output of the given physical tile type 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, unsigned num_of_avail_layer); - /** * @brief Returns the corresponding physical pin based on the input parameters: * diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index f006a83438..b230746fd2 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -65,12 +65,6 @@ void print_rr_graph_stats(); ///@brief given a specific type, it returns layers that the type are located at std::set get_layers_of_physical_types(const t_physical_tile_type_ptr type); -///@brief given a specific pin number and type, it returns layers that the pin should be connected to -std::set get_layers_pin_is_connected_to(const t_physical_tile_type_ptr type, int from_layer, int pin_index); - -///@brief given a specific layer number and type, it returns layers which have same pin_index connected to the given layer -std::set get_layers_connected_to_pin(const t_physical_tile_type_ptr type, int to_layer, int pin_index); - /** * @brief This routine calculates pin connections to tracks for either all input or all output pins based on the Fc value defined in the architecture file. * For the requested pin type (input or output), it will loop through all segments and calculate how many connections should be made, @@ -85,10 +79,10 @@ std::set get_layers_connected_to_pin(const t_physical_tile_type_ptr type, i * @param seg_inf Segments type information, such as length, frequency, and etc. * @param sets_per_seg_type Number of available sets within the channel_width of each segment type. * - * @return an 5D matrix which keeps the track indicies connected to each pin ([0..num_pins-1][0..width-1][0..height-1][0..layer-1][0..sides-1]). + * @return an 4D matrix which keeps the track indices connected to each pin ([0..num_pins-1][0..width-1][0..height-1][0..layer-1][0..sides-1]). * */ -static vtr::NdMatrix, 5> alloc_and_load_pin_to_track_map(const e_pin_type pin_type, +static vtr::NdMatrix, 4> alloc_and_load_pin_to_track_map(const e_pin_type pin_type, const vtr::Matrix& Fc, const t_physical_tile_type_ptr tile_type, const std::set& type_layer, @@ -111,10 +105,10 @@ static vtr::NdMatrix, 5> alloc_and_load_pin_to_track_map(const * @param perturb_switch_pattern Specifies whether connections should be distributed unevenly across the channel or not. * @param directionality Segment directionality, should be either *UNI-DIRECTIONAL* or *BI-DIRECTIONAL* * - * @return an 6D matrix which keeps the track indicies connected to each pin ([0..num_pins-1][0..width-1][0..height-1][0..layer-1][0..sides-1][0..Fc_to_curr_seg_type-1]). + * @return an 5D matrix which keeps the track indices connected to each pin ([0..num_pins-1][0..width-1][0..height-1][0..layer-1][0..sides-1][0..Fc_to_curr_seg_type-1]). * */ -static vtr::NdMatrix alloc_and_load_pin_to_seg_type(const e_pin_type pin_type, +static vtr::NdMatrix alloc_and_load_pin_to_seg_type(const e_pin_type pin_type, const vtr::Matrix& Fc, const int seg_type_tracks, const int seg_index, @@ -126,7 +120,7 @@ static vtr::NdMatrix alloc_and_load_pin_to_seg_type(const e_pin_type pin static void advance_to_next_block_side(t_physical_tile_type_ptr tile_type, int& width_offset, int& height_offset, e_side& side); -static vtr::NdMatrix, 5> alloc_and_load_track_to_pin_lookup(vtr::NdMatrix, 5> pin_to_track_map, +static vtr::NdMatrix, 4> alloc_and_load_track_to_pin_lookup(vtr::NdMatrix, 4> pin_to_track_map, const vtr::Matrix& Fc, const t_physical_tile_type_ptr tile_type, const std::set& type_layer, @@ -251,7 +245,7 @@ static float pattern_fmod(float a, float b); * @param directionality Segment directionality, should be either *UNI-DIRECTIONAL* or *BI-DIRECTIONAL* * */ -static void load_uniform_connection_block_pattern(vtr::NdMatrix& tracks_connected_to_pin, +static void load_uniform_connection_block_pattern(vtr::NdMatrix& tracks_connected_to_pin, const std::vector& pin_locations, const vtr::Matrix& Fc, const int seg_index, @@ -268,10 +262,9 @@ static void load_uniform_connection_block_pattern(vtr::NdMatrix& tracks_ * @param y_chan_width Number of tracks in y-axis. * @param Fc Actual Fc value described in the architecture file for all pins of the specific phyiscal type ([0..number_of_pins-1][0..number_of_segment_types-1]). * @param seg_index The index of the segment type to which the function tries to connect pins. - * @param directionality Segment directionality, should be either *UNI-DIRECTIONAL* or *BI-DIRECTIONAL* - * + * @param directionality Segment directionality, should be either *UNI-DIRECTIONAL* or *BI-DIRECTIONAL* */ -static void load_perturbed_connection_block_pattern(vtr::NdMatrix& tracks_connected_to_pin, +static void load_perturbed_connection_block_pattern(vtr::NdMatrix& tracks_connected_to_pin, const std::vector& pin_locations, const int x_chan_width, const int y_chan_width, @@ -613,28 +606,6 @@ std::set get_layers_of_physical_types(const t_physical_tile_type_ptr type) return phy_type_layers; } -std::set get_layers_pin_is_connected_to(const t_physical_tile_type_ptr type, int from_layer, int pin_index) { - const DeviceContext& device_ctx = g_vpr_ctx.device(); - std::set layer_pin_index_is_connected_to; - for (int layer = 0; layer < (int)device_ctx.grid.get_num_layers(); layer++) { - if (is_pin_conencted_to_layer(type, pin_index, from_layer, layer, device_ctx.grid.get_num_layers())) { - layer_pin_index_is_connected_to.insert(layer); - } - } - return layer_pin_index_is_connected_to; -} - -std::set get_layers_connected_to_pin(const t_physical_tile_type_ptr type, int to_layer, int pin_index) { - const DeviceContext& device_ctx = g_vpr_ctx.device(); - std::set layers_connected_to_pin; - for (int layer = 0; layer < (int)device_ctx.grid.get_num_layers(); layer++) { - if (is_pin_conencted_to_layer(type, pin_index, layer, to_layer, device_ctx.grid.get_num_layers())) { - layers_connected_to_pin.insert(layer); - } - } - return layers_connected_to_pin; -} - static void build_rr_graph(e_graph_type graph_type, const std::vector& types, const DeviceGrid& grid, @@ -1727,13 +1698,11 @@ static void build_bidir_rr_opins(RRGraphBuilder& rr_graph_builder, RRNodeId node_index = rr_graph_builder.node_lookup().find_node(layer, i, j, e_rr_type::OPIN, pin_index, side); VTR_ASSERT(node_index); - for (int connected_layer : get_layers_pin_is_connected_to(type, layer, pin_index)) { - if (total_pin_Fc > 0) { - get_bidir_opin_connections(rr_graph_builder, layer, connected_layer, i, j, pin_index, - node_index, rr_edges_to_create, opin_to_track_map, - chan_details_x, - chan_details_y); - } + if (total_pin_Fc > 0) { + get_bidir_opin_connections(rr_graph_builder, layer, i, j, pin_index, + node_index, rr_edges_to_create, opin_to_track_map, + chan_details_x, + chan_details_y); } // Add in direct connections @@ -1850,7 +1819,7 @@ static void build_rr_chan(RRGraphBuilder& rr_graph_builder, // Add the edges from this track to all it's connected pins into the list get_track_to_pins(rr_graph_builder, layer, start, chan_coord, track, tracks_per_chan, node, rr_edges_to_create, track_to_pin_lookup, seg_details, chan_type, seg_dimension, - wire_to_ipin_switch, wire_to_pin_between_dice_switch, directionality); + wire_to_ipin_switch, directionality); // Add edges going from the current track into channel segments which are perpendicular to it if (chan_coord > 0) { @@ -1960,7 +1929,7 @@ void alloc_and_load_edges(RRGraphBuilder& rr_graph_builder, const t_rr_edge_info /* allocate pin to track map for each segment type individually and then combine into a single * vector */ -static vtr::NdMatrix, 5> alloc_and_load_pin_to_track_map(const e_pin_type pin_type, +static vtr::NdMatrix, 4> alloc_and_load_pin_to_track_map(const e_pin_type pin_type, const vtr::Matrix& Fc, const t_physical_tile_type_ptr tile_type, const std::set& type_layer, @@ -1970,12 +1939,10 @@ static vtr::NdMatrix, 5> alloc_and_load_pin_to_track_map(const const std::vector& sets_per_seg_type) { // allocate 'result' matrix and initialize entries to UNDEFINED. also allocate and initialize matrix which will be used // to index into the correct entries when loading up 'result' - auto& grid = g_vpr_ctx.device().grid; - auto result = vtr::NdMatrix, 5>({ + auto result = vtr::NdMatrix, 4>({ size_t(tile_type->num_pins), //[0..num_pins-1] size_t(tile_type->width), //[0..width-1] size_t(tile_type->height), //[0..height-1] - size_t(grid.get_num_layers()), //[0..layer-1] 4, //[0..sides-1] }); @@ -2012,16 +1979,13 @@ static vtr::NdMatrix, 5> alloc_and_load_pin_to_track_map(const for (int iheight = 0; iheight < tile_type->height; iheight++) { for (int iside = 0; iside < 4; iside++) { for (int iconn = 0; iconn < cur_Fc; iconn++) { - for (int connected_layer : get_layers_pin_is_connected_to(tile_type, type_layer_index, ipin)) { - int relative_track_ind = pin_to_seg_type_map[ipin][iwidth][iheight][connected_layer][iside][iconn]; - if (relative_track_ind != UNDEFINED) { - VTR_ASSERT(relative_track_ind <= num_seg_type_tracks); - int absolute_track_ind = relative_track_ind + seg_type_start_track; - - VTR_ASSERT(absolute_track_ind >= 0); - result[ipin][iwidth][iheight][connected_layer][iside].push_back( - absolute_track_ind); - } + int relative_track_ind = pin_to_seg_type_map[ipin][iwidth][iheight][iside][iconn]; + if (relative_track_ind != UNDEFINED) { + VTR_ASSERT(relative_track_ind <= num_seg_type_tracks); + int absolute_track_ind = relative_track_ind + seg_type_start_track; + + VTR_ASSERT(absolute_track_ind >= 0); + result[ipin][iwidth][iheight][iside].push_back(absolute_track_ind); } } } @@ -2037,7 +2001,7 @@ static vtr::NdMatrix, 5> alloc_and_load_pin_to_track_map(const return result; } -static vtr::NdMatrix alloc_and_load_pin_to_seg_type(const e_pin_type pin_type, +static vtr::NdMatrix alloc_and_load_pin_to_seg_type(const e_pin_type pin_type, const vtr::Matrix& Fc, const int num_seg_type_tracks, const int seg_index, @@ -2058,14 +2022,13 @@ static vtr::NdMatrix alloc_and_load_pin_to_seg_type(const e_pin_type pin auto& grid = g_vpr_ctx.device().grid; if (tile_type->num_pins < 1) { - return vtr::NdMatrix(); + return vtr::NdMatrix(); } - auto tracks_connected_to_pin = vtr::NdMatrix({ + auto tracks_connected_to_pin = vtr::NdMatrix({ size_t(tile_type->num_pins), // [0..num_pins-1] size_t(tile_type->width), // [0..width-1] size_t(tile_type->height), // [0..height-1] - size_t(grid.get_num_layers()), // [0..layer-1] NUM_2D_SIDES, // [0..NUM_2D_SIDES-1] size_t(max_Fc) // [0..Fc-1] }, @@ -2121,10 +2084,8 @@ static vtr::NdMatrix alloc_and_load_pin_to_seg_type(const e_pin_type pin for (int height = 0; height < tile_type->height; ++height) { for (e_side side : TOTAL_2D_SIDES) { if (tile_type->pinloc[width][height][side][pin] == 1) { - for (int i = 0; i < (int)get_layers_connected_to_pin(tile_type, type_layer_index, pin).size(); i++) { - dir_list[width][height][type_layer_index][side][num_dir[width][height][type_layer_index][side]] = pin; - num_dir[width][height][type_layer_index][side]++; - } + dir_list[width][height][type_layer_index][side][num_dir[width][height][type_layer_index][side]] = pin; + num_dir[width][height][type_layer_index][side]++; } } } @@ -2351,7 +2312,7 @@ static float pattern_fmod(float a, float b) { return raw_result; } -static void load_uniform_connection_block_pattern(vtr::NdMatrix& tracks_connected_to_pin, +static void load_uniform_connection_block_pattern(vtr::NdMatrix& tracks_connected_to_pin, const std::vector& pin_locations, const vtr::Matrix& Fc, const int seg_index, @@ -2542,14 +2503,14 @@ static void load_uniform_connection_block_pattern(vtr::NdMatrix& tracks_ /* Assign the group of tracks for the Fc pattern */ for (int k = 0; k < group_size; ++k) { - tracks_connected_to_pin[pin][width][height][layer][side][group_size * j + k] = (itrack + k) % max_chan_width; + tracks_connected_to_pin[pin][width][height][side][group_size * j + k] = (itrack + k) % max_chan_width; excess_tracks_selected[side][width][height][(itrack + k) % max_chan_width]++; } } } } -static void load_perturbed_connection_block_pattern(vtr::NdMatrix& tracks_connected_to_pin, +static void load_perturbed_connection_block_pattern(vtr::NdMatrix& tracks_connected_to_pin, const std::vector& pin_locations, const int x_chan_width, const int y_chan_width, @@ -2576,7 +2537,6 @@ static void load_perturbed_connection_block_pattern(vtr::NdMatrix& track e_side side = pin_locations[i].side; int width = pin_locations[i].width_offset; int height = pin_locations[i].height_offset; - int layer = pin_locations[i].layer_offset; int pin_Fc = Fc[pin][seg_index]; int Fc_dense = (pin_Fc / 2) + 1; @@ -2606,7 +2566,7 @@ static void load_perturbed_connection_block_pattern(vtr::NdMatrix& track * so connection is valid and fine */ int itrack = (int)ftrack; itrack = itrack % max_chan_width; - tracks_connected_to_pin[pin][width][height][layer][side][iconn] = itrack; + tracks_connected_to_pin[pin][width][height][side][iconn] = itrack; ftrack += spacing[ihalf]; iconn++; @@ -2654,7 +2614,7 @@ static void check_all_tracks_reach_pins(t_logical_block_type_ptr type, /* Allocates and loads the track to ipin lookup for each physical grid type. This * is the same information as the ipin_to_track map but accessed in a different way. */ -static vtr::NdMatrix, 5> alloc_and_load_track_to_pin_lookup(vtr::NdMatrix, 5> pin_to_track_map, +static vtr::NdMatrix, 4> alloc_and_load_track_to_pin_lookup(vtr::NdMatrix, 4> pin_to_track_map, const vtr::Matrix& Fc, const t_physical_tile_type_ptr tile_type, const std::set& type_layer, @@ -2676,13 +2636,13 @@ static vtr::NdMatrix, 5> alloc_and_load_track_to_pin_lookup(vtr * here is always in the perspective of the CLB */ if (num_pins < 1) { - return vtr::NdMatrix, 5>(); + return vtr::NdMatrix, 4>(); } const int num_seg_types = seg_inf.size(); auto& grid = g_vpr_ctx.device().grid; /* Alloc and zero the the lookup table */ - auto track_to_pin_lookup = vtr::NdMatrix, 5>({size_t(max_chan_width), size_t(type_width), size_t(type_height), size_t(grid.get_num_layers()), 4}); + auto track_to_pin_lookup = vtr::NdMatrix, 4>({size_t(max_chan_width), size_t(type_width), size_t(type_height), 4}); /* Count number of pins to which each track connects */ for (int type_layer_index : type_layer) { @@ -2695,16 +2655,14 @@ static vtr::NdMatrix, 5> alloc_and_load_track_to_pin_lookup(vtr for (int iseg = 0; iseg < num_seg_types; iseg++) { num_tracks += Fc[pin][seg_inf[iseg].seg_index]; // Fc_in and Fc_out matrices are unified for all segments so need to map index. } - for (int connected_layer : get_layers_pin_is_connected_to(tile_type, type_layer_index, pin)) { - if (!pin_to_track_map[pin][width][height][connected_layer][side].empty()) { - num_tracks = std::min(num_tracks, - (int)pin_to_track_map[pin][width][height][connected_layer][side].size()); - for (int conn = 0; conn < num_tracks; ++conn) { - int track = pin_to_track_map[pin][width][height][connected_layer][side][conn]; - VTR_ASSERT(track < max_chan_width); - VTR_ASSERT(track >= 0); - track_to_pin_lookup[track][width][height][connected_layer][side].push_back(pin); - } + if (!pin_to_track_map[pin][width][height][side].empty()) { + num_tracks = std::min(num_tracks, + (int)pin_to_track_map[pin][width][height][side].size()); + for (int conn = 0; conn < num_tracks; ++conn) { + int track = pin_to_track_map[pin][width][height][side][conn]; + VTR_ASSERT(track < max_chan_width); + VTR_ASSERT(track >= 0); + track_to_pin_lookup[track][width][height][side].push_back(pin); } } } @@ -2812,15 +2770,13 @@ static void build_unidir_rr_opins(RRGraphBuilder& rr_graph_builder, // Get the list of opin to mux connections for that chan seg. bool clipped; - for (int connected_layer : get_layers_pin_is_connected_to(type, layer, pin_index)) { - /* Check the pin physical layer and connect it to the same layer if necessary */ - rr_edge_count += get_unidir_opin_connections(rr_graph_builder, layer, connected_layer, chan, seg, - seg_type_Fc, seg_index, chan_type, seg_details, - opin_node_index, - rr_edges_to_create, - Fc_ofs, max_len, nodes_per_chan, - &clipped); - } + // Check the pin physical layer and connect it to the same layer if necessary + rr_edge_count += get_unidir_opin_connections(rr_graph_builder, layer, chan, seg, + seg_type_Fc, seg_index, chan_type, seg_details, + opin_node_index, + rr_edges_to_create, + Fc_ofs, max_len, nodes_per_chan, + &clipped); if (clipped) { *Fc_clipped = true; diff --git a/vpr/src/route/rr_graph_generation/rr_graph2.cpp b/vpr/src/route/rr_graph_generation/rr_graph2.cpp index c1a37d1a9d..6ab33d8176 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph2.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph2.cpp @@ -597,8 +597,7 @@ int get_seg_end(const t_chan_seg_details* seg_details, const int itrack, const i /* Returns the number of tracks to which clb opin #ipin at (i,j) connects. * * Also stores the nodes to which this pin connects in rr_edges_to_create */ int get_bidir_opin_connections(RRGraphBuilder& rr_graph_builder, - const int opin_layer, - const int track_layer, + const int layer, const int i, const int j, const int ipin, @@ -607,73 +606,66 @@ int get_bidir_opin_connections(RRGraphBuilder& rr_graph_builder, const t_pin_to_track_lookup& opin_to_track_map, const t_chan_details& chan_details_x, const t_chan_details& chan_details_y) { - int num_conn, tr_i, tr_j, chan, seg; - int to_switch; - int is_connected_track; - t_physical_tile_type_ptr type; - e_rr_type to_type; - - auto& device_ctx = g_vpr_ctx.device(); + const DeviceContext& device_ctx = g_vpr_ctx.device(); - type = device_ctx.grid.get_physical_type({i, j, track_layer}); - int width_offset = device_ctx.grid.get_width_offset({i, j, track_layer}); - int height_offset = device_ctx.grid.get_height_offset({i, j, track_layer}); + t_physical_tile_type_ptr type = device_ctx.grid.get_physical_type({i, j, layer}); + int width_offset = device_ctx.grid.get_width_offset({i, j, layer}); + int height_offset = device_ctx.grid.get_height_offset({i, j, layer}); - num_conn = 0; + int num_conn = 0; - /* [0..device_ctx.num_block_types-1][0..num_pins-1][0..width][0..height][0..3][0..Fc-1] */ + // [0..device_ctx.num_block_types-1][0..num_pins-1][0..width][0..height][0..3][0..Fc-1] for (e_side side : TOTAL_2D_SIDES) { - /* Figure out coords of channel segment based on side */ - tr_i = ((side == LEFT) ? (i - 1) : i); - tr_j = ((side == BOTTOM) ? (j - 1) : j); + // Figure out coords of channel segment based on side + int tr_i = (side == LEFT) ? i - 1 : i; + int tr_j = (side == BOTTOM) ? j - 1 : j; - to_type = ((side == LEFT) || (side == RIGHT)) ? e_rr_type::CHANY : e_rr_type::CHANX; + e_rr_type to_type = ((side == LEFT) || (side == RIGHT)) ? e_rr_type::CHANY : e_rr_type::CHANX; - chan = ((to_type == e_rr_type::CHANX) ? tr_j : tr_i); - seg = ((to_type == e_rr_type::CHANX) ? tr_i : tr_j); + int chan = (to_type == e_rr_type::CHANX) ? tr_j : tr_i; + int seg = (to_type == e_rr_type::CHANX) ? tr_i : tr_j; bool vert = !((side == TOP) || (side == BOTTOM)); - /* Don't connect where no tracks on fringes */ - if ((tr_i < 0) || (tr_i > int(device_ctx.grid.width() - 2))) { //-2 for no perimeter channels + // Don't connect where no tracks on fringes + if (tr_i < 0 || tr_i > int(device_ctx.grid.width() - 2)) { //-2 for no perimeter channels continue; } - if ((tr_j < 0) || (tr_j > int(device_ctx.grid.height() - 2))) { //-2 for no perimeter channels + if (tr_j < 0 || tr_j > int(device_ctx.grid.height() - 2)) { //-2 for no perimeter channels continue; } - if ((e_rr_type::CHANX == to_type) && (tr_i < 1)) { + if (e_rr_type::CHANX == to_type && tr_i < 1) { continue; } - if ((e_rr_type::CHANY == to_type) && (tr_j < 1)) { + if (e_rr_type::CHANY == to_type && tr_j < 1) { continue; } if (opin_to_track_map[type->index].empty()) { continue; } - is_connected_track = false; + bool is_connected_track = false; const t_chan_seg_details* seg_details = (vert ? chan_details_y[chan][seg] : chan_details_x[seg][chan]).data(); - /* Iterate of the opin to track connections */ - - for (int to_track : opin_to_track_map[type->index][ipin][width_offset][height_offset][track_layer][side]) { + // Iterate of the opin to track connections + for (int to_track : opin_to_track_map[type->index][ipin][width_offset][height_offset][side]) { /* Skip unconnected connections */ if (UNDEFINED == to_track || is_connected_track) { is_connected_track = true; - VTR_ASSERT(UNDEFINED == opin_to_track_map[type->index][ipin][width_offset][height_offset][track_layer][side][0]); + VTR_ASSERT(UNDEFINED == opin_to_track_map[type->index][ipin][width_offset][height_offset][side][0]); continue; } - /* Only connect to wire if there is a CB */ + // Only connect to wire if there is a CB if (is_cblock(chan, seg, to_track, seg_details)) { - RRNodeId to_node = rr_graph_builder.node_lookup().find_node(track_layer, tr_i, tr_j, to_type, to_track); + RRNodeId to_node = rr_graph_builder.node_lookup().find_node(layer, tr_i, tr_j, to_type, to_track); if (!to_node) { continue; } - to_switch = (track_layer == opin_layer) ? seg_details[to_track].arch_wire_switch() : seg_details[to_track].arch_inter_die_switch(); + int to_switch = seg_details[to_track].arch_wire_switch(); rr_edges_to_create.emplace_back(from_rr_node, to_node, to_switch, false); ++num_conn; @@ -691,8 +683,7 @@ int get_bidir_opin_connections(RRGraphBuilder& rr_graph_builder, * routine used in this function. */ int get_unidir_opin_connections(RRGraphBuilder& rr_graph_builder, - const int opin_layer, - const int track_layer, + const int layer, const int chan, const int seg, int Fc, @@ -750,19 +741,19 @@ int get_unidir_opin_connections(RRGraphBuilder& rr_graph_builder, int dec_track = dec_muxes[dec_mux]; /* Figure the inodes of those muxes */ - RRNodeId inc_inode_index = rr_graph_builder.node_lookup().find_node(track_layer, x, y, chan_type, inc_track); - RRNodeId dec_inode_index = rr_graph_builder.node_lookup().find_node(track_layer, x, y, chan_type, dec_track); + RRNodeId inc_inode_index = rr_graph_builder.node_lookup().find_node(layer, x, y, chan_type, inc_track); + RRNodeId dec_inode_index = rr_graph_builder.node_lookup().find_node(layer, x, y, chan_type, dec_track); if (!inc_inode_index || !dec_inode_index) { continue; } /* Add to the list. */ - short to_switch = (opin_layer == track_layer) ? seg_details[inc_track].arch_opin_switch() : seg_details[inc_track].arch_inter_die_switch(); + short to_switch = seg_details[inc_track].arch_opin_switch(); rr_edges_to_create.emplace_back(from_rr_node, inc_inode_index, to_switch, false); ++num_edges; - to_switch = (opin_layer == track_layer) ? seg_details[dec_track].arch_opin_switch() : seg_details[dec_track].arch_inter_die_switch(); + to_switch = seg_details[dec_track].arch_opin_switch(); rr_edges_to_create.emplace_back(from_rr_node, dec_inode_index, to_switch, false); ++num_edges; } @@ -966,21 +957,18 @@ void dump_track_to_pin_map(t_track_to_pin_lookup& track_to_pin_map, int max_chan_width, FILE* fp) { if (fp) { - auto& device_ctx = g_vpr_ctx.device(); for (unsigned int i = 0; i < types.size(); i++) { if (!track_to_pin_map[i].empty()) { - for (size_t layer = 0; layer < device_ctx.grid.get_num_layers(); layer++) { - for (int track = 0; track < max_chan_width; ++track) { - for (int width = 0; width < types[i].width; ++width) { - for (int height = 0; height < types[i].height; ++height) { - for (int side = 0; side < 4; ++side) { - fprintf(fp, "\nTYPE:%s width:%d height:%d layer:%lu\n", types[i].name.c_str(), width, height, layer); - fprintf(fp, "\nSIDE:%d TRACK:%d \n", side, track); - for (size_t con = 0; con < track_to_pin_map[i][track][width][height][layer][side].size(); con++) { - fprintf(fp, "%d ", track_to_pin_map[i][track][width][height][layer][side][con]); - } - fprintf(fp, "\n=====================\n"); + for (int track = 0; track < max_chan_width; ++track) { + for (int width = 0; width < types[i].width; ++width) { + for (int height = 0; height < types[i].height; ++height) { + for (int side = 0; side < 4; ++side) { + fprintf(fp, "\nTYPE:%s width:%d height:%d \n", types[i].name.c_str(), width, height); + fprintf(fp, "\nSIDE:%d TRACK:%d \n", side, track); + for (size_t con = 0; con < track_to_pin_map[i][track][width][height][side].size(); con++) { + fprintf(fp, "%d ", track_to_pin_map[i][track][width][height][side][con]); } + fprintf(fp, "\n=====================\n"); } } } @@ -1003,7 +991,6 @@ int get_track_to_pins(RRGraphBuilder& rr_graph_builder, e_rr_type chan_type, int chan_length, int wire_to_ipin_switch, - int wire_to_pin_between_dice_switch, e_directionality directionality) { const DeviceContext& device_ctx = g_vpr_ctx.device(); @@ -1028,38 +1015,32 @@ int get_track_to_pins(RRGraphBuilder& rr_graph_builder, side = (0 == pass ? RIGHT : LEFT); } - for (int layer_index = 0; layer_index < (int)device_ctx.grid.get_num_layers(); layer_index++) { - /* PAJ - if the pointed to is an EMPTY then shouldn't look for ipins */ - t_physical_tile_type_ptr type = device_ctx.grid.get_physical_type({x, y, layer_index}); - if (type == device_ctx.EMPTY_PHYSICAL_TILE_TYPE) - continue; + /* PAJ - if the pointed to is an EMPTY then shouldn't look for ipins */ + t_physical_tile_type_ptr type = device_ctx.grid.get_physical_type({x, y, layer}); + if (type == device_ctx.EMPTY_PHYSICAL_TILE_TYPE) + continue; - /* Move from logical (straight) to physical (twisted) track index - * - algorithm assigns ipin connections to same physical track index - * so that the logical track gets distributed uniformly */ + /* Move from logical (straight) to physical (twisted) track index + * - algorithm assigns ipin connections to same physical track index + * so that the logical track gets distributed uniformly */ - int phy_track = vpr_to_phy_track(track, chan, j, seg_details, directionality); - phy_track %= tracks_per_chan; + int phy_track = vpr_to_phy_track(track, chan, j, seg_details, directionality); + phy_track %= tracks_per_chan; - /* We need the type to find the ipin map for this type */ + /* We need the type to find the ipin map for this type */ - int width_offset = device_ctx.grid.get_width_offset({x, y, layer_index}); - int height_offset = device_ctx.grid.get_height_offset({x, y, layer_index}); + int width_offset = device_ctx.grid.get_width_offset({x, y, layer}); + int height_offset = device_ctx.grid.get_height_offset({x, y, layer}); - const int max_conn = track_to_pin_lookup[type->index][phy_track][width_offset][height_offset][layer][side].size(); - for (int iconn = 0; iconn < max_conn; iconn++) { - const int ipin = track_to_pin_lookup[type->index][phy_track][width_offset][height_offset][layer][side][iconn]; - if (!is_pin_conencted_to_layer(type, ipin, layer_index, layer, device_ctx.grid.get_num_layers())) { - continue; - } + const int max_conn = track_to_pin_lookup[type->index][phy_track][width_offset][height_offset][side].size(); + for (int iconn = 0; iconn < max_conn; iconn++) { + const int ipin = track_to_pin_lookup[type->index][phy_track][width_offset][height_offset][side][iconn]; - /* Check there is a connection and Fc map isn't wrong */ - RRNodeId to_node = rr_graph_builder.node_lookup().find_node(layer_index, x, y, e_rr_type::IPIN, ipin, side); - int switch_type = (layer_index == layer) ? wire_to_ipin_switch : wire_to_pin_between_dice_switch; - if (to_node) { - rr_edges_to_create.emplace_back(from_rr_node, to_node, switch_type, false); - ++num_conn; - } + // Check there is a connection and Fc map isn't wrong + RRNodeId to_node = rr_graph_builder.node_lookup().find_node(layer, x, y, e_rr_type::IPIN, ipin, side); + if (to_node) { + rr_edges_to_create.emplace_back(from_rr_node, to_node, wire_to_ipin_switch, false); + ++num_conn; } } } diff --git a/vpr/src/route/rr_graph_generation/rr_graph2.h b/vpr/src/route/rr_graph_generation/rr_graph2.h index 1d32978733..1693d1a4a5 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph2.h +++ b/vpr/src/route/rr_graph_generation/rr_graph2.h @@ -64,8 +64,7 @@ bool is_sblock(const int chan, const enum e_directionality directionality); int get_bidir_opin_connections(RRGraphBuilder& rr_graph_builder, - const int opin_layer, - const int track_layer, + const int layer, const int i, const int j, const int ipin, @@ -76,8 +75,7 @@ int get_bidir_opin_connections(RRGraphBuilder& rr_graph_builder, const t_chan_details& chan_details_y); int get_unidir_opin_connections(RRGraphBuilder& rr_graph_builder, - const int opin_layer, - const int track_layer, + const int layer, const int chan, const int seg, int Fc, @@ -105,7 +103,6 @@ int get_track_to_pins(RRGraphBuilder& rr_graph_builder, e_rr_type chan_type, int chan_length, int wire_to_ipin_switch, - int wire_to_pin_between_dice_switch, e_directionality directionality); int get_track_to_tracks(RRGraphBuilder& rr_graph_builder, diff --git a/vpr/src/route/rr_graph_generation/rr_types.h b/vpr/src/route/rr_graph_generation/rr_types.h index a1059f530d..518a5b2ca9 100644 --- a/vpr/src/route/rr_graph_generation/rr_types.h +++ b/vpr/src/route/rr_graph_generation/rr_types.h @@ -14,14 +14,14 @@ * * The matrix should be accessed as follows as a result after allocation in rr_graph.cpp: alloc_pin_to_track_lookup (used by unidir and bidir) * [0..device_ctx.physical_tile_types.size()-1][0..num_pins-1][0..width][0..height][0..layer-1][0..3][0..Fc-1] */ -typedef std::vector, 5>> t_pin_to_track_lookup; +typedef std::vector, 4>> 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. * 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] * * Note that when we model different channels based on position not axis, we can't use this anymore and need to have a lookup for each grid location. */ -typedef std::vector, 5>> t_track_to_pin_lookup; +typedef std::vector, 4>> t_track_to_pin_lookup; /** * @brief Lists detailed information about wire segments. [0 .. W-1]. From 6857133a7090565d8dc1e923391ba964bbe7ebfe Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Fri, 10 Oct 2025 16:22:44 -0400 Subject: [PATCH 04/32] remove arch_inter_die_switch --- libs/libarchfpga/src/physical_types.h | 8 -------- libs/libarchfpga/src/read_xml_arch_file.cpp | 13 ------------- vpr/src/route/rr_graph_generation/rr_graph2.cpp | 3 --- vpr/src/route/rr_graph_generation/rr_types.h | 8 -------- 4 files changed, 32 deletions(-) diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index 2c122e1773..171ad73b7a 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -1620,14 +1620,6 @@ struct t_segment_inf { */ short arch_opin_switch_dec = ARCH_FPGA_UNDEFINED_VAL; - /** - * @brief Index of the switch type that connects output pins (OPINs) to this - * segment from another die (layer). Note that this index is in relation to - * the switches from the architecture file, not the expanded list of switches - * that is built at the end of build_rr_graph. - */ - short arch_inter_die_switch = ARCH_FPGA_UNDEFINED_VAL; - /** * @brief The fraction of logic blocks along its length to which this segment can connect. * (i.e. internal population). diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index fad3679758..0186085b27 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -3979,19 +3979,6 @@ static std::vector process_segments(pugi::xml_node parent, //Verify only expected sub-tags are found expect_only_children(Node, expected_subtags, loc_data); - //Get the switch name for different dice wire and track connections - SubElem = get_single_child(Node, "mux_inter_die", loc_data, ReqOpt::OPTIONAL); - tmp = get_attribute(SubElem, "name", loc_data, ReqOpt::OPTIONAL).as_string(""); - if (strlen(tmp) != 0) { - /* Match names */ - int switch_idx = find_switch_by_name(switches, tmp); - if (switch_idx < 0) { - archfpga_throw(loc_data.filename_c_str(), loc_data.line(SubElem), - vtr::string_fmt("'%s' is not a valid mux name.\n", tmp).c_str()); - } - Segs[i].arch_inter_die_switch = switch_idx; - } - /* Get the wire and opin switches, or mux switch if unidir */ if (UNI_DIRECTIONAL == Segs[i].directionality) { //Get the switch name for same die wire and track connections diff --git a/vpr/src/route/rr_graph_generation/rr_graph2.cpp b/vpr/src/route/rr_graph_generation/rr_graph2.cpp index 6ab33d8176..8901caeb9e 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph2.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph2.cpp @@ -295,7 +295,6 @@ std::vector alloc_and_load_seg_details(int* max_chan_width, const int arch_opin_switch = segment_inf[i].arch_opin_switch; const int arch_wire_switch_dec = segment_inf[i].arch_wire_switch_dec; const int arch_opin_switch_dec = segment_inf[i].arch_opin_switch_dec; - const int arch_inter_die_switch = segment_inf[i].arch_inter_die_switch; VTR_ASSERT((arch_wire_switch == arch_opin_switch && arch_wire_switch_dec == arch_opin_switch_dec) || (directionality != UNI_DIRECTIONAL)); // Set up the tracks of same type @@ -354,8 +353,6 @@ std::vector alloc_and_load_seg_details(int* max_chan_width, seg_details[cur_track].Cmetal = segment_inf[i].Cmetal; //seg_details[cur_track].Cmetal_per_m = segment_inf[i].Cmetal_per_m; - seg_details[cur_track].arch_inter_die_switch = arch_inter_die_switch; - if (BI_DIRECTIONAL == directionality) { seg_details[cur_track].direction = Direction::BIDIR; } else { diff --git a/vpr/src/route/rr_graph_generation/rr_types.h b/vpr/src/route/rr_graph_generation/rr_types.h index 518a5b2ca9..395ed421f4 100644 --- a/vpr/src/route/rr_graph_generation/rr_types.h +++ b/vpr/src/route/rr_graph_generation/rr_types.h @@ -58,13 +58,6 @@ struct t_seg_details { */ short arch_opin_switch = 0; - /** @brief Index of the switch type that connects output pins (OPINs) *to* this segment - * from *another dice*. Note that this index is in relation to the switches from the - * architecture file, not the expanded list of switches that is built at the end of - * build_rr_graph. - */ - short arch_inter_die_switch = 0; - /** @brief Resistance of a routing track, per unit logic block length. */ float Rmetal = 0; @@ -137,7 +130,6 @@ class t_chan_seg_details { short arch_wire_switch() const { return seg_detail_->arch_wire_switch; } short arch_opin_switch() const { return seg_detail_->arch_opin_switch; } - short arch_inter_die_switch() const { return seg_detail_->arch_inter_die_switch; } Direction direction() const { return seg_detail_->direction; } From bd51bd94b2e5cb4a16141e2740a1902e9cfe7687 Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Tue, 28 Oct 2025 15:53:12 -0400 Subject: [PATCH 05/32] remove pin layer offset and ipin_cblock_switch_index_between_dice --- libs/libarchfpga/src/echo_arch.cpp | 14 +-- libs/libarchfpga/src/physical_types.h | 8 +- .../src/read_fpga_interchange_arch.cpp | 2 +- libs/libarchfpga/src/read_xml_arch_file.cpp | 80 ++++++--------- libs/librrgraph/src/io/rr_graph_reader.cpp | 2 - libs/librrgraph/src/io/rr_graph_reader.h | 1 - .../src/io/rr_graph_uxsdcxx_serializer.h | 26 ++--- libs/librrgraph/src/io/rr_graph_writer.cpp | 1 - vpr/src/base/CheckArch.cpp | 23 ++--- vpr/src/base/setup_vpr.cpp | 99 +++++++++---------- vpr/src/base/vpr_types.h | 8 -- .../route/rr_graph_generation/rr_graph.cpp | 94 +++++++----------- 12 files changed, 130 insertions(+), 228 deletions(-) diff --git a/libs/libarchfpga/src/echo_arch.cpp b/libs/libarchfpga/src/echo_arch.cpp index 2105b8fd7e..99ec9d140b 100644 --- a/libs/libarchfpga/src/echo_arch.cpp +++ b/libs/libarchfpga/src/echo_arch.cpp @@ -11,10 +11,6 @@ #include "vtr_memory.h" #include "vtr_assert.h" -/// @brief indices to lookup IPIN connection block switch name -constexpr int ipin_cblock_switch_index_within_die = 0; -constexpr int ipin_cblock_switch_index_between_dice = 1; - void PrintArchInfo(FILE* Echo, const t_arch* arch); static void print_model(FILE* echo, const t_model& model); static void PrintPb_types_rec(FILE* Echo, const t_pb_type* pb_type, int level, const LogicalModels& models); @@ -198,15 +194,7 @@ void PrintArchInfo(FILE* Echo, const t_arch* arch) { break; } - fprintf(Echo, "\tInput Connect Block Switch Name Within a Same Die: %s\n", arch->ipin_cblock_switch_name[ipin_cblock_switch_index_within_die].c_str()); - - //if there is more than one layer available, print the connection block switch name that is used for connection between two dice - for (const t_grid_def& layout : arch->grid_layouts) { - int num_layers = (int)layout.layers.size(); - if (num_layers > 1) { - fprintf(Echo, "\tInput Connect Block Switch Name Between Two Dice: %s\n", arch->ipin_cblock_switch_name[ipin_cblock_switch_index_between_dice].c_str()); - } - } + fprintf(Echo, "\tInput Connect Block Switch Name: %s\n", arch->ipin_cblock_switch_name.c_str()); fprintf(Echo, "*************************************************\n\n"); //Switch list diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index 0aee5bd797..29f5bd8f6b 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -560,7 +560,6 @@ struct t_physical_tile_type { int primitive_class_starting_idx = -1; std::unordered_map primitive_class_inf; // [primitive_class_num] -> primitive_class_inf - std::vector pin_layer_offset; // [0..num_pins-1] std::vector pin_width_offset; // [0..num_pins-1] std::vector pin_height_offset; // [0..num_pins-1] std::vector pin_class; // [0..num_pins-1] @@ -2053,11 +2052,8 @@ struct t_arch { std::vector lut_cells; std::unordered_map> lut_elements; - // The name of the switch used for the input connection block (i.e. to - // connect routing tracks to block pins). tracks can be connected to - // ipins through the same die or from other dice, each of these - // types of connections requires a different switch, all names should correspond to a switch in Switches. - std::vector ipin_cblock_switch_name; + // The name of the switch used for the input connection block (i.e. to connect routing tracks to block pins). + std::string ipin_cblock_switch_name; std::vector grid_layouts; //Set of potential device layouts diff --git a/libs/libarchfpga/src/read_fpga_interchange_arch.cpp b/libs/libarchfpga/src/read_fpga_interchange_arch.cpp index d382428d01..995064b059 100644 --- a/libs/libarchfpga/src/read_fpga_interchange_arch.cpp +++ b/libs/libarchfpga/src/read_fpga_interchange_arch.cpp @@ -2327,7 +2327,7 @@ struct ArchReader { arch_->Chans.chan_y_dist.width = 0; arch_->Chans.chan_y_dist.xpeak = 0; arch_->Chans.chan_y_dist.dc = 0; - arch_->ipin_cblock_switch_name.push_back(std::string("generic")); + arch_->ipin_cblock_switch_name = "generic"; arch_->sb_type = e_switch_block_type::WILTON; arch_->Fs = 3; default_fc_.specified = true; diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index 1f67c127f0..810b9ab7f0 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -44,17 +44,16 @@ #include "logic_types.h" #include "physical_types.h" -#include "pugixml.hpp" -#include "pugixml_util.hpp" +#include "parse_switchblocks.h" +#include "physical_types_util.h" -#include "read_xml_arch_file_interposer.h" -#include "read_xml_arch_file_vib.h" #include "vtr_assert.h" #include "vtr_log.h" #include "vtr_util.h" #include "vtr_digest.h" #include "vtr_token.h" #include "vtr_bimap.h" +#include "vtr_expr_eval.h" #include "arch_check.h" #include "arch_error.h" @@ -63,13 +62,13 @@ #include "read_xml_arch_file.h" #include "read_xml_util.h" -#include "parse_switchblocks.h" - -#include "physical_types_util.h" -#include "vtr_expr_eval.h" +#include "pugixml.hpp" +#include "pugixml_util.hpp" #include "read_xml_arch_file_noc_tag.h" #include "read_xml_arch_file_sg.h" +#include "read_xml_arch_file_interposer.h" +#include "read_xml_arch_file_vib.h" #include "interposer_types.h" @@ -102,8 +101,8 @@ struct t_pin_locs { public: e_pin_location_distr distribution = e_pin_location_distr::SPREAD; - /* [0..num_sub_tiles-1][0..width-1][0..height-1][0..num_of_layer-1][0..3][0..num_tokens-1] */ - vtr::NdMatrix, 5> assignments; + /* [0..num_sub_tiles-1][0..width-1][0..height-1][0..3][0..num_tokens-1] */ + vtr::NdMatrix, 4> assignments; bool is_distribution_set() const { return distribution_set; @@ -585,12 +584,10 @@ static void load_pin_loc(pugi::xml_node Locations, const int num_of_avail_layer) { type->pin_width_offset.resize(type->num_pins, 0); type->pin_height_offset.resize(type->num_pins, 0); - //layer_offset is not used if the distribution is not custom - type->pin_layer_offset.resize(type->num_pins, 0); std::vector physical_pin_counts(type->num_pins, 0); if (pin_locs->distribution == e_pin_location_distr::SPREAD) { - /* evenly distribute pins starting at bottom left corner */ + // Evenly distribute pins starting at bottom left corner int num_sides = 4 * (type->width * type->height); int side_index = 0; @@ -615,7 +612,7 @@ static void load_pin_loc(pugi::xml_node Locations, VTR_ASSERT(side_index == num_sides); VTR_ASSERT(count == type->num_pins); } else if (pin_locs->distribution == e_pin_location_distr::PERIMETER) { - //Add one pin at-a-time to perimeter sides in round-robin order + // Add one pin at-a-time to perimeter sides in round-robin order int ipin = 0; while (ipin < type->num_pins) { for (int width = 0; width < type->width; ++width) { @@ -641,11 +638,11 @@ static void load_pin_loc(pugi::xml_node Locations, VTR_ASSERT(ipin == type->num_pins); } else if (pin_locs->distribution == e_pin_location_distr::SPREAD_INPUTS_PERIMETER_OUTPUTS) { - //Collect the sets of block input/output pins + // Collect the sets of block input/output pins std::vector input_pins; std::vector output_pins; for (int pin_num = 0; pin_num < type->num_pins; ++pin_num) { - auto class_type = get_pin_type_from_pin_physical_num(type, pin_num); + e_pin_type class_type = get_pin_type_from_pin_physical_num(type, pin_num); if (class_type == e_pin_type::RECEIVER) { input_pins.push_back(pin_num); @@ -655,15 +652,14 @@ static void load_pin_loc(pugi::xml_node Locations, } } - //Allocate the inputs one pin at-a-time in a round-robin order - //to all sides + // Allocate the inputs one pin at-a-time in a round-robin order to all sides size_t ipin = 0; while (ipin < input_pins.size()) { for (int width = 0; width < type->width; ++width) { for (int height = 0; height < type->height; ++height) { for (e_side side : TOTAL_2D_SIDES) { if (ipin < input_pins.size()) { - //Pins still to allocate + // Pins still to allocate int pin_num = input_pins[ipin]; @@ -679,7 +675,7 @@ static void load_pin_loc(pugi::xml_node Locations, } VTR_ASSERT(ipin == input_pins.size()); - //Allocate the outputs one pin at-a-time to perimeter sides in round-robin order + // Allocate the outputs one pin at-a-time to perimeter sides in round-robin order ipin = 0; while (ipin < output_pins.size()) { for (int width = 0; width < type->width; ++width) { @@ -716,7 +712,7 @@ static void load_pin_loc(pugi::xml_node Locations, for (int width = 0; width < type->width; ++width) { for (int height = 0; height < type->height; ++height) { for (e_side side : TOTAL_2D_SIDES) { - for (const std::string& token : pin_locs->assignments[sub_tile_index][width][height][layer][side]) { + for (const std::string& token : pin_locs->assignments[sub_tile_index][width][height][side]) { auto pin_range = process_pin_string(Locations, &sub_tile, token.c_str(), @@ -747,7 +743,6 @@ static void load_pin_loc(pugi::xml_node Locations, type->pinloc[width][height][side][physical_pin_index] = true; type->pin_width_offset[physical_pin_index] += width; type->pin_height_offset[physical_pin_index] += height; - type->pin_layer_offset[physical_pin_index] = layer; physical_pin_counts[physical_pin_index] += 1; } } @@ -767,7 +762,6 @@ static void load_pin_loc(pugi::xml_node Locations, VTR_ASSERT(type->pin_width_offset[ipin] >= 0 && type->pin_width_offset[ipin] < type->width); VTR_ASSERT(type->pin_height_offset[ipin] >= 0 && type->pin_height_offset[ipin] < type->height); - VTR_ASSERT(type->pin_layer_offset[ipin] >= 0 && type->pin_layer_offset[ipin] < num_of_avail_layer); } } @@ -2941,12 +2935,8 @@ static void process_device(pugi::xml_node Node, t_arch* arch, t_default_fc_spec& // tag Cur = get_single_child(Node, "connection_block", loc_data); - expect_only_attributes(Cur, {"input_switch_name", "input_inter_die_switch_name"}, loc_data); - arch->ipin_cblock_switch_name.emplace_back(get_attribute(Cur, "input_switch_name", loc_data).as_string()); - std::string inter_die_conn = get_attribute(Cur, "input_inter_die_switch_name", loc_data, ReqOpt::OPTIONAL).as_string(""); - if (inter_die_conn != "") { - arch->ipin_cblock_switch_name.push_back(inter_die_conn); - } + expect_only_attributes(Cur, {"input_switch_name"}, loc_data); + arch->ipin_cblock_switch_name = get_attribute(Cur, "input_switch_name", loc_data).as_string(); // tag Cur = get_single_child(Node, "switch_block", loc_data); @@ -3482,21 +3472,20 @@ static void process_pin_locations(pugi::xml_node Locations, const int sub_tile_index = SubTile->index; - /* Load the pin locations */ + // Load the pin locations if (distribution == e_pin_location_distr::CUSTOM) { expect_only_children(Locations, {"loc"}, loc_data); Cur = Locations.first_child(); - //check for duplications ([0..3][0..type->width-1][0..type->height-1][0..num_of_avail_layer-1]) - std::set> seen_sides; + // check for duplications ([0..3][0..type->width-1][0..type->height-1]) + std::set> seen_sides; while (Cur) { check_node(Cur, "loc", loc_data); - expect_only_attributes(Cur, {"side", "xoffset", "yoffset", "layer_offset"}, loc_data); + expect_only_attributes(Cur, {"side", "xoffset", "yoffset"}, loc_data); /* Get offset (height, width, layer) */ int x_offset = get_attribute(Cur, "xoffset", loc_data, ReqOpt::OPTIONAL).as_int(0); int y_offset = get_attribute(Cur, "yoffset", loc_data, ReqOpt::OPTIONAL).as_int(0); - int layer_offset = pugiutil::get_attribute(Cur, "layer_offset", loc_data, ReqOpt::OPTIONAL).as_int(0); /* Get side */ e_side side = TOP; @@ -3527,15 +3516,8 @@ static void process_pin_locations(pugi::xml_node Locations, .c_str()); } - if ((layer_offset < 0) || layer_offset >= num_of_avail_layer) { - archfpga_throw(loc_data.filename_c_str(), loc_data.line(Cur), - vtr::string_fmt("'%d' is an invalid layer offset for type '%s' (must be within [0, num_avail_layer-1]).\n", - y_offset, PhysicalTileType->name.c_str(), PhysicalTileType->height - 1) - .c_str()); - } - //Check for duplicate side specifications, since the code below silently overwrites if there are duplicates - auto side_offset = std::make_tuple(side, x_offset, y_offset, layer_offset); + std::tuple side_offset = std::make_tuple(side, x_offset, y_offset); if (seen_sides.count(side_offset)) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(Cur), vtr::string_fmt("Duplicate pin location side/offset specification." @@ -3550,7 +3532,7 @@ static void process_pin_locations(pugi::xml_node Locations, if (Count > 0) { for (int pin = 0; pin < Count; ++pin) { /* Store location assignment */ - pin_locs->assignments[sub_tile_index][x_offset][y_offset][std::abs(layer_offset)][side].emplace_back(Tokens[pin].c_str()); + pin_locs->assignments[sub_tile_index][x_offset][y_offset][side].emplace_back(Tokens[pin].c_str()); /* Advance through list of pins in this location */ } } @@ -3565,7 +3547,7 @@ static void process_pin_locations(pugi::xml_node Locations, for (int w = 0; w < PhysicalTileType->width; ++w) { for (int h = 0; h < PhysicalTileType->height; ++h) { for (e_side side : TOTAL_2D_SIDES) { - for (const std::string& token : pin_locs->assignments[sub_tile_index][w][h][l][side]) { + for (const std::string& token : pin_locs->assignments[sub_tile_index][w][h][side]) { InstPort inst_port(token); //A pin specification should contain only the block name, and not any instance count information @@ -3666,13 +3648,13 @@ static void process_sub_tiles(pugi::xml_node Node, pugi::xml_node CurSubTile; pugi::xml_node Cur; - unsigned long int num_sub_tiles = count_children(Node, "sub_tile", loc_data); - unsigned long int width = PhysicalTileType->width; - unsigned long int height = PhysicalTileType->height; - unsigned long int num_sides = 4; + size_t num_sub_tiles = count_children(Node, "sub_tile", loc_data); + size_t width = PhysicalTileType->width; + size_t height = PhysicalTileType->height; + size_t num_sides = 4; t_pin_locs pin_locs; - pin_locs.assignments.resize({num_sub_tiles, width, height, (unsigned long int)num_of_avail_layer, num_sides}); + pin_locs.assignments.resize({num_sub_tiles, width, height, num_sides}); if (num_sub_tiles == 0) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(Node), diff --git a/libs/librrgraph/src/io/rr_graph_reader.cpp b/libs/librrgraph/src/io/rr_graph_reader.cpp index ff0f8b9e4a..a765570794 100644 --- a/libs/librrgraph/src/io/rr_graph_reader.cpp +++ b/libs/librrgraph/src/io/rr_graph_reader.cpp @@ -67,7 +67,6 @@ void load_rr_file(RRGraphBuilder* rr_graph_builder, t_chan_width* chan_width, const e_base_cost_type base_cost_type, RRSwitchId* wire_to_rr_ipin_switch, - int* wire_to_rr_ipin_switch_between_dice, const char* read_rr_graph_name, std::string* loaded_rr_graph_filename, bool read_edge_metadata, @@ -87,7 +86,6 @@ void load_rr_file(RRGraphBuilder* rr_graph_builder, graph_type, base_cost_type, wire_to_rr_ipin_switch, - wire_to_rr_ipin_switch_between_dice, do_check_rr_graph, read_rr_graph_name, loaded_rr_graph_filename, diff --git a/libs/librrgraph/src/io/rr_graph_reader.h b/libs/librrgraph/src/io/rr_graph_reader.h index 1f3efbe2ae..f4aed0ac82 100644 --- a/libs/librrgraph/src/io/rr_graph_reader.h +++ b/libs/librrgraph/src/io/rr_graph_reader.h @@ -24,7 +24,6 @@ void load_rr_file(RRGraphBuilder* rr_graph_builder, t_chan_width* chan_width, const e_base_cost_type base_cost_type, RRSwitchId* wire_to_rr_ipin_switch, - int* wire_to_rr_ipin_switch_between_dice, const char* read_rr_graph_name, std::string* loaded_rr_graph_filename, bool read_edge_metadata, diff --git a/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h b/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h index 629227fdff..711551e8f0 100644 --- a/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h +++ b/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h @@ -273,9 +273,8 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { public: RrGraphSerializer( const e_graph_type graph_type, - const enum e_base_cost_type base_cost_type, + const e_base_cost_type base_cost_type, RRSwitchId* wire_to_rr_ipin_switch, - int* wire_to_rr_ipin_switch_between_dice, bool do_check_rr_graph, const char* read_rr_graph_name, std::string* loaded_rr_graph_filename, @@ -298,7 +297,6 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { vtr::string_internment* strings, bool is_flat) : wire_to_rr_ipin_switch_(wire_to_rr_ipin_switch) - , wire_to_rr_ipin_switch_between_dice_(wire_to_rr_ipin_switch_between_dice) , chan_width_(chan_width) , rr_nodes_(rr_nodes) , rr_graph_builder_(rr_graph_builder) @@ -1158,7 +1156,6 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { //switch for different layer Track to IPIN connection std::vector count_for_wire_to_ipin_switches_between_dice; count_for_wire_to_ipin_switches_between_dice.resize(rr_switch_inf_->size(), 0); - std::pair most_frequent_switch_between_dice(-1,0); // Partition the rr graph edges for efficient access to // configurable/non-configurable edge subsets. Must be done after RR @@ -1184,34 +1181,26 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { } auto node = (*rr_nodes_)[source_node]; - /*Keeps track of the number of the specific type of switch that connects a wire to an ipin - * use the pair data structure to keep the maximum*/ + // Keeps track of the number of the specific type of switch that connects a wire to an ipin + // use the pair data structure to keep the maximum if (rr_graph.node_type(node.id()) == e_rr_type::CHANX || rr_graph.node_type(node.id()) == e_rr_type::CHANY) { - if(rr_graph.node_type(RRNodeId(sink_node)) == e_rr_type::IPIN){ + if (rr_graph.node_type(RRNodeId(sink_node)) == e_rr_type::IPIN){ if (rr_graph.node_layer_low(RRNodeId(sink_node)) == rr_graph.node_layer_low(RRNodeId(source_node))) { count_for_wire_to_ipin_switches[switch_id]++; if (count_for_wire_to_ipin_switches[switch_id] > most_frequent_switch.second) { most_frequent_switch.first = switch_id; most_frequent_switch.second = count_for_wire_to_ipin_switches[switch_id]; } - } else{ - VTR_ASSERT(rr_graph.node_layer_low(RRNodeId(sink_node)) != rr_graph.node_layer_low(RRNodeId(source_node))); - count_for_wire_to_ipin_switches_between_dice[switch_id]++; - if(count_for_wire_to_ipin_switches_between_dice[switch_id] > most_frequent_switch_between_dice.second){ - most_frequent_switch_between_dice.first = switch_id; - most_frequent_switch_between_dice.second = count_for_wire_to_ipin_switches_between_dice[switch_id]; - } } } + } else if (rr_graph.node_type(node.id()) == e_rr_type::CHANZ && rr_graph.node_type(RRNodeId(sink_node)) == e_rr_type::IPIN) { + VTR_ASSERT_MSG(false, "CHANZ nodes should not connect to IPINs directly"); } } } VTR_ASSERT(wire_to_rr_ipin_switch_ != nullptr); *wire_to_rr_ipin_switch_ = (RRSwitchId)most_frequent_switch.first; - - VTR_ASSERT(wire_to_rr_ipin_switch_between_dice_ != nullptr); - *wire_to_rr_ipin_switch_between_dice_ = most_frequent_switch_between_dice.first; } inline EdgeWalker get_rr_graph_rr_edges(void*& /*ctx*/) final { @@ -2194,7 +2183,6 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { // Output for loads, and constant data for writes. RRSwitchId* wire_to_rr_ipin_switch_; - int* wire_to_rr_ipin_switch_between_dice_; t_chan_width* chan_width_; t_rr_graph_storage* rr_nodes_; RRGraphBuilder* rr_graph_builder_; @@ -2207,7 +2195,7 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { // Constant data for loads and writes. const e_graph_type graph_type_; - const enum e_base_cost_type base_cost_type_; + const e_base_cost_type base_cost_type_; const bool do_check_rr_graph_; const char* read_rr_graph_name_; const bool read_edge_metadata_; diff --git a/libs/librrgraph/src/io/rr_graph_writer.cpp b/libs/librrgraph/src/io/rr_graph_writer.cpp index 341bb67c41..0b5c51df85 100644 --- a/libs/librrgraph/src/io/rr_graph_writer.cpp +++ b/libs/librrgraph/src/io/rr_graph_writer.cpp @@ -43,7 +43,6 @@ void write_rr_graph(RRGraphBuilder* rr_graph_builder, /*graph_type=*/e_graph_type(), /*base_cost_type=*/e_base_cost_type(), /*wire_to_rr_ipin_switch=*/nullptr, - /*wire_to_rr_ipin_switch_between_dice=*/nullptr, /*do_check_rr_graph=*/false, /*read_rr_graph_name=*/nullptr, /*read_rr_graph_filename=*/nullptr, diff --git a/vpr/src/base/CheckArch.cpp b/vpr/src/base/CheckArch.cpp index e37ec0a21f..a880af0d1c 100644 --- a/vpr/src/base/CheckArch.cpp +++ b/vpr/src/base/CheckArch.cpp @@ -17,9 +17,8 @@ void CheckArch(const t_arch& Arch) { static void CheckSwitches(const t_arch& Arch) { int ipin_cblock_switch_index = UNDEFINED; - int ipin_cblock_switch_index_between_dice = UNDEFINED; - /* Check transistors in switches won't be less than minimum size */ + // Check transistors in switches won't be less than minimum size for (int i = 0; i < (int)Arch.switches.size(); i++) { const t_arch_switch_inf& CurSwitch = Arch.switches[i]; /* This assumes all segments have the same directionality */ @@ -43,15 +42,11 @@ static void CheckSwitches(const t_arch& Arch) { CurSwitch.name.c_str(), CurSwitch.R, Arch.R_minW_nmos, get_arch_file_name()); } } - for (auto cb_switch_name = 0; cb_switch_name < (int)Arch.ipin_cblock_switch_name.size(); cb_switch_name++) { - /* find the ipin cblock switch index, if it exists */ - if (Arch.switches[i].name == Arch.ipin_cblock_switch_name[cb_switch_name]) { - if (cb_switch_name == 0) { - ipin_cblock_switch_index = i; - } else { - ipin_cblock_switch_index_between_dice = i; - } - } + + + // find the ipin cblock switch index, if it exists + if (Arch.switches[i].name == Arch.ipin_cblock_switch_name) { + ipin_cblock_switch_index = i; } } @@ -67,12 +62,6 @@ static void CheckSwitches(const t_arch& Arch) { "Not currently allowing an ipin cblock switch to have fanin dependent values"); } } - if (ipin_cblock_switch_index_between_dice != UNDEFINED) { - if (!Arch.switches[ipin_cblock_switch_index_between_dice].fixed_Tdel()) { - VPR_FATAL_ERROR(VPR_ERROR_ARCH, - "Not currently allowing an ipin cblock switch to have fanin dependent values"); - } - } } static void CheckSegments(const t_arch& Arch) { diff --git a/vpr/src/base/setup_vpr.cpp b/vpr/src/base/setup_vpr.cpp index 8bdbed39dc..0bbe1ab6b6 100644 --- a/vpr/src/base/setup_vpr.cpp +++ b/vpr/src/base/setup_vpr.cpp @@ -44,19 +44,18 @@ static void setup_server_opts(const t_options& Options, static void setup_routing_arch(const t_arch& Arch, t_det_routing_arch& RoutingArch); static void setup_timing(const t_options& Options, const bool TimingEnabled, t_timing_inf* Timing); -static void setup_switches(const t_arch& Arch, - t_det_routing_arch& RoutingArch, +static void setup_switches(const t_arch& arch, + t_det_routing_arch& routing_arch, const std::vector& arch_switches); static void setup_analysis_opts(const t_options& Options, t_analysis_opts& analysis_opts); static void setup_power_opts(const t_options& Options, t_power_opts* power_opts, t_arch* Arch); /** * @brief Identify which switch must be used for *track* to *IPIN* connections based on architecture file specification. - * @param Arch Architecture file specification - * @param wire_to_arch_ipin_switch Switch id that must be used when *track* and *IPIN* are located at the same die - * @param wire_to_arch_ipin_switch_between_dice Switch id that must be used when *track* and *IPIN* are located at different dice. + * @param arch Architecture file specification + * @return Switch id that must be used to connect *track* and *IPIN* nodes. */ -static void find_ipin_cblock_switch_index(const t_arch& Arch, int& wire_to_arch_ipin_switch, int& wire_to_arch_ipin_switch_between_dice); +static int find_ipin_cblock_switch_index(const t_arch& arch); // Fill the data structures used when flat_routing is enabled to speed-up routing static void alloc_and_load_intra_cluster_resources(bool reachability_analysis); @@ -363,20 +362,20 @@ static void setup_timing(const t_options& Options, const bool TimingEnabled, t_t * @brief This loads up VPR's arch_switch_inf data by combining the switches * from the arch file with the special switches that VPR needs. */ -static void setup_switches(const t_arch& Arch, - t_det_routing_arch& RoutingArch, +static void setup_switches(const t_arch& arch, + t_det_routing_arch& routing_arch, const std::vector& arch_switches) { DeviceContext& device_ctx = g_vpr_ctx.mutable_device(); int switches_to_copy = (int)arch_switches.size(); int num_arch_switches = (int)arch_switches.size(); - find_ipin_cblock_switch_index(Arch, RoutingArch.wire_to_arch_ipin_switch, RoutingArch.wire_to_arch_ipin_switch_between_dice); + routing_arch.wire_to_arch_ipin_switch = find_ipin_cblock_switch_index(arch); - /* Depends on device_ctx.num_arch_switches */ - RoutingArch.delayless_switch = num_arch_switches++; + // Depends on device_ctx.num_arch_switches + routing_arch.delayless_switch = num_arch_switches++; - /* Alloc the list now that we know the final num_arch_switches value */ + // Alloc the list now that we know the final num_arch_switches value device_ctx.arch_switch_inf.resize(num_arch_switches); for (int iswitch = 0; iswitch < switches_to_copy; iswitch++) { device_ctx.arch_switch_inf[iswitch] = arch_switches[iswitch]; @@ -385,33 +384,33 @@ static void setup_switches(const t_arch& Arch, device_ctx.all_sw_inf[iswitch] = arch_switches[iswitch]; } - /* Delayless switch for connecting sinks and sources with their pins. */ - device_ctx.arch_switch_inf[RoutingArch.delayless_switch].set_type(e_switch_type::MUX); - device_ctx.arch_switch_inf[RoutingArch.delayless_switch].name = std::string(VPR_DELAYLESS_SWITCH_NAME); - device_ctx.arch_switch_inf[RoutingArch.delayless_switch].R = 0.; - device_ctx.arch_switch_inf[RoutingArch.delayless_switch].Cin = 0.; - device_ctx.arch_switch_inf[RoutingArch.delayless_switch].Cout = 0.; - device_ctx.arch_switch_inf[RoutingArch.delayless_switch].set_Tdel(t_arch_switch_inf::UNDEFINED_FANIN, 0.); - device_ctx.arch_switch_inf[RoutingArch.delayless_switch].power_buffer_type = POWER_BUFFER_TYPE_NONE; - device_ctx.arch_switch_inf[RoutingArch.delayless_switch].mux_trans_size = 0.; - device_ctx.arch_switch_inf[RoutingArch.delayless_switch].buf_size_type = e_buffer_size::ABSOLUTE; - device_ctx.arch_switch_inf[RoutingArch.delayless_switch].buf_size = 0.; - VTR_ASSERT_MSG(device_ctx.arch_switch_inf[RoutingArch.delayless_switch].buffered(), "Delayless switch expected to be buffered (isolating)"); - VTR_ASSERT_MSG(device_ctx.arch_switch_inf[RoutingArch.delayless_switch].configurable(), "Delayless switch expected to be configurable"); + // Delayless switch for connecting sinks and sources with their pins. + device_ctx.arch_switch_inf[routing_arch.delayless_switch].set_type(e_switch_type::MUX); + device_ctx.arch_switch_inf[routing_arch.delayless_switch].name = std::string(VPR_DELAYLESS_SWITCH_NAME); + device_ctx.arch_switch_inf[routing_arch.delayless_switch].R = 0.; + device_ctx.arch_switch_inf[routing_arch.delayless_switch].Cin = 0.; + device_ctx.arch_switch_inf[routing_arch.delayless_switch].Cout = 0.; + device_ctx.arch_switch_inf[routing_arch.delayless_switch].set_Tdel(t_arch_switch_inf::UNDEFINED_FANIN, 0.); + device_ctx.arch_switch_inf[routing_arch.delayless_switch].power_buffer_type = POWER_BUFFER_TYPE_NONE; + device_ctx.arch_switch_inf[routing_arch.delayless_switch].mux_trans_size = 0.; + device_ctx.arch_switch_inf[routing_arch.delayless_switch].buf_size_type = e_buffer_size::ABSOLUTE; + device_ctx.arch_switch_inf[routing_arch.delayless_switch].buf_size = 0.; + VTR_ASSERT_MSG(device_ctx.arch_switch_inf[routing_arch.delayless_switch].buffered(), "Delayless switch expected to be buffered (isolating)"); + VTR_ASSERT_MSG(device_ctx.arch_switch_inf[routing_arch.delayless_switch].configurable(), "Delayless switch expected to be configurable"); - device_ctx.all_sw_inf[RoutingArch.delayless_switch] = device_ctx.arch_switch_inf[RoutingArch.delayless_switch]; + device_ctx.all_sw_inf[routing_arch.delayless_switch] = device_ctx.arch_switch_inf[routing_arch.delayless_switch]; - RoutingArch.global_route_switch = RoutingArch.delayless_switch; + routing_arch.global_route_switch = routing_arch.delayless_switch; - device_ctx.delayless_switch_idx = RoutingArch.delayless_switch; + device_ctx.delayless_switch_idx = routing_arch.delayless_switch; - //Warn about non-zero Cout values for the ipin switch, since these values have no effect. - //VPR do not model the R/C's of block internal routing connection. + // Warn about non-zero Cout values for the ipin switch, since these values have no effect. + // VPR do not model the R/C's of block internal routing connection. // - //Note that we don't warn about the R value as it may be used to size the buffer (if buf_size_type is AUTO) - if (device_ctx.arch_switch_inf[RoutingArch.wire_to_arch_ipin_switch].Cout != 0.) { + // Note that we don't warn about the R value as it may be used to size the buffer (if buf_size_type is AUTO) + if (device_ctx.arch_switch_inf[routing_arch.wire_to_arch_ipin_switch].Cout != 0.) { VTR_LOG_WARN("Non-zero switch output capacitance (%g) has no effect when switch '%s' is used for connection block inputs\n", - device_ctx.arch_switch_inf[RoutingArch.wire_to_arch_ipin_switch].Cout, Arch.ipin_cblock_switch_name[0].c_str()); + device_ctx.arch_switch_inf[routing_arch.wire_to_arch_ipin_switch].Cout, arch.ipin_cblock_switch_name.c_str()); } } @@ -809,30 +808,24 @@ static void setup_server_opts(const t_options& Options, t_server_opts* ServerOpt ServerOpts->port_num = Options.server_port_num; } -static void find_ipin_cblock_switch_index(const t_arch& Arch, int& wire_to_arch_ipin_switch, int& wire_to_arch_ipin_switch_between_dice) { - for (int cb_switch_name_index = 0; cb_switch_name_index < (int)Arch.ipin_cblock_switch_name.size(); cb_switch_name_index++) { - int ipin_cblock_switch_index = UNDEFINED; - for (int iswitch = 0; iswitch < (int)Arch.switches.size(); ++iswitch) { - if (Arch.switches[iswitch].name == Arch.ipin_cblock_switch_name[cb_switch_name_index]) { - if (ipin_cblock_switch_index != UNDEFINED) { - VPR_FATAL_ERROR(VPR_ERROR_ARCH, "Found duplicate switches named '%s'\n", - Arch.ipin_cblock_switch_name[cb_switch_name_index].c_str()); - } else { - ipin_cblock_switch_index = iswitch; - } +static int find_ipin_cblock_switch_index(const t_arch& arch) { + int ipin_cblock_switch_index = UNDEFINED; + for (size_t iswitch = 0; iswitch < arch.switches.size(); ++iswitch) { + if (arch.switches[iswitch].name == arch.ipin_cblock_switch_name) { + if (ipin_cblock_switch_index != UNDEFINED) { + VPR_FATAL_ERROR(VPR_ERROR_ARCH, "Found duplicate switches named '%s'\n", + arch.ipin_cblock_switch_name.c_str()); } + ipin_cblock_switch_index = iswitch; } - if (ipin_cblock_switch_index == UNDEFINED) { - VPR_FATAL_ERROR(VPR_ERROR_ARCH, "Failed to find connection block input pin switch named '%s'\n", Arch.ipin_cblock_switch_name[0].c_str()); - } + } - //first index in Arch.ipin_cblock_switch_name is related to same die connections - if (cb_switch_name_index == 0) { - wire_to_arch_ipin_switch = ipin_cblock_switch_index; - } else { - wire_to_arch_ipin_switch_between_dice = ipin_cblock_switch_index; - } + if (ipin_cblock_switch_index == UNDEFINED) { + VPR_FATAL_ERROR(VPR_ERROR_ARCH, "Failed to find connection block input pin switch named '%s'\n", + arch.ipin_cblock_switch_name.c_str()); } + + return ipin_cblock_switch_index; } static void alloc_and_load_intra_cluster_resources(bool reachability_analysis) { diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index 4bd8b1557d..aef23111d0 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -1489,18 +1489,10 @@ struct t_det_routing_arch { /// Keeps track of the type of architecture switch that connects wires to ipins int wire_to_arch_ipin_switch; - /// Keeps track of the type of architecture switch that connects - /// wires from another die to ipins in different die - int wire_to_arch_ipin_switch_between_dice = -1; - /// keeps track of the type of RR graph switch /// that connects wires to ipins in the RR graph RRSwitchId wire_to_rr_ipin_switch; - /// keeps track of the type of RR graph switch that connects wires - /// from another die to ipins in different die in the RR graph - int wire_to_rr_ipin_switch_between_dice = -1; - /// Resistance (in Ohms) of a minimum width nmos transistor. /// Used only in the FPGA area model. float R_minW_nmos; diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index 9339d35ec4..edce3072aa 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -122,8 +122,6 @@ static void advance_to_next_block_side(t_physical_tile_type_ptr tile_type, int& static vtr::NdMatrix, 4> alloc_and_load_track_to_pin_lookup(vtr::NdMatrix, 4> pin_to_track_map, const vtr::Matrix& Fc, - const t_physical_tile_type_ptr tile_type, - const std::set& type_layer, const int width, const int height, const int num_pins, @@ -200,7 +198,6 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder const std::vector>& Fc_out, const t_chan_width& chan_width, const int wire_to_ipin_switch, - const int wire_to_pin_between_dice_switch, const int delayless_switch, const e_directionality directionality, bool* Fc_clipped, @@ -323,7 +320,6 @@ static void build_rr_chan(RRGraphBuilder& rr_graph_builder, const t_chan_details& chan_details_y, t_rr_edge_info_set& rr_edges_to_create, const int wire_to_ipin_switch, - const int wire_to_pin_between_dice_switch, const e_directionality directionality); void alloc_and_load_edges(RRGraphBuilder& rr_graph_builder, @@ -347,7 +343,6 @@ static void build_rr_graph(e_graph_type graph_type, const std::vector& segment_inf, const int global_route_switch, const int wire_to_arch_ipin_switch, - const int wire_to_pin_between_dice_switch, const int delayless_switch, const float R_minW_nmos, const float R_minW_pmos, @@ -421,7 +416,6 @@ void create_rr_graph(e_graph_type graph_type, &mutable_device_ctx.chan_width, router_opts.base_cost_type, &det_routing_arch.wire_to_rr_ipin_switch, - &det_routing_arch.wire_to_arch_ipin_switch_between_dice, det_routing_arch.read_rr_graph_filename.c_str(), &mutable_device_ctx.loaded_rr_graph_filename, router_opts.read_rr_edge_metadata, @@ -448,7 +442,6 @@ void create_rr_graph(e_graph_type graph_type, segment_inf, det_routing_arch.global_route_switch, det_routing_arch.wire_to_arch_ipin_switch, - det_routing_arch.wire_to_arch_ipin_switch_between_dice, det_routing_arch.delayless_switch, det_routing_arch.R_minW_nmos, det_routing_arch.R_minW_pmos, @@ -626,7 +619,6 @@ static void build_rr_graph(e_graph_type graph_type, const std::vector& segment_inf, const int global_route_switch, const int wire_to_arch_ipin_switch, - const int wire_to_pin_between_dice_switch, const int delayless_switch, const float R_minW_nmos, const float R_minW_pmos, @@ -931,15 +923,13 @@ static void build_rr_graph(e_graph_type graph_type, segment_inf_y, sets_per_seg_type_y); track_to_pin_lookup_x[itype] = alloc_and_load_track_to_pin_lookup(ipin_to_track_map_x[itype], Fc_in[itype], - &types[itype], - type_layer, types[itype].width, + types[itype].width, types[itype].height, types[itype].num_pins, nodes_per_chan.x_max, segment_inf_x); track_to_pin_lookup_y[itype] = alloc_and_load_track_to_pin_lookup(ipin_to_track_map_y[itype], Fc_in[itype], - &types[itype], - type_layer, types[itype].width, + types[itype].width, types[itype].height, types[itype].num_pins, nodes_per_chan.y_max, segment_inf_y); @@ -999,7 +989,6 @@ static void build_rr_graph(e_graph_type graph_type, Fc_out, nodes_per_chan, wire_to_arch_ipin_switch, - wire_to_pin_between_dice_switch, delayless_switch, directionality, &Fc_clipped, @@ -1407,7 +1396,6 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder const std::vector>& Fc_out, const t_chan_width& chan_width, const int wire_to_ipin_switch, - const int wire_to_pin_between_dice_switch, const int delayless_switch, const e_directionality directionality, bool* Fc_clipped, @@ -1555,7 +1543,6 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder sblock_pattern, Fs / 3, chan_details_x, chan_details_y, rr_edges_to_create, wire_to_ipin_switch, - wire_to_pin_between_dice_switch, directionality); // Create the actual CHAN->CHAN edges @@ -1574,7 +1561,6 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder sblock_pattern, Fs / 3, chan_details_x, chan_details_y, rr_edges_to_create, wire_to_ipin_switch, - wire_to_pin_between_dice_switch, directionality); //Create the actual CHAN->CHAN edges @@ -1813,7 +1799,6 @@ static void build_rr_chan(RRGraphBuilder& rr_graph_builder, const t_chan_details& chan_details_y, t_rr_edge_info_set& rr_edges_to_create, const int wire_to_ipin_switch, - const int wire_to_pin_between_dice_switch, const e_directionality directionality) { // this function builds both x and y-directed channel segments, so set up our coordinates based on channel type @@ -2029,21 +2014,19 @@ static vtr::NdMatrix, 4> alloc_and_load_pin_to_track_map(const // connections in pin_to_seg_type_map are within that seg type -- i.e. in the [0,num_seg_type_tracks-1] range. // now load up 'result' array with these connections, but offset them so they are relative to the channel as a whole - for (int type_layer_index : type_layer) { - for (int ipin = 0; ipin < tile_type->num_pins; ipin++) { - int cur_Fc = Fc[ipin][seg_inf[iseg].seg_index]; - for (int iwidth = 0; iwidth < tile_type->width; iwidth++) { - for (int iheight = 0; iheight < tile_type->height; iheight++) { - for (int iside = 0; iside < 4; iside++) { - for (int iconn = 0; iconn < cur_Fc; iconn++) { - int relative_track_ind = pin_to_seg_type_map[ipin][iwidth][iheight][iside][iconn]; - if (relative_track_ind != UNDEFINED) { - VTR_ASSERT(relative_track_ind <= num_seg_type_tracks); - int absolute_track_ind = relative_track_ind + seg_type_start_track; - - VTR_ASSERT(absolute_track_ind >= 0); - result[ipin][iwidth][iheight][iside].push_back(absolute_track_ind); - } + for (int ipin = 0; ipin < tile_type->num_pins; ipin++) { + int cur_Fc = Fc[ipin][seg_inf[iseg].seg_index]; + for (int iwidth = 0; iwidth < tile_type->width; iwidth++) { + for (int iheight = 0; iheight < tile_type->height; iheight++) { + for (int iside = 0; iside < 4; iside++) { + for (int iconn = 0; iconn < cur_Fc; iconn++) { + int relative_track_ind = pin_to_seg_type_map[ipin][iwidth][iheight][iside][iconn]; + if (relative_track_ind != UNDEFINED) { + VTR_ASSERT(relative_track_ind <= num_seg_type_tracks); + int absolute_track_ind = relative_track_ind + seg_type_start_track; + + VTR_ASSERT(absolute_track_ind >= 0); + result[ipin][iwidth][iheight][iside].push_back(absolute_track_ind); } } } @@ -2470,9 +2453,9 @@ static void load_uniform_connection_block_pattern(vtr::NdMatrix& tracks_ VTR_ASSERT(pin_fc % group_size == 0); - /* Bi-directional treats each track separately, uni-directional works with pairs of tracks */ + // Bi-directional treats each track separately, uni-directional works with pairs of tracks for (int j = 0; j < (pin_fc / group_size); ++j) { - int max_chan_width = (((side == TOP) || (side == BOTTOM)) ? x_chan_width : y_chan_width); + int max_chan_width = (side == TOP || side == BOTTOM) ? x_chan_width : y_chan_width; // if the number of tracks we can assign is zero break from the loop if (max_chan_width == 0) { @@ -2673,8 +2656,6 @@ static void check_all_tracks_reach_pins(t_logical_block_type_ptr type, static vtr::NdMatrix, 4> alloc_and_load_track_to_pin_lookup(vtr::NdMatrix, 4> pin_to_track_map, const vtr::Matrix& Fc, - const t_physical_tile_type_ptr tile_type, - const std::set& type_layer, const int type_width, const int type_height, const int num_pins, @@ -2697,30 +2678,27 @@ static vtr::NdMatrix, 4> alloc_and_load_track_to_pin_lookup(vtr } const int num_seg_types = seg_inf.size(); - auto& grid = g_vpr_ctx.device().grid; - /* Alloc and zero the the lookup table */ + // Alloc and zero the lookup table auto track_to_pin_lookup = vtr::NdMatrix, 4>({size_t(max_chan_width), size_t(type_width), size_t(type_height), 4}); - /* Count number of pins to which each track connects */ - for (int type_layer_index : type_layer) { - for (int pin = 0; pin < num_pins; ++pin) { - for (int width = 0; width < type_width; ++width) { - for (int height = 0; height < type_height; ++height) { - for (int side = 0; side < 4; ++side) { - /* get number of tracks to which this pin connects */ - int num_tracks = 0; - for (int iseg = 0; iseg < num_seg_types; iseg++) { - num_tracks += Fc[pin][seg_inf[iseg].seg_index]; // Fc_in and Fc_out matrices are unified for all segments so need to map index. - } - if (!pin_to_track_map[pin][width][height][side].empty()) { - num_tracks = std::min(num_tracks, - (int)pin_to_track_map[pin][width][height][side].size()); - for (int conn = 0; conn < num_tracks; ++conn) { - int track = pin_to_track_map[pin][width][height][side][conn]; - VTR_ASSERT(track < max_chan_width); - VTR_ASSERT(track >= 0); - track_to_pin_lookup[track][width][height][side].push_back(pin); - } + // Count number of pins to which each track connects + for (int pin = 0; pin < num_pins; ++pin) { + for (int width = 0; width < type_width; ++width) { + for (int height = 0; height < type_height; ++height) { + for (int side = 0; side < 4; ++side) { + // get number of tracks to which this pin connects + int num_tracks = 0; + for (int iseg = 0; iseg < num_seg_types; iseg++) { + num_tracks += Fc[pin][seg_inf[iseg].seg_index]; // Fc_in and Fc_out matrices are unified for all segments so need to map index. + } + if (!pin_to_track_map[pin][width][height][side].empty()) { + num_tracks = std::min(num_tracks, + (int)pin_to_track_map[pin][width][height][side].size()); + for (int conn = 0; conn < num_tracks; ++conn) { + int track = pin_to_track_map[pin][width][height][side][conn]; + VTR_ASSERT(track < max_chan_width); + VTR_ASSERT(track >= 0); + track_to_pin_lookup[track][width][height][side].push_back(pin); } } } From 2c37b80c15c8860e82bcd591df045fdea648d63a Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Tue, 28 Oct 2025 15:53:27 -0400 Subject: [PATCH 06/32] remove layer_offset from rr_graph.cpp --- .../route/rr_graph_generation/rr_graph.cpp | 169 +++++++----------- 1 file changed, 64 insertions(+), 105 deletions(-) diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index edce3072aa..54c946ec45 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -53,7 +53,6 @@ struct t_pin_loc { int pin_index; int width_offset; int height_offset; - int layer_offset; e_side side; }; @@ -62,18 +61,14 @@ struct t_pin_loc { /********************* Subroutines local to this module. *******************/ void print_rr_graph_stats(); -///@brief given a specific type, it returns layers that the type are located at -std::set get_layers_of_physical_types(const t_physical_tile_type_ptr type); - /** * @brief This routine calculates pin connections to tracks for either all input or all output pins based on the Fc value defined in the architecture file. * For the requested pin type (input or output), it will loop through all segments and calculate how many connections should be made, * returns the connections to be made for that type of pin in a matrix. * * @param pin_type Specifies whether the routine should connect tracks to *INPUT* pins or connect *OUTPUT* pins to tracks. - * @param Fc Actual Fc value described in the architecture file for all pins of the specific phyiscal type ([0..number_of_pins-1][0..number_of_segments_types-1]). - * @param tile_type Physical type information, such as total number of pins, block width, block height, and etc. - * @param type_layer Layer indicies on which the physical tile type is located. + * @param Fc Actual Fc value described in the architecture file for all pins of the specific physical type ([0..number_of_pins-1][0..number_of_segments_types-1]). + * @param tile_type Physical type information, such as total number of pins, block width, block height, and etc. * @param perturb_switch_pattern Specifies whether connections should be distributed unevenly across the channel or not. * @param directionality Segment directionality: should be either *UNI-DIRECTIONAL* or *BI-DIRECTIONAL* * @param seg_inf Segments type information, such as length, frequency, and etc. @@ -85,7 +80,6 @@ std::set get_layers_of_physical_types(const t_physical_tile_type_ptr type); static vtr::NdMatrix, 4> alloc_and_load_pin_to_track_map(const e_pin_type pin_type, const vtr::Matrix& Fc, const t_physical_tile_type_ptr tile_type, - const std::set& type_layer, const std::vector& perturb_switch_pattern, const e_directionality directionality, const std::vector& seg_inf, @@ -100,8 +94,7 @@ static vtr::NdMatrix, 4> alloc_and_load_pin_to_track_map(const * @param seg_type_tracks Number of tracks that is avaliable for the specific segment type. * @param seg_index The index of the segment type to which the function tries to connect pins. * @param max_Fc Used to allocate max possible space for simplicity. - * @param tile_type Physical type information, such as total number of pins, block width, block height, and etc. - * @param type_layer Layer indicies on which the physical type located. + * @param tile_type Physical type information, such as total number of pins, block width, block height, and etc. * @param perturb_switch_pattern Specifies whether connections should be distributed unevenly across the channel or not. * @param directionality Segment directionality, should be either *UNI-DIRECTIONAL* or *BI-DIRECTIONAL* * @@ -114,7 +107,6 @@ static vtr::NdMatrix alloc_and_load_pin_to_seg_type(const e_pin_type pin const int seg_index, const int max_Fc, const t_physical_tile_type_ptr tile_type, - const std::set& type_layer, const bool perturb_switch_pattern, const e_directionality directionality); @@ -598,17 +590,6 @@ void print_rr_graph_stats() { VTR_LOG(" RR Graph Edges: %zu\n", num_rr_edges); } -std::set get_layers_of_physical_types(const t_physical_tile_type_ptr type) { - const DeviceContext& device_ctx = g_vpr_ctx.device(); - std::set phy_type_layers; - for (int layer = 0; layer < (int)device_ctx.grid.get_num_layers(); layer++) { - if (device_ctx.grid.num_instances(type, layer) != 0) { - phy_type_layers.insert(layer); - } - } - return phy_type_layers; -} - static void build_rr_graph(e_graph_type graph_type, const std::vector& types, const DeviceGrid& grid, @@ -910,15 +891,13 @@ static void build_rr_graph(e_graph_type graph_type, t_track_to_pin_lookup track_to_pin_lookup_y(types.size()); for (size_t itype = 0; itype < types.size(); ++itype) { - std::set type_layer = get_layers_of_physical_types(&types[itype]); - ipin_to_track_map_x[itype] = alloc_and_load_pin_to_track_map(e_pin_type::RECEIVER, - Fc_in[itype], &types[itype], type_layer, + Fc_in[itype], &types[itype], perturb_ipins[itype], directionality, segment_inf_x, sets_per_seg_type_x); ipin_to_track_map_y[itype] = alloc_and_load_pin_to_track_map(e_pin_type::RECEIVER, - Fc_in[itype], &types[itype], type_layer, + Fc_in[itype], &types[itype], perturb_ipins[itype], directionality, segment_inf_y, sets_per_seg_type_y); @@ -950,11 +929,10 @@ static void build_rr_graph(e_graph_type graph_type, t_pin_to_track_lookup opin_to_track_map(types.size()); // [0..device_ctx.physical_tile_types.size()-1][0..num_pins-1][0..width][0..height][0..3][0..Fc-1] if (BI_DIRECTIONAL == directionality) { for (size_t itype = 0; itype < types.size(); ++itype) { - std::set type_layer = get_layers_of_physical_types(&types[itype]); std::vector perturb_opins = alloc_and_load_perturb_opins(&types[itype], Fc_out[itype], max_chan_width, segment_inf); opin_to_track_map[itype] = alloc_and_load_pin_to_track_map(e_pin_type::DRIVER, - Fc_out[itype], &types[itype], type_layer, perturb_opins, directionality, + Fc_out[itype], &types[itype], perturb_opins, directionality, segment_inf, sets_per_seg_type); } } @@ -1974,7 +1952,6 @@ void alloc_and_load_edges(RRGraphBuilder& rr_graph_builder, const t_rr_edge_info static vtr::NdMatrix, 4> alloc_and_load_pin_to_track_map(const e_pin_type pin_type, const vtr::Matrix& Fc, const t_physical_tile_type_ptr tile_type, - const std::set& type_layer, const std::vector& perturb_switch_pattern, const e_directionality directionality, const std::vector& seg_inf, @@ -2010,7 +1987,7 @@ static vtr::NdMatrix, 4> alloc_and_load_pin_to_track_map(const } // get pin connections to tracks of the current segment type - auto pin_to_seg_type_map = alloc_and_load_pin_to_seg_type(pin_type, Fc, num_seg_type_tracks, seg_inf[iseg].seg_index, max_Fc, tile_type, type_layer, perturb_switch_pattern[seg_inf[iseg].seg_index], directionality); + auto pin_to_seg_type_map = alloc_and_load_pin_to_seg_type(pin_type, Fc, num_seg_type_tracks, seg_inf[iseg].seg_index, max_Fc, tile_type, perturb_switch_pattern[seg_inf[iseg].seg_index], directionality); // connections in pin_to_seg_type_map are within that seg type -- i.e. in the [0,num_seg_type_tracks-1] range. // now load up 'result' array with these connections, but offset them so they are relative to the channel as a whole @@ -2047,7 +2024,6 @@ static vtr::NdMatrix alloc_and_load_pin_to_seg_type(const e_pin_type pin const int seg_index, const int max_Fc, const t_physical_tile_type_ptr tile_type, - const std::set& type_layer, const bool perturb_switch_pattern, const e_directionality directionality) { // Note: currently a single value of Fc is used across each pin. In the future the looping below will @@ -2059,8 +2035,6 @@ static vtr::NdMatrix alloc_and_load_pin_to_seg_type(const e_pin_type pin // If pin ipin on side iside does not exist or is of the wrong type, // tracks_connected_to_pin[ipin][iside][0] = UNDEFINED. - auto& grid = g_vpr_ctx.device().grid; - if (tile_type->num_pins < 1) { return vtr::NdMatrix(); } @@ -2078,73 +2052,65 @@ static vtr::NdMatrix alloc_and_load_pin_to_seg_type(const e_pin_type pin // Note that his may be more than the logical number of pins (i.e. // Type->num_pins) if a logical pin has multiple specified physical // pinlocations (i.e. appears on multiple sides of the block) - auto num_dir = vtr::NdMatrix({ + auto num_dir = vtr::NdMatrix({ size_t(tile_type->width), // [0..width-1] size_t(tile_type->height), // [0..height-1] - size_t(grid.get_num_layers()), // [0..layer-1] NUM_2D_SIDES // [0..NUM_2D_SIDES-1] }, 0); // List of *physical* pins of the correct type on each side of the current - // block type. For a specific width/height/side the valid enteries in the + // block type. For a specific width/height/side the valid entries in the // last dimension are [0 .. num_dir[width][height][side]-1] // - //Max possible space alloced for simplicity - auto dir_list = vtr::NdMatrix({ - size_t(tile_type->width), // [0..width-1] - size_t(tile_type->height), // [0..height-1] - size_t(grid.get_num_layers()), // [0..layer-1] - NUM_2D_SIDES, // [0..NUM_2D_SIDES-1] - size_t(tile_type->num_pins) * size_t(grid.get_num_layers()) // [0..num_pins * num_layers-1] + // Max possible space allocated for simplicity + auto dir_list = vtr::NdMatrix({ + size_t(tile_type->width), // [0..width-1] + size_t(tile_type->height), // [0..height-1] + NUM_2D_SIDES, // [0..NUM_2D_SIDES-1] + size_t(tile_type->num_pins) // [0..num_pins * num_layers-1] }, -1); // Defensive coding: Initialize to invalid // Number of currently assigned physical pins - auto num_done_per_dir = vtr::NdMatrix({ + auto num_done_per_dir = vtr::NdMatrix({ size_t(tile_type->width), // [0..width-1] size_t(tile_type->height), // [0..height-1] - size_t(grid.get_num_layers()), // [0..layer-1] NUM_2D_SIDES // [0..NUM_2D_SIDES-1] }, 0); // Record the physical pin locations and counts per side/offsets combination for (int pin = 0; pin < tile_type->num_pins; ++pin) { - auto curr_pin_type = get_pin_type_from_pin_physical_num(tile_type, pin); - if (curr_pin_type != pin_type) /* Doing either ipins OR opins */ + e_pin_type curr_pin_type = get_pin_type_from_pin_physical_num(tile_type, pin); + if (curr_pin_type != pin_type) // Doing either ipins OR opins continue; - /* Pins connecting only to global resources get no switches -> keeps area model accurate. */ + // Pins connecting only to global resources get no switches -> keeps area model accurate. if (tile_type->is_ignored_pin[pin]) continue; - for (int type_layer_index : type_layer) { - for (int width = 0; width < tile_type->width; ++width) { - for (int height = 0; height < tile_type->height; ++height) { - for (e_side side : TOTAL_2D_SIDES) { - if (tile_type->pinloc[width][height][side][pin] == 1) { - dir_list[width][height][type_layer_index][side][num_dir[width][height][type_layer_index][side]] = pin; - num_dir[width][height][type_layer_index][side]++; - } + + for (int width = 0; width < tile_type->width; ++width) { + for (int height = 0; height < tile_type->height; ++height) { + for (e_side side : TOTAL_2D_SIDES) { + if (tile_type->pinloc[width][height][side][pin] == 1) { + dir_list[width][height][side][num_dir[width][height][side]] = pin; + num_dir[width][height][side]++; } } } } } - // Total the number of physical pins - std::vector num_phys_pins_per_layer; - for (int layer = 0; layer < (int)grid.get_num_layers(); layer++) { - int num_phys_pins = 0; - for (int width = 0; width < tile_type->width; ++width) { - for (int height = 0; height < tile_type->height; ++height) { - for (e_side side : TOTAL_2D_SIDES) { - num_phys_pins += num_dir[width][height][layer][side]; /* Num. physical pins per type */ - } + // Total the number of physical pin + int num_phys_pins = 0; + for (int width = 0; width < tile_type->width; ++width) { + for (int height = 0; height < tile_type->height; ++height) { + for (e_side side : TOTAL_2D_SIDES) { + num_phys_pins += num_dir[width][height][side]; // Num. physical pins per type } } - num_phys_pins_per_layer.push_back(num_phys_pins); } std::vector pin_ordering; @@ -2154,54 +2120,48 @@ static vtr::NdMatrix alloc_and_load_pin_to_seg_type(const e_pin_type pin // (potentially in other C blocks) connect to the remaining tracks first. Doesn't matter for large Fc, // but should make a fairly good low Fc block that leverages the fact that usually lots of pins are logically equivalent. - for (int layer_index = 0; layer_index < (int)grid.get_num_layers(); layer_index++) { - const e_side init_side = LEFT; - const int init_width = 0; - const int init_height = 0; - - e_side side = init_side; - int width = init_width; - int height = init_height; - int pin = 0; - int pin_index = -1; - - // Determine the order in which physical pins will be considered while building - // the connection block. This generally tries to order the pins so they are 'spread' - // out (in hopes of yielding good connection diversity) - while (pin < num_phys_pins_per_layer[layer_index]) { - if (height == init_height && width == init_width && side == init_side) { - // Completed one loop through all the possible offsets/side combinations - pin_index++; - } + e_side side = LEFT; + int width = 0; + int height = 0; + int pin = 0; + int pin_index = -1; - advance_to_next_block_side(tile_type, width, height, side); + // Determine the order in which physical pins will be considered while building + // the connection block. This generally tries to order the pins so they are 'spread' + // out (in hopes of yielding good connection diversity) + while (pin < num_phys_pins) { + if (height == 0 && width == 0 && side == LEFT) { + // Completed one loop through all the possible offsets/side combinations + pin_index++; + } - VTR_ASSERT_MSG(pin_index < num_phys_pins_per_layer[layer_index], "Physical block pins bound number of logical block pins"); + advance_to_next_block_side(tile_type, width, height, side); - if (num_done_per_dir[width][height][layer_index][side] >= num_dir[width][height][layer_index][side]) { - continue; - } + VTR_ASSERT_MSG(pin_index < num_phys_pins, "Physical block pins bound number of logical block pins"); - int pin_num = dir_list[width][height][layer_index][side][pin_index]; - VTR_ASSERT(pin_num >= 0); - VTR_ASSERT(tile_type->pinloc[width][height][side][pin_num]); + if (num_done_per_dir[width][height][side] >= num_dir[width][height][side]) { + continue; + } - t_pin_loc pin_loc; - pin_loc.pin_index = pin_num; - pin_loc.width_offset = width; - pin_loc.height_offset = height; - pin_loc.layer_offset = layer_index; - pin_loc.side = side; + int pin_num = dir_list[width][height][side][pin_index]; + VTR_ASSERT(pin_num >= 0); + VTR_ASSERT(tile_type->pinloc[width][height][side][pin_num]); - pin_ordering.push_back(pin_loc); + t_pin_loc pin_loc; + pin_loc.pin_index = pin_num; + pin_loc.width_offset = width; + pin_loc.height_offset = height; + pin_loc.side = side; - num_done_per_dir[width][height][layer_index][side]++; - pin++; - } + pin_ordering.push_back(pin_loc); - VTR_ASSERT(pin == num_phys_pins_per_layer[layer_index]); + num_done_per_dir[width][height][side]++; + pin++; } + VTR_ASSERT(pin == num_phys_pins); + + if (perturb_switch_pattern) { load_perturbed_connection_block_pattern(tracks_connected_to_pin, pin_ordering, @@ -2448,7 +2408,6 @@ static void load_uniform_connection_block_pattern(vtr::NdMatrix& tracks_ e_side side = pin_locations[i].side; int width = pin_locations[i].width_offset; int height = pin_locations[i].height_offset; - int layer = pin_locations[i].layer_offset; int pin_fc = Fc[pin][seg_index]; VTR_ASSERT(pin_fc % group_size == 0); From c5d509cae9965bbd797f7446d9c3108e1b10b3ba Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Wed, 29 Oct 2025 13:36:36 -0400 Subject: [PATCH 07/32] doxygen comment for process_fc() --- libs/libarchfpga/src/read_xml_arch_file.cpp | 62 ++++++++++++--------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index 810b9ab7f0..5bc7a8880f 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -262,13 +262,25 @@ static void process_mode(pugi::xml_node Parent, int& parent_pb_idx); static void process_fc_values(pugi::xml_node Node, t_default_fc_spec& spec, const pugiutil::loc_data& loc_data); + +/** + * @brief Processes the XML node for a given sub-tile and initializes + * the Fc specifications for its pins. + * + * This function parses default Fc values and any tags defined + * within the XML node, then applies them to all port/segment combinations + * of the specified sub-tile. If no node is present, it falls back to + * the architecture-wide default Fc specification. The resulting Fc settings + * are stored in the given physical tile type. + */ static void process_fc(pugi::xml_node Node, t_physical_tile_type* PhysicalTileType, - t_sub_tile* SubTile, + const t_sub_tile& sub_tile, t_pin_counts pin_counts, - std::vector& segments, + const std::vector& segments, const t_default_fc_spec& arch_def_fc, const pugiutil::loc_data& loc_data); + static t_fc_override process_fc_override(pugi::xml_node node, const pugiutil::loc_data& loc_data); /** @@ -287,7 +299,8 @@ static void process_switch_block_locations(pugi::xml_node switchblock_locations, const t_arch& arch, const pugiutil::loc_data& loc_data); -static e_fc_value_type string_to_fc_value_type(const std::string& str, pugi::xml_node node, const pugiutil::loc_data& loc_data); +static e_fc_value_type string_to_fc_value_type(std::string_view str, pugi::xml_node node, const pugiutil::loc_data& loc_data); + static void process_chan_width_distr(pugi::xml_node Node, t_arch* arch, const pugiutil::loc_data& loc_data); @@ -1996,14 +2009,14 @@ static void process_mode(pugi::xml_node Parent, static void process_fc_values(pugi::xml_node Node, t_default_fc_spec& spec, const pugiutil::loc_data& loc_data) { spec.specified = true; - /* Load the default fc_in */ + // Load the default fc_in auto default_fc_in_attrib = get_attribute(Node, "in_type", loc_data); spec.in_value_type = string_to_fc_value_type(default_fc_in_attrib.value(), Node, loc_data); auto in_val_attrib = get_attribute(Node, "in_val", loc_data); spec.in_value = vtr::atof(in_val_attrib.value()); - /* Load the default fc_out */ + // Load the default fc_out auto default_fc_out_attrib = get_attribute(Node, "out_type", loc_data); spec.out_value_type = string_to_fc_value_type(default_fc_out_attrib.value(), Node, loc_data); @@ -2011,27 +2024,25 @@ static void process_fc_values(pugi::xml_node Node, t_default_fc_spec& spec, cons spec.out_value = vtr::atof(out_val_attrib.value()); } -/* Takes in the node ptr for the 'fc' elements and initializes - * the appropriate fields of type. */ static void process_fc(pugi::xml_node Node, t_physical_tile_type* PhysicalTileType, - t_sub_tile* SubTile, + const t_sub_tile& sub_tile, t_pin_counts pin_counts, - std::vector& segments, + const std::vector& segments, const t_default_fc_spec& arch_def_fc, const pugiutil::loc_data& loc_data) { std::vector fc_overrides; t_default_fc_spec def_fc_spec; if (Node) { - /* Load the default Fc values from the node */ + // Load the default Fc values from the node process_fc_values(Node, def_fc_spec, loc_data); - /* Load any tags */ + // Load any tags for (auto child_node : Node.children()) { t_fc_override fc_override = process_fc_override(child_node, loc_data); fc_overrides.push_back(fc_override); } } else { - /* Use the default value, if available */ + // Use the default value, if available if (!arch_def_fc.specified) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(Node), vtr::string_fmt(" is missing child , and no specified in architecture\n").c_str()); @@ -2042,12 +2053,12 @@ static void process_fc(pugi::xml_node Node, /* Go through all the port/segment combinations and create the (potentially * overriden) pin/seg Fc specifications */ for (size_t iseg = 0; iseg < segments.size(); ++iseg) { - for (int icapacity = 0; icapacity < SubTile->capacity.total(); ++icapacity) { + for (int icapacity = 0; icapacity < sub_tile.capacity.total(); ++icapacity) { //If capacity > 0, we need t offset the block index by the number of pins per instance //this ensures that all pins have an Fc specification int iblk_pin = icapacity * pin_counts.total(); - for (const auto& port : SubTile->ports) { + for (const t_physical_tile_port& port : sub_tile.ports) { t_fc_specification fc_spec; fc_spec.seg_index = iseg; @@ -2110,7 +2121,7 @@ static void process_fc(pugi::xml_node Node, for (int iport_pin = 0; iport_pin < port.num_pins; ++iport_pin) { //XXX: this assumes that iterating through the tile ports // in order yields the block pin order - int true_physical_blk_pin = SubTile->sub_tile_to_tile_pin_indices[iblk_pin]; + int true_physical_blk_pin = sub_tile.sub_tile_to_tile_pin_indices[iblk_pin]; fc_spec.pins.push_back(true_physical_blk_pin); ++iblk_pin; } @@ -2124,7 +2135,7 @@ static void process_fc(pugi::xml_node Node, static t_fc_override process_fc_override(pugi::xml_node node, const pugiutil::loc_data& loc_data) { if (node.name() != std::string("fc_override")) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(node), - vtr::string_fmt("Unexpeted node of type '%s' (expected optional 'fc_override')", + vtr::string_fmt("Unexpected node of type '%s' (expected optional 'fc_override')", node.name()) .c_str()); } @@ -2137,21 +2148,22 @@ static t_fc_override process_fc_override(pugi::xml_node node, const pugiutil::lo bool seen_fc_value = false; bool seen_port_or_seg = false; for (auto attrib : node.attributes()) { - if (attrib.name() == std::string("port_name")) { + std::string_view attribute_name = attrib.name(); + if (attribute_name == "port_name") { fc_override.port_name = attrib.value(); seen_port_or_seg |= true; - } else if (attrib.name() == std::string("segment_name")) { + } else if (attribute_name == "segment_name") { fc_override.seg_name = attrib.value(); seen_port_or_seg |= true; - } else if (attrib.name() == std::string("fc_type")) { + } else if (attribute_name == "fc_type") { fc_override.fc_value_type = string_to_fc_value_type(attrib.value(), node, loc_data); seen_fc_type = true; - } else if (attrib.name() == std::string("fc_val")) { + } else if (attribute_name == "fc_val") { fc_override.fc_value = vtr::atof(attrib.value()); seen_fc_value = true; } else { archfpga_throw(loc_data.filename_c_str(), loc_data.line(node), - vtr::string_fmt("Unexpected attribute '%s'", attrib.name()).c_str()); + vtr::string_fmt("Unexpected attribute '%s'", attribute_name).c_str()); } } @@ -2173,7 +2185,7 @@ static t_fc_override process_fc_override(pugi::xml_node node, const pugiutil::lo return fc_override; } -static e_fc_value_type string_to_fc_value_type(const std::string& str, pugi::xml_node node, const pugiutil::loc_data& loc_data) { +static e_fc_value_type string_to_fc_value_type(std::string_view str, pugi::xml_node node, const pugiutil::loc_data& loc_data) { e_fc_value_type fc_value_type = e_fc_value_type::FRACTIONAL; if (str == "frac") { @@ -2182,9 +2194,7 @@ static e_fc_value_type string_to_fc_value_type(const std::string& str, pugi::xml fc_value_type = e_fc_value_type::ABSOLUTE; } else { archfpga_throw(loc_data.filename_c_str(), loc_data.line(node), - vtr::string_fmt("Invalid fc_type '%s'. Must be 'abs' or 'frac'.\n", - str.c_str()) - .c_str()); + vtr::string_fmt("Invalid fc_type '%s'. Must be 'abs' or 'frac'.\n", str).c_str()); } return fc_value_type; @@ -3726,7 +3736,7 @@ static void process_sub_tiles(pugi::xml_node Node, /* Load Fc */ Cur = get_single_child(CurSubTile, "fc", loc_data, ReqOpt::OPTIONAL); - process_fc(Cur, PhysicalTileType, &SubTile, pin_counts, segments, arch_def_fc, loc_data); + process_fc(Cur, PhysicalTileType, SubTile, pin_counts, segments, arch_def_fc, loc_data); //Load equivalent sites information Cur = get_single_child(CurSubTile, "equivalent_sites", loc_data, ReqOpt::REQUIRED); From 1f13be8a55ba305ad83fd9c3e79ca1175915e474 Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Thu, 30 Oct 2025 16:55:21 -0400 Subject: [PATCH 08/32] doxygen comment for label_wire_muxes() --- .../route/rr_graph_generation/rr_graph.cpp | 2 +- .../route/rr_graph_generation/rr_graph2.cpp | 45 ++++++++++--------- .../tileable_rr_graph_builder.cpp | 4 +- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index c9dc33ddf2..da6ef2f686 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -1516,7 +1516,7 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder } } - //Create the actual OPIN->CHANX/CHANY edges + // Create the actual OPIN->CHANX/CHANY edges uniquify_edges(rr_edges_to_create); alloc_and_load_edges(rr_graph_builder, rr_edges_to_create); num_edges += rr_edges_to_create.size(); diff --git a/vpr/src/route/rr_graph_generation/rr_graph2.cpp b/vpr/src/route/rr_graph_generation/rr_graph2.cpp index 8901caeb9e..582655371a 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph2.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph2.cpp @@ -130,6 +130,17 @@ static int vpr_to_phy_track(const int itrack, const t_chan_seg_details* seg_details, const enum e_directionality directionality); + +/** + * @brief Identifies and labels all mux endpoints at a given channel segment coordinate. + * + * This routine scans all routing tracks within a channel segment (specified by + * 'chan_num' and 'seg_num') and collects the track indices corresponding to + * valid mux endpoints that can be driven by OPINs in that channel segment. + * The resulting list of eligible tracks is returned in natural (increasing) track order. + * + * @details If @p seg_type_index is UNDEFINED, all segment types are considered. + */ static void label_wire_muxes(const int chan_num, const int seg_num, const t_chan_seg_details* seg_details, @@ -673,7 +684,7 @@ int get_bidir_opin_connections(RRGraphBuilder& rr_graph_builder, return num_conn; } -/* AA: Actually builds the edges from the OPIN nodes already allocated to their correct tracks for segment seg_Inf[seg_type_index]. +/* Actually builds the edges from the OPIN nodes already allocated to their correct tracks for segment seg_Inf[seg_type_index]. * Note that this seg_inf vector is NOT the segment_info vectored as stored in the device variable. This index is w.r.t to seg_inf_x * or seg_inf_y for x-adjacent and y-adjacent segments respectively. This index is assigned in get_seg_details earlier * in the rr_graph_builder routine. This t_seg_detail is then used to build t_chan_seg_details which is passed in to label_wire mux @@ -696,21 +707,20 @@ int get_unidir_opin_connections(RRGraphBuilder& rr_graph_builder, /* Gets a linked list of Fc nodes of specified seg_type_index to connect * to in given chan seg. Fc_ofs is used for the opin staggering pattern. */ - int num_inc_muxes, num_dec_muxes; - *Fc_clipped = false; - /* Fc is assigned in pairs so check it is even. */ + // Fc is assigned in pairs so check it is even. VTR_ASSERT(Fc % 2 == 0); - /* get_rr_node_indices needs x and y coords. */ - int x = ((e_rr_type::CHANX == chan_type) ? seg : chan); - int y = ((e_rr_type::CHANX == chan_type) ? chan : seg); + // get_rr_node_indices needs x and y coords. + int x = (e_rr_type::CHANX == chan_type) ? seg : chan; + int y = (e_rr_type::CHANX == chan_type) ? chan : seg; - /* Get the lists of possible muxes. */ + // Get the lists of possible muxes. int dummy; std::vector inc_muxes; std::vector dec_muxes; + int num_inc_muxes, num_dec_muxes; // Determine the channel width instead of using max channels to not create hanging nodes int max_chan_width = (e_rr_type::CHANX == chan_type) ? nodes_per_chan.x_list[y] : nodes_per_chan.y_list[x]; @@ -719,25 +729,25 @@ int get_unidir_opin_connections(RRGraphBuilder& rr_graph_builder, label_wire_muxes(chan, seg, seg_details, seg_type_index, max_len, Direction::DEC, max_chan_width, true, dec_muxes, &num_dec_muxes, &dummy); - /* Clip Fc to the number of muxes. */ + // Clip Fc to the number of muxes. if (((Fc / 2) > num_inc_muxes) || ((Fc / 2) > num_dec_muxes)) { *Fc_clipped = true; Fc = 2 * std::min(num_inc_muxes, num_dec_muxes); } - /* Assign tracks to meet Fc demand */ + // Assign tracks to meet Fc demand int num_edges = 0; for (int iconn = 0; iconn < (Fc / 2); ++iconn) { - /* Figure of the next mux to use for the 'inc' and 'dec' connections */ + // Figure of the next mux to use for the 'inc' and 'dec' connections int inc_mux = Fc_ofs[chan][seg][seg_type_index] % num_inc_muxes; int dec_mux = Fc_ofs[chan][seg][seg_type_index] % num_dec_muxes; ++Fc_ofs[chan][seg][seg_type_index]; - /* Figure out the track it corresponds to. */ + // Figure out the track it corresponds to. int inc_track = inc_muxes[inc_mux]; int dec_track = dec_muxes[dec_mux]; - /* Figure the inodes of those muxes */ + // Figure the inodes of those muxes RRNodeId inc_inode_index = rr_graph_builder.node_lookup().find_node(layer, x, y, chan_type, inc_track); RRNodeId dec_inode_index = rr_graph_builder.node_lookup().find_node(layer, x, y, chan_type, dec_track); @@ -745,7 +755,7 @@ int get_unidir_opin_connections(RRGraphBuilder& rr_graph_builder, continue; } - /* Add to the list. */ + // Add to the list. short to_switch = seg_details[inc_track].arch_opin_switch(); rr_edges_to_create.emplace_back(from_rr_node, inc_inode_index, to_switch, false); ++num_edges; @@ -1962,11 +1972,6 @@ void load_sblock_pattern_lookup(const int i, } } -/* Labels the muxes on that side (seg_num, chan_num, direction). The returned array - * maps a label to the actual track #: array[0] = - * This routine orders wire muxes by their natural order, i.e. track # - * If seg_type_index == UNDEFINED, all segments in the channel are considered. Otherwise this routine - * only looks at segments that belong to the specified segment type. */ static void label_wire_muxes(const int chan_num, const int seg_num, const t_chan_seg_details* seg_details, @@ -1985,7 +1990,7 @@ static void label_wire_muxes(const int chan_num, /* Alloc the list on LOAD pass */ if (pass > 0) { labels.resize(num_labels); - std::fill(labels.begin(), labels.end(), 0); + std::ranges::fill(labels, 0); num_labels = 0; } diff --git a/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_builder.cpp b/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_builder.cpp index 4c9369b9d8..1de177f97a 100644 --- a/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_builder.cpp +++ b/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_builder.cpp @@ -223,7 +223,7 @@ void build_tileable_unidir_rr_graph(const std::vector& typ bool Fc_clipped = false; // [0..num_types-1][0..num_pins-1] std::vector> Fc_in; - Fc_in = alloc_and_load_actual_fc(types, max_pins, segment_inf, sets_per_seg_type, (const t_chan_width*)&chan_width, + Fc_in = alloc_and_load_actual_fc(types, max_pins, segment_inf, sets_per_seg_type, &chan_width, e_fc_type::IN, UNI_DIRECTIONAL, &Fc_clipped, false); if (Fc_clipped) { *Warnings |= RR_GRAPH_WARN_FC_CLIPPED; @@ -232,7 +232,7 @@ void build_tileable_unidir_rr_graph(const std::vector& typ Fc_clipped = false; // [0..num_types-1][0..num_pins-1] std::vector> Fc_out; - Fc_out = alloc_and_load_actual_fc(types, max_pins, segment_inf, sets_per_seg_type, (const t_chan_width*)&chan_width, + Fc_out = alloc_and_load_actual_fc(types, max_pins, segment_inf, sets_per_seg_type, &chan_width, e_fc_type::OUT, UNI_DIRECTIONAL, &Fc_clipped, false); if (Fc_clipped) { From 4104e2331f4d0665e3b11dbedd72e2433b0eb654 Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Thu, 30 Oct 2025 19:04:30 -0400 Subject: [PATCH 09/32] Fc for OPIN-CHANZ can be 1 --- vpr/src/route/rr_graph_generation/rr_graph.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index da6ef2f686..e75d1e8907 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -1319,7 +1319,7 @@ std::vector> alloc_and_load_actual_fc(const std::vector> alloc_and_load_actual_fc(const std::vector Date: Fri, 31 Oct 2025 20:25:00 -0400 Subject: [PATCH 10/32] update the 3d_full_opin arch file --- ...l_OPIN_inter_die_stratixiv_arch.timing.xml | 746 +++++++----------- 1 file changed, 299 insertions(+), 447 deletions(-) diff --git a/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_stratixiv_arch.timing.xml b/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_stratixiv_arch.timing.xml index 5dd5a516ab..2fb73bb3ba 100644 --- a/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_stratixiv_arch.timing.xml +++ b/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_stratixiv_arch.timing.xml @@ -4427,24 +4427,22 @@ - + + + - - io.core_out[0:19] - io.core_in[0:24] io.clk[0:2] - io.core_out[20:39] - io.core_in[24:49] io.clk[3:4] - io.core_out[0:19] - io.core_in[0:24] io.clk[0:2] - io.core_out[20:39] - io.core_in[24:49] io.clk[3:4] + io.core_out[0:19] io.core_in[0:24] io.clk[0:2] + io.core_out[20:39] io.core_in[24:49] io.clk[3:4] + io.core_out[0:19] io.core_in[0:24] io.clk[0:2] + io.core_in[24:49] io.clk[3:4] io.core_out[20:39] @@ -4457,16 +4455,15 @@ - + + + + - PLL.out_clock PLL.out_signal - PLL.in_signal PLL.in_clock - PLL.out_clock PLL.out_signal - PLL.in_signal PLL.in_clock - PLL.out_clock PLL.out_signal - PLL.in_signal PLL.in_clock - PLL.out_clock PLL.out_signal - PLL.in_signal PLL.in_clock + PLL.out_clock PLL.out_signal PLL.in_signal PLL.in_clock + PLL.out_clock PLL.out_signal PLL.in_signal PLL.in_clock + PLL.out_clock PLL.out_signal PLL.in_signal PLL.in_clock + PLL.out_clock PLL.out_signal PLL.in_signal PLL.in_clock @@ -4509,11 +4506,13 @@ - @@ -4528,13 +4527,10 @@ each block pin can connect to some Vertical and some Horizontal wires in Stratix IV. Note that Fc_in/Fc_out have been scaled to account for this. --> - LAB.data_out[0:19] - LAB.data_in[0:39] LAB.control_in[0:3] LAB.clk[0] - LAB.data_out[20:39] - LAB.data_in[40:79] LAB.control_in[4:6] LAB.clk[1] - LAB.data_out - LAB.data_in LAB.control_in LAB.clk LAB.cin LAB.sharein - LAB.cout LAB.shareout + LAB.data_out[0:19] LAB.data_in[0:39] LAB.control_in[0:3] LAB.clk[0] + LAB.data_out[20:39] LAB.data_in[40:79] LAB.control_in[4:6] LAB.clk[1] + LAB.data_out LAB.data_in LAB.control_in LAB.clk LAB.cin LAB.sharein + LAB.cout LAB.shareout @@ -4567,9 +4563,14 @@ Fc_in: 0.0275 Fc_out: 0.0375 --> + + + + + - - - DSP.data_out_top[17:0] DSP.scan_a_out[1:0] - DSP.data_in[35:0] DSP.control_in[2:0] DSP.scan_a_in[1:0] DSP.clk[0] - DSP.data_out_top[35:18] DSP.scan_a_out[3:2] DSP.signal_out[0:0] - DSP.data_in[71:36] DSP.control_in[4:3] DSP.scan_a_in[4:2] - DSP.data_out_top[53:36] DSP.scan_a_out[5:4] DSP.signal_out[1:1] - DSP.data_in[107:72] DSP.control_in[6:5] DSP.scan_a_in[6:5] DSP.clk[1] - DSP.data_out_top[71:54] DSP.scan_a_out[7:6] DSP.signal_out[2:2] - DSP.data_in[144:108] DSP.control_in[8:6] DSP.scan_a_in[8:7] - DSP.data_out_top[35:0] DSP.scan_a_out[3:0] DSP.signal_out[0:0] - DSP.data_in[143:72] DSP.control_in[3:0] DSP.scan_a_in[3:0] DSP.clk[0] DSP.chain_in - DSP.data_out_top[71:36] DSP.scan_a_out[9:4] DSP.signal_out[2:1] - DSP.data_in[71:0] DSP.control_in[8:4] DSP.scan_a_in[8:4] DSP.clk[1] + DSP.data_out_top[17:0] DSP.scan_a_out[1:0] DSP.data_in[35:0] DSP.control_in[2:0] DSP.scan_a_in[1:0] DSP.clk[0] + DSP.data_out_top[35:18] DSP.scan_a_out[3:2] DSP.signal_out[0:0] DSP.data_in[71:36] DSP.control_in[4:3] DSP.scan_a_in[4:2] + DSP.data_out_top[53:36] DSP.scan_a_out[5:4] DSP.signal_out[1:1] DSP.data_in[107:72] DSP.control_in[6:5] DSP.scan_a_in[6:5] DSP.clk[1] + DSP.data_out_top[71:54] DSP.scan_a_out[7:6] DSP.signal_out[2:2] DSP.data_in[144:108] DSP.control_in[8:6] DSP.scan_a_in[8:7] + DSP.data_out_top[35:0] DSP.scan_a_out[3:0] DSP.signal_out[0:0] DSP.data_in[143:72] DSP.control_in[3:0] DSP.scan_a_in[3:0] DSP.clk[0] DSP.chain_in + DSP.data_out_top[71:36] DSP.scan_a_out[9:4] DSP.signal_out[2:1] DSP.data_in[71:0] DSP.control_in[8:4] DSP.scan_a_in[8:4] DSP.clk[1] - DSP.data_out_bot[17:0] DSP.scan_a_out[9:8] - DSP.data_in[179:145] DSP.control_in[11:9] DSP.scan_a_in[10:9] DSP.clk[2] - DSP.data_out_bot[35:18] DSP.scan_a_out[11:10] DSP.signal_out[3:3] - DSP.data_in[215:180] DSP.control_in[13:12] DSP.scan_a_in[12:11] - DSP.data_out_bot[53:36] DSP.scan_a_out[13:12] DSP.signal_out[4:4] - DSP.data_in[251:216] DSP.control_in[15:14] DSP.scan_a_in[14:13] - DSP.data_out_bot[71:54] DSP.scan_a_out[15:14] DSP.signal_out[5:5] - DSP.data_in[287:252] DSP.control_in[20:16] DSP.scan_a_in[17:15] DSP.clk[3] - DSP.data_out_bot[35:0] DSP.scan_a_out[12:10] DSP.signal_out[3:3] - DSP.data_in[287:215] DSP.control_in[13:9] DSP.scan_a_in[13:9] DSP.clk[2] - DSP.data_out_bot[71:36] DSP.scan_a_out[17:13] DSP.signal_out[5:4] - DSP.data_in[214:144] DSP.control_in[20:16] DSP.scan_a_in[17:14] DSP.clk[3] + DSP.data_out_bot[17:0] DSP.scan_a_out[9:8] DSP.data_in[179:145] DSP.control_in[11:9] DSP.scan_a_in[10:9] DSP.clk[2] + DSP.data_out_bot[35:18] DSP.scan_a_out[11:10] DSP.signal_out[3:3] DSP.data_in[215:180] DSP.control_in[13:12] DSP.scan_a_in[12:11] + DSP.data_in[251:216] DSP.control_in[15:14] DSP.scan_a_in[14:13] DSP.data_out_bot[53:36] DSP.scan_a_out[13:12] DSP.signal_out[4:4] + DSP.data_in[287:252] DSP.control_in[20:16] DSP.scan_a_in[17:15] DSP.clk[3] DSP.data_out_bot[71:54] DSP.scan_a_out[15:14] DSP.signal_out[5:5] + DSP.data_in[287:215] DSP.control_in[13:9] DSP.scan_a_in[13:9] DSP.clk[2] DSP.data_out_bot[35:0] DSP.scan_a_out[12:10] DSP.signal_out[3:3] + DSP.data_in[214:144] DSP.control_in[20:16] DSP.scan_a_in[17:14] DSP.clk[3] DSP.data_out_bot[71:36] DSP.scan_a_out[17:13] DSP.signal_out[5:4] - DSP.chain_out + DSP.chain_out @@ -4666,22 +4655,21 @@ Fc_in: 0.0275 Fc_out: 0.0375 --> + + - - M9K.data_out[17:0] M9K.control_out[1:0] - M9K.data_addr_control_in[51:0] M9K.clk_in[0] - M9K.data_out[35:18] M9K.control_out[2:2] - M9K.data_addr_control_in[103:52] M9K.clk_in[1] - M9K.data_out M9K.control_out - M9K.data_addr_control_in M9K.clk_in + M9K.data_out[17:0] M9K.control_out[1:0] M9K.data_addr_control_in[51:0] M9K.clk_in[0] + M9K.data_out[35:18] M9K.control_out[2:2] M9K.data_addr_control_in[103:52] M9K.clk_in[1] + M9K.data_out M9K.control_out M9K.data_addr_control_in M9K.clk_in @@ -4709,64 +4697,42 @@ Fc_in: 0.0275 Fc_out: 0.0375 --> + + - - M144K.data_out[7:0] - M144K.data_addr_control_in[24:0] - M144K.data_out[15:8] - M144K.data_addr_control_in[50:25] - M144K.data_out[22:16] - M144K.data_addr_control_in[76:51] - M144K.data_out[29:23] - M144K.data_addr_control_in[102:77] - M144K.data_out[36:30] M144K.control_out[0] - M144K.data_addr_control_in[128:103] M144K.clk_in[0] - M144K.data_out[43:37] M144K.control_out[1] - M144K.data_addr_control_in[154:129] - M144K.data_out[51:44] - M144K.data_addr_control_in[180:155] - M144K.data_out[59:52] - M144K.data_addr_control_in[206:181] - M144K.data_out[67:60] - M144K.data_addr_control_in[232:207] - M144K.data_out[75:68] - M144K.data_addr_control_in[258:233] - M144K.data_out[82:76] - M144K.data_addr_control_in[284:259] - M144K.data_out[89:83] M144K.control_out[2] - M144K.data_addr_control_in[310:285] - M144K.data_out[96:90] - M144K.data_addr_control_in[336:311] M144K.clk_in[1] - M144K.data_out[103:97] - M144K.data_addr_control_in[362:337] - M144K.data_out[111:104] - M144K.data_addr_control_in[388:363] - M144K.data_out[119:112] - M144K.data_addr_control_in[415:389] - M144K.data_out[14:0] - M144K.data_addr_control_in[51:0] - M144K.data_out[29:15] - M144K.data_addr_control_in[103:52] - M144K.data_out[44:30] M144K.control_out[0] - M144K.data_addr_control_in[155:104] - M144K.data_out[59:45] M144K.control_out[1] - M144K.data_addr_control_in[207:156] M144K.clk_in[0] - M144K.data_addr_control_in[259:208] M144K.clk_in[1] - M144K.data_out[74:60] M144K.control_out[2] - M144K.data_out[89:75] - M144K.data_addr_control_in[311:260] - M144K.data_out[104:90] - M144K.data_addr_control_in[363:312] - M144K.data_out[119:105] - M144K.data_addr_control_in[415:364] + M144K.data_out[7:0] M144K.data_addr_control_in[24:0] + M144K.data_out[15:8] M144K.data_addr_control_in[50:25] + M144K.data_out[22:16] M144K.data_addr_control_in[76:51] + M144K.data_out[29:23] + M144K.data_out[36:30] M144K.control_out[0] M144K.data_addr_control_in[128:103] M144K.clk_in[0] + M144K.data_out[43:37] M144K.control_out[1] M144K.data_addr_control_in[154:129] + M144K.data_out[51:44] M144K.data_addr_control_in[180:155] + M144K.data_out[59:52] M144K.data_addr_control_in[206:181] + M144K.data_out[67:60] M144K.data_addr_control_in[232:207] + M144K.data_out[75:68] M144K.data_addr_control_in[258:233] + M144K.data_out[82:76] M144K.data_addr_control_in[284:259] + M144K.data_out[89:83] M144K.control_out[2] M144K.data_addr_control_in[310:285] + M144K.data_out[96:90] M144K.data_addr_control_in[336:311] M144K.clk_in[1] + M144K.data_out[103:97] M144K.data_addr_control_in[362:337] + M144K.data_out[111:104] M144K.data_addr_control_in[388:363] + M144K.data_out[119:112] M144K.data_addr_control_in[415:389] + M144K.data_out[14:0] M144K.data_addr_control_in[51:0] + M144K.data_out[29:15] M144K.data_addr_control_in[103:52] + M144K.data_out[44:30] M144K.control_out[0] M144K.data_addr_control_in[155:104] + M144K.data_out[59:45] M144K.control_out[1] M144K.data_addr_control_in[207:156] M144K.clk_in[0] + M144K.data_addr_control_in[259:208] M144K.clk_in[1] M144K.data_out[74:60] M144K.control_out[2] + M144K.data_out[89:75] M144K.data_addr_control_in[311:260] + M144K.data_out[104:90] M144K.data_addr_control_in[363:312] + M144K.data_out[119:105] M144K.data_addr_control_in[415:364] @@ -4787,7 +4753,7 @@ 'in' from the true perimeter (which is left empty). This means that they are fully surrounded by routing channels, allowing them to connect to both horizontal and vertical channels. This is a - minor approximation since on real Stratix IV devices there is no + minor approximation since on real Stratix IV devices there is no perimeter-side vertical routing channel --> @@ -4798,8 +4764,8 @@ - @@ -4853,7 +4819,7 @@ 'in' from the true perimeter (which is left empty). This means that they are fully surrounded by routing channels, allowing them to connect to both horizontal and vertical channels. This is a - minor approximation since on real Stratix IV devices there is no + minor approximation since on real Stratix IV devices there is no perimeter-side vertical routing channel --> @@ -4864,8 +4830,8 @@ - @@ -4915,140 +4881,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - + + - + 1 1 1 1 1 1 1 1 1 - + - 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 @@ -5379,8 +5209,8 @@ - @@ -5484,20 +5314,20 @@ - @@ -6269,7 +6099,7 @@ - @@ -6582,30 +6412,30 @@ - - - @@ -6879,13 +6709,13 @@ @@ -6914,11 +6744,11 @@ - @@ -7111,10 +6941,10 @@ Specifically, the signa, signb, dataa and datab inputs, and also the scanouta output may be used in registered or combinational mode independently. While it would be unusuall to have these in different - modes, it is permitted in the Startix IV architecture. - + modes, it is permitted in the Startix IV architecture. + To fully model this behaviour would require choosing (# inputs + # outputs) each having two modes (registered, - and combinational). Then we have a set of 10 (5 ports * 2 modes [reg, comb]) and we must choose 5. + and combinational). Then we have a set of 10 (5 ports * 2 modes [reg, comb]) and we must choose 5. This yeilds: 10!/(5!(10!-5!)) = 252 modes, far too many to model here. This is why we make the above approximation. @@ -7133,7 +6963,7 @@ - @@ -7420,12 +7250,12 @@ - @@ -7477,14 +7307,14 @@ @@ -7647,7 +7477,7 @@ @@ -7749,12 +7579,12 @@ - @@ -7827,7 +7657,7 @@ - @@ -12536,8 +12366,8 @@ - @@ -12558,7 +12388,7 @@ - @@ -48258,16 +48088,16 @@ - - @@ -48416,7 +48246,7 @@ - + + + + + + + + + + + + + + + + + + + + + From 9210a3dbe3f3b777950737aa93dd1f10bb6c6fdc Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Fri, 31 Oct 2025 20:25:49 -0400 Subject: [PATCH 11/32] add OPIN--CHANZ edges --- .../router_lookahead_map_utils.cpp | 2 +- .../build_scatter_gathers.cpp | 2 +- .../route/rr_graph_generation/rr_graph.cpp | 198 ++++++++++++------ 3 files changed, 137 insertions(+), 65 deletions(-) diff --git a/vpr/src/route/router_lookahead/router_lookahead_map_utils.cpp b/vpr/src/route/router_lookahead/router_lookahead_map_utils.cpp index a8eeb09b80..524b53c717 100644 --- a/vpr/src/route/router_lookahead/router_lookahead_map_utils.cpp +++ b/vpr/src/route/router_lookahead/router_lookahead_map_utils.cpp @@ -1017,7 +1017,7 @@ static void dijkstra_flood_to_wires(int itile, e_rr_type curr_rr_type = rr_graph.node_type(curr.node); int curr_layer_num = rr_graph.node_layer_low(curr.node); - if (curr_rr_type == e_rr_type::CHANX || curr_rr_type == e_rr_type::CHANY || curr_rr_type == e_rr_type::SINK) { + if (curr_rr_type == e_rr_type::CHANX || curr_rr_type == e_rr_type::CHANY || curr_rr_type == e_rr_type::CHANZ || curr_rr_type == e_rr_type::SINK) { //We stop expansion at any CHANX/CHANY/SINK int seg_index; if (curr_rr_type != e_rr_type::SINK) { diff --git a/vpr/src/route/rr_graph_generation/build_scatter_gathers.cpp b/vpr/src/route/rr_graph_generation/build_scatter_gathers.cpp index 9b63e0a910..34ff5b8954 100644 --- a/vpr/src/route/rr_graph_generation/build_scatter_gathers.cpp +++ b/vpr/src/route/rr_graph_generation/build_scatter_gathers.cpp @@ -276,7 +276,7 @@ std::vector alloc_and_load_scatter_gather_connections(const s scatter_loc.layer_num, scatter_loc.x, scatter_loc.y, scatter_wire_candidates.size()); - continue; + // continue; } const bool is_3d_link = (sg_link.z_offset != 0); diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index e75d1e8907..89c8b58c85 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -3,6 +3,8 @@ #include #include #include +#include + #include "alloc_and_load_rr_indexed_data.h" #include "build_scatter_gathers.h" #include "get_parallel_segs.h" @@ -84,6 +86,15 @@ static vtr::NdMatrix, 4> alloc_and_load_pin_to_track_map(const const e_directionality directionality, const std::vector& seg_inf, const std::vector& sets_per_seg_type); + +static void add_edges_opin_chanz(RRGraphBuilder& rr_graph_builder, + const RRGraphView& rr_graph, + int layer, int x, int y, + const std::vector>& Fc_out, + const t_unified_to_parallel_seg_index& seg_index_map, + int num_seg_types, + t_rr_edge_info_set& rr_edges_to_create, + const std::vector& interdie_3d_links); /** * @brief This routine calculates pin connections to tracks for a specific type and a specific segment based on the Fc value * defined for each pin in the architecture file. This routine is called twice for each combination of block type and segment @@ -1293,13 +1304,7 @@ std::vector> alloc_and_load_actual_fc(const std::vectorx_max % fac) == 0 && (nodes_per_chan->y_max % fac) == 0); + // VTR_ASSERT((nodes_per_chan->x_max % fac) == 0 && (nodes_per_chan->y_max % fac) == 0); for (const t_physical_tile_type& type : types) { // Skip EMPTY int itype = type.index; @@ -1316,63 +1321,72 @@ std::vector> alloc_and_load_actual_fc(const std::vector 0); - VTR_ASSERT(total_connections % fac == 0); - - // We walk through all the pins this fc_spec applies to, adding fac connections - // to each pin, until we run out of connections. This should distribute the connections - // as evenly as possible (if total_connections % pins.size() != 0, there will be - // some inevitable imbalance). - int connections_remaining = total_connections; - while (connections_remaining != 0) { - // Add one set of connections to each pin - for (int ipin : fc_spec.pins) { - if (connections_remaining >= fac) { - Fc[itype][ipin][iseg] += fac; - connections_remaining -= fac; - } else { - VTR_ASSERT(connections_remaining == 0); - break; - } + if (fc_spec.fc_value < fac && segment_inf[iseg].parallel_axis != e_parallel_axis::Z_AXIS) { + VPR_FATAL_ERROR(VPR_ERROR_ROUTE, "Absolute Fc value must be at least %d (was %f) between block pin '%s' to wire segment %s", + fac, fc_spec.fc_value, + block_type_pin_index_to_name(&type, fc_spec.pins[0], is_flat).c_str(), + segment_inf[iseg].name.c_str()); + } + + total_connections = vtr::nint(fc_spec.fc_value) * fc_spec.pins.size(); + } + + // Ensure that there are at least fac connections, this ensures that low Fc ports + // targeting small sets of segs get connection(s), even if flt_total_connections < fac. + total_connections = std::max(total_connections, fac); + + // Ensure total evenly divides fac by adding the remainder + total_connections += (total_connections % fac); + + VTR_ASSERT(total_connections > 0); + VTR_ASSERT(total_connections % fac == 0); + + // We walk through all the pins this fc_spec applies to, adding fac connections + // to each pin, until we run out of connections. This should distribute the connections + // as evenly as possible (if total_connections % pins.size() != 0, there will be + // some inevitable imbalance). + int connections_remaining = total_connections; + while (connections_remaining != 0) { + // Add one set of connections to each pin + for (int ipin : fc_spec.pins) { + if (connections_remaining >= fac) { + Fc[itype][ipin][iseg] += fac; + connections_remaining -= fac; + } else { + VTR_ASSERT(connections_remaining == 0); + break; } } + } + if (segment_inf[iseg].parallel_axis != e_parallel_axis::Z_AXIS) { for (int ipin : fc_spec.pins) { // It is possible that we may want more connections that wires of this type exist; // clip to the maximum number of wires @@ -1515,13 +1529,21 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder *Fc_clipped = true; } } - - // Create the actual OPIN->CHANX/CHANY edges - uniquify_edges(rr_edges_to_create); - alloc_and_load_edges(rr_graph_builder, rr_edges_to_create); - num_edges += rr_edges_to_create.size(); - rr_edges_to_create.clear(); } + + add_edges_opin_chanz(rr_graph_builder, rr_graph, + layer, i, j, + Fc_out, + seg_index_map, + num_seg_types, + rr_edges_to_create, + interdie_3d_links[i][j]); + + // Create the actual OPIN->CHANX/CHANY edges + uniquify_edges(rr_edges_to_create); + alloc_and_load_edges(rr_graph_builder, rr_edges_to_create); + num_edges += rr_edges_to_create.size(); + rr_edges_to_create.clear(); } } } @@ -2800,6 +2822,57 @@ static vtr::NdMatrix, 4> alloc_and_load_track_to_pin_lookup(vtr return track_to_pin_lookup; } +static void add_edges_opin_chanz(RRGraphBuilder& rr_graph_builder, + const RRGraphView& rr_graph, + int layer, int x, int y, + const std::vector>& Fc_out, + const t_unified_to_parallel_seg_index& seg_index_map, + int num_seg_types, + t_rr_edge_info_set& rr_edges_to_create, + const std::vector& interdie_3d_links) { + const RRSpatialLookup& node_lookup = rr_graph.node_lookup(); + const DeviceGrid& grid = g_vpr_ctx.device().grid; + + t_physical_tile_type_ptr type = grid.get_physical_type({x, y, layer}); + + std::vector opin_nodes = node_lookup.find_grid_nodes_at_all_sides(layer, x, y, e_rr_type::OPIN); + std::ranges::stable_sort(opin_nodes, std::less<>{}, [](RRNodeId id) noexcept { return size_t(id); }); + // Remove adjacent duplicates + auto [unique_end, _] = std::ranges::unique(opin_nodes); + opin_nodes.erase(unique_end, opin_nodes.end()); + + std::vector> selected_chanz_nodes; + + for (int iseg = 0; iseg < num_seg_types; iseg++) { + int seg_index = get_parallel_seg_index(iseg, seg_index_map, e_parallel_axis::Z_AXIS); + if (seg_index < 0) { + continue; + } + + selected_chanz_nodes.clear(); + for (size_t track_num = 0; track_num < interdie_3d_links.size(); track_num++) { + const t_bottleneck_link& bottleneck_link = interdie_3d_links[track_num]; + if (bottleneck_link.parallel_segment_index == seg_index && bottleneck_link.gather_loc.layer_num == layer) { + RRNodeId node_id = node_lookup.find_node(layer, x, y, e_rr_type::CHANZ, track_num); + selected_chanz_nodes.push_back({node_id, bottleneck_link.arch_wire_switch}); + } + } + + int chanz_idx = 0; + for (RRNodeId opin_node_id : opin_nodes) { + int pin_number = rr_graph.node_pin_num(opin_node_id); + int fc = Fc_out[type->index][pin_number][iseg]; + + for (int i = 0; i < fc; i++) { + RRNodeId chanz_node_id = selected_chanz_nodes[chanz_idx % selected_chanz_nodes.size()].first; + short switch_id = selected_chanz_nodes[chanz_idx % selected_chanz_nodes.size()].second; + chanz_idx++; + rr_edges_to_create.emplace_back(opin_node_id, chanz_node_id, switch_id, false); + } + } + } +} + static void build_unidir_rr_opins(RRGraphBuilder& rr_graph_builder, const RRGraphView& rr_graph, const int layer, @@ -2824,7 +2897,6 @@ static void build_unidir_rr_opins(RRGraphBuilder& rr_graph_builder, *Fc_clipped = false; t_physical_tile_type_ptr type = grid.get_physical_type({i, j, layer}); - int width_offset = grid.get_width_offset({i, j, layer}); int height_offset = grid.get_height_offset({i, j, layer}); From f747061acc8edec4b9d47181a579e61fa9be8d47 Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Sat, 1 Nov 2025 15:03:17 -0400 Subject: [PATCH 12/32] move get_parallel_seg_index() to get_parallel_sets.cpp --- libs/librrgraph/src/base/get_parallel_segs.cpp | 15 +++++++++++++++ libs/librrgraph/src/base/get_parallel_segs.h | 4 ++++ vpr/src/route/rr_graph_generation/rr_graph2.cpp | 15 --------------- vpr/src/route/rr_graph_generation/rr_graph2.h | 4 ---- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/libs/librrgraph/src/base/get_parallel_segs.cpp b/libs/librrgraph/src/base/get_parallel_segs.cpp index 9f3738d895..8f9b780955 100644 --- a/libs/librrgraph/src/base/get_parallel_segs.cpp +++ b/libs/librrgraph/src/base/get_parallel_segs.cpp @@ -22,3 +22,18 @@ std::vector get_parallel_segs(const std::vector& s } return result; } + +int get_parallel_seg_index(const int abs_index, + const t_unified_to_parallel_seg_index& index_map, + const e_parallel_axis parallel_axis) { + int index = -1; + auto itr_pair = index_map.equal_range(abs_index); + + for (auto itr = itr_pair.first; itr != itr_pair.second; ++itr) { + if (itr->second.second == parallel_axis) { + index = itr->second.first; + } + } + + return index; +} diff --git a/libs/librrgraph/src/base/get_parallel_segs.h b/libs/librrgraph/src/base/get_parallel_segs.h index 19fc84be1c..f06670d8c0 100644 --- a/libs/librrgraph/src/base/get_parallel_segs.h +++ b/libs/librrgraph/src/base/get_parallel_segs.h @@ -21,3 +21,7 @@ std::vector get_parallel_segs(const std::vector& s t_unified_to_parallel_seg_index& seg_index_map, e_parallel_axis parallel_axis, bool keep_original_index = false); + +int get_parallel_seg_index(const int abs, + const t_unified_to_parallel_seg_index& index_map, + const e_parallel_axis parallel_axis); \ No newline at end of file diff --git a/vpr/src/route/rr_graph_generation/rr_graph2.cpp b/vpr/src/route/rr_graph_generation/rr_graph2.cpp index 582655371a..124eb1f817 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph2.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph2.cpp @@ -235,21 +235,6 @@ std::vector get_seg_track_counts(int num_sets, return result; } -int get_parallel_seg_index(const int abs_index, - const t_unified_to_parallel_seg_index& index_map, - const e_parallel_axis parallel_axis) { - int index = -1; - auto itr_pair = index_map.equal_range(abs_index); - - for (auto itr = itr_pair.first; itr != itr_pair.second; ++itr) { - if (itr->second.second == parallel_axis) { - index = itr->second.first; - } - } - - return index; -} - std::vector alloc_and_load_seg_details(int* max_chan_width, const int max_len, const std::vector& segment_inf, diff --git a/vpr/src/route/rr_graph_generation/rr_graph2.h b/vpr/src/route/rr_graph_generation/rr_graph2.h index 1693d1a4a5..d64fffba2a 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph2.h +++ b/vpr/src/route/rr_graph_generation/rr_graph2.h @@ -140,10 +140,6 @@ void load_sblock_pattern_lookup(const int i, const enum e_switch_block_type switch_block_type, t_sblock_pattern& sblock_pattern); -int get_parallel_seg_index(const int abs, - const t_unified_to_parallel_seg_index& index_map, - const e_parallel_axis parallel_axis); - /** * @brief Assigns routing tracks to each segment type based on their frequencies and lengths. * From 230fead795e7ee75c80fa72dc31b62a54fe76970 Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Sat, 1 Nov 2025 15:04:02 -0400 Subject: [PATCH 13/32] move add_edges_opin_chanz to rr_graph_3d --- .../route/rr_graph_generation/rr_graph.cpp | 75 ++----------------- vpr/src/route/rr_graph_generation/rr_graph.h | 1 - .../route/rr_graph_generation/rr_graph_3d.cpp | 51 +++++++++++++ .../route/rr_graph_generation/rr_graph_3d.h | 11 +++ .../tileable_rr_graph_builder.cpp | 4 +- 5 files changed, 71 insertions(+), 71 deletions(-) diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index 89c8b58c85..e40c195818 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -87,22 +87,14 @@ static vtr::NdMatrix, 4> alloc_and_load_pin_to_track_map(const const std::vector& seg_inf, const std::vector& sets_per_seg_type); -static void add_edges_opin_chanz(RRGraphBuilder& rr_graph_builder, - const RRGraphView& rr_graph, - int layer, int x, int y, - const std::vector>& Fc_out, - const t_unified_to_parallel_seg_index& seg_index_map, - int num_seg_types, - t_rr_edge_info_set& rr_edges_to_create, - const std::vector& interdie_3d_links); /** * @brief This routine calculates pin connections to tracks for a specific type and a specific segment based on the Fc value * defined for each pin in the architecture file. This routine is called twice for each combination of block type and segment * type: 1) connecting tracks to input pins 2) connecting output pins to tracks. * * @param pin_type Specifies whether the routine should connect tracks to *INPUT* pins or connect *OUTPUT* pins to tracks. - * @param Fc Actual Fc value described in the architecture file for all pins of the specific phyiscal type ([0..number_of_pins-1][0..number_of_segments_types-1]). - * @param seg_type_tracks Number of tracks that is avaliable for the specific segment type. + * @param Fc Actual Fc value described in the architecture file for all pins of the specific physical type ([0..number_of_pins-1][0..number_of_segments_types-1]). + * @param seg_type_tracks Number of tracks that is available for the specific segment type. * @param seg_index The index of the segment type to which the function tries to connect pins. * @param max_Fc Used to allocate max possible space for simplicity. * @param tile_type Physical type information, such as total number of pins, block width, block height, and etc. @@ -110,7 +102,6 @@ static void add_edges_opin_chanz(RRGraphBuilder& rr_graph_builder, * @param directionality Segment directionality, should be either *UNI-DIRECTIONAL* or *BI-DIRECTIONAL* * * @return an 5D matrix which keeps the track indices connected to each pin ([0..num_pins-1][0..width-1][0..height-1][0..layer-1][0..sides-1][0..Fc_to_curr_seg_type-1]). - * */ static vtr::NdMatrix alloc_and_load_pin_to_seg_type(const e_pin_type pin_type, const vtr::Matrix& Fc, @@ -791,13 +782,13 @@ static void build_rr_graph(e_graph_type graph_type, Fc_out = std::vector>(types.size(), ones); } else { bool Fc_clipped = false; - Fc_in = alloc_and_load_actual_fc(types, max_pins, segment_inf, sets_per_seg_type, &nodes_per_chan, + Fc_in = alloc_and_load_actual_fc(types, max_pins, segment_inf, sets_per_seg_type, e_fc_type::IN, directionality, &Fc_clipped, is_flat); if (Fc_clipped) { *Warnings |= RR_GRAPH_WARN_FC_CLIPPED; } Fc_clipped = false; - Fc_out = alloc_and_load_actual_fc(types, max_pins, segment_inf, sets_per_seg_type, &nodes_per_chan, + Fc_out = alloc_and_load_actual_fc(types, max_pins, segment_inf, sets_per_seg_type, e_fc_type::OUT, directionality, &Fc_clipped, is_flat); if (Fc_clipped) { *Warnings |= RR_GRAPH_WARN_FC_CLIPPED; @@ -1218,7 +1209,7 @@ static std::vector> alloc_and_load_perturb_ipins(const int L_n const std::vector& sets_per_seg_type, const std::vector>& Fc_in, const std::vector>& Fc_out, - const enum e_directionality directionality) { + const e_directionality directionality) { std::vector> result(L_num_types); for (std::vector& seg_type_bools : result) { seg_type_bools.resize(num_seg_types, false); @@ -1293,7 +1284,6 @@ std::vector> alloc_and_load_actual_fc(const std::vector& segment_inf, const std::vector& sets_per_seg_type, - const t_chan_width* nodes_per_chan, const e_fc_type fc_type, const e_directionality directionality, bool* Fc_clipped, @@ -1531,8 +1521,8 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder } } - add_edges_opin_chanz(rr_graph_builder, rr_graph, - layer, i, j, + add_edges_opin_chanz(rr_graph, + layer, i, j, Fc_out, seg_index_map, num_seg_types, @@ -2822,57 +2812,6 @@ static vtr::NdMatrix, 4> alloc_and_load_track_to_pin_lookup(vtr return track_to_pin_lookup; } -static void add_edges_opin_chanz(RRGraphBuilder& rr_graph_builder, - const RRGraphView& rr_graph, - int layer, int x, int y, - const std::vector>& Fc_out, - const t_unified_to_parallel_seg_index& seg_index_map, - int num_seg_types, - t_rr_edge_info_set& rr_edges_to_create, - const std::vector& interdie_3d_links) { - const RRSpatialLookup& node_lookup = rr_graph.node_lookup(); - const DeviceGrid& grid = g_vpr_ctx.device().grid; - - t_physical_tile_type_ptr type = grid.get_physical_type({x, y, layer}); - - std::vector opin_nodes = node_lookup.find_grid_nodes_at_all_sides(layer, x, y, e_rr_type::OPIN); - std::ranges::stable_sort(opin_nodes, std::less<>{}, [](RRNodeId id) noexcept { return size_t(id); }); - // Remove adjacent duplicates - auto [unique_end, _] = std::ranges::unique(opin_nodes); - opin_nodes.erase(unique_end, opin_nodes.end()); - - std::vector> selected_chanz_nodes; - - for (int iseg = 0; iseg < num_seg_types; iseg++) { - int seg_index = get_parallel_seg_index(iseg, seg_index_map, e_parallel_axis::Z_AXIS); - if (seg_index < 0) { - continue; - } - - selected_chanz_nodes.clear(); - for (size_t track_num = 0; track_num < interdie_3d_links.size(); track_num++) { - const t_bottleneck_link& bottleneck_link = interdie_3d_links[track_num]; - if (bottleneck_link.parallel_segment_index == seg_index && bottleneck_link.gather_loc.layer_num == layer) { - RRNodeId node_id = node_lookup.find_node(layer, x, y, e_rr_type::CHANZ, track_num); - selected_chanz_nodes.push_back({node_id, bottleneck_link.arch_wire_switch}); - } - } - - int chanz_idx = 0; - for (RRNodeId opin_node_id : opin_nodes) { - int pin_number = rr_graph.node_pin_num(opin_node_id); - int fc = Fc_out[type->index][pin_number][iseg]; - - for (int i = 0; i < fc; i++) { - RRNodeId chanz_node_id = selected_chanz_nodes[chanz_idx % selected_chanz_nodes.size()].first; - short switch_id = selected_chanz_nodes[chanz_idx % selected_chanz_nodes.size()].second; - chanz_idx++; - rr_edges_to_create.emplace_back(opin_node_id, chanz_node_id, switch_id, false); - } - } - } -} - static void build_unidir_rr_opins(RRGraphBuilder& rr_graph_builder, const RRGraphView& rr_graph, const int layer, diff --git a/vpr/src/route/rr_graph_generation/rr_graph.h b/vpr/src/route/rr_graph_generation/rr_graph.h index 4aca0d82b7..da462d575d 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.h +++ b/vpr/src/route/rr_graph_generation/rr_graph.h @@ -52,7 +52,6 @@ std::vector> alloc_and_load_actual_fc(const std::vector& segment_inf, const std::vector& sets_per_seg_type, - const t_chan_width* nodes_per_chan, const e_fc_type fc_type, const e_directionality directionality, bool* Fc_clipped, diff --git a/vpr/src/route/rr_graph_generation/rr_graph_3d.cpp b/vpr/src/route/rr_graph_generation/rr_graph_3d.cpp index 6ed0e9d61e..2fe2bf6bf3 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_3d.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph_3d.cpp @@ -5,6 +5,7 @@ #include "rr_rc_data.h" #include "build_scatter_gathers.h" #include "globals.h" +#include "get_parallel_segs.h" void add_inter_die_3d_edges(RRGraphBuilder& rr_graph_builder, int x_coord, @@ -98,3 +99,53 @@ void build_inter_die_3d_rr_chan(RRGraphBuilder& rr_graph_builder, } } } + +void add_edges_opin_chanz(const RRGraphView& rr_graph, + int layer, int x, int y, + const std::vector>& Fc_out, + const t_unified_to_parallel_seg_index& seg_index_map, + int num_seg_types, + t_rr_edge_info_set& rr_edges_to_create, + const std::vector& interdie_3d_links) { + const RRSpatialLookup& node_lookup = rr_graph.node_lookup(); + const DeviceGrid& grid = g_vpr_ctx.device().grid; + + t_physical_tile_type_ptr type = grid.get_physical_type({x, y, layer}); + + std::vector opin_nodes = node_lookup.find_grid_nodes_at_all_sides(layer, x, y, e_rr_type::OPIN); + std::ranges::stable_sort(opin_nodes, std::less<>{}, [](RRNodeId id) noexcept { return size_t(id); }); + // Remove adjacent duplicates + auto [unique_end, _] = std::ranges::unique(opin_nodes); + opin_nodes.erase(unique_end, opin_nodes.end()); + + std::vector> selected_chanz_nodes; + + for (int iseg = 0; iseg < num_seg_types; iseg++) { + int seg_index = get_parallel_seg_index(iseg, seg_index_map, e_parallel_axis::Z_AXIS); + if (seg_index < 0) { + continue; + } + + selected_chanz_nodes.clear(); + for (size_t track_num = 0; track_num < interdie_3d_links.size(); track_num++) { + const t_bottleneck_link& bottleneck_link = interdie_3d_links[track_num]; + if (bottleneck_link.parallel_segment_index == seg_index && bottleneck_link.gather_loc.layer_num == layer) { + RRNodeId node_id = node_lookup.find_node(layer, x, y, e_rr_type::CHANZ, track_num); + selected_chanz_nodes.push_back({node_id, bottleneck_link.arch_wire_switch}); + } + } + + int chanz_idx = 0; + for (RRNodeId opin_node_id : opin_nodes) { + int pin_number = rr_graph.node_pin_num(opin_node_id); + int fc = Fc_out[type->index][pin_number][iseg]; + + for (int i = 0; i < fc; i++) { + RRNodeId chanz_node_id = selected_chanz_nodes[chanz_idx % selected_chanz_nodes.size()].first; + short switch_id = selected_chanz_nodes[chanz_idx % selected_chanz_nodes.size()].second; + chanz_idx++; + rr_edges_to_create.emplace_back(opin_node_id, chanz_node_id, switch_id, false); + } + } + } +} \ No newline at end of file diff --git a/vpr/src/route/rr_graph_generation/rr_graph_3d.h b/vpr/src/route/rr_graph_generation/rr_graph_3d.h index 39bb6a3432..5154f82d12 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_3d.h +++ b/vpr/src/route/rr_graph_generation/rr_graph_3d.h @@ -4,8 +4,10 @@ #include #include "rr_types.h" #include "rr_edge.h" +#include "rr_graph_type.h" class RRGraphBuilder; +class RRGraphView; struct t_bottleneck_link; /** @@ -28,3 +30,12 @@ void add_inter_die_3d_edges(RRGraphBuilder& rr_graph_builder, const t_chan_details& chan_details_y, const std::vector& interdie_3d_links, t_rr_edge_info_set& interdie_3d_rr_edges_to_create); + + +void add_edges_opin_chanz(const RRGraphView& rr_graph, + int layer, int x, int y, + const std::vector>& Fc_out, + const t_unified_to_parallel_seg_index& seg_index_map, + int num_seg_types, + t_rr_edge_info_set& rr_edges_to_create, + const std::vector& interdie_3d_links); diff --git a/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_builder.cpp b/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_builder.cpp index 1de177f97a..720464b06c 100644 --- a/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_builder.cpp +++ b/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_builder.cpp @@ -223,7 +223,7 @@ void build_tileable_unidir_rr_graph(const std::vector& typ bool Fc_clipped = false; // [0..num_types-1][0..num_pins-1] std::vector> Fc_in; - Fc_in = alloc_and_load_actual_fc(types, max_pins, segment_inf, sets_per_seg_type, &chan_width, + Fc_in = alloc_and_load_actual_fc(types, max_pins, segment_inf, sets_per_seg_type, e_fc_type::IN, UNI_DIRECTIONAL, &Fc_clipped, false); if (Fc_clipped) { *Warnings |= RR_GRAPH_WARN_FC_CLIPPED; @@ -232,7 +232,7 @@ void build_tileable_unidir_rr_graph(const std::vector& typ Fc_clipped = false; // [0..num_types-1][0..num_pins-1] std::vector> Fc_out; - Fc_out = alloc_and_load_actual_fc(types, max_pins, segment_inf, sets_per_seg_type, &chan_width, + Fc_out = alloc_and_load_actual_fc(types, max_pins, segment_inf, sets_per_seg_type, e_fc_type::OUT, UNI_DIRECTIONAL, &Fc_clipped, false); if (Fc_clipped) { From 0097c569dc36eb0ae7c8057d98b91312fdab0500 Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Sat, 1 Nov 2025 15:16:37 -0400 Subject: [PATCH 14/32] remove pins_connected() function and rename rr_graph_3d files to rr_graph_sg --- .../route/rr_graph_generation/rr_graph.cpp | 61 +------------------ vpr/src/route/rr_graph_generation/rr_graph.h | 6 -- .../{rr_graph_3d.cpp => rr_graph_sg.cpp} | 2 +- .../{rr_graph_3d.h => rr_graph_sg.h} | 0 4 files changed, 2 insertions(+), 67 deletions(-) rename vpr/src/route/rr_graph_generation/{rr_graph_3d.cpp => rr_graph_sg.cpp} (99%) rename vpr/src/route/rr_graph_generation/{rr_graph_3d.h => rr_graph_sg.h} (100%) diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index e40c195818..279c2f70cd 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -33,7 +33,7 @@ #include "rr_graph_sbox.h" #include "rr_graph_intra_cluster.h" #include "rr_graph_tile_nodes.h" -#include "rr_graph_3d.h" +#include "rr_graph_sg.h" #include "rr_graph_timing_params.h" #include "check_rr_graph.h" #include "echo_files.h" @@ -3247,65 +3247,6 @@ t_non_configurable_rr_sets identify_non_configurable_rr_sets() { return groups.output_sets(); } -bool pins_connected(t_block_loc cluster_loc, - t_physical_tile_type_ptr physical_type, - t_logical_block_type_ptr logical_block, - int from_pin_logical_num, - int to_pin_logical_num) { - const auto& rr_graph = g_vpr_ctx.device().rr_graph; - const auto& rr_spatial_look_up = rr_graph.node_lookup(); - - t_physical_tile_loc loc; - loc.x = cluster_loc.loc.x; - loc.y = cluster_loc.loc.y; - loc.layer_num = cluster_loc.loc.layer; - int abs_cap = cluster_loc.loc.sub_tile; - const t_sub_tile* sub_tile = nullptr; - - for (const t_sub_tile& sub_tile_ : physical_type->sub_tiles) { - if (sub_tile_.capacity.is_in_range(abs_cap)) { - sub_tile = &sub_tile_; - break; - } - } - VTR_ASSERT(sub_tile != nullptr); - int rel_cap = abs_cap - sub_tile->capacity.low; - VTR_ASSERT(rel_cap >= 0); - - auto from_pb_pin = logical_block->pin_logical_num_to_pb_pin_mapping.at(from_pin_logical_num); - int from_pin_physical_num = get_pb_pin_physical_num(physical_type, - sub_tile, - logical_block, - rel_cap, - from_pb_pin); - VTR_ASSERT(from_pin_physical_num != UNDEFINED); - - auto to_pb_pin = logical_block->pin_logical_num_to_pb_pin_mapping.at(to_pin_logical_num); - int to_pin_physical_num = get_pb_pin_physical_num(physical_type, - sub_tile, - logical_block, - rel_cap, - to_pb_pin); - - VTR_ASSERT(to_pin_physical_num != UNDEFINED); - - RRNodeId from_node = get_pin_rr_node_id(rr_spatial_look_up, physical_type, loc, from_pin_physical_num); - VTR_ASSERT(from_node != RRNodeId::INVALID()); - - RRNodeId to_node = get_pin_rr_node_id(rr_spatial_look_up, physical_type, loc, to_pin_physical_num); - VTR_ASSERT(to_node != RRNodeId::INVALID()); - - int num_edges = rr_graph.num_edges(from_node); - - for (int iedge = 0; iedge < num_edges; iedge++) { - RRNodeId sink_node = rr_graph.edge_sink_node(from_node, iedge); - if (sink_node == to_node) { - return true; - } - } - return false; -} - static void process_non_config_sets() { auto& device_ctx = g_vpr_ctx.mutable_device(); EdgeGroups groups; diff --git a/vpr/src/route/rr_graph_generation/rr_graph.h b/vpr/src/route/rr_graph_generation/rr_graph.h index da462d575d..f1bc55958b 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.h +++ b/vpr/src/route/rr_graph_generation/rr_graph.h @@ -58,9 +58,3 @@ std::vector> alloc_and_load_actual_fc(const std::vector Date: Sat, 1 Nov 2025 15:21:33 -0400 Subject: [PATCH 15/32] move add_and_connect_non_3d_sg_links() to rr_graph_sg --- .../route/rr_graph_generation/rr_graph.cpp | 110 ------------------ .../route/rr_graph_generation/rr_graph_sg.cpp | 86 ++++++++++++++ .../route/rr_graph_generation/rr_graph_sg.h | 24 ++++ 3 files changed, 110 insertions(+), 110 deletions(-) diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index 279c2f70cd..2261bc6408 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -360,30 +360,6 @@ static void build_rr_graph(e_graph_type graph_type, static int get_delayless_switch_id(const t_det_routing_arch& det_routing_arch, bool load_rr_graph); -/** - * @brief Adds and connects non-3D scatter–gather (SG) links to the RR graph. - * - * For each bottleneck link, this function creates a corresponding RR node - * representing the non-3D SG link, and records edges between the node and - * gather and scatter wires. The edges are stored in `non_3d_sg_rr_edges_to_create` - * for deferred creation. - * - * @param rr_graph_builder Reference to the RR graph builder. - * @param sg_links List of scatter–gather bottleneck links. - * @param sg_node_indices RR node IDs and track numbers for SG links. - * @param chan_details_x Channel details for CHANX segments. - * @param chan_details_y Channel details for CHANY segments. - * @param num_seg_types_x Number of segment types in the X direction. - * @param non_3d_sg_rr_edges_to_create Set collecting RR edges to create later. - */ -static void add_and_connect_non_3d_sg_links(RRGraphBuilder& rr_graph_builder, - const std::vector& sg_links, - const std::vector>& sg_node_indices, - const t_chan_details& chan_details_x, - const t_chan_details& chan_details_y, - size_t num_seg_types_x, - t_rr_edge_info_set& non_3d_sg_rr_edges_to_create); - /** * @brief Calculates the routing channel width at each grid location. * @@ -2001,92 +1977,6 @@ static void build_rr_chan(RRGraphBuilder& rr_graph_builder, } } -static void add_and_connect_non_3d_sg_links(RRGraphBuilder& rr_graph_builder, - const std::vector& sg_links, - const std::vector>& sg_node_indices, - const t_chan_details& chan_details_x, - const t_chan_details& chan_details_y, - size_t num_seg_types_x, - t_rr_edge_info_set& non_3d_sg_rr_edges_to_create) { - // Each SG link should have a corresponding RR node index - VTR_ASSERT(sg_links.size() == sg_node_indices.size()); - const size_t num_links = sg_links.size(); - - for (size_t i = 0; i < num_links; i++) { - - const t_bottleneck_link& link = sg_links[i]; - - int xlow, xhigh, ylow, yhigh; - Direction direction; - e_rr_type chan_type; - const t_physical_tile_loc& src_loc = link.gather_loc; - const t_physical_tile_loc& dst_loc = link.scatter_loc; - - // Step 1: Determine the link’s direction and its spatial span. - // SG links are confined to one layer (non-3D), but can run in X or Y. - VTR_ASSERT_SAFE(src_loc.layer_num == dst_loc.layer_num); - const int layer = src_loc.layer_num; - compute_non_3d_sg_link_geometry(src_loc, dst_loc, chan_type, xlow, xhigh, ylow, yhigh,direction); - - // Retrieve the node ID and track number allocated earlier - const RRNodeId node_id = sg_node_indices[i].first; - const int track_num = sg_node_indices[i].second; - - // Step 2: Assign coordinates - rr_graph_builder.set_node_layer(node_id, layer, layer); - rr_graph_builder.set_node_coordinates(node_id, xlow, ylow, xhigh, yhigh); - rr_graph_builder.set_node_capacity(node_id, 1); - - // Step 3: Set cost index based on segment type and orientation - const size_t cons_index = link.chan_type == e_rr_type::CHANX ? CHANX_COST_INDEX_START + link.parallel_segment_index - : CHANX_COST_INDEX_START + num_seg_types_x + link.parallel_segment_index; - rr_graph_builder.set_node_cost_index(node_id, RRIndexedDataId(cons_index)); - - // Step 4: Assign electrical characteristics - const NodeRCIndex rc_index = find_create_rr_rc_data(link.R_metal, link.C_metal, g_vpr_ctx.mutable_device().rr_rc_data); - rr_graph_builder.set_node_rc_index(node_id, rc_index); - // Step 5: Set node type, track number, and direction - rr_graph_builder.set_node_type(node_id, link.chan_type); - rr_graph_builder.set_node_track_num(node_id, track_num); - rr_graph_builder.set_node_direction(node_id, direction); - - // Step 6: Add incoming edges from gather (fanin) channel wires - // Each gather wire connects to this SG link node using the SG wire switch. - for (const t_sg_candidate& gather_wire : link.gather_fanin_connections) { - const t_physical_tile_loc& chan_loc = gather_wire.chan_loc.location; - e_rr_type gather_chan_type = gather_wire.chan_loc.chan_type; - - // Locate the source RR node for this gather wire - RRNodeId gather_node = rr_graph_builder.node_lookup().find_node(chan_loc.layer_num, - chan_loc.x, - chan_loc.y, - gather_chan_type, - gather_wire.wire_switchpoint.wire); - // Record deferred edge creation (gather_node --> sg_node) - non_3d_sg_rr_edges_to_create.emplace_back(gather_node, node_id, link.arch_wire_switch, false); - } - - // Step 7: Add outgoing edges to scatter (fanout) channel wires - // Each scatter wire connects from this SG link node outward. - for (const t_sg_candidate& scatter_wire : link.scatter_fanout_connections) { - const t_physical_tile_loc& chan_loc = scatter_wire.chan_loc.location; - e_rr_type scatter_chan_type = scatter_wire.chan_loc.chan_type; - const t_chan_details& chan_details = (scatter_chan_type == e_rr_type::CHANX) ? chan_details_x : chan_details_y; - - // Locate the destination RR node for this scatter wire - RRNodeId scatter_node = rr_graph_builder.node_lookup().find_node(chan_loc.layer_num, - chan_loc.x, - chan_loc.y, - scatter_chan_type, - scatter_wire.wire_switchpoint.wire); - // Determine which architecture switch this edge should use - int switch_index = chan_details[chan_loc.x][chan_loc.y][scatter_wire.wire_switchpoint.wire].arch_wire_switch(); - // Record deferred edge creation (sg_node --> scatter_node) - non_3d_sg_rr_edges_to_create.emplace_back(node_id, scatter_node, switch_index, false); - } - } -} - void alloc_and_load_edges(RRGraphBuilder& rr_graph_builder, const t_rr_edge_info_set& rr_edges_to_create) { rr_graph_builder.alloc_and_load_edges(&rr_edges_to_create); } diff --git a/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp b/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp index f8a001fee5..ee0891a976 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp @@ -148,4 +148,90 @@ void add_edges_opin_chanz(const RRGraphView& rr_graph, } } } +} + +void add_and_connect_non_3d_sg_links(RRGraphBuilder& rr_graph_builder, + const std::vector& sg_links, + const std::vector>& sg_node_indices, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + size_t num_seg_types_x, + t_rr_edge_info_set& non_3d_sg_rr_edges_to_create) { + // Each SG link should have a corresponding RR node index + VTR_ASSERT(sg_links.size() == sg_node_indices.size()); + const size_t num_links = sg_links.size(); + + for (size_t i = 0; i < num_links; i++) { + + const t_bottleneck_link& link = sg_links[i]; + + int xlow, xhigh, ylow, yhigh; + Direction direction; + e_rr_type chan_type; + const t_physical_tile_loc& src_loc = link.gather_loc; + const t_physical_tile_loc& dst_loc = link.scatter_loc; + + // Step 1: Determine the link’s direction and its spatial span. + // SG links are confined to one layer (non-3D), but can run in X or Y. + VTR_ASSERT_SAFE(src_loc.layer_num == dst_loc.layer_num); + const int layer = src_loc.layer_num; + compute_non_3d_sg_link_geometry(src_loc, dst_loc, chan_type, xlow, xhigh, ylow, yhigh,direction); + + // Retrieve the node ID and track number allocated earlier + const RRNodeId node_id = sg_node_indices[i].first; + const int track_num = sg_node_indices[i].second; + + // Step 2: Assign coordinates + rr_graph_builder.set_node_layer(node_id, layer, layer); + rr_graph_builder.set_node_coordinates(node_id, xlow, ylow, xhigh, yhigh); + rr_graph_builder.set_node_capacity(node_id, 1); + + // Step 3: Set cost index based on segment type and orientation + const size_t cons_index = link.chan_type == e_rr_type::CHANX ? CHANX_COST_INDEX_START + link.parallel_segment_index + : CHANX_COST_INDEX_START + num_seg_types_x + link.parallel_segment_index; + rr_graph_builder.set_node_cost_index(node_id, RRIndexedDataId(cons_index)); + + // Step 4: Assign electrical characteristics + const NodeRCIndex rc_index = find_create_rr_rc_data(link.R_metal, link.C_metal, g_vpr_ctx.mutable_device().rr_rc_data); + rr_graph_builder.set_node_rc_index(node_id, rc_index); + // Step 5: Set node type, track number, and direction + rr_graph_builder.set_node_type(node_id, link.chan_type); + rr_graph_builder.set_node_track_num(node_id, track_num); + rr_graph_builder.set_node_direction(node_id, direction); + + // Step 6: Add incoming edges from gather (fanin) channel wires + // Each gather wire connects to this SG link node using the SG wire switch. + for (const t_sg_candidate& gather_wire : link.gather_fanin_connections) { + const t_physical_tile_loc& chan_loc = gather_wire.chan_loc.location; + e_rr_type gather_chan_type = gather_wire.chan_loc.chan_type; + + // Locate the source RR node for this gather wire + RRNodeId gather_node = rr_graph_builder.node_lookup().find_node(chan_loc.layer_num, + chan_loc.x, + chan_loc.y, + gather_chan_type, + gather_wire.wire_switchpoint.wire); + // Record deferred edge creation (gather_node --> sg_node) + non_3d_sg_rr_edges_to_create.emplace_back(gather_node, node_id, link.arch_wire_switch, false); + } + + // Step 7: Add outgoing edges to scatter (fanout) channel wires + // Each scatter wire connects from this SG link node outward. + for (const t_sg_candidate& scatter_wire : link.scatter_fanout_connections) { + const t_physical_tile_loc& chan_loc = scatter_wire.chan_loc.location; + e_rr_type scatter_chan_type = scatter_wire.chan_loc.chan_type; + const t_chan_details& chan_details = (scatter_chan_type == e_rr_type::CHANX) ? chan_details_x : chan_details_y; + + // Locate the destination RR node for this scatter wire + RRNodeId scatter_node = rr_graph_builder.node_lookup().find_node(chan_loc.layer_num, + chan_loc.x, + chan_loc.y, + scatter_chan_type, + scatter_wire.wire_switchpoint.wire); + // Determine which architecture switch this edge should use + int switch_index = chan_details[chan_loc.x][chan_loc.y][scatter_wire.wire_switchpoint.wire].arch_wire_switch(); + // Record deferred edge creation (sg_node --> scatter_node) + non_3d_sg_rr_edges_to_create.emplace_back(node_id, scatter_node, switch_index, false); + } + } } \ No newline at end of file diff --git a/vpr/src/route/rr_graph_generation/rr_graph_sg.h b/vpr/src/route/rr_graph_generation/rr_graph_sg.h index 5154f82d12..d85d84a8c1 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_sg.h +++ b/vpr/src/route/rr_graph_generation/rr_graph_sg.h @@ -39,3 +39,27 @@ void add_edges_opin_chanz(const RRGraphView& rr_graph, int num_seg_types, t_rr_edge_info_set& rr_edges_to_create, const std::vector& interdie_3d_links); + +/** + * @brief Adds and connects non-3D scatter–gather (SG) links to the RR graph. + * + * For each bottleneck link, this function creates a corresponding RR node + * representing the non-3D SG link, and records edges between the node and + * gather and scatter wires. The edges are stored in `non_3d_sg_rr_edges_to_create` + * for deferred creation. + * + * @param rr_graph_builder Reference to the RR graph builder. + * @param sg_links List of scatter–gather bottleneck links. + * @param sg_node_indices RR node IDs and track numbers for SG links. + * @param chan_details_x Channel details for CHANX segments. + * @param chan_details_y Channel details for CHANY segments. + * @param num_seg_types_x Number of segment types in the X direction. + * @param non_3d_sg_rr_edges_to_create Set collecting RR edges to create later. + */ +void add_and_connect_non_3d_sg_links(RRGraphBuilder& rr_graph_builder, + const std::vector& sg_links, + const std::vector>& sg_node_indices, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + size_t num_seg_types_x, + t_rr_edge_info_set& non_3d_sg_rr_edges_to_create); From 21dfd5dd44f341f489751465be71fca600a074cf Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Sat, 1 Nov 2025 22:59:24 -0400 Subject: [PATCH 16/32] noexcept for strongid methods --- libs/libvtrutil/src/vtr_strong_id.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/libvtrutil/src/vtr_strong_id.h b/libs/libvtrutil/src/vtr_strong_id.h index 48970bfaa1..909a1b08d6 100644 --- a/libs/libvtrutil/src/vtr_strong_id.h +++ b/libs/libvtrutil/src/vtr_strong_id.h @@ -160,10 +160,10 @@ class StrongId; * friend them */ template -constexpr bool operator==(const StrongId& lhs, const StrongId& rhs); +constexpr bool operator==(const StrongId& lhs, const StrongId& rhs) noexcept; template -constexpr bool operator!=(const StrongId& lhs, const StrongId& rhs); +constexpr bool operator!=(const StrongId& lhs, const StrongId& rhs) noexcept; template constexpr bool operator<(const StrongId& lhs, const StrongId& rhs) noexcept; @@ -211,9 +211,9 @@ class StrongId { * Note that since these are templated functions we provide an empty set of template parameters * after the function name (i.e. <>) */ - friend constexpr bool operator== <>(const StrongId& lhs, const StrongId& rhs); + friend constexpr bool operator== <>(const StrongId& lhs, const StrongId& rhs) noexcept; ///@brief != operator - friend constexpr bool operator!= <>(const StrongId& lhs, const StrongId& rhs); + friend constexpr bool operator!= <>(const StrongId& lhs, const StrongId& rhs) noexcept; ///@brief < operator friend constexpr bool operator< <>(const StrongId& lhs, const StrongId& rhs) noexcept; @@ -228,13 +228,13 @@ class StrongId { ///@brief == operator template -constexpr bool operator==(const StrongId& lhs, const StrongId& rhs) { +constexpr bool operator==(const StrongId& lhs, const StrongId& rhs) noexcept { return lhs.id_ == rhs.id_; } ///@brief != operator template -constexpr bool operator!=(const StrongId& lhs, const StrongId& rhs) { +constexpr bool operator!=(const StrongId& lhs, const StrongId& rhs) noexcept { return !(lhs == rhs); } From 6803792026f8b440d3db5fc5f229c1d4daf35669 Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Sat, 1 Nov 2025 23:01:07 -0400 Subject: [PATCH 17/32] use the correct layer for CHANZ nodes when initalizing src_opin_delays --- vpr/src/base/read_options.cpp | 2 +- .../place/delay_model/simple_delay_model.cpp | 8 ++-- .../route/router_lookahead/router_lookahead.h | 3 +- .../router_lookahead/router_lookahead_map.cpp | 33 ++++++------- .../router_lookahead_map_utils.cpp | 46 +++++++++---------- 5 files changed, 41 insertions(+), 51 deletions(-) diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index fca403f89e..40553f2d3d 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -1104,7 +1104,7 @@ struct ParseRouteBBUpdate { struct ParseRouterLookahead { ConvertedValue from_str(std::string str) { - std::transform(str.begin(), str.end(), str.begin(), ::tolower); + std::ranges::transform(str, str.begin(), ::tolower); ConvertedValue conv_value; if (str == "classic") conv_value.set_value(e_router_lookahead::CLASSIC); diff --git a/vpr/src/place/delay_model/simple_delay_model.cpp b/vpr/src/place/delay_model/simple_delay_model.cpp index 04d94b0fba..933a1944a5 100644 --- a/vpr/src/place/delay_model/simple_delay_model.cpp +++ b/vpr/src/place/delay_model/simple_delay_model.cpp @@ -13,7 +13,7 @@ void SimpleDelayModel::compute(RouterDelayProfiler& route_profiler, const t_placer_opts& /*placer_opts*/, const t_router_opts& /*router_opts*/, int /*longest_length*/) { - const auto& grid = g_vpr_ctx.device().grid; + const DeviceGrid& grid = g_vpr_ctx.device().grid; const size_t num_physical_tile_types = g_vpr_ctx.device().physical_tile_types.size(); const size_t num_layers = grid.get_num_layers(); @@ -31,10 +31,8 @@ void SimpleDelayModel::compute(RouterDelayProfiler& route_profiler, for (size_t dx = 0; dx < grid.width(); ++dx) { for (size_t dy = 0; dy < grid.height(); ++dy) { float min_delay = route_profiler.get_min_delay(physical_tile_type_idx, - from_layer, - to_layer, - dx, - dy); + from_layer, to_layer, + dx, dy); delays_[physical_tile_type_idx][from_layer][to_layer][dx][dy] = min_delay; } } diff --git a/vpr/src/route/router_lookahead/router_lookahead.h b/vpr/src/route/router_lookahead/router_lookahead.h index 0d1a0c73ac..0d49393776 100644 --- a/vpr/src/route/router_lookahead/router_lookahead.h +++ b/vpr/src/route/router_lookahead/router_lookahead.h @@ -66,7 +66,8 @@ class RouterLookahead { virtual void write_intra_cluster(const std::string& file) const = 0; /** - * @brief Retrieve the minimum delay to a point on the "to_layer," which is dx and dy away, across all the OPINs on the physical tile identified by "physical_tile_idx." + * @brief Retrieve the minimum delay to a point on the "to_layer," which is dx and dy away, + * across all the OPINs on the physical tile identified by "physical_tile_idx". * @param physical_tile_idx The index of the physical tile from which the cost is calculated * @param from_layer The layer that the tile is located on * @param to_layer The layer on which the destination is located diff --git a/vpr/src/route/router_lookahead/router_lookahead_map.cpp b/vpr/src/route/router_lookahead/router_lookahead_map.cpp index c7ea331f45..fe798cb54f 100644 --- a/vpr/src/route/router_lookahead/router_lookahead_map.cpp +++ b/vpr/src/route/router_lookahead/router_lookahead_map.cpp @@ -118,10 +118,8 @@ static void store_min_cost_to_sinks(std::unordered_map& distance_min_cost); /** - * @brief // Given the src/opin map of each physical tile type, iterate over all OPINs/sources of a type and create + * @brief Given the src/opin map of each physical tile type, iterate over all OPINs/sources of a type and create * the minimum cost map across all of them for each tile type. - * @param src_opin_delays - * @param distance_min_cost */ static void min_opin_distance_cost_map(const util::t_src_opin_delays& src_opin_delays, vtr::NdMatrix& distance_min_cost); @@ -390,8 +388,6 @@ std::pair MapLookahead::get_expected_delay_and_cong(RRNodeId from_ delta_x, delta_y, to_layer_num); - expected_delay_cost = cost_entry.delay; - expected_cong_cost = cost_entry.congestion; VTR_ASSERT_SAFE_MSG(std::isfinite(expected_delay_cost), vtr::string_fmt("Lookahead failed to estimate cost from %s: %s", @@ -835,13 +831,11 @@ static void min_chann_global_cost_map(vtr::NdMatrix& distan } static void min_opin_distance_cost_map(const util::t_src_opin_delays& src_opin_delays, vtr::NdMatrix& distance_min_cost) { - /** - * This function calculates and stores the minimum cost to reach a point on layer `n_sink`, which is `dx` and `dy` further from the current point - * on layer `n_source` and is located on physical tile type `t`. To compute this cost, the function iterates over all output pins of tile `t`, - * and for each pin, iterates over all segment types accessible by it. It then determines and stores the minimum cost to the destination point. - * "src_opin_delays" stores the routing segments accessible by each OPIN of each physical type on each layer. After getting the accessible segment types, - * "get_wire_cost_entry" is called to get the cost from that segment type to the destination point. - */ + // This function calculates and stores the minimum cost to reach a point on layer `n_sink`, which is `dx` and `dy` further from the current point + // on layer `n_source` and is located on physical tile type `t`. To compute this cost, the function iterates over all output pins of tile `t`, + // and for each pin, iterates over all segment types accessible by it. It then determines and stores the minimum cost to the destination point. + // "src_opin_delays" stores the routing segments accessible by each OPIN of each physical type on each layer. After getting the accessible segment types, + // "get_wire_cost_entry" is called to get the cost from that segment type to the destination point. int num_tile_types = g_vpr_ctx.device().physical_tile_types.size(); int num_layers = g_vpr_ctx.device().grid.get_num_layers(); int width = (int)g_vpr_ctx.device().grid.width(); @@ -874,14 +868,13 @@ static void min_opin_distance_cost_map(const util::t_src_opin_delays& src_opin_d if (reachable_wire_inf.wire_rr_type == e_rr_type::SINK) { continue; } - util::Cost_Entry wire_cost_entry; - - wire_cost_entry = get_wire_cost_entry(reachable_wire_inf.wire_rr_type, - reachable_wire_inf.wire_seg_index, - reachable_wire_inf.layer_number, - dx, - dy, - to_layer_num); + + util::Cost_Entry wire_cost_entry = get_wire_cost_entry(reachable_wire_inf.wire_rr_type, + reachable_wire_inf.wire_seg_index, + reachable_wire_inf.layer_number, + dx, + dy, + to_layer_num); float this_delay_cost = reachable_wire_inf.delay + wire_cost_entry.delay; float this_cong_cost = reachable_wire_inf.congestion + wire_cost_entry.congestion; diff --git a/vpr/src/route/router_lookahead/router_lookahead_map_utils.cpp b/vpr/src/route/router_lookahead/router_lookahead_map_utils.cpp index 524b53c717..9c6f7ef949 100644 --- a/vpr/src/route/router_lookahead/router_lookahead_map_utils.cpp +++ b/vpr/src/route/router_lookahead/router_lookahead_map_utils.cpp @@ -11,6 +11,7 @@ * To access the utility functions, the util namespace needs to be used. */ #include +#include #include "globals.h" #include "physical_types_util.h" #include "vpr_context.h" @@ -372,8 +373,7 @@ t_src_opin_delays compute_router_src_opin_lookahead(bool is_flat, int num_layers = device_ctx.grid.get_num_layers(); - t_src_opin_delays src_opin_delays; - src_opin_delays.resize(num_layers); + t_src_opin_delays src_opin_delays(num_layers); std::vector tile_max_ptc(device_ctx.physical_tile_types.size(), UNDEFINED); // Get the maximum OPIN ptc for each tile type to reserve src_opin_delays @@ -392,8 +392,8 @@ t_src_opin_delays compute_router_src_opin_lookahead(bool is_flat, } } - //We assume that the routing connectivity of each instance of a physical tile is the same, - //and so only measure one instance of each type + // We assume that the routing connectivity of each instance of a physical tile is the same, + // and so only measure one instance of each type for (int from_layer_num = 0; from_layer_num < num_layers; from_layer_num++) { for (size_t itile = 0; itile < device_ctx.physical_tile_types.size(); ++itile) { if (device_ctx.grid.num_instances(&device_ctx.physical_tile_types[itile], from_layer_num) == 0) { @@ -430,11 +430,9 @@ t_src_opin_delays compute_router_src_opin_lookahead(bool is_flat, VTR_ASSERT(ptc < int(src_opin_delays[from_layer_num][itile].size())); - //Find the wire types which are reachable from inode and record them and - //the cost to reach them - dijkstra_flood_to_wires(itile, - node_id, - src_opin_delays); + // Find the wire types which are reachable from inode and record them and + // the cost to reach them + dijkstra_flood_to_wires(itile, node_id, src_opin_delays); bool reachable_wire_found = false; for (int to_layer_num = 0; to_layer_num < num_layers; to_layer_num++) { @@ -876,7 +874,7 @@ std::pair get_cost_from_src_opin(const std::map Date: Sun, 2 Nov 2025 16:15:21 -0500 Subject: [PATCH 18/32] allow OPIN to be connected to CHANZ in check_adjacent() --- vpr/src/route/check_route.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/vpr/src/route/check_route.cpp b/vpr/src/route/check_route.cpp index 2c6613d1a9..2966fc8c9b 100644 --- a/vpr/src/route/check_route.cpp +++ b/vpr/src/route/check_route.cpp @@ -310,8 +310,8 @@ static bool check_adjacent(RRNodeId from_node, RRNodeId to_node, bool is_flat) { int num_adj = 0; - auto from_rr = RRNodeId(from_node); - auto to_rr = RRNodeId(to_node); + RRNodeId from_rr = from_node; + RRNodeId to_rr = to_node; e_rr_type from_type = rr_graph.node_type(from_rr); int from_layer = rr_graph.node_layer_low(from_rr); int from_xlow = rr_graph.node_xlow(from_rr); @@ -346,7 +346,7 @@ static bool check_adjacent(RRNodeId from_node, RRNodeId to_node, bool is_flat) { case e_rr_type::SOURCE: VTR_ASSERT(to_type == e_rr_type::OPIN); - //The OPIN should be contained within the bounding box of it's connected source + // The OPIN should be contained within the bounding box of it's connected source if (from_xlow <= to_xlow && from_ylow <= to_ylow && from_xhigh >= to_xhigh && from_yhigh >= to_yhigh) { from_grid_type = device_ctx.grid.get_physical_type({from_xlow, from_ylow, from_layer}); to_grid_type = device_ctx.grid.get_physical_type({to_xlow, to_ylow, to_layer}); @@ -359,19 +359,19 @@ static bool check_adjacent(RRNodeId from_node, RRNodeId to_node, bool is_flat) { break; case e_rr_type::SINK: - /* SINKS are adjacent to not connected */ + // SINKS are adjacent to not connected break; case e_rr_type::OPIN: from_grid_type = device_ctx.grid.get_physical_type({from_xlow, from_ylow, from_layer}); - if (to_type == e_rr_type::CHANX || to_type == e_rr_type::CHANY || to_type == e_rr_type::MUX) { - num_adj += 1; //adjacent + if (to_type == e_rr_type::CHANX || to_type == e_rr_type::CHANY || to_type == e_rr_type::CHANZ || to_type == e_rr_type::MUX) { + num_adj += 1; // adjacent } else if (is_flat) { VTR_ASSERT(to_type == e_rr_type::OPIN || to_type == e_rr_type::IPIN); // If pin is located inside a cluster return true; } else { - VTR_ASSERT(to_type == e_rr_type::IPIN); /* direct OPIN to IPIN connections not necessarily adjacent */ - return true; /* Special case, direct OPIN to IPIN connections need not be adjacent */ + VTR_ASSERT(to_type == e_rr_type::IPIN); // direct OPIN to IPIN connections not necessarily adjacent + return true; // Special case, direct OPIN to IPIN connections need not be adjacent } break; @@ -384,7 +384,7 @@ static bool check_adjacent(RRNodeId from_node, RRNodeId to_node, bool is_flat) { VTR_ASSERT(to_type == e_rr_type::SINK); } - //An IPIN should be contained within the bounding box of its connected sink's tile + // An IPIN should be contained within the bounding box of its connected sink's tile if (to_type == e_rr_type::SINK) { if (from_xlow >= to_xlow && from_ylow >= to_ylow From ea14ba1f69fff0b8ffffe63a7f294667640901c8 Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Sun, 2 Nov 2025 16:31:14 -0500 Subject: [PATCH 19/32] make format --- libs/libarchfpga/src/arch_util.cpp | 2 +- libs/libarchfpga/src/read_xml_arch_file.cpp | 6 ++- vpr/src/base/CheckArch.cpp | 3 +- .../build_scatter_gathers.cpp | 8 +-- .../build_scatter_gathers.h | 14 ++--- .../route/rr_graph_generation/rr_graph.cpp | 52 +++++++++---------- .../route/rr_graph_generation/rr_graph2.cpp | 1 - .../route/rr_graph_generation/rr_graph_sg.cpp | 8 +-- .../route/rr_graph_generation/rr_graph_sg.h | 5 +- .../rr_graph_generation/rr_node_indices.cpp | 2 +- 10 files changed, 53 insertions(+), 48 deletions(-) diff --git a/libs/libarchfpga/src/arch_util.cpp b/libs/libarchfpga/src/arch_util.cpp index 1dd153b7fd..eaf067258e 100644 --- a/libs/libarchfpga/src/arch_util.cpp +++ b/libs/libarchfpga/src/arch_util.cpp @@ -545,7 +545,7 @@ void ProcessLutClass(t_pb_type* lut_pb_type) { for (size_t i = 0; i < num_annotations; i++) { lut_pb_type->modes[0].interconnect[0].annotations[i].clock = lut_pb_type->annotations[i].clock; lut_pb_type->modes[0].interconnect[0].annotations[i].input_pins = lut_pb_type->annotations[i].input_pins; - lut_pb_type->modes[0].interconnect[0].annotations[i].output_pins =lut_pb_type->annotations[i].output_pins; + lut_pb_type->modes[0].interconnect[0].annotations[i].output_pins = lut_pb_type->annotations[i].output_pins; lut_pb_type->modes[0].interconnect[0].annotations[i].line_num = lut_pb_type->annotations[i].line_num; lut_pb_type->modes[0].interconnect[0].annotations[i].format = lut_pb_type->annotations[i].format; lut_pb_type->modes[0].interconnect[0].annotations[i].type = lut_pb_type->annotations[i].type; diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index c6e58ef2c0..f288e85112 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -3489,7 +3489,8 @@ static void process_pin_locations(pugi::xml_node Locations, if ((y_offset < 0) || (y_offset >= physical_tile_type->height)) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(cur), vtr::string_fmt("'%d' is an invalid vertical offset for type '%s' (must be within [0, %d]).\n", - y_offset, physical_tile_type->name.c_str(), physical_tile_type->height - 1).c_str()); + y_offset, physical_tile_type->name.c_str(), physical_tile_type->height - 1) + .c_str()); } // Check for duplicate side specifications, since the code below silently overwrites if there are duplicates @@ -3635,7 +3636,8 @@ static void process_sub_tiles(pugi::xml_node node, archfpga_throw(loc_data.filename_c_str(), loc_data.line(node), vtr::string_fmt("No sub tile found for the Physical Tile %s.\n" "At least one sub tile is needed to correctly describe the Physical Tile.\n", - physical_tile_type->name.c_str()).c_str()); + physical_tile_type->name.c_str()) + .c_str()); } // used to find duplicate subtile names diff --git a/vpr/src/base/CheckArch.cpp b/vpr/src/base/CheckArch.cpp index a880af0d1c..f532341399 100644 --- a/vpr/src/base/CheckArch.cpp +++ b/vpr/src/base/CheckArch.cpp @@ -43,10 +43,9 @@ static void CheckSwitches(const t_arch& Arch) { } } - // find the ipin cblock switch index, if it exists if (Arch.switches[i].name == Arch.ipin_cblock_switch_name) { - ipin_cblock_switch_index = i; + ipin_cblock_switch_index = i; } } diff --git a/vpr/src/route/rr_graph_generation/build_scatter_gathers.cpp b/vpr/src/route/rr_graph_generation/build_scatter_gathers.cpp index 34ff5b8954..b57ab85dd1 100644 --- a/vpr/src/route/rr_graph_generation/build_scatter_gathers.cpp +++ b/vpr/src/route/rr_graph_generation/build_scatter_gathers.cpp @@ -399,8 +399,10 @@ void convert_interposer_cuts_to_sg_patterns(const std::vector& inte void compute_non_3d_sg_link_geometry(const t_physical_tile_loc& src_loc, const t_physical_tile_loc& dst_loc, e_rr_type& chan_type, - int& xlow, int& xhigh, - int& ylow, int& yhigh, + int& xlow, + int& xhigh, + int& ylow, + int& yhigh, Direction& direction) { VTR_ASSERT_SAFE(src_loc.layer_num == dst_loc.layer_num); @@ -431,4 +433,4 @@ void compute_non_3d_sg_link_geometry(const t_physical_tile_loc& src_loc, } else { VTR_ASSERT_MSG(false, "Source and destination locations cannot be identical"); } -} \ No newline at end of file +} diff --git a/vpr/src/route/rr_graph_generation/build_scatter_gathers.h b/vpr/src/route/rr_graph_generation/build_scatter_gathers.h index b4b087f073..4cafd53aec 100644 --- a/vpr/src/route/rr_graph_generation/build_scatter_gathers.h +++ b/vpr/src/route/rr_graph_generation/build_scatter_gathers.h @@ -78,12 +78,14 @@ void convert_interposer_cuts_to_sg_patterns(const std::vector& inte std::vector& sg_patterns); /** -* @brief Computes the channel type, direction, and coordinate span between two locations -* on the same layer. Used by SG link construction routines to determine geometry. -*/ + * @brief Computes the channel type, direction, and coordinate span between two locations + * on the same layer. Used by SG link construction routines to determine geometry. + */ void compute_non_3d_sg_link_geometry(const t_physical_tile_loc& src_loc, const t_physical_tile_loc& dst_loc, e_rr_type& chan_type, - int& xlow, int& xhigh, - int& ylow, int& yhigh, - Direction& direction); \ No newline at end of file + int& xlow, + int& xhigh, + int& ylow, + int& yhigh, + Direction& direction); diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index 2261bc6408..5af15bee1c 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -1498,12 +1498,12 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder } add_edges_opin_chanz(rr_graph, - layer, i, j, - Fc_out, - seg_index_map, - num_seg_types, - rr_edges_to_create, - interdie_3d_links[i][j]); + layer, i, j, + Fc_out, + seg_index_map, + num_seg_types, + rr_edges_to_create, + interdie_3d_links[i][j]); // Create the actual OPIN->CHANX/CHANY edges uniquify_edges(rr_edges_to_create); @@ -1993,10 +1993,10 @@ static vtr::NdMatrix, 4> alloc_and_load_pin_to_track_map(const // allocate 'result' matrix and initialize entries to UNDEFINED. also allocate and initialize matrix which will be used // to index into the correct entries when loading up 'result' auto result = vtr::NdMatrix, 4>({ - size_t(tile_type->num_pins), //[0..num_pins-1] - size_t(tile_type->width), //[0..width-1] - size_t(tile_type->height), //[0..height-1] - 4, //[0..sides-1] + size_t(tile_type->num_pins), //[0..num_pins-1] + size_t(tile_type->width), //[0..width-1] + size_t(tile_type->height), //[0..height-1] + 4, //[0..sides-1] }); // multiplier for unidirectional vs bidirectional architectures @@ -2074,11 +2074,11 @@ static vtr::NdMatrix alloc_and_load_pin_to_seg_type(const e_pin_type pin } auto tracks_connected_to_pin = vtr::NdMatrix({ - size_t(tile_type->num_pins), // [0..num_pins-1] - size_t(tile_type->width), // [0..width-1] - size_t(tile_type->height), // [0..height-1] - NUM_2D_SIDES, // [0..NUM_2D_SIDES-1] - size_t(max_Fc) // [0..Fc-1] + size_t(tile_type->num_pins), // [0..num_pins-1] + size_t(tile_type->width), // [0..width-1] + size_t(tile_type->height), // [0..height-1] + NUM_2D_SIDES, // [0..NUM_2D_SIDES-1] + size_t(max_Fc) // [0..Fc-1] }, UNDEFINED); // Unconnected @@ -2087,9 +2087,9 @@ static vtr::NdMatrix alloc_and_load_pin_to_seg_type(const e_pin_type pin // Type->num_pins) if a logical pin has multiple specified physical // pinlocations (i.e. appears on multiple sides of the block) auto num_dir = vtr::NdMatrix({ - size_t(tile_type->width), // [0..width-1] - size_t(tile_type->height), // [0..height-1] - NUM_2D_SIDES // [0..NUM_2D_SIDES-1] + size_t(tile_type->width), // [0..width-1] + size_t(tile_type->height), // [0..height-1] + NUM_2D_SIDES // [0..NUM_2D_SIDES-1] }, 0); @@ -2099,18 +2099,18 @@ static vtr::NdMatrix alloc_and_load_pin_to_seg_type(const e_pin_type pin // // Max possible space allocated for simplicity auto dir_list = vtr::NdMatrix({ - size_t(tile_type->width), // [0..width-1] - size_t(tile_type->height), // [0..height-1] - NUM_2D_SIDES, // [0..NUM_2D_SIDES-1] - size_t(tile_type->num_pins) // [0..num_pins * num_layers-1] + size_t(tile_type->width), // [0..width-1] + size_t(tile_type->height), // [0..height-1] + NUM_2D_SIDES, // [0..NUM_2D_SIDES-1] + size_t(tile_type->num_pins) // [0..num_pins * num_layers-1] }, -1); // Defensive coding: Initialize to invalid // Number of currently assigned physical pins auto num_done_per_dir = vtr::NdMatrix({ - size_t(tile_type->width), // [0..width-1] - size_t(tile_type->height), // [0..height-1] - NUM_2D_SIDES // [0..NUM_2D_SIDES-1] + size_t(tile_type->width), // [0..width-1] + size_t(tile_type->height), // [0..height-1] + NUM_2D_SIDES // [0..NUM_2D_SIDES-1] }, 0); @@ -2124,7 +2124,6 @@ static vtr::NdMatrix alloc_and_load_pin_to_seg_type(const e_pin_type pin if (tile_type->is_ignored_pin[pin]) continue; - for (int width = 0; width < tile_type->width; ++width) { for (int height = 0; height < tile_type->height; ++height) { for (e_side side : TOTAL_2D_SIDES) { @@ -2195,7 +2194,6 @@ static vtr::NdMatrix alloc_and_load_pin_to_seg_type(const e_pin_type pin VTR_ASSERT(pin == num_phys_pins); - if (perturb_switch_pattern) { load_perturbed_connection_block_pattern(tracks_connected_to_pin, pin_ordering, diff --git a/vpr/src/route/rr_graph_generation/rr_graph2.cpp b/vpr/src/route/rr_graph_generation/rr_graph2.cpp index 124eb1f817..0acee9e5fb 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph2.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph2.cpp @@ -130,7 +130,6 @@ static int vpr_to_phy_track(const int itrack, const t_chan_seg_details* seg_details, const enum e_directionality directionality); - /** * @brief Identifies and labels all mux endpoints at a given channel segment coordinate. * diff --git a/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp b/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp index ee0891a976..36a046a195 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp @@ -101,7 +101,9 @@ void build_inter_die_3d_rr_chan(RRGraphBuilder& rr_graph_builder, } void add_edges_opin_chanz(const RRGraphView& rr_graph, - int layer, int x, int y, + int layer, + int x, + int y, const std::vector>& Fc_out, const t_unified_to_parallel_seg_index& seg_index_map, int num_seg_types, @@ -175,7 +177,7 @@ void add_and_connect_non_3d_sg_links(RRGraphBuilder& rr_graph_builder, // SG links are confined to one layer (non-3D), but can run in X or Y. VTR_ASSERT_SAFE(src_loc.layer_num == dst_loc.layer_num); const int layer = src_loc.layer_num; - compute_non_3d_sg_link_geometry(src_loc, dst_loc, chan_type, xlow, xhigh, ylow, yhigh,direction); + compute_non_3d_sg_link_geometry(src_loc, dst_loc, chan_type, xlow, xhigh, ylow, yhigh, direction); // Retrieve the node ID and track number allocated earlier const RRNodeId node_id = sg_node_indices[i].first; @@ -234,4 +236,4 @@ void add_and_connect_non_3d_sg_links(RRGraphBuilder& rr_graph_builder, non_3d_sg_rr_edges_to_create.emplace_back(node_id, scatter_node, switch_index, false); } } -} \ No newline at end of file +} diff --git a/vpr/src/route/rr_graph_generation/rr_graph_sg.h b/vpr/src/route/rr_graph_generation/rr_graph_sg.h index d85d84a8c1..9151de091f 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_sg.h +++ b/vpr/src/route/rr_graph_generation/rr_graph_sg.h @@ -31,9 +31,10 @@ void add_inter_die_3d_edges(RRGraphBuilder& rr_graph_builder, const std::vector& interdie_3d_links, t_rr_edge_info_set& interdie_3d_rr_edges_to_create); - void add_edges_opin_chanz(const RRGraphView& rr_graph, - int layer, int x, int y, + int layer, + int x, + int y, const std::vector>& Fc_out, const t_unified_to_parallel_seg_index& seg_index_map, int num_seg_types, 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 8aa8a37592..3932fefd1e 100644 --- a/vpr/src/route/rr_graph_generation/rr_node_indices.cpp +++ b/vpr/src/route/rr_graph_generation/rr_node_indices.cpp @@ -386,7 +386,7 @@ std::vector> alloc_and_load_non_3d_sg_pattern_rr_node_i // Step 1: Determine the channel type (CHANX/CHANY) and span coordinates const int layer = src_loc.layer_num; - compute_non_3d_sg_link_geometry(src_loc, dst_loc, chan_type, xlow, xhigh, ylow, yhigh,direction); + compute_non_3d_sg_link_geometry(src_loc, dst_loc, chan_type, xlow, xhigh, ylow, yhigh, direction); // Select the appropriate ptc matrix for this channel type vtr::NdMatrix& ptc_matrix = (chan_type == e_rr_type::CHANX) ? chanx_ptc : chany_ptc; From 78afdc20419ac33a92f39fca08fb94a2f4c3b2d0 Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Mon, 3 Nov 2025 17:45:20 -0500 Subject: [PATCH 20/32] add find_pin_nodes_at_side() to RRSpatialLookup --- libs/librrgraph/src/base/rr_spatial_lookup.cpp | 12 ++++++++++++ libs/librrgraph/src/base/rr_spatial_lookup.h | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/libs/librrgraph/src/base/rr_spatial_lookup.cpp b/libs/librrgraph/src/base/rr_spatial_lookup.cpp index 48c81e40f1..44ed9bf59c 100644 --- a/libs/librrgraph/src/base/rr_spatial_lookup.cpp +++ b/libs/librrgraph/src/base/rr_spatial_lookup.cpp @@ -210,6 +210,18 @@ std::vector RRSpatialLookup::find_grid_nodes_at_all_sides(int layer, return nodes; } +std::vector RRSpatialLookup::find_pin_nodes_at_side(int layer, + int x, + int y, + e_rr_type pin_type, + e_side side) const { + VTR_ASSERT(pin_type == e_rr_type::OPIN || pin_type == e_rr_type::IPIN); + + std::vector nodes = find_nodes(layer,x, y, pin_type, side); + return nodes; + +} + void RRSpatialLookup::reserve_nodes(int layer, int x, int y, diff --git a/libs/librrgraph/src/base/rr_spatial_lookup.h b/libs/librrgraph/src/base/rr_spatial_lookup.h index 4fa2830be5..8b8b9315fd 100644 --- a/libs/librrgraph/src/base/rr_spatial_lookup.h +++ b/libs/librrgraph/src/base/rr_spatial_lookup.h @@ -139,6 +139,13 @@ class RRSpatialLookup { int y, e_rr_type rr_type) const; + + std::vector find_pin_nodes_at_side(int layer, + int x, + int y, + e_rr_type pin_type, + e_side side) const; + /* -- Mutators -- */ public: /** @brief Reserve the memory for a list of nodes at (layer, x, y) location with given type and side */ From 0dcb2faf3cbc3e3047284ee3bb055abbdad50503 Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Mon, 3 Nov 2025 18:58:51 -0500 Subject: [PATCH 21/32] add add_edges_opin_chanz_per_side() --- .../route/rr_graph_generation/rr_graph.cpp | 22 +-- .../route/rr_graph_generation/rr_graph_sg.cpp | 125 ++++++++++++++++-- .../route/rr_graph_generation/rr_graph_sg.h | 30 +++-- 3 files changed, 151 insertions(+), 26 deletions(-) diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index 5af15bee1c..07a63cdec2 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -1471,6 +1471,8 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder vtr::NdMatrix Fc_xofs({grid.height() - 1, grid.width() - 1, num_seg_types_x}, 0); vtr::NdMatrix Fc_yofs({grid.width() - 1, grid.height() - 1, num_seg_types_y}, 0); + vtr::NdMatrix Fc_zofs({grid.width(), grid.height(), num_seg_types_y}, 0); + // Build opins int rr_edges_before_directs = 0; for (size_t layer = 0; layer < grid.get_num_layers(); layer++) { @@ -1495,15 +1497,17 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder *Fc_clipped = true; } } - } - add_edges_opin_chanz(rr_graph, - layer, i, j, - Fc_out, - seg_index_map, - num_seg_types, - rr_edges_to_create, - interdie_3d_links[i][j]); + add_edges_opin_chanz_per_side(rr_graph, + layer, i, j, + side, + Fc_out, + seg_index_map, + num_seg_types, + Fc_zofs, + rr_edges_to_create, + interdie_3d_links); + } // Create the actual OPIN->CHANX/CHANY edges uniquify_edges(rr_edges_to_create); @@ -1512,6 +1516,8 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder rr_edges_to_create.clear(); } } + + Fc_zofs.fill(0); } VTR_LOGV(route_verbosity > 1, "OPIN->CHANX/CHANY edge count before creating direct connections: %d\n", rr_edges_before_directs); diff --git a/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp b/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp index 36a046a195..9d8717d680 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp @@ -100,15 +100,122 @@ void build_inter_die_3d_rr_chan(RRGraphBuilder& rr_graph_builder, } } -void add_edges_opin_chanz(const RRGraphView& rr_graph, - int layer, - int x, - int y, - const std::vector>& Fc_out, - const t_unified_to_parallel_seg_index& seg_index_map, - int num_seg_types, - t_rr_edge_info_set& rr_edges_to_create, - const std::vector& interdie_3d_links) { +void add_edges_opin_chanz_per_side(const RRGraphView& rr_graph, + int layer, + int x, + int y, + e_side side, + const std::vector>& Fc_out, + const t_unified_to_parallel_seg_index& seg_index_map, + int num_seg_types, + vtr::NdMatrix& Fc_zofs, + t_rr_edge_info_set& rr_edges_to_create, + const vtr::NdMatrix, 2>& interdie_3d_links) { + const RRSpatialLookup& node_lookup = rr_graph.node_lookup(); + const DeviceGrid& grid = g_vpr_ctx.device().grid; + + t_physical_tile_type_ptr type = grid.get_physical_type({x, y, layer}); + + std::vector opin_nodes = node_lookup.find_pin_nodes_at_side(layer, x, y, e_rr_type::OPIN, side); + + t_physical_tile_loc sb_loc0, sb_loc1; + switch (side) { + case TOP: + sb_loc0 = {x, y, layer}; + sb_loc1 = {x - 1, y, layer}; + break; + + case BOTTOM: + sb_loc0 = {x, y - 1, layer}; + sb_loc1 = {x - 1, y - 1, layer}; + break; + + case RIGHT: + sb_loc0 = {x, y, layer}; + sb_loc1 = {x , y - 1, layer}; + break; + + case LEFT: + sb_loc0 = {x - 1, y, layer}; + sb_loc1 = {x - 1 , y - 1, layer}; + break; + + default: + VTR_ASSERT_SAFE(false); + } + + const int grid_width = grid.width(); + const int grid_height = grid.height(); + + sb_loc0.x = std::clamp(sb_loc0.x, 0, grid_width - 1); + sb_loc0.y = std::clamp(sb_loc0.y, 0, grid_height - 1); + + sb_loc1.x = std::clamp(sb_loc1.x, 0, grid_width - 1); + sb_loc1.y = std::clamp(sb_loc1.y, 0, grid_height - 1); + + std::vector> selected_chanz_nodes0; + std::vector> selected_chanz_nodes1; + + for (int iseg = 0; iseg < num_seg_types; iseg++) { + int seg_index = get_parallel_seg_index(iseg, seg_index_map, e_parallel_axis::Z_AXIS); + if (seg_index < 0) { + continue; + } + + selected_chanz_nodes0.clear(); + for (size_t track_num = 0; track_num < interdie_3d_links[sb_loc0.x][sb_loc0.y].size(); track_num++) { + const t_bottleneck_link& bottleneck_link = interdie_3d_links[sb_loc0.x][sb_loc0.y][track_num]; + if (bottleneck_link.parallel_segment_index == seg_index && bottleneck_link.gather_loc.layer_num == layer) { + RRNodeId node_id = node_lookup.find_node(sb_loc0.layer_num, sb_loc0.x, sb_loc0.y, e_rr_type::CHANZ, track_num); + selected_chanz_nodes0.push_back({node_id, bottleneck_link.arch_wire_switch}); + } + } + + selected_chanz_nodes1.clear(); + for (size_t track_num = 0; track_num < interdie_3d_links[sb_loc1.x][sb_loc1.y].size(); track_num++) { + const t_bottleneck_link& bottleneck_link = interdie_3d_links[sb_loc1.x][sb_loc1.y][track_num]; + if (bottleneck_link.parallel_segment_index == seg_index && bottleneck_link.gather_loc.layer_num == layer) { + RRNodeId node_id = node_lookup.find_node(sb_loc1.layer_num, sb_loc1.x, sb_loc1.y, e_rr_type::CHANZ, track_num); + selected_chanz_nodes1.push_back({node_id, bottleneck_link.arch_wire_switch}); + } + } + + for (RRNodeId opin_node_id : opin_nodes) { + int pin_number = rr_graph.node_pin_num(opin_node_id); + int fc = Fc_out[type->index][pin_number][iseg]; + + for (int i = 0; i < fc; i++) { + + RRNodeId chanz_node_id; + short switch_id; + if (Fc_zofs[sb_loc0.x][sb_loc0.y][seg_index] < Fc_zofs[sb_loc1.x][sb_loc1.y][seg_index]) { + int chanz_idx = Fc_zofs[sb_loc0.x][sb_loc0.y][seg_index]; + chanz_node_id = selected_chanz_nodes0[chanz_idx % selected_chanz_nodes0.size()].first; + switch_id = selected_chanz_nodes0[chanz_idx % selected_chanz_nodes0.size()].second; + Fc_zofs[sb_loc0.x][sb_loc0.y][seg_index]++; + } else { + int chanz_idx = Fc_zofs[sb_loc1.x][sb_loc1.y][seg_index]; + chanz_node_id = selected_chanz_nodes1[chanz_idx % selected_chanz_nodes1.size()].first; + switch_id = selected_chanz_nodes1[chanz_idx % selected_chanz_nodes1.size()].second; + Fc_zofs[sb_loc1.x][sb_loc1.y][seg_index]++; + } + + rr_edges_to_create.emplace_back(opin_node_id, chanz_node_id, switch_id, false); + } + } + } + +} + +void add_edges_opin_chanz_per_block(const RRGraphView& rr_graph, + int layer, + int x, + int y, + const std::vector>& Fc_out, + const t_unified_to_parallel_seg_index& seg_index_map, + int num_seg_types, + t_rr_edge_info_set& rr_edges_to_create, + const std::vector& interdie_3d_links) { const RRSpatialLookup& node_lookup = rr_graph.node_lookup(); const DeviceGrid& grid = g_vpr_ctx.device().grid; diff --git a/vpr/src/route/rr_graph_generation/rr_graph_sg.h b/vpr/src/route/rr_graph_generation/rr_graph_sg.h index 9151de091f..4116f8bce0 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_sg.h +++ b/vpr/src/route/rr_graph_generation/rr_graph_sg.h @@ -31,15 +31,27 @@ void add_inter_die_3d_edges(RRGraphBuilder& rr_graph_builder, const std::vector& interdie_3d_links, t_rr_edge_info_set& interdie_3d_rr_edges_to_create); -void add_edges_opin_chanz(const RRGraphView& rr_graph, - int layer, - int x, - int y, - const std::vector>& Fc_out, - const t_unified_to_parallel_seg_index& seg_index_map, - int num_seg_types, - t_rr_edge_info_set& rr_edges_to_create, - const std::vector& interdie_3d_links); +void add_edges_opin_chanz_per_side(const RRGraphView& rr_graph, + int layer, + int x, + int y, + e_side side, + const std::vector>& Fc_out, + const t_unified_to_parallel_seg_index& seg_index_map, + int num_seg_types, + vtr::NdMatrix& Fc_zofs, + t_rr_edge_info_set& rr_edges_to_create, + const vtr::NdMatrix, 2>& interdie_3d_links); + +void add_edges_opin_chanz_per_block(const RRGraphView& rr_graph, + int layer, + int x, + int y, + const std::vector>& Fc_out, + const t_unified_to_parallel_seg_index& seg_index_map, + int num_seg_types, + t_rr_edge_info_set& rr_edges_to_create, + const std::vector& interdie_3d_links); /** * @brief Adds and connects non-3D scatter–gather (SG) links to the RR graph. From 72e130c253f6cb4f05364944b6ae3524adc45f20 Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Tue, 4 Nov 2025 14:29:34 -0500 Subject: [PATCH 22/32] update inter_layer_connections_limited_to_opin() to check OPIN-CHANZ --- libs/librrgraph/src/base/rr_graph_utils.cpp | 16 +++++++--------- libs/librrgraph/src/base/rr_graph_utils.h | 3 +-- vpr/src/base/vpr_context.cpp | 2 +- vpr/src/base/vpr_context.h | 2 +- .../route/rr_graph_generation/rr_graph_sg.cpp | 5 ++--- 5 files changed, 12 insertions(+), 16 deletions(-) diff --git a/libs/librrgraph/src/base/rr_graph_utils.cpp b/libs/librrgraph/src/base/rr_graph_utils.cpp index 62358b3dba..adc4a6d449 100644 --- a/libs/librrgraph/src/base/rr_graph_utils.cpp +++ b/libs/librrgraph/src/base/rr_graph_utils.cpp @@ -240,19 +240,17 @@ void rr_set_sink_locs(const RRGraphView& rr_graph, RRGraphBuilder& rr_graph_buil } bool inter_layer_connections_limited_to_opin(const RRGraphView& rr_graph) { - // TODO: once OPINs are connected to CHANZ nodes, this function should be reworked. bool limited_to_opin = true; + for (const RRNodeId from_node : rr_graph.nodes()) { + e_rr_type from_type = rr_graph.node_type(from_node); for (t_edge_size edge : rr_graph.edges(from_node)) { RRNodeId to_node = rr_graph.edge_sink_node(from_node, edge); - int from_layer = rr_graph.node_layer_low(from_node); - int to_layer = rr_graph.node_layer_low(to_node); - - if (from_layer != to_layer) { - if (rr_graph.node_type(from_node) != e_rr_type::OPIN) { - limited_to_opin = false; - break; - } + e_rr_type to_type = rr_graph.node_type(to_node); + + if (to_type == e_rr_type::CHANZ && from_type != e_rr_type::OPIN) { + limited_to_opin = false; + break; } } if (!limited_to_opin) { diff --git a/libs/librrgraph/src/base/rr_graph_utils.h b/libs/librrgraph/src/base/rr_graph_utils.h index ebe48e3b37..02cd96a498 100644 --- a/libs/librrgraph/src/base/rr_graph_utils.h +++ b/libs/librrgraph/src/base/rr_graph_utils.h @@ -93,8 +93,7 @@ int seg_index_of_sblock(const RRGraphView& rr_graph, int from_node, int to_node) * box to be used to estimate the wire-length of a net. * * @param rr_graph The routing resource graph - * - * @return limited_to_opin + * @return True if inter-die 3D connections are driven only by OPIN nodes; otherwise, false. */ bool inter_layer_connections_limited_to_opin(const RRGraphView& rr_graph); diff --git a/vpr/src/base/vpr_context.cpp b/vpr/src/base/vpr_context.cpp index 78f678b97c..bf13643ace 100644 --- a/vpr/src/base/vpr_context.cpp +++ b/vpr/src/base/vpr_context.cpp @@ -88,7 +88,7 @@ static bool is_cube_bb(const e_place_bounding_box_mode place_bb_mode, cube_bb = true; } else { // The user has specifically asked for PER_LAYER_BB - VTR_ASSERT_SAFE(place_bb_mode == e_place_bounding_box_mode::PER_LAYER_BB); + VTR_ASSERT(place_bb_mode == e_place_bounding_box_mode::PER_LAYER_BB); cube_bb = false; } diff --git a/vpr/src/base/vpr_context.h b/vpr/src/base/vpr_context.h index 28f5a86989..6a49a91fd6 100644 --- a/vpr/src/base/vpr_context.h +++ b/vpr/src/base/vpr_context.h @@ -44,7 +44,7 @@ class SetupHoldTimingInfo; class PostClusterDelayCalculator; -#endif /* NO_SERVER */ +#endif // NO_SERVER struct t_rr_node_route_inf; diff --git a/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp b/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp index 9d8717d680..fcbbfdb6b7 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp @@ -132,12 +132,12 @@ void add_edges_opin_chanz_per_side(const RRGraphView& rr_graph, case RIGHT: sb_loc0 = {x, y, layer}; - sb_loc1 = {x , y - 1, layer}; + sb_loc1 = {x, y - 1, layer}; break; case LEFT: sb_loc0 = {x - 1, y, layer}; - sb_loc1 = {x - 1 , y - 1, layer}; + sb_loc1 = {x - 1, y - 1, layer}; break; default: @@ -204,7 +204,6 @@ void add_edges_opin_chanz_per_side(const RRGraphView& rr_graph, } } } - } void add_edges_opin_chanz_per_block(const RRGraphView& rr_graph, From 361050384f58d6905ee5e3ba6008ed39d2558156 Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Tue, 4 Nov 2025 15:18:37 -0500 Subject: [PATCH 23/32] some cleanups in rr_graph files --- .../route/rr_graph_generation/rr_graph.cpp | 35 ++++--- .../route/rr_graph_generation/rr_graph2.cpp | 91 ++++++++----------- .../route/rr_graph_generation/rr_graph_sg.cpp | 6 +- 3 files changed, 58 insertions(+), 74 deletions(-) diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index 07a63cdec2..741efa5b71 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -963,8 +963,7 @@ static void build_rr_graph(e_graph_type graph_type, // alloc_and_load_rr_switch_inf() device_ctx.rr_graph_builder.reserve_switches(device_ctx.all_sw_inf.size()); // Create the switches - for (const auto& sw_pair : device_ctx.all_sw_inf) { - const t_arch_switch_inf& arch_sw = sw_pair.second; + for (const t_arch_switch_inf& arch_sw : device_ctx.all_sw_inf | std::views::values) { t_rr_switch_inf rr_switch = create_rr_switch_from_arch_switch(arch_sw, R_minW_nmos, R_minW_pmos); @@ -1278,7 +1277,7 @@ std::vector> alloc_and_load_actual_fc(const std::vector 0); + VTR_ASSERT(!fc_spec.pins.empty()); int iseg = fc_spec.seg_index; @@ -2941,7 +2940,7 @@ static int get_opin_direct_connections(RRGraphBuilder& rr_graph_builder, inodes = rr_graph_builder.node_lookup().find_nodes_at_all_sides(layer, final_ipin_x, final_ipin_y, e_rr_type::IPIN, ipin); } - if (inodes.size() > 0) { + if (!inodes.empty()) { // There may be multiple physical pins corresponding to the logical // target ipin. We only need to connect to one of them (since the physical pins // are logically equivalent). This also ensures the graphics look reasonable and map @@ -2963,16 +2962,13 @@ static std::vector alloc_and_load_perturb_opins(const t_physical_tile_type const vtr::Matrix& Fc_out, const int max_chan_width, const std::vector& segment_inf) { - int i, Fc_max, iclass, num_wire_types; - int num, max_primes, factor, num_factors; - int* prime_factors; + int num_wire_types; float step_size = 0; float n = 0; float threshold = 0.07; std::vector perturb_opins(segment_inf.size(), false); - i = Fc_max = iclass = 0; if (segment_inf.size() > 1) { /* Segments of one length are grouped together in the channel. * * In the future we can determine if any of these segments will * @@ -2987,8 +2983,9 @@ static std::vector alloc_and_load_perturb_opins(const t_physical_tile_type num_wire_types = segment_inf[0].length; } - /* get Fc_max */ - for (i = 0; i < type->num_pins; ++i) { + // get Fc_max + int Fc_max = 0; + for (int i = 0; i < type->num_pins; ++i) { auto pin_type = get_pin_type_from_pin_physical_num(type, i); if (Fc_out[i][0] > Fc_max && pin_type == e_pin_type::DRIVER) { Fc_max = Fc_out[i][0]; @@ -3005,19 +3002,19 @@ static std::vector alloc_and_load_perturb_opins(const t_physical_tile_type * will always skip some wires. Thus, we perturb pins if we detect this * * case. */ - /* get an upper bound on the number of prime factors of num_wire_types */ - max_primes = (int)floor(log((float)num_wire_types) / log(2.0)); + // get an upper bound on the number of prime factors of num_wire_types + int max_primes = (int)floor(log((float)num_wire_types) / log(2.0)); max_primes = std::max(max_primes, 1); //Minimum of 1 to ensure we allocate space for at least one prime_factor - prime_factors = new int[max_primes]; - for (i = 0; i < max_primes; i++) { + int* prime_factors = new int[max_primes]; + for (int i = 0; i < max_primes; i++) { prime_factors[i] = 0; } - /* Find the prime factors of num_wire_types */ - num = num_wire_types; - factor = 2; - num_factors = 0; + // Find the prime factors of num_wire_types + int num = num_wire_types; + int factor = 2; + int num_factors = 0; while (pow((float)factor, 2) <= num) { if (num % factor == 0) { num /= factor; @@ -3036,7 +3033,7 @@ static std::vector alloc_and_load_perturb_opins(const t_physical_tile_type /* Now see if step size is an approximate multiple of one of the factors. A * * threshold is used because step size may not be an integer. */ step_size = (float)max_chan_width / Fc_max; - for (i = 0; i < num_factors; i++) { + for (int i = 0; i < num_factors; i++) { if (vtr::nint(step_size) < prime_factors[i]) { perturb_opins[0] = false; break; diff --git a/vpr/src/route/rr_graph_generation/rr_graph2.cpp b/vpr/src/route/rr_graph_generation/rr_graph2.cpp index 0acee9e5fb..c7bb69c33c 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph2.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph2.cpp @@ -128,7 +128,7 @@ static int vpr_to_phy_track(const int itrack, const int chan_num, const int seg_num, const t_chan_seg_details* seg_details, - const enum e_directionality directionality); + const e_directionality directionality); /** * @brief Identifies and labels all mux endpoints at a given channel segment coordinate. @@ -189,9 +189,9 @@ std::vector get_seg_track_counts(int num_sets, // Scale factor so we can divide by any length and still use integers double scale = 1; int freq_sum = 0; - for (size_t i = 0; i < segment_inf.size(); ++i) { - scale *= segment_inf[i].length; - freq_sum += segment_inf[i].frequency; + for (const t_segment_inf& seg_inf : segment_inf) { + scale *= seg_inf.length; + freq_sum += seg_inf.frequency; } const double reduce = scale * freq_sum; @@ -1082,10 +1082,10 @@ int get_track_to_tracks(RRGraphBuilder& rr_graph_builder, const t_sb_connection_map* sb_conn_map) { int to_chan, to_sb; std::vector conn_tracks; - bool from_is_sblock, is_behind, Fs_clipped; + bool Fs_clipped; e_side to_side; - /* check whether a custom switch block will be used */ + // check whether a custom switch block will be used bool custom_switch_block = false; if (sb_conn_map != nullptr) { custom_switch_block = true; @@ -1134,9 +1134,9 @@ int get_track_to_tracks(RRGraphBuilder& rr_graph_builder, continue; } - /* Figure out if we are at a sblock */ - from_is_sblock = is_sblock(from_chan, from_seg, sb_seg, from_track, - from_seg_details, directionality); + // Figure out if we are at a sblock + bool from_is_sblock = is_sblock(from_chan, from_seg, sb_seg, from_track, + from_seg_details, directionality); if (sb_seg == end_sb_seg || sb_seg == start_sb_seg) { /* end of wire must be an sblock */ from_is_sblock = true; @@ -1173,9 +1173,9 @@ int get_track_to_tracks(RRGraphBuilder& rr_graph_builder, if (to_seg_details[0].length() == 0) continue; - /* Figure out whether the switch block at the current sb_seg coordinate is *behind* - * the target channel segment (with respect to VPR coordinate system) */ - is_behind = false; + // Figure out whether the switch block at the current sb_seg coordinate is *behind* + // the target channel segment (with respect to VPR coordinate system) + bool is_behind = false; if (to_type == from_type) { if (sb_seg == start) { is_behind = true; @@ -1296,12 +1296,10 @@ static int get_bidir_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, const enum e_directionality directionality, RRNodeId from_rr_node, t_rr_edge_info_set& rr_edges_to_create) { - unsigned iconn; - int to_track, to_switch, num_conn, to_x, to_y, i; - bool to_is_sblock; + int to_x, to_y; short switch_types[2]; - /* x, y coords for get_rr_node lookups */ + // x, y coords for get_rr_node lookups if (e_rr_type::CHANX == to_type) { to_x = to_seg; to_y = to_chan; @@ -1311,10 +1309,9 @@ static int get_bidir_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, to_y = to_seg; } - /* Go through the list of tracks we can connect to */ - num_conn = 0; - for (iconn = 0; iconn < conn_tracks.size(); ++iconn) { - to_track = conn_tracks[iconn]; + // Go through the list of tracks we can connect to + int num_conn = 0; + for (int to_track : conn_tracks) { RRNodeId to_node = rr_graph_builder.node_lookup().find_node(layer, to_x, to_y, to_type, to_track); if (!to_node) { @@ -1322,16 +1319,15 @@ static int get_bidir_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, } /* Get the switches for any edges between the two tracks */ - to_switch = seg_details[to_track].arch_wire_switch(); + int to_switch = seg_details[to_track].arch_wire_switch(); - to_is_sblock = is_sblock(to_chan, to_seg, to_sb, to_track, seg_details, - directionality); + bool to_is_sblock = is_sblock(to_chan, to_seg, to_sb, to_track, seg_details, directionality); get_switch_type(from_is_sblock, to_is_sblock, from_switch, to_switch, switch_override, switch_types); - /* There are up to two switch edges allowed from track to track */ - for (i = 0; i < 2; ++i) { + // There are up to two switch edges allowed from track to track + for (int i = 0; i < 2; ++i) { /* If the switch_type entry is empty, skip it */ if (UNDEFINED == switch_types[i]) { continue; @@ -1365,7 +1361,7 @@ static void get_switchblocks_edges(RRGraphBuilder& rr_graph_builder, // Coordinate to index into the SB map SwitchblockLookupKey sb_coord(tile_x, tile_y, layer, from_side, to_side); - if (sb_conn_map.count(sb_coord) > 0) { + if (sb_conn_map.contains(sb_coord)) { // Reference to the connections vector which lists all destination wires for a given source wire // at a specific coordinate sb_coord const std::vector& sb_edges = sb_conn_map.at(sb_coord); @@ -1549,24 +1545,22 @@ static int get_unidir_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, } bool is_sblock(const int chan, int wire_seg, const int sb_seg, const int track, const t_chan_seg_details* seg_details, const enum e_directionality directionality) { - int length, ofs, fac; - - fac = 1; + int fac = 1; if (UNI_DIRECTIONAL == directionality) { fac = 2; } - length = seg_details[track].length(); + int length = seg_details[track].length(); - /* Make sure they gave us correct start */ + // Make sure they gave us correct start wire_seg = get_seg_start(seg_details, track, chan, wire_seg); - ofs = sb_seg - wire_seg + 1; /* Offset 0 is behind us, so add 1 */ + int ofs = sb_seg - wire_seg + 1; // Offset 0 is behind us, so add 1 VTR_ASSERT(ofs >= 0); VTR_ASSERT(ofs < (length + 1)); - /* If unidir segment that is going backwards, we need to flip the ofs */ + // If unidir segment that is going backwards, we need to flip the ofs if ((ofs % fac) > 0) { ofs = length - ofs; } @@ -1661,28 +1655,21 @@ static int vpr_to_phy_track(const int itrack, const int chan_num, const int seg_num, const t_chan_seg_details* seg_details, - const enum e_directionality directionality) { - int group_start, group_size; - int vpr_offset_for_first_phy_track; - int vpr_offset, phy_offset; - int phy_track; - int fac; + const e_directionality directionality) { - /* Assign in pairs if unidir. */ - fac = 1; + // Assign in pairs if unidir. + int fac = 1; if (UNI_DIRECTIONAL == directionality) { fac = 2; } - group_start = seg_details[itrack].group_start(); - group_size = seg_details[itrack].group_size(); + int group_start = seg_details[itrack].group_start(); + int group_size = seg_details[itrack].group_size(); - vpr_offset_for_first_phy_track = (chan_num + seg_num - 1) - % (group_size / fac); - vpr_offset = (itrack - group_start) / fac; - phy_offset = (vpr_offset_for_first_phy_track + vpr_offset) - % (group_size / fac); - phy_track = group_start + (fac * phy_offset) + (itrack - group_start) % fac; + int vpr_offset_for_first_phy_track = (chan_num + seg_num - 1) % (group_size / fac); + int vpr_offset = (itrack - group_start) / fac; + int phy_offset = (vpr_offset_for_first_phy_track + vpr_offset) % (group_size / fac); + int phy_track = group_start + (fac * phy_offset) + (itrack - group_start) % fac; return phy_track; } @@ -2047,7 +2034,7 @@ static void label_incoming_wires(const int chan_num, /* Alloc the list of labels for the tracks */ labels.resize(max_chan_width); - std::fill(labels.begin(), labels.end(), UN_SET); + std::ranges::fill(labels, UN_SET); int num_ending = 0; int num_passing = 0; @@ -2134,12 +2121,12 @@ static int should_create_switchblock(const DeviceGrid& grid, int layer_num, int x_coord = from_chan_coord; } - auto blk_type = grid.get_physical_type({x_coord, y_coord, layer_num}); + t_physical_tile_type_ptr blk_type = grid.get_physical_type({x_coord, y_coord, layer_num}); int width_offset = grid.get_width_offset({x_coord, y_coord, layer_num}); int height_offset = grid.get_height_offset({x_coord, y_coord, layer_num}); e_sb_type sb_type = blk_type->switchblock_locations[width_offset][height_offset]; - auto switch_override = blk_type->switchblock_switch_overrides[width_offset][height_offset]; + int switch_override = blk_type->switchblock_switch_overrides[width_offset][height_offset]; if (sb_type == e_sb_type::FULL) { return switch_override; diff --git a/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp b/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp index fcbbfdb6b7..85974def4e 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp @@ -167,7 +167,7 @@ void add_edges_opin_chanz_per_side(const RRGraphView& rr_graph, const t_bottleneck_link& bottleneck_link = interdie_3d_links[sb_loc0.x][sb_loc0.y][track_num]; if (bottleneck_link.parallel_segment_index == seg_index && bottleneck_link.gather_loc.layer_num == layer) { RRNodeId node_id = node_lookup.find_node(sb_loc0.layer_num, sb_loc0.x, sb_loc0.y, e_rr_type::CHANZ, track_num); - selected_chanz_nodes0.push_back({node_id, bottleneck_link.arch_wire_switch}); + selected_chanz_nodes0.emplace_back(node_id, bottleneck_link.arch_wire_switch); } } @@ -176,7 +176,7 @@ void add_edges_opin_chanz_per_side(const RRGraphView& rr_graph, const t_bottleneck_link& bottleneck_link = interdie_3d_links[sb_loc1.x][sb_loc1.y][track_num]; if (bottleneck_link.parallel_segment_index == seg_index && bottleneck_link.gather_loc.layer_num == layer) { RRNodeId node_id = node_lookup.find_node(sb_loc1.layer_num, sb_loc1.x, sb_loc1.y, e_rr_type::CHANZ, track_num); - selected_chanz_nodes1.push_back({node_id, bottleneck_link.arch_wire_switch}); + selected_chanz_nodes1.emplace_back(node_id, bottleneck_link.arch_wire_switch); } } @@ -239,7 +239,7 @@ void add_edges_opin_chanz_per_block(const RRGraphView& rr_graph, const t_bottleneck_link& bottleneck_link = interdie_3d_links[track_num]; if (bottleneck_link.parallel_segment_index == seg_index && bottleneck_link.gather_loc.layer_num == layer) { RRNodeId node_id = node_lookup.find_node(layer, x, y, e_rr_type::CHANZ, track_num); - selected_chanz_nodes.push_back({node_id, bottleneck_link.arch_wire_switch}); + selected_chanz_nodes.emplace_back(node_id, bottleneck_link.arch_wire_switch); } } From a57748067631237faf85ee2bdd6edf825d7c1616 Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Wed, 5 Nov 2025 14:04:12 -0500 Subject: [PATCH 24/32] add rr_graph_opin_chan_edges files --- .../route/rr_graph_generation/rr_graph.cpp | 491 +----------- .../route/rr_graph_generation/rr_graph2.cpp | 220 +----- vpr/src/route/rr_graph_generation/rr_graph2.h | 48 +- .../rr_graph_opin_chan_edges.cpp | 717 ++++++++++++++++++ .../rr_graph_opin_chan_edges.h | 33 + 5 files changed, 793 insertions(+), 716 deletions(-) create mode 100644 vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.cpp create mode 100644 vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.h diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index 741efa5b71..daca181369 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 "rr_graph_sbox.h" #include "rr_graph_intra_cluster.h" #include "rr_graph_tile_nodes.h" +#include "rr_graph_opin_chan_edges.h" #include "rr_graph_sg.h" #include "rr_graph_timing_params.h" #include "check_rr_graph.h" @@ -122,55 +123,6 @@ static vtr::NdMatrix, 4> alloc_and_load_track_to_pin_lookup(vtr const int max_chan_width, const std::vector& seg_inf); -static void build_bidir_rr_opins(RRGraphBuilder& rr_graph_builder, - const RRGraphView& rr_graph, - const int layer, - const int i, - const int j, - const e_side side, - const t_pin_to_track_lookup& opin_to_track_map, - const std::vector>& Fc_out, - t_rr_edge_info_set& created_rr_edges, - const t_chan_details& chan_details_x, - const t_chan_details& chan_details_y, - const DeviceGrid& grid, - const std::vector& directs, - const std::vector& clb_to_clb_directs, - const int num_seg_types); - -static void build_unidir_rr_opins(RRGraphBuilder& rr_graph_builder, - const RRGraphView& rr_graph, - const int layer, - const int i, - const int j, - const e_side side, - const DeviceGrid& grid, - const std::vector>& Fc_out, - const t_chan_width& nodes_per_chan, - const t_chan_details& chan_details_x, - const t_chan_details& chan_details_y, - vtr::NdMatrix& Fc_xofs, - vtr::NdMatrix& Fc_yofs, - t_rr_edge_info_set& created_rr_edges, - bool* Fc_clipped, - const t_unified_to_parallel_seg_index& seg_index_map, - const std::vector& directs, - const std::vector& clb_to_clb_directs, - const int num_seg_types, - int& edge_count); - -static int get_opin_direct_connections(RRGraphBuilder& rr_graph_builder, - const RRGraphView& rr_graph, - int layer, - int x, - int y, - e_side side, - int opin, - RRNodeId from_rr_node, - t_rr_edge_info_set& rr_edges_to_create, - const std::vector& directs, - const std::vector& clb_to_clb_directs); - static std::function alloc_and_load_rr_graph(RRGraphBuilder& rr_graph_builder, t_rr_graph_storage& L_rr_node, const RRGraphView& rr_graph, @@ -322,10 +274,6 @@ void alloc_and_load_edges(RRGraphBuilder& rr_graph_builder, static std::vector alloc_and_load_global_route_seg_details(const int global_route_switch); -static RRNodeId pick_best_direct_connect_target_rr_node(const RRGraphView& rr_graph, - RRNodeId from_rr, - const std::vector& candidate_rr_nodes); - static void process_non_config_sets(); static void build_rr_graph(e_graph_type graph_type, @@ -1463,61 +1411,12 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder VTR_LOGV(route_verbosity > 1, "SOURCE->OPIN and IPIN->SINK edge count:%d\n", num_edges); num_edges = 0; - // These are data structures used by the unidir opin mapping. They are used - // to spread connections evenly for each segment type among the available - // wire start points - // [0..grid.height()-2][0..grid.width()-2][0..num_seg_types_x/y-1] - vtr::NdMatrix Fc_xofs({grid.height() - 1, grid.width() - 1, num_seg_types_x}, 0); - vtr::NdMatrix Fc_yofs({grid.width() - 1, grid.height() - 1, num_seg_types_y}, 0); - - vtr::NdMatrix Fc_zofs({grid.width(), grid.height(), num_seg_types_y}, 0); - - // Build opins int rr_edges_before_directs = 0; - for (size_t layer = 0; layer < grid.get_num_layers(); layer++) { - for (size_t i = 0; i < grid.width(); ++i) { - for (size_t j = 0; j < grid.height(); ++j) { - for (e_side side : TOTAL_2D_SIDES) { - if (BI_DIRECTIONAL == directionality) { - build_bidir_rr_opins(rr_graph_builder, rr_graph, layer, i, j, side, - opin_to_track_map, Fc_out, rr_edges_to_create, chan_details_x, - chan_details_y, - grid, - directs, clb_to_clb_directs, num_seg_types); - } else { - VTR_ASSERT(UNI_DIRECTIONAL == directionality); - bool clipped; - build_unidir_rr_opins(rr_graph_builder, rr_graph, layer, i, j, side, grid, Fc_out, chan_width, - chan_details_x, chan_details_y, Fc_xofs, Fc_yofs, - rr_edges_to_create, &clipped, seg_index_map, - directs, clb_to_clb_directs, num_seg_types, - rr_edges_before_directs); - if (clipped) { - *Fc_clipped = true; - } - } - - add_edges_opin_chanz_per_side(rr_graph, - layer, i, j, - side, - Fc_out, - seg_index_map, - num_seg_types, - Fc_zofs, - rr_edges_to_create, - interdie_3d_links); - } - - // Create the actual OPIN->CHANX/CHANY edges - uniquify_edges(rr_edges_to_create); - alloc_and_load_edges(rr_graph_builder, rr_edges_to_create); - num_edges += rr_edges_to_create.size(); - rr_edges_to_create.clear(); - } - } - - Fc_zofs.fill(0); - } + add_opin_chan_edges(rr_graph_builder, rr_graph, num_seg_types, num_seg_types_x, num_seg_types_y, + chan_width, chan_details_x, chan_details_y, + seg_index_map, opin_to_track_map, interdie_3d_links, + Fc_out, directs, clb_to_clb_directs, directionality, + rr_edges_to_create, num_edges, rr_edges_before_directs, Fc_clipped); VTR_LOGV(route_verbosity > 1, "OPIN->CHANX/CHANY edge count before creating direct connections: %d\n", rr_edges_before_directs); VTR_LOGV(route_verbosity > 1, "OPIN->CHANX/CHANY edge count after creating direct connections: %d\n", num_edges); @@ -1709,68 +1608,7 @@ static void alloc_and_load_tile_rr_graph(RRGraphBuilder& rr_graph_builder, rr_graph_builder.rr_nodes().shrink_to_fit(); } -static void build_bidir_rr_opins(RRGraphBuilder& rr_graph_builder, - const RRGraphView& rr_graph, - const int layer, - const int i, - const int j, - const e_side side, - const t_pin_to_track_lookup& opin_to_track_map, - const std::vector>& Fc_out, - t_rr_edge_info_set& rr_edges_to_create, - const t_chan_details& chan_details_x, - const t_chan_details& chan_details_y, - const DeviceGrid& grid, - const std::vector& directs, - const std::vector& clb_to_clb_directs, - const int num_seg_types) { - // Don't connect pins which are not adjacent to channels around the perimeter - if ((i == 0 && side != RIGHT) - || (i == int(grid.width() - 1) && side != LEFT) - || (j == 0 && side != TOP) - || (j == int(grid.height() - 1) && side != BOTTOM)) { - return; - } - t_physical_tile_type_ptr type = grid.get_physical_type({i, j, layer}); - int width_offset = grid.get_width_offset({i, j, layer}); - int height_offset = grid.get_height_offset({i, j, layer}); - - const vtr::Matrix& Fc = Fc_out[type->index]; - - for (int pin_index = 0; pin_index < type->num_pins; ++pin_index) { - // We only are working with opins so skip non-drivers - if (get_pin_type_from_pin_physical_num(type, pin_index) != e_pin_type::DRIVER) { - continue; - } - - // Can't do anything if pin isn't at this location - if (0 == type->pinloc[width_offset][height_offset][side][pin_index]) { - continue; - } - - // get number of tracks that this pin connects to - int total_pin_Fc = 0; - for (int iseg = 0; iseg < num_seg_types; iseg++) { - total_pin_Fc += Fc[pin_index][iseg]; - } - - RRNodeId node_index = rr_graph_builder.node_lookup().find_node(layer, i, j, e_rr_type::OPIN, pin_index, side); - VTR_ASSERT(node_index); - - if (total_pin_Fc > 0) { - get_bidir_opin_connections(rr_graph_builder, layer, i, j, pin_index, - node_index, rr_edges_to_create, opin_to_track_map, - chan_details_x, - chan_details_y); - } - - // Add in direct connections - get_opin_direct_connections(rr_graph_builder, rr_graph, layer, i, j, side, pin_index, - node_index, rr_edges_to_create, - directs, clb_to_clb_directs); - } -} void free_rr_graph() { // Frees all the routing graph data structures, if they have been allocated. @@ -2705,259 +2543,6 @@ static vtr::NdMatrix, 4> alloc_and_load_track_to_pin_lookup(vtr return track_to_pin_lookup; } -static void build_unidir_rr_opins(RRGraphBuilder& rr_graph_builder, - const RRGraphView& rr_graph, - const int layer, - const int i, - const int j, - const e_side side, - const DeviceGrid& grid, - const std::vector>& Fc_out, - const t_chan_width& nodes_per_chan, - const t_chan_details& chan_details_x, - const t_chan_details& chan_details_y, - vtr::NdMatrix& Fc_xofs, - vtr::NdMatrix& Fc_yofs, - t_rr_edge_info_set& rr_edges_to_create, - bool* Fc_clipped, - const t_unified_to_parallel_seg_index& seg_index_map, - const std::vector& directs, - const std::vector& clb_to_clb_directs, - const int num_seg_types, - int& rr_edge_count) { - // This routine adds the edges from opins to channels at the specified grid location (i,j) and grid tile side - *Fc_clipped = false; - - t_physical_tile_type_ptr type = grid.get_physical_type({i, j, layer}); - int width_offset = grid.get_width_offset({i, j, layer}); - int height_offset = grid.get_height_offset({i, j, layer}); - - // Go through each pin and find its fanout. - for (int pin_index = 0; pin_index < type->num_pins; ++pin_index) { - e_pin_type pin_type = get_pin_type_from_pin_physical_num(type, pin_index); - - // Skip global pins and pins that are not of DRIVER type - if (pin_type != e_pin_type::DRIVER || type->is_ignored_pin[pin_index]) { - continue; - } - - RRNodeId opin_node_index = rr_graph_builder.node_lookup().find_node(layer, i, j, e_rr_type::OPIN, pin_index, side); - if (!opin_node_index) { - continue; // No valid from node - } - - for (int iseg = 0; iseg < num_seg_types; iseg++) { - // Fc for this segment type - int seg_type_Fc = Fc_out[type->index][pin_index][iseg]; - VTR_ASSERT(seg_type_Fc >= 0); - - // Skip if the pin is not at this location or is not connected - if (seg_type_Fc == 0 || !type->pinloc[width_offset][height_offset][side][pin_index]) { - continue; - } - - // Figure out the chan seg at that side. - // side is the side of the logic or io block. - bool vert = (side == TOP) || (side == BOTTOM); - bool pos_dir = (side == TOP) || (side == RIGHT); - e_rr_type chan_type = (vert ? e_rr_type::CHANX : e_rr_type::CHANY); - int chan = (vert ? (j) : (i)); - int seg = (vert ? (i) : (j)); - int max_len = (vert ? grid.width() : grid.height()); - e_parallel_axis wanted_axis = chan_type == e_rr_type::CHANX ? e_parallel_axis::X_AXIS : e_parallel_axis::Y_AXIS; - int seg_index = get_parallel_seg_index(iseg, seg_index_map, wanted_axis); - - // The segment at index iseg doesn't have the proper adjacency so skip building Fc_out connections for it. - if (seg_index < 0) { - continue; - } - - vtr::NdMatrix& Fc_ofs = (vert ? Fc_xofs : Fc_yofs); - if (false == pos_dir) { - --chan; - } - - // Skip the location if there is no channel. - if (chan < 0) { - continue; - } - if (seg < 1) { - continue; - } - if (seg > int(vert ? grid.width() : grid.height()) - 2) { //-2 since no channels around perim - continue; - } - if (chan > int(vert ? grid.height() : grid.width()) - 2) { //-2 since no channels around perim - continue; - } - - const t_chan_seg_details* seg_details = (chan_type == e_rr_type::CHANX ? chan_details_x[seg][chan] : chan_details_y[chan][seg]).data(); - - if (seg_details[0].length() == 0) { - continue; - } - - // Get the list of opin to mux connections for that chan seg. - bool clipped; - - // Check the pin physical layer and connect it to the same layer if necessary - rr_edge_count += get_unidir_opin_connections(rr_graph_builder, layer, chan, seg, - seg_type_Fc, seg_index, chan_type, seg_details, - opin_node_index, - rr_edges_to_create, - Fc_ofs, max_len, nodes_per_chan, - &clipped); - - if (clipped) { - *Fc_clipped = true; - } - } - - // Add in direct connections - get_opin_direct_connections(rr_graph_builder, rr_graph, layer, i, j, side, pin_index, opin_node_index, rr_edges_to_create, - directs, clb_to_clb_directs); - } -} - -/* Add all direct clb-pin-to-clb-pin edges to given opin - * - * The current opin is located at (layer,x,y) along the specified side - */ -static int get_opin_direct_connections(RRGraphBuilder& rr_graph_builder, - const RRGraphView& rr_graph, - int layer, - int x, - int y, - e_side side, - int opin, - RRNodeId from_rr_node, - t_rr_edge_info_set& rr_edges_to_create, - const std::vector& directs, - const std::vector& clb_to_clb_directs) { - auto& device_ctx = g_vpr_ctx.device(); - - t_physical_tile_type_ptr curr_type = device_ctx.grid.get_physical_type({x, y, layer}); - - int num_pins = 0; - - int width_offset = device_ctx.grid.get_width_offset({x, y, layer}); - int height_offset = device_ctx.grid.get_height_offset({x, y, layer}); - if (!curr_type->pinloc[width_offset][height_offset][side][opin]) { - return num_pins; //No source pin on this side - } - - //Capacity location determined by pin number relative to pins per capacity instance - auto [z, relative_opin] = get_capacity_location_from_physical_pin(curr_type, opin); - VTR_ASSERT(z >= 0 && z < curr_type->capacity); - const int num_directs = directs.size(); - - // Iterate through all direct connections - for (int i = 0; i < num_directs; i++) { - // Find matching direct clb-to-clb connections with the same type as current grid location - if (clb_to_clb_directs[i].from_clb_type == curr_type) { //We are at a valid starting point - if (directs[i].from_side != NUM_2D_SIDES && directs[i].from_side != side) continue; - - // Offset must be in range - if (x + directs[i].x_offset < int(device_ctx.grid.width() - 1) - && x + directs[i].x_offset > 0 - && y + directs[i].y_offset < int(device_ctx.grid.height() - 1) - && y + directs[i].y_offset > 0) { - // Only add connections if the target clb type matches the type in the direct specification - t_physical_tile_type_ptr target_type = device_ctx.grid.get_physical_type({x + directs[i].x_offset, - y + directs[i].y_offset, - layer}); - - if (clb_to_clb_directs[i].to_clb_type == target_type - && z + directs[i].sub_tile_offset < int(target_type->capacity) - && z + directs[i].sub_tile_offset >= 0) { - // Compute index of opin with regards to given pins - int max_index = UNDEFINED, min_index = UNDEFINED; - bool swap = false; - if (clb_to_clb_directs[i].from_clb_pin_start_index > clb_to_clb_directs[i].from_clb_pin_end_index) { - swap = true; - max_index = clb_to_clb_directs[i].from_clb_pin_start_index; - min_index = clb_to_clb_directs[i].from_clb_pin_end_index; - } else { - swap = false; - min_index = clb_to_clb_directs[i].from_clb_pin_start_index; - max_index = clb_to_clb_directs[i].from_clb_pin_end_index; - } - - if (max_index >= relative_opin && min_index <= relative_opin) { - int offset = relative_opin - min_index; - // This opin is specified to connect directly to an ipin, now compute which ipin to connect to - int relative_ipin = UNDEFINED; - if (clb_to_clb_directs[i].to_clb_pin_start_index > clb_to_clb_directs[i].to_clb_pin_end_index) { - if (swap) { - relative_ipin = clb_to_clb_directs[i].to_clb_pin_end_index + offset; - } else { - relative_ipin = clb_to_clb_directs[i].to_clb_pin_start_index - offset; - } - } else { - if (swap) { - relative_ipin = clb_to_clb_directs[i].to_clb_pin_end_index - offset; - } else { - relative_ipin = clb_to_clb_directs[i].to_clb_pin_start_index + offset; - } - } - - //directs[i].sub_tile_offset is added to from_capacity(z) to get the - // target_capacity - int target_cap = z + directs[i].sub_tile_offset; - - // Iterate over all sub_tiles to get the sub_tile which the target_cap belongs to. - const t_sub_tile* target_sub_tile = nullptr; - for (const t_sub_tile& sub_tile : target_type->sub_tiles) { - if (sub_tile.capacity.is_in_range(target_cap)) { - target_sub_tile = &sub_tile; - break; - } - } - VTR_ASSERT(target_sub_tile != nullptr); - if (relative_ipin >= target_sub_tile->num_phy_pins) continue; - - // If this block has capacity > 1 then the pins of z position > 0 are offset - // by the number of pins per capacity instance - int ipin = get_physical_pin_from_capacity_location(target_type, relative_ipin, target_cap); - - // Add new ipin edge to list of edges - std::vector inodes; - - int target_width_offset = device_ctx.grid.get_width_offset({x + directs[i].x_offset, y + directs[i].y_offset, layer}); - int target_height_offset = device_ctx.grid.get_height_offset({x + directs[i].x_offset, y + directs[i].y_offset, layer}); - int final_ipin_x = x + directs[i].x_offset - target_width_offset + target_type->pin_width_offset[ipin]; - int final_ipin_y = y + directs[i].y_offset - target_height_offset + target_type->pin_height_offset[ipin]; - - if (directs[i].to_side != NUM_2D_SIDES) { - //Explicit side specified, only create if pin exists on that side - RRNodeId inode = rr_graph_builder.node_lookup().find_node(layer, final_ipin_x, final_ipin_y, - e_rr_type::IPIN, ipin, directs[i].to_side); - if (inode) { - inodes.push_back(inode); - } - } else { - //No side specified, get all candidates - inodes = rr_graph_builder.node_lookup().find_nodes_at_all_sides(layer, final_ipin_x, final_ipin_y, e_rr_type::IPIN, ipin); - } - - if (!inodes.empty()) { - // There may be multiple physical pins corresponding to the logical - // target ipin. We only need to connect to one of them (since the physical pins - // are logically equivalent). This also ensures the graphics look reasonable and map - // back fairly directly to the architecture file in the case of pin equivalence - RRNodeId inode = pick_best_direct_connect_target_rr_node(rr_graph, from_rr_node, inodes); - - rr_edges_to_create.emplace_back(from_rr_node, inode, clb_to_clb_directs[i].switch_index, false); - ++num_pins; - } - } - } - } - } - } - return num_pins; -} - static std::vector alloc_and_load_perturb_opins(const t_physical_tile_type_ptr type, const vtr::Matrix& Fc_out, const int max_chan_width, @@ -3053,70 +2638,6 @@ static std::vector alloc_and_load_perturb_opins(const t_physical_tile_type return perturb_opins; } -static RRNodeId pick_best_direct_connect_target_rr_node(const RRGraphView& rr_graph, - RRNodeId from_rr, - const std::vector& candidate_rr_nodes) { - //With physically equivalent pins there may be multiple candidate rr nodes (which are equivalent) - //to connect the direct edge to. - //As a result it does not matter (from a correctness standpoint) which is picked. - // - //However intuitively we would expect (e.g. when visualizing the drawn RR graph) that the 'closest' - //candidate would be picked (i.e. to minimize the drawn edge length). - // - //This function attempts to pick the 'best/closest' of the candidates. - VTR_ASSERT(rr_graph.node_type(from_rr) == e_rr_type::OPIN); - - float best_dist = std::numeric_limits::infinity(); - RRNodeId best_rr = RRNodeId::INVALID(); - - for (const e_side& from_side : TOTAL_2D_SIDES) { - /* Bypass those side where the node does not appear */ - if (!rr_graph.is_node_on_specific_side(from_rr, from_side)) { - continue; - } - - for (RRNodeId to_rr : candidate_rr_nodes) { - VTR_ASSERT(rr_graph.node_type(to_rr) == e_rr_type::IPIN); - float to_dist = std::abs(rr_graph.node_xlow(from_rr) - rr_graph.node_xlow(to_rr)) - + std::abs(rr_graph.node_ylow(from_rr) - rr_graph.node_ylow(to_rr)); - - for (const e_side& to_side : TOTAL_2D_SIDES) { - /* Bypass those side where the node does not appear */ - if (!rr_graph.is_node_on_specific_side(to_rr, to_side)) { - continue; - } - - //Include a partial unit of distance based on side alignment to ensure - //we prefer facing sides - if ((from_side == RIGHT && to_side == LEFT) - || (from_side == LEFT && to_side == RIGHT) - || (from_side == TOP && to_side == BOTTOM) - || (from_side == BOTTOM && to_side == TOP)) { - //Facing sides - to_dist += 0.25; - } else if (((from_side == RIGHT || from_side == LEFT) && (to_side == TOP || to_side == BOTTOM)) - || ((from_side == TOP || from_side == BOTTOM) && (to_side == RIGHT || to_side == LEFT))) { - //Perpendicular sides - to_dist += 0.5; - - } else { - //Opposite sides - to_dist += 0.75; - } - - if (to_dist < best_dist) { - best_dist = to_dist; - best_rr = to_rr; - } - } - } - } - - VTR_ASSERT(best_rr); - - return best_rr; -} - //Collects the sets of connected non-configurable edges in the RR graph static void create_edge_groups(EdgeGroups* groups) { auto& device_ctx = g_vpr_ctx.device(); diff --git a/vpr/src/route/rr_graph_generation/rr_graph2.cpp b/vpr/src/route/rr_graph_generation/rr_graph2.cpp index c7bb69c33c..54c43332a0 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph2.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph2.cpp @@ -130,28 +130,6 @@ static int vpr_to_phy_track(const int itrack, const t_chan_seg_details* seg_details, const e_directionality directionality); -/** - * @brief Identifies and labels all mux endpoints at a given channel segment coordinate. - * - * This routine scans all routing tracks within a channel segment (specified by - * 'chan_num' and 'seg_num') and collects the track indices corresponding to - * valid mux endpoints that can be driven by OPINs in that channel segment. - * The resulting list of eligible tracks is returned in natural (increasing) track order. - * - * @details If @p seg_type_index is UNDEFINED, all segment types are considered. - */ -static void label_wire_muxes(const int chan_num, - const int seg_num, - const t_chan_seg_details* seg_details, - const int seg_type_index, - const int max_len, - const enum Direction dir, - const int max_chan_width, - const bool check_cb, - std::vector& labels, - int* num_wire_muxes, - int* num_wire_muxes_cb_restricted); - static void label_incoming_wires(const int chan_num, const int seg_num, const int sb_seg, @@ -586,172 +564,6 @@ int get_seg_end(const t_chan_seg_details* seg_details, const int itrack, const i return seg_end; } -/* Returns the number of tracks to which clb opin #ipin at (i,j) connects. * - * Also stores the nodes to which this pin connects in rr_edges_to_create */ -int get_bidir_opin_connections(RRGraphBuilder& rr_graph_builder, - const int layer, - const int i, - const int j, - const int ipin, - RRNodeId from_rr_node, - t_rr_edge_info_set& rr_edges_to_create, - const t_pin_to_track_lookup& opin_to_track_map, - const t_chan_details& chan_details_x, - const t_chan_details& chan_details_y) { - const DeviceContext& device_ctx = g_vpr_ctx.device(); - - t_physical_tile_type_ptr type = device_ctx.grid.get_physical_type({i, j, layer}); - int width_offset = device_ctx.grid.get_width_offset({i, j, layer}); - int height_offset = device_ctx.grid.get_height_offset({i, j, layer}); - - int num_conn = 0; - - // [0..device_ctx.num_block_types-1][0..num_pins-1][0..width][0..height][0..3][0..Fc-1] - for (e_side side : TOTAL_2D_SIDES) { - // Figure out coords of channel segment based on side - int tr_i = (side == LEFT) ? i - 1 : i; - int tr_j = (side == BOTTOM) ? j - 1 : j; - - e_rr_type to_type = ((side == LEFT) || (side == RIGHT)) ? e_rr_type::CHANY : e_rr_type::CHANX; - - int chan = (to_type == e_rr_type::CHANX) ? tr_j : tr_i; - int seg = (to_type == e_rr_type::CHANX) ? tr_i : tr_j; - - bool vert = !((side == TOP) || (side == BOTTOM)); - - // Don't connect where no tracks on fringes - if (tr_i < 0 || tr_i > int(device_ctx.grid.width() - 2)) { //-2 for no perimeter channels - continue; - } - if (tr_j < 0 || tr_j > int(device_ctx.grid.height() - 2)) { //-2 for no perimeter channels - continue; - } - if (e_rr_type::CHANX == to_type && tr_i < 1) { - continue; - } - if (e_rr_type::CHANY == to_type && tr_j < 1) { - continue; - } - if (opin_to_track_map[type->index].empty()) { - continue; - } - - bool is_connected_track = false; - - const t_chan_seg_details* seg_details = (vert ? chan_details_y[chan][seg] : chan_details_x[seg][chan]).data(); - - // Iterate of the opin to track connections - for (int to_track : opin_to_track_map[type->index][ipin][width_offset][height_offset][side]) { - /* Skip unconnected connections */ - if (UNDEFINED == to_track || is_connected_track) { - is_connected_track = true; - VTR_ASSERT(UNDEFINED == opin_to_track_map[type->index][ipin][width_offset][height_offset][side][0]); - continue; - } - - // Only connect to wire if there is a CB - if (is_cblock(chan, seg, to_track, seg_details)) { - RRNodeId to_node = rr_graph_builder.node_lookup().find_node(layer, tr_i, tr_j, to_type, to_track); - - if (!to_node) { - continue; - } - - int to_switch = seg_details[to_track].arch_wire_switch(); - rr_edges_to_create.emplace_back(from_rr_node, to_node, to_switch, false); - - ++num_conn; - } - } - } - - return num_conn; -} - -/* Actually builds the edges from the OPIN nodes already allocated to their correct tracks for segment seg_Inf[seg_type_index]. - * Note that this seg_inf vector is NOT the segment_info vectored as stored in the device variable. This index is w.r.t to seg_inf_x - * or seg_inf_y for x-adjacent and y-adjacent segments respectively. This index is assigned in get_seg_details earlier - * in the rr_graph_builder routine. This t_seg_detail is then used to build t_chan_seg_details which is passed in to label_wire mux - * routine used in this function. - */ -int get_unidir_opin_connections(RRGraphBuilder& rr_graph_builder, - const int layer, - const int chan, - const int seg, - int Fc, - const int seg_type_index, - const e_rr_type chan_type, - const t_chan_seg_details* seg_details, - RRNodeId from_rr_node, - t_rr_edge_info_set& rr_edges_to_create, - vtr::NdMatrix& Fc_ofs, - const int max_len, - const t_chan_width& nodes_per_chan, - bool* Fc_clipped) { - /* Gets a linked list of Fc nodes of specified seg_type_index to connect - * to in given chan seg. Fc_ofs is used for the opin staggering pattern. */ - - *Fc_clipped = false; - - // Fc is assigned in pairs so check it is even. - VTR_ASSERT(Fc % 2 == 0); - - // get_rr_node_indices needs x and y coords. - int x = (e_rr_type::CHANX == chan_type) ? seg : chan; - int y = (e_rr_type::CHANX == chan_type) ? chan : seg; - - // Get the lists of possible muxes. - int dummy; - std::vector inc_muxes; - std::vector dec_muxes; - int num_inc_muxes, num_dec_muxes; - // Determine the channel width instead of using max channels to not create hanging nodes - int max_chan_width = (e_rr_type::CHANX == chan_type) ? nodes_per_chan.x_list[y] : nodes_per_chan.y_list[x]; - - label_wire_muxes(chan, seg, seg_details, seg_type_index, max_len, - Direction::INC, max_chan_width, true, inc_muxes, &num_inc_muxes, &dummy); - label_wire_muxes(chan, seg, seg_details, seg_type_index, max_len, - Direction::DEC, max_chan_width, true, dec_muxes, &num_dec_muxes, &dummy); - - // Clip Fc to the number of muxes. - if (((Fc / 2) > num_inc_muxes) || ((Fc / 2) > num_dec_muxes)) { - *Fc_clipped = true; - Fc = 2 * std::min(num_inc_muxes, num_dec_muxes); - } - - // Assign tracks to meet Fc demand - int num_edges = 0; - for (int iconn = 0; iconn < (Fc / 2); ++iconn) { - // Figure of the next mux to use for the 'inc' and 'dec' connections - int inc_mux = Fc_ofs[chan][seg][seg_type_index] % num_inc_muxes; - int dec_mux = Fc_ofs[chan][seg][seg_type_index] % num_dec_muxes; - ++Fc_ofs[chan][seg][seg_type_index]; - - // Figure out the track it corresponds to. - int inc_track = inc_muxes[inc_mux]; - int dec_track = dec_muxes[dec_mux]; - - // Figure the inodes of those muxes - RRNodeId inc_inode_index = rr_graph_builder.node_lookup().find_node(layer, x, y, chan_type, inc_track); - RRNodeId dec_inode_index = rr_graph_builder.node_lookup().find_node(layer, x, y, chan_type, dec_track); - - if (!inc_inode_index || !dec_inode_index) { - continue; - } - - // Add to the list. - short to_switch = seg_details[inc_track].arch_opin_switch(); - rr_edges_to_create.emplace_back(from_rr_node, inc_inode_index, to_switch, false); - ++num_edges; - - to_switch = seg_details[dec_track].arch_opin_switch(); - rr_edges_to_create.emplace_back(from_rr_node, dec_inode_index, to_switch, false); - ++num_edges; - } - - return num_edges; -} - bool is_cblock(const int chan, const int seg, const int track, const t_chan_seg_details* seg_details) { int length = seg_details[track].length(); @@ -1943,7 +1755,7 @@ void load_sblock_pattern_lookup(const int i, } } -static void label_wire_muxes(const int chan_num, +void label_wire_muxes(const int chan_num, const int seg_num, const t_chan_seg_details* seg_details, const int seg_type_index, @@ -1954,55 +1766,53 @@ static void label_wire_muxes(const int chan_num, std::vector& labels, int* num_wire_muxes, int* num_wire_muxes_cb_restricted) { - /* COUNT pass then a LOAD pass */ + // COUNT pass then a LOAD pass int num_labels = 0; int num_labels_restricted = 0; for (int pass = 0; pass < 2; ++pass) { - /* Alloc the list on LOAD pass */ + // Alloc the list on LOAD pass if (pass > 0) { labels.resize(num_labels); std::ranges::fill(labels, 0); num_labels = 0; } - /* Find the tracks that are starting. */ + // Find the tracks that are starting. for (int itrack = 0; itrack < max_chan_width; ++itrack) { int start = get_seg_start(seg_details, itrack, chan_num, seg_num); int end = get_seg_end(seg_details, itrack, start, chan_num, max_len); - /* Skip tracks that are undefined */ + // Skip tracks that are undefined if (seg_details[itrack].length() == 0) { continue; } - /* Skip tracks going the wrong way */ + // Skip tracks going the wrong way if (seg_details[itrack].direction() != dir) { continue; } if (seg_type_index != UNDEFINED) { - /* skip tracks that don't belong to the specified segment type */ + // skip tracks that don't belong to the specified segment type if (seg_details[itrack].index() != seg_type_index) { continue; } } - /* Determine if we are a wire startpoint */ + // Determine if we are a wire startpoint bool is_endpoint = (seg_num == start); if (Direction::DEC == seg_details[itrack].direction()) { is_endpoint = (seg_num == end); } - /* Count the labels and load if LOAD pass */ + // Count the labels and load if LOAD pass if (is_endpoint) { - /* - * not all wire endpoints can be driven by OPIN (depending on the pattern in the arch file) - * the check_cb is targeting this arch specification: - * if this function is called by get_unidir_opin_connections(), - * then we need to check if mux connections can be added to this type of wire, - * otherwise, this function should not consider specification. - */ - if ((!check_cb) || (seg_details[itrack].cb(0) == true)) { + // not all wire endpoints can be driven by OPIN (depending on the pattern in the arch file) + // the check_cb is targeting this arch specification: + // if this function is called by get_unidir_opin_connections(), + // then we need to check if mux connections can be added to this type of wire, + // otherwise, this function should not consider specification. + if (!check_cb || seg_details[itrack].cb(0) == true) { if (pass > 0) { labels[num_labels] = itrack; } diff --git a/vpr/src/route/rr_graph_generation/rr_graph2.h b/vpr/src/route/rr_graph_generation/rr_graph2.h index d64fffba2a..4650c69222 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph2.h +++ b/vpr/src/route/rr_graph_generation/rr_graph2.h @@ -63,32 +63,6 @@ bool is_sblock(const int chan, const t_chan_seg_details* seg_details, const enum e_directionality directionality); -int get_bidir_opin_connections(RRGraphBuilder& rr_graph_builder, - const int layer, - const int i, - const int j, - const int ipin, - RRNodeId from_rr_node, - t_rr_edge_info_set& rr_edges_to_create, - const t_pin_to_track_lookup& opin_to_track_map, - const t_chan_details& chan_details_x, - const t_chan_details& chan_details_y); - -int get_unidir_opin_connections(RRGraphBuilder& rr_graph_builder, - const int layer, - const int chan, - const int seg, - int Fc, - const int seg_type_index, - const e_rr_type chan_type, - const t_chan_seg_details* seg_details, - RRNodeId from_rr_node, - t_rr_edge_info_set& rr_edges_to_create, - vtr::NdMatrix& Fc_ofs, - const int max_len, - const t_chan_width& nodes_per_chan, - bool* Fc_clipped); - /// Adds the fan-out edges from wire segment at (chan, seg, track) to adjacent blocks along the wire's length int get_track_to_pins(RRGraphBuilder& rr_graph_builder, int layer, @@ -127,6 +101,28 @@ int get_track_to_tracks(RRGraphBuilder& rr_graph_builder, const vtr::NdMatrix, 3>& switch_block_conn, const t_sb_connection_map* sb_conn_map); +/** + * @brief Identifies and labels all mux endpoints at a given channel segment coordinate. + * + * This routine scans all routing tracks within a channel segment (specified by + * 'chan_num' and 'seg_num') and collects the track indices corresponding to + * valid mux endpoints that can be driven by OPINs in that channel segment. + * The resulting list of eligible tracks is returned in natural (increasing) track order. + * + * @details If @p seg_type_index is UNDEFINED, all segment types are considered. + */ +void label_wire_muxes(const int chan_num, + const int seg_num, + const t_chan_seg_details* seg_details, + const int seg_type_index, + const int max_len, + const enum Direction dir, + const int max_chan_width, + const bool check_cb, + std::vector& labels, + int* num_wire_muxes, + int* num_wire_muxes_cb_restricted); + t_sblock_pattern alloc_sblock_pattern_lookup(const DeviceGrid& grid, const t_chan_width& nodes_per_chan); diff --git a/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.cpp b/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.cpp new file mode 100644 index 0000000000..c102e4f8d7 --- /dev/null +++ b/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.cpp @@ -0,0 +1,717 @@ + +#include "rr_graph_opin_chan_edges.h" + +#include "rr_graph2.h" +#include "rr_graph_sg.h" +#include "rr_graph_builder.h" +#include "rr_graph_view.h" +#include "rr_types.h" +#include "rr_graph_type.h" +#include "clb2clb_directs.h" +#include "get_parallel_segs.h" +#include "build_scatter_gathers.h" + +#include "globals.h" +#include "physical_types_util.h" + +static void build_bidir_rr_opins(RRGraphBuilder& rr_graph_builder, + const RRGraphView& rr_graph, + int layer, + int i, + int j, + e_side side, + const t_pin_to_track_lookup& opin_to_track_map, + const std::vector>& Fc_out, + t_rr_edge_info_set& created_rr_edges, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + const DeviceGrid& grid, + const std::vector& directs, + const std::vector& clb_to_clb_directs, + int num_seg_types); + +static void build_unidir_rr_opins(RRGraphBuilder& rr_graph_builder, + const RRGraphView& rr_graph, + int layer, + int i, + int j, + e_side side, + const DeviceGrid& grid, + const std::vector>& Fc_out, + const t_chan_width& nodes_per_chan, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + vtr::NdMatrix& Fc_xofs, + vtr::NdMatrix& Fc_yofs, + t_rr_edge_info_set& created_rr_edges, + bool* Fc_clipped, + const t_unified_to_parallel_seg_index& seg_index_map, + const std::vector& directs, + const std::vector& clb_to_clb_directs, + int num_seg_types, + int& edge_count); + +static int get_bidir_opin_connections(RRGraphBuilder& rr_graph_builder, + int layer, + int i, + int j, + int ipin, + RRNodeId from_rr_node, + t_rr_edge_info_set& rr_edges_to_create, + const t_pin_to_track_lookup& opin_to_track_map, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y); + +static int get_unidir_opin_connections(RRGraphBuilder& rr_graph_builder, + int layer, + int chan, + int seg, + int Fc, + int seg_type_index, + e_rr_type chan_type, + const t_chan_seg_details* seg_details, + RRNodeId from_rr_node, + t_rr_edge_info_set& rr_edges_to_create, + vtr::NdMatrix& Fc_ofs, + int max_len, + const t_chan_width& nodes_per_chan, + bool* Fc_clipped); + +static int get_opin_direct_connections(RRGraphBuilder& rr_graph_builder, + const RRGraphView& rr_graph, + int layer, + int x, + int y, + e_side side, + int opin, + RRNodeId from_rr_node, + t_rr_edge_info_set& rr_edges_to_create, + const std::vector& directs, + const std::vector& clb_to_clb_directs); + +static RRNodeId pick_best_direct_connect_target_rr_node(const RRGraphView& rr_graph, + RRNodeId from_rr, + const std::vector& candidate_rr_nodes); + + +static void build_bidir_rr_opins(RRGraphBuilder& rr_graph_builder, + const RRGraphView& rr_graph, + int layer, + int i, + int j, + e_side side, + const t_pin_to_track_lookup& opin_to_track_map, + const std::vector>& Fc_out, + t_rr_edge_info_set& rr_edges_to_create, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + const DeviceGrid& grid, + const std::vector& directs, + const std::vector& clb_to_clb_directs, + int num_seg_types) { + // Don't connect pins which are not adjacent to channels around the perimeter + if ((i == 0 && side != RIGHT) + || (i == int(grid.width() - 1) && side != LEFT) + || (j == 0 && side != TOP) + || (j == int(grid.height() - 1) && side != BOTTOM)) { + return; + } + + t_physical_tile_type_ptr type = grid.get_physical_type({i, j, layer}); + int width_offset = grid.get_width_offset({i, j, layer}); + int height_offset = grid.get_height_offset({i, j, layer}); + + const vtr::Matrix& Fc = Fc_out[type->index]; + + for (int pin_index = 0; pin_index < type->num_pins; ++pin_index) { + // We only are working with opins so skip non-drivers + if (get_pin_type_from_pin_physical_num(type, pin_index) != e_pin_type::DRIVER) { + continue; + } + + // Can't do anything if pin isn't at this location + if (0 == type->pinloc[width_offset][height_offset][side][pin_index]) { + continue; + } + + // get number of tracks that this pin connects to + int total_pin_Fc = 0; + for (int iseg = 0; iseg < num_seg_types; iseg++) { + total_pin_Fc += Fc[pin_index][iseg]; + } + + RRNodeId node_index = rr_graph_builder.node_lookup().find_node(layer, i, j, e_rr_type::OPIN, pin_index, side); + VTR_ASSERT(node_index); + + if (total_pin_Fc > 0) { + get_bidir_opin_connections(rr_graph_builder, layer, i, j, pin_index, + node_index, rr_edges_to_create, opin_to_track_map, + chan_details_x, + chan_details_y); + } + + // Add in direct connections + get_opin_direct_connections(rr_graph_builder, rr_graph, layer, i, j, side, pin_index, + node_index, rr_edges_to_create, + directs, clb_to_clb_directs); + } +} + +static void build_unidir_rr_opins(RRGraphBuilder& rr_graph_builder, + const RRGraphView& rr_graph, + int layer, + int i, + int j, + e_side side, + const DeviceGrid& grid, + const std::vector>& Fc_out, + const t_chan_width& nodes_per_chan, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + vtr::NdMatrix& Fc_xofs, + vtr::NdMatrix& Fc_yofs, + t_rr_edge_info_set& rr_edges_to_create, + bool* Fc_clipped, + const t_unified_to_parallel_seg_index& seg_index_map, + const std::vector& directs, + const std::vector& clb_to_clb_directs, + int num_seg_types, + int& rr_edge_count) { + // This routine adds the edges from opins to channels at the specified grid location (i,j) and grid tile side + *Fc_clipped = false; + + t_physical_tile_type_ptr type = grid.get_physical_type({i, j, layer}); + int width_offset = grid.get_width_offset({i, j, layer}); + int height_offset = grid.get_height_offset({i, j, layer}); + + // Go through each pin and find its fanout. + for (int pin_index = 0; pin_index < type->num_pins; ++pin_index) { + e_pin_type pin_type = get_pin_type_from_pin_physical_num(type, pin_index); + + // Skip global pins and pins that are not of DRIVER type + if (pin_type != e_pin_type::DRIVER || type->is_ignored_pin[pin_index]) { + continue; + } + + RRNodeId opin_node_index = rr_graph_builder.node_lookup().find_node(layer, i, j, e_rr_type::OPIN, pin_index, side); + if (!opin_node_index) { + continue; // No valid from node + } + + for (int iseg = 0; iseg < num_seg_types; iseg++) { + // Fc for this segment type + int seg_type_Fc = Fc_out[type->index][pin_index][iseg]; + VTR_ASSERT(seg_type_Fc >= 0); + + // Skip if the pin is not at this location or is not connected + if (seg_type_Fc == 0 || !type->pinloc[width_offset][height_offset][side][pin_index]) { + continue; + } + + // Figure out the chan seg at that side. + // side is the side of the logic or io block. + bool vert = (side == TOP) || (side == BOTTOM); + bool pos_dir = (side == TOP) || (side == RIGHT); + e_rr_type chan_type = (vert ? e_rr_type::CHANX : e_rr_type::CHANY); + int chan = (vert ? (j) : (i)); + int seg = (vert ? (i) : (j)); + int max_len = (vert ? grid.width() : grid.height()); + e_parallel_axis wanted_axis = chan_type == e_rr_type::CHANX ? e_parallel_axis::X_AXIS : e_parallel_axis::Y_AXIS; + int seg_index = get_parallel_seg_index(iseg, seg_index_map, wanted_axis); + + // The segment at index iseg doesn't have the proper adjacency so skip building Fc_out connections for it. + if (seg_index < 0) { + continue; + } + + vtr::NdMatrix& Fc_ofs = (vert ? Fc_xofs : Fc_yofs); + if (false == pos_dir) { + --chan; + } + + // Skip the location if there is no channel. + if (chan < 0) { + continue; + } + if (seg < 1) { + continue; + } + if (seg > int(vert ? grid.width() : grid.height()) - 2) { //-2 since no channels around perim + continue; + } + if (chan > int(vert ? grid.height() : grid.width()) - 2) { //-2 since no channels around perim + continue; + } + + const t_chan_seg_details* seg_details = (chan_type == e_rr_type::CHANX ? chan_details_x[seg][chan] : chan_details_y[chan][seg]).data(); + + if (seg_details[0].length() == 0) { + continue; + } + + // Get the list of opin to mux connections for that chan seg. + bool clipped; + + // Check the pin physical layer and connect it to the same layer if necessary + rr_edge_count += get_unidir_opin_connections(rr_graph_builder, layer, chan, seg, + seg_type_Fc, seg_index, chan_type, seg_details, + opin_node_index, + rr_edges_to_create, + Fc_ofs, max_len, nodes_per_chan, + &clipped); + + if (clipped) { + *Fc_clipped = true; + } + } + + // Add in direct connections + get_opin_direct_connections(rr_graph_builder, rr_graph, layer, i, j, side, pin_index, opin_node_index, rr_edges_to_create, + directs, clb_to_clb_directs); + } +} + +/* Returns the number of tracks to which clb opin #ipin at (i,j) connects. * + * Also stores the nodes to which this pin connects in rr_edges_to_create */ +int get_bidir_opin_connections(RRGraphBuilder& rr_graph_builder, + int layer, + int i, + int j, + int ipin, + RRNodeId from_rr_node, + t_rr_edge_info_set& rr_edges_to_create, + const t_pin_to_track_lookup& opin_to_track_map, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y) { + const DeviceContext& device_ctx = g_vpr_ctx.device(); + + t_physical_tile_type_ptr type = device_ctx.grid.get_physical_type({i, j, layer}); + int width_offset = device_ctx.grid.get_width_offset({i, j, layer}); + int height_offset = device_ctx.grid.get_height_offset({i, j, layer}); + + int num_conn = 0; + + // [0..device_ctx.num_block_types-1][0..num_pins-1][0..width][0..height][0..3][0..Fc-1] + for (e_side side : TOTAL_2D_SIDES) { + // Figure out coords of channel segment based on side + int tr_i = (side == LEFT) ? i - 1 : i; + int tr_j = (side == BOTTOM) ? j - 1 : j; + + e_rr_type to_type = ((side == LEFT) || (side == RIGHT)) ? e_rr_type::CHANY : e_rr_type::CHANX; + + int chan = (to_type == e_rr_type::CHANX) ? tr_j : tr_i; + int seg = (to_type == e_rr_type::CHANX) ? tr_i : tr_j; + + bool vert = !((side == TOP) || (side == BOTTOM)); + + // Don't connect where no tracks on fringes + if (tr_i < 0 || tr_i > int(device_ctx.grid.width() - 2)) { //-2 for no perimeter channels + continue; + } + if (tr_j < 0 || tr_j > int(device_ctx.grid.height() - 2)) { //-2 for no perimeter channels + continue; + } + if (e_rr_type::CHANX == to_type && tr_i < 1) { + continue; + } + if (e_rr_type::CHANY == to_type && tr_j < 1) { + continue; + } + if (opin_to_track_map[type->index].empty()) { + continue; + } + + bool is_connected_track = false; + + const t_chan_seg_details* seg_details = (vert ? chan_details_y[chan][seg] : chan_details_x[seg][chan]).data(); + + // Iterate of the opin to track connections + for (int to_track : opin_to_track_map[type->index][ipin][width_offset][height_offset][side]) { + // Skip unconnected connections + if (UNDEFINED == to_track || is_connected_track) { + is_connected_track = true; + VTR_ASSERT(UNDEFINED == opin_to_track_map[type->index][ipin][width_offset][height_offset][side][0]); + continue; + } + + // Only connect to wire if there is a CB + if (is_cblock(chan, seg, to_track, seg_details)) { + RRNodeId to_node = rr_graph_builder.node_lookup().find_node(layer, tr_i, tr_j, to_type, to_track); + + if (!to_node) { + continue; + } + + int to_switch = seg_details[to_track].arch_wire_switch(); + rr_edges_to_create.emplace_back(from_rr_node, to_node, to_switch, false); + + ++num_conn; + } + } + } + + return num_conn; +} + +/* Actually builds the edges from the OPIN nodes already allocated to their correct tracks for segment seg_Inf[seg_type_index]. + * Note that this seg_inf vector is NOT the segment_info vectored as stored in the device variable. This index is w.r.t to seg_inf_x + * or seg_inf_y for x-adjacent and y-adjacent segments respectively. This index is assigned in get_seg_details earlier + * in the rr_graph_builder routine. This t_seg_detail is then used to build t_chan_seg_details which is passed in to label_wire mux + * routine used in this function. + */ +int get_unidir_opin_connections(RRGraphBuilder& rr_graph_builder, + int layer, + int chan, + int seg, + int Fc, + int seg_type_index, + e_rr_type chan_type, + const t_chan_seg_details* seg_details, + RRNodeId from_rr_node, + t_rr_edge_info_set& rr_edges_to_create, + vtr::NdMatrix& Fc_ofs, + int max_len, + const t_chan_width& nodes_per_chan, + bool* Fc_clipped) { + /* Gets a linked list of Fc nodes of specified seg_type_index to connect + * to in given chan seg. Fc_ofs is used for the opin staggering pattern. */ + + *Fc_clipped = false; + + // Fc is assigned in pairs so check it is even. + VTR_ASSERT(Fc % 2 == 0); + + // get_rr_node_indices needs x and y coords. + int x = (e_rr_type::CHANX == chan_type) ? seg : chan; + int y = (e_rr_type::CHANX == chan_type) ? chan : seg; + + // Get the lists of possible muxes. + int dummy; + std::vector inc_muxes; + std::vector dec_muxes; + int num_inc_muxes, num_dec_muxes; + // Determine the channel width instead of using max channels to not create hanging nodes + int max_chan_width = (e_rr_type::CHANX == chan_type) ? nodes_per_chan.x_list[y] : nodes_per_chan.y_list[x]; + + label_wire_muxes(chan, seg, seg_details, seg_type_index, max_len, + Direction::INC, max_chan_width, true, inc_muxes, &num_inc_muxes, &dummy); + label_wire_muxes(chan, seg, seg_details, seg_type_index, max_len, + Direction::DEC, max_chan_width, true, dec_muxes, &num_dec_muxes, &dummy); + + // Clip Fc to the number of muxes. + if (((Fc / 2) > num_inc_muxes) || ((Fc / 2) > num_dec_muxes)) { + *Fc_clipped = true; + Fc = 2 * std::min(num_inc_muxes, num_dec_muxes); + } + + // Assign tracks to meet Fc demand + int num_edges = 0; + for (int iconn = 0; iconn < (Fc / 2); ++iconn) { + // Figure of the next mux to use for the 'inc' and 'dec' connections + int inc_mux = Fc_ofs[chan][seg][seg_type_index] % num_inc_muxes; + int dec_mux = Fc_ofs[chan][seg][seg_type_index] % num_dec_muxes; + ++Fc_ofs[chan][seg][seg_type_index]; + + // Figure out the track it corresponds to. + int inc_track = inc_muxes[inc_mux]; + int dec_track = dec_muxes[dec_mux]; + + // Figure the inodes of those muxes + RRNodeId inc_inode_index = rr_graph_builder.node_lookup().find_node(layer, x, y, chan_type, inc_track); + RRNodeId dec_inode_index = rr_graph_builder.node_lookup().find_node(layer, x, y, chan_type, dec_track); + + if (!inc_inode_index || !dec_inode_index) { + continue; + } + + // Add to the list. + short to_switch = seg_details[inc_track].arch_opin_switch(); + rr_edges_to_create.emplace_back(from_rr_node, inc_inode_index, to_switch, false); + ++num_edges; + + to_switch = seg_details[dec_track].arch_opin_switch(); + rr_edges_to_create.emplace_back(from_rr_node, dec_inode_index, to_switch, false); + ++num_edges; + } + + return num_edges; +} + +/* Add all direct clb-pin-to-clb-pin edges to given opin + * + * The current opin is located at (layer,x,y) along the specified side + */ +static int get_opin_direct_connections(RRGraphBuilder& rr_graph_builder, + const RRGraphView& rr_graph, + int layer, + int x, + int y, + e_side side, + int opin, + RRNodeId from_rr_node, + t_rr_edge_info_set& rr_edges_to_create, + const std::vector& directs, + const std::vector& clb_to_clb_directs) { + auto& device_ctx = g_vpr_ctx.device(); + + t_physical_tile_type_ptr curr_type = device_ctx.grid.get_physical_type({x, y, layer}); + + int num_pins = 0; + + int width_offset = device_ctx.grid.get_width_offset({x, y, layer}); + int height_offset = device_ctx.grid.get_height_offset({x, y, layer}); + if (!curr_type->pinloc[width_offset][height_offset][side][opin]) { + return num_pins; //No source pin on this side + } + + //Capacity location determined by pin number relative to pins per capacity instance + auto [z, relative_opin] = get_capacity_location_from_physical_pin(curr_type, opin); + VTR_ASSERT(z >= 0 && z < curr_type->capacity); + const int num_directs = directs.size(); + + // Iterate through all direct connections + for (int i = 0; i < num_directs; i++) { + // Find matching direct clb-to-clb connections with the same type as current grid location + if (clb_to_clb_directs[i].from_clb_type == curr_type) { //We are at a valid starting point + if (directs[i].from_side != NUM_2D_SIDES && directs[i].from_side != side) continue; + + // Offset must be in range + if (x + directs[i].x_offset < int(device_ctx.grid.width() - 1) + && x + directs[i].x_offset > 0 + && y + directs[i].y_offset < int(device_ctx.grid.height() - 1) + && y + directs[i].y_offset > 0) { + // Only add connections if the target clb type matches the type in the direct specification + t_physical_tile_type_ptr target_type = device_ctx.grid.get_physical_type({x + directs[i].x_offset, + y + directs[i].y_offset, + layer}); + + if (clb_to_clb_directs[i].to_clb_type == target_type + && z + directs[i].sub_tile_offset < int(target_type->capacity) + && z + directs[i].sub_tile_offset >= 0) { + // Compute index of opin with regards to given pins + int max_index, min_index; + bool swap = false; + if (clb_to_clb_directs[i].from_clb_pin_start_index > clb_to_clb_directs[i].from_clb_pin_end_index) { + swap = true; + max_index = clb_to_clb_directs[i].from_clb_pin_start_index; + min_index = clb_to_clb_directs[i].from_clb_pin_end_index; + } else { + swap = false; + min_index = clb_to_clb_directs[i].from_clb_pin_start_index; + max_index = clb_to_clb_directs[i].from_clb_pin_end_index; + } + + if (max_index >= relative_opin && min_index <= relative_opin) { + int offset = relative_opin - min_index; + // This opin is specified to connect directly to an ipin, now compute which ipin to connect to + int relative_ipin; + if (clb_to_clb_directs[i].to_clb_pin_start_index > clb_to_clb_directs[i].to_clb_pin_end_index) { + if (swap) { + relative_ipin = clb_to_clb_directs[i].to_clb_pin_end_index + offset; + } else { + relative_ipin = clb_to_clb_directs[i].to_clb_pin_start_index - offset; + } + } else { + if (swap) { + relative_ipin = clb_to_clb_directs[i].to_clb_pin_end_index - offset; + } else { + relative_ipin = clb_to_clb_directs[i].to_clb_pin_start_index + offset; + } + } + + // directs[i].sub_tile_offset is added to from_capacity(z) to get the + // target_capacity + int target_cap = z + directs[i].sub_tile_offset; + + // Iterate over all sub_tiles to get the sub_tile which the target_cap belongs to. + const t_sub_tile* target_sub_tile = nullptr; + for (const t_sub_tile& sub_tile : target_type->sub_tiles) { + if (sub_tile.capacity.is_in_range(target_cap)) { + target_sub_tile = &sub_tile; + break; + } + } + VTR_ASSERT(target_sub_tile != nullptr); + if (relative_ipin >= target_sub_tile->num_phy_pins) continue; + + // If this block has capacity > 1 then the pins of z position > 0 are offset + // by the number of pins per capacity instance + int ipin = get_physical_pin_from_capacity_location(target_type, relative_ipin, target_cap); + + // Add new ipin edge to list of edges + std::vector inodes; + + int target_width_offset = device_ctx.grid.get_width_offset({x + directs[i].x_offset, y + directs[i].y_offset, layer}); + int target_height_offset = device_ctx.grid.get_height_offset({x + directs[i].x_offset, y + directs[i].y_offset, layer}); + int final_ipin_x = x + directs[i].x_offset - target_width_offset + target_type->pin_width_offset[ipin]; + int final_ipin_y = y + directs[i].y_offset - target_height_offset + target_type->pin_height_offset[ipin]; + + if (directs[i].to_side != NUM_2D_SIDES) { + //Explicit side specified, only create if pin exists on that side + RRNodeId inode = rr_graph_builder.node_lookup().find_node(layer, final_ipin_x, final_ipin_y, + e_rr_type::IPIN, ipin, directs[i].to_side); + if (inode) { + inodes.push_back(inode); + } + } else { + //No side specified, get all candidates + inodes = rr_graph_builder.node_lookup().find_nodes_at_all_sides(layer, final_ipin_x, final_ipin_y, e_rr_type::IPIN, ipin); + } + + if (!inodes.empty()) { + // There may be multiple physical pins corresponding to the logical + // target ipin. We only need to connect to one of them (since the physical pins + // are logically equivalent). This also ensures the graphics look reasonable and map + // back fairly directly to the architecture file in the case of pin equivalence + RRNodeId inode = pick_best_direct_connect_target_rr_node(rr_graph, from_rr_node, inodes); + + rr_edges_to_create.emplace_back(from_rr_node, inode, clb_to_clb_directs[i].switch_index, false); + ++num_pins; + } + } + } + } + } + } + return num_pins; +} + +static RRNodeId pick_best_direct_connect_target_rr_node(const RRGraphView& rr_graph, + RRNodeId from_rr, + const std::vector& candidate_rr_nodes) { + //With physically equivalent pins there may be multiple candidate rr nodes (which are equivalent) + //to connect the direct edge to. + //As a result it does not matter (from a correctness standpoint) which is picked. + // + //However intuitively we would expect (e.g. when visualizing the drawn RR graph) that the 'closest' + //candidate would be picked (i.e. to minimize the drawn edge length). + // + //This function attempts to pick the 'best/closest' of the candidates. + VTR_ASSERT(rr_graph.node_type(from_rr) == e_rr_type::OPIN); + + float best_dist = std::numeric_limits::infinity(); + RRNodeId best_rr = RRNodeId::INVALID(); + + for (const e_side& from_side : TOTAL_2D_SIDES) { + /* Bypass those side where the node does not appear */ + if (!rr_graph.is_node_on_specific_side(from_rr, from_side)) { + continue; + } + + for (RRNodeId to_rr : candidate_rr_nodes) { + VTR_ASSERT(rr_graph.node_type(to_rr) == e_rr_type::IPIN); + float to_dist = std::abs(rr_graph.node_xlow(from_rr) - rr_graph.node_xlow(to_rr)) + + std::abs(rr_graph.node_ylow(from_rr) - rr_graph.node_ylow(to_rr)); + + for (const e_side& to_side : TOTAL_2D_SIDES) { + /* Bypass those side where the node does not appear */ + if (!rr_graph.is_node_on_specific_side(to_rr, to_side)) { + continue; + } + + //Include a partial unit of distance based on side alignment to ensure + //we prefer facing sides + if ((from_side == RIGHT && to_side == LEFT) + || (from_side == LEFT && to_side == RIGHT) + || (from_side == TOP && to_side == BOTTOM) + || (from_side == BOTTOM && to_side == TOP)) { + //Facing sides + to_dist += 0.25; + } else if (((from_side == RIGHT || from_side == LEFT) && (to_side == TOP || to_side == BOTTOM)) + || ((from_side == TOP || from_side == BOTTOM) && (to_side == RIGHT || to_side == LEFT))) { + //Perpendicular sides + to_dist += 0.5; + + } else { + //Opposite sides + to_dist += 0.75; + } + + if (to_dist < best_dist) { + best_dist = to_dist; + best_rr = to_rr; + } + } + } + } + + VTR_ASSERT(best_rr); + + return best_rr; +} + +void add_opin_chan_edges(RRGraphBuilder& rr_graph_builder, + const RRGraphView& rr_graph, + size_t num_seg_types, + size_t num_seg_types_x, + size_t num_seg_types_y, + const t_chan_width& chan_width, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + const t_unified_to_parallel_seg_index& seg_index_map, + const t_pin_to_track_lookup& opin_to_track_map, + const vtr::NdMatrix, 2>& interdie_3d_links, + const std::vector>& Fc_out, + const std::vector& directs, + const std::vector& clb_to_clb_directs, + e_directionality directionality, + t_rr_edge_info_set& rr_edges_to_create, + int& num_edges, + int& rr_edges_before_directs, + bool* Fc_clipped) { + const DeviceGrid& grid = g_vpr_ctx.device().grid; + + // These are data structures used by the unidir opin mapping. They are used + // to spread connections evenly for each segment type among the available + // wire start points + // [0..grid.height()-2][0..grid.width()-2][0..num_seg_types_x/y-1] + vtr::NdMatrix Fc_xofs({grid.height() - 1, grid.width() - 1, num_seg_types_x}, 0); + vtr::NdMatrix Fc_yofs({grid.width() - 1, grid.height() - 1, num_seg_types_y}, 0); + + vtr::NdMatrix Fc_zofs({grid.width(), grid.height(), num_seg_types_y}, 0); + + for (size_t layer = 0; layer < grid.get_num_layers(); layer++) { + for (size_t i = 0; i < grid.width(); ++i) { + for (size_t j = 0; j < grid.height(); ++j) { + for (e_side side : TOTAL_2D_SIDES) { + if (BI_DIRECTIONAL == directionality) { + build_bidir_rr_opins(rr_graph_builder, rr_graph, layer, i, j, side, + opin_to_track_map, Fc_out, rr_edges_to_create, chan_details_x, + chan_details_y, + grid, + directs, clb_to_clb_directs, num_seg_types); + } else { + VTR_ASSERT(UNI_DIRECTIONAL == directionality); + bool clipped; + build_unidir_rr_opins(rr_graph_builder, rr_graph, layer, i, j, side, grid, Fc_out, chan_width, + chan_details_x, chan_details_y, Fc_xofs, Fc_yofs, + rr_edges_to_create, &clipped, seg_index_map, + directs, clb_to_clb_directs, num_seg_types, + rr_edges_before_directs); + if (clipped) { + *Fc_clipped = true; + } + } + + add_edges_opin_chanz_per_side(rr_graph, + layer, i, j, + side, + Fc_out, + seg_index_map, + num_seg_types, + Fc_zofs, + rr_edges_to_create, + interdie_3d_links); + } + + // Create the actual OPIN->CHANX/CHANY edges + uniquify_edges(rr_edges_to_create); + rr_graph_builder.alloc_and_load_edges(&rr_edges_to_create); + num_edges += rr_edges_to_create.size(); + rr_edges_to_create.clear(); + } + } + + Fc_zofs.fill(0); + } +} \ No newline at end of file diff --git a/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.h b/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.h new file mode 100644 index 0000000000..ad758845be --- /dev/null +++ b/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include "rr_types.h" +#include "rr_graph_type.h" +#include "rr_edge.h" + + +class RRGraphBuilder; +class RRGraphView; +struct t_chan_width; +struct t_bottleneck_link; +struct t_clb_to_clb_directs; + +void add_opin_chan_edges(RRGraphBuilder& rr_graph_builder, + const RRGraphView& rr_graph, + size_t num_seg_types, + size_t num_seg_types_x, + size_t num_seg_types_y, + const t_chan_width& chan_width, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + const t_unified_to_parallel_seg_index& seg_index_map, + const t_pin_to_track_lookup& opin_to_track_map, + const vtr::NdMatrix, 2>& interdie_3d_links, + const std::vector>& Fc_out, + const std::vector& directs, + const std::vector& clb_to_clb_directs, + e_directionality directionality, + t_rr_edge_info_set& rr_edges_to_create, + int& num_edges, + int& rr_edges_before_directs, + bool* Fc_clipped); From 109896eca208d2ea925f62c471cbe24ed624606d Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Wed, 5 Nov 2025 14:09:52 -0500 Subject: [PATCH 25/32] doxygen comment for add_opin_chan_edges() --- .../rr_graph_generation/rr_graph_opin_chan_edges.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.h b/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.h index ad758845be..eadaa2ed82 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.h +++ b/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.h @@ -5,13 +5,23 @@ #include "rr_graph_type.h" #include "rr_edge.h" - class RRGraphBuilder; class RRGraphView; struct t_chan_width; struct t_bottleneck_link; struct t_clb_to_clb_directs; +/** + * @brief Builds all OPIN-->CHAN edges in the RR graph. + * + * For each grid tile (all layers and sides), connects OPIN nodes to adjacent + * CHANX/CHANY wires based on architecture directionality: + * - **BI_DIRECTIONAL**: uses pin-to-track lookups. + * - **UNI_DIRECTIONAL**: distributes Fc connections using staggered offsets. + * + * Also adds direct CLB-to-CLB pin connections and inter-die (3D) links. + * Duplicates are removed before committing edges to the RR graph. + */ void add_opin_chan_edges(RRGraphBuilder& rr_graph_builder, const RRGraphView& rr_graph, size_t num_seg_types, From d7b67ea670c8591c3d3343abb289aea206b04892 Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Wed, 5 Nov 2025 14:10:34 -0500 Subject: [PATCH 26/32] make format --- .../route/rr_graph_generation/rr_graph.cpp | 2 - .../route/rr_graph_generation/rr_graph2.cpp | 20 ++++---- vpr/src/route/rr_graph_generation/rr_graph2.h | 20 ++++---- .../rr_graph_opin_chan_edges.cpp | 47 +++++++++---------- 4 files changed, 43 insertions(+), 46 deletions(-) diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index daca181369..4a044aee46 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -1608,8 +1608,6 @@ static void alloc_and_load_tile_rr_graph(RRGraphBuilder& rr_graph_builder, rr_graph_builder.rr_nodes().shrink_to_fit(); } - - void free_rr_graph() { // Frees all the routing graph data structures, if they have been allocated. // I use rr_mem_chunk_list_head as a flag to indicate whether or not the graph has been allocated -- if it is not NULL, diff --git a/vpr/src/route/rr_graph_generation/rr_graph2.cpp b/vpr/src/route/rr_graph_generation/rr_graph2.cpp index 54c43332a0..577c661541 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph2.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph2.cpp @@ -1756,16 +1756,16 @@ void load_sblock_pattern_lookup(const int i, } void label_wire_muxes(const int chan_num, - const int seg_num, - const t_chan_seg_details* seg_details, - const int seg_type_index, - const int max_len, - const enum Direction dir, - const int max_chan_width, - const bool check_cb, - std::vector& labels, - int* num_wire_muxes, - int* num_wire_muxes_cb_restricted) { + const int seg_num, + const t_chan_seg_details* seg_details, + const int seg_type_index, + const int max_len, + const enum Direction dir, + const int max_chan_width, + const bool check_cb, + std::vector& labels, + int* num_wire_muxes, + int* num_wire_muxes_cb_restricted) { // COUNT pass then a LOAD pass int num_labels = 0; int num_labels_restricted = 0; diff --git a/vpr/src/route/rr_graph_generation/rr_graph2.h b/vpr/src/route/rr_graph_generation/rr_graph2.h index 4650c69222..14b56ed9c0 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph2.h +++ b/vpr/src/route/rr_graph_generation/rr_graph2.h @@ -112,16 +112,16 @@ int get_track_to_tracks(RRGraphBuilder& rr_graph_builder, * @details If @p seg_type_index is UNDEFINED, all segment types are considered. */ void label_wire_muxes(const int chan_num, - const int seg_num, - const t_chan_seg_details* seg_details, - const int seg_type_index, - const int max_len, - const enum Direction dir, - const int max_chan_width, - const bool check_cb, - std::vector& labels, - int* num_wire_muxes, - int* num_wire_muxes_cb_restricted); + const int seg_num, + const t_chan_seg_details* seg_details, + const int seg_type_index, + const int max_len, + const enum Direction dir, + const int max_chan_width, + const bool check_cb, + std::vector& labels, + int* num_wire_muxes, + int* num_wire_muxes_cb_restricted); t_sblock_pattern alloc_sblock_pattern_lookup(const DeviceGrid& grid, const t_chan_width& nodes_per_chan); diff --git a/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.cpp b/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.cpp index c102e4f8d7..38c7c3a391 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.cpp @@ -52,30 +52,30 @@ static void build_unidir_rr_opins(RRGraphBuilder& rr_graph_builder, int& edge_count); static int get_bidir_opin_connections(RRGraphBuilder& rr_graph_builder, - int layer, - int i, - int j, - int ipin, - RRNodeId from_rr_node, - t_rr_edge_info_set& rr_edges_to_create, - const t_pin_to_track_lookup& opin_to_track_map, - const t_chan_details& chan_details_x, - const t_chan_details& chan_details_y); + int layer, + int i, + int j, + int ipin, + RRNodeId from_rr_node, + t_rr_edge_info_set& rr_edges_to_create, + const t_pin_to_track_lookup& opin_to_track_map, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y); static int get_unidir_opin_connections(RRGraphBuilder& rr_graph_builder, - int layer, - int chan, - int seg, - int Fc, - int seg_type_index, - e_rr_type chan_type, - const t_chan_seg_details* seg_details, - RRNodeId from_rr_node, - t_rr_edge_info_set& rr_edges_to_create, - vtr::NdMatrix& Fc_ofs, - int max_len, - const t_chan_width& nodes_per_chan, - bool* Fc_clipped); + int layer, + int chan, + int seg, + int Fc, + int seg_type_index, + e_rr_type chan_type, + const t_chan_seg_details* seg_details, + RRNodeId from_rr_node, + t_rr_edge_info_set& rr_edges_to_create, + vtr::NdMatrix& Fc_ofs, + int max_len, + const t_chan_width& nodes_per_chan, + bool* Fc_clipped); static int get_opin_direct_connections(RRGraphBuilder& rr_graph_builder, const RRGraphView& rr_graph, @@ -93,7 +93,6 @@ static RRNodeId pick_best_direct_connect_target_rr_node(const RRGraphView& rr_gr RRNodeId from_rr, const std::vector& candidate_rr_nodes); - static void build_bidir_rr_opins(RRGraphBuilder& rr_graph_builder, const RRGraphView& rr_graph, int layer, @@ -714,4 +713,4 @@ void add_opin_chan_edges(RRGraphBuilder& rr_graph_builder, Fc_zofs.fill(0); } -} \ No newline at end of file +} From 9a125930f4a094ac3ff781442a00b1ac25c8a94e Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Wed, 5 Nov 2025 14:19:30 -0500 Subject: [PATCH 27/32] doxygen comments for some function in rr_graph_opin_chan_edges --- .../rr_graph_opin_chan_edges.cpp | 70 ++++++++++--------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.cpp b/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.cpp index 38c7c3a391..4834b1d450 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.cpp @@ -50,7 +50,13 @@ static void build_unidir_rr_opins(RRGraphBuilder& rr_graph_builder, const std::vector& clb_to_clb_directs, int num_seg_types, int& edge_count); - +/** + * @brief Builds bidirectional OPIN-->CHAN edges for a given CLB output pin. + * + * Finds all routing tracks that the OPIN at (i, j, layer, ipin) connects to + * based on the pin-to-track mapping and channel details, and appends the + * corresponding RR edges to @p rr_edges_to_create. + */ static int get_bidir_opin_connections(RRGraphBuilder& rr_graph_builder, int layer, int i, @@ -62,6 +68,12 @@ static int get_bidir_opin_connections(RRGraphBuilder& rr_graph_builder, const t_chan_details& chan_details_x, const t_chan_details& chan_details_y); +/** + * @brief Creates unidirectional OPIN-->CHAN edges for a given segment type. + * + * Connects an OPIN node to nearby routing tracks (INC/DEC muxes) based on Fc. + * Uses @p Fc_ofs to stagger connections and may clip Fc if not enough muxes exist + */ static int get_unidir_opin_connections(RRGraphBuilder& rr_graph_builder, int layer, int chan, @@ -77,6 +89,13 @@ static int get_unidir_opin_connections(RRGraphBuilder& rr_graph_builder, const t_chan_width& nodes_per_chan, bool* Fc_clipped); +/** + * @brief Adds direct CLB-to-CLB OPIN-->IPIN connections for a given OPIN. + * + * Finds and creates all direct pin-to-pin edges (bypassing routing channels) + * from the OPIN at (layer, x, y, side) to corresponding IPINs defined by + * architecture-specified direct connections. + */ static int get_opin_direct_connections(RRGraphBuilder& rr_graph_builder, const RRGraphView& rr_graph, int layer, @@ -270,8 +289,6 @@ static void build_unidir_rr_opins(RRGraphBuilder& rr_graph_builder, } } -/* Returns the number of tracks to which clb opin #ipin at (i,j) connects. * - * Also stores the nodes to which this pin connects in rr_edges_to_create */ int get_bidir_opin_connections(RRGraphBuilder& rr_graph_builder, int layer, int i, @@ -352,12 +369,6 @@ int get_bidir_opin_connections(RRGraphBuilder& rr_graph_builder, return num_conn; } -/* Actually builds the edges from the OPIN nodes already allocated to their correct tracks for segment seg_Inf[seg_type_index]. - * Note that this seg_inf vector is NOT the segment_info vectored as stored in the device variable. This index is w.r.t to seg_inf_x - * or seg_inf_y for x-adjacent and y-adjacent segments respectively. This index is assigned in get_seg_details earlier - * in the rr_graph_builder routine. This t_seg_detail is then used to build t_chan_seg_details which is passed in to label_wire mux - * routine used in this function. - */ int get_unidir_opin_connections(RRGraphBuilder& rr_graph_builder, int layer, int chan, @@ -372,9 +383,6 @@ int get_unidir_opin_connections(RRGraphBuilder& rr_graph_builder, int max_len, const t_chan_width& nodes_per_chan, bool* Fc_clipped) { - /* Gets a linked list of Fc nodes of specified seg_type_index to connect - * to in given chan seg. Fc_ofs is used for the opin staggering pattern. */ - *Fc_clipped = false; // Fc is assigned in pairs so check it is even. @@ -398,7 +406,7 @@ int get_unidir_opin_connections(RRGraphBuilder& rr_graph_builder, Direction::DEC, max_chan_width, true, dec_muxes, &num_dec_muxes, &dummy); // Clip Fc to the number of muxes. - if (((Fc / 2) > num_inc_muxes) || ((Fc / 2) > num_dec_muxes)) { + if ((Fc / 2 > num_inc_muxes) || (Fc / 2 > num_dec_muxes)) { *Fc_clipped = true; Fc = 2 * std::min(num_inc_muxes, num_dec_muxes); } @@ -436,10 +444,6 @@ int get_unidir_opin_connections(RRGraphBuilder& rr_graph_builder, return num_edges; } -/* Add all direct clb-pin-to-clb-pin edges to given opin - * - * The current opin is located at (layer,x,y) along the specified side - */ static int get_opin_direct_connections(RRGraphBuilder& rr_graph_builder, const RRGraphView& rr_graph, int layer, @@ -451,7 +455,7 @@ static int get_opin_direct_connections(RRGraphBuilder& rr_graph_builder, t_rr_edge_info_set& rr_edges_to_create, const std::vector& directs, const std::vector& clb_to_clb_directs) { - auto& device_ctx = g_vpr_ctx.device(); + const DeviceContext& device_ctx = g_vpr_ctx.device(); t_physical_tile_type_ptr curr_type = device_ctx.grid.get_physical_type({x, y, layer}); @@ -463,7 +467,7 @@ static int get_opin_direct_connections(RRGraphBuilder& rr_graph_builder, return num_pins; //No source pin on this side } - //Capacity location determined by pin number relative to pins per capacity instance + // Capacity location determined by pin number relative to pins per capacity instance auto [z, relative_opin] = get_capacity_location_from_physical_pin(curr_type, opin); VTR_ASSERT(z >= 0 && z < curr_type->capacity); const int num_directs = directs.size(); @@ -546,14 +550,14 @@ static int get_opin_direct_connections(RRGraphBuilder& rr_graph_builder, int final_ipin_y = y + directs[i].y_offset - target_height_offset + target_type->pin_height_offset[ipin]; if (directs[i].to_side != NUM_2D_SIDES) { - //Explicit side specified, only create if pin exists on that side + // Explicit side specified, only create if pin exists on that side RRNodeId inode = rr_graph_builder.node_lookup().find_node(layer, final_ipin_x, final_ipin_y, e_rr_type::IPIN, ipin, directs[i].to_side); if (inode) { inodes.push_back(inode); } } else { - //No side specified, get all candidates + // No side specified, get all candidates inodes = rr_graph_builder.node_lookup().find_nodes_at_all_sides(layer, final_ipin_x, final_ipin_y, e_rr_type::IPIN, ipin); } @@ -578,14 +582,14 @@ static int get_opin_direct_connections(RRGraphBuilder& rr_graph_builder, static RRNodeId pick_best_direct_connect_target_rr_node(const RRGraphView& rr_graph, RRNodeId from_rr, const std::vector& candidate_rr_nodes) { - //With physically equivalent pins there may be multiple candidate rr nodes (which are equivalent) - //to connect the direct edge to. - //As a result it does not matter (from a correctness standpoint) which is picked. + // With physically equivalent pins there may be multiple candidate rr nodes (which are equivalent) + // to connect the direct edge to. + // As a result it does not matter (from a correctness standpoint) which is picked. // - //However intuitively we would expect (e.g. when visualizing the drawn RR graph) that the 'closest' - //candidate would be picked (i.e. to minimize the drawn edge length). + // However intuitively we would expect (e.g. when visualizing the drawn RR graph) that the 'closest' + // candidate would be picked (i.e. to minimize the drawn edge length). // - //This function attempts to pick the 'best/closest' of the candidates. + // This function attempts to pick the 'best/closest' of the candidates. VTR_ASSERT(rr_graph.node_type(from_rr) == e_rr_type::OPIN); float best_dist = std::numeric_limits::infinity(); @@ -603,26 +607,26 @@ static RRNodeId pick_best_direct_connect_target_rr_node(const RRGraphView& rr_gr + std::abs(rr_graph.node_ylow(from_rr) - rr_graph.node_ylow(to_rr)); for (const e_side& to_side : TOTAL_2D_SIDES) { - /* Bypass those side where the node does not appear */ + // Bypass those side where the node does not appear if (!rr_graph.is_node_on_specific_side(to_rr, to_side)) { continue; } - //Include a partial unit of distance based on side alignment to ensure - //we prefer facing sides + // Include a partial unit of distance based on side alignment to ensure + // we prefer facing sides if ((from_side == RIGHT && to_side == LEFT) || (from_side == LEFT && to_side == RIGHT) || (from_side == TOP && to_side == BOTTOM) || (from_side == BOTTOM && to_side == TOP)) { - //Facing sides + // Facing sides to_dist += 0.25; } else if (((from_side == RIGHT || from_side == LEFT) && (to_side == TOP || to_side == BOTTOM)) || ((from_side == TOP || from_side == BOTTOM) && (to_side == RIGHT || to_side == LEFT))) { - //Perpendicular sides + // Perpendicular sides to_dist += 0.5; } else { - //Opposite sides + // Opposite sides to_dist += 0.75; } From fd6d5c55cae00b4852cae252009f644e106cfdda Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Wed, 5 Nov 2025 16:02:07 -0500 Subject: [PATCH 28/32] add rr_graph_chan_chan_edges --- .../route/rr_graph_generation/rr_graph.cpp | 299 +---- .../route/rr_graph_generation/rr_graph2.cpp | 856 +----------- vpr/src/route/rr_graph_generation/rr_graph2.h | 39 +- .../rr_graph_chan_chan_edges.cpp | 1168 +++++++++++++++++ .../rr_graph_chan_chan_edges.h | 26 + .../rr_graph_opin_chan_edges.cpp | 3 +- .../rr_graph_opin_chan_edges.h | 1 - .../route/rr_graph_generation/rr_graph_sg.cpp | 13 +- .../route/rr_graph_generation/rr_graph_sg.h | 4 +- 9 files changed, 1228 insertions(+), 1181 deletions(-) create mode 100644 vpr/src/route/rr_graph_generation/rr_graph_chan_chan_edges.cpp create mode 100644 vpr/src/route/rr_graph_generation/rr_graph_chan_chan_edges.h diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index 4a044aee46..6c093570fc 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -34,6 +34,7 @@ #include "rr_graph_intra_cluster.h" #include "rr_graph_tile_nodes.h" #include "rr_graph_opin_chan_edges.h" +#include "rr_graph_chan_chan_edges.h" #include "rr_graph_sg.h" #include "rr_graph_timing_params.h" #include "check_rr_graph.h" @@ -249,26 +250,6 @@ static void add_intra_tile_edges_rr_graph(RRGraphBuilder& rr_graph_builder, t_physical_tile_type_ptr physical_tile, const t_physical_tile_loc& root_loc); -static void build_rr_chan(RRGraphBuilder& rr_graph_builder, - const int layer, - const int x_coord, - const int y_coord, - const e_rr_type chan_type, - const t_track_to_pin_lookup& track_to_pin_lookup, - t_sb_connection_map* sb_conn_map, - const vtr::NdMatrix, 3>& switch_block_conn, - const int cost_index_offset, - const t_chan_width& nodes_per_chan, - const DeviceGrid& grid, - const int tracks_per_chan, - t_sblock_pattern& sblock_pattern, - const int Fs_per_side, - const t_chan_details& chan_details_x, - const t_chan_details& chan_details_y, - t_rr_edge_info_set& rr_edges_to_create, - const int wire_to_ipin_switch, - const e_directionality directionality); - void alloc_and_load_edges(RRGraphBuilder& rr_graph_builder, const t_rr_edge_info_set& rr_edges_to_create); @@ -1409,98 +1390,34 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder } VTR_LOGV(route_verbosity > 1, "SOURCE->OPIN and IPIN->SINK edge count:%d\n", num_edges); - num_edges = 0; + num_edges = 0; int rr_edges_before_directs = 0; add_opin_chan_edges(rr_graph_builder, rr_graph, num_seg_types, num_seg_types_x, num_seg_types_y, chan_width, chan_details_x, chan_details_y, seg_index_map, opin_to_track_map, interdie_3d_links, Fc_out, directs, clb_to_clb_directs, directionality, - rr_edges_to_create, num_edges, rr_edges_before_directs, Fc_clipped); + num_edges, rr_edges_before_directs, Fc_clipped); VTR_LOGV(route_verbosity > 1, "OPIN->CHANX/CHANY edge count before creating direct connections: %d\n", rr_edges_before_directs); VTR_LOGV(route_verbosity > 1, "OPIN->CHANX/CHANY edge count after creating direct connections: %d\n", num_edges); num_edges = 0; - // Build channels - VTR_ASSERT(Fs % 3 == 0); - - t_rr_edge_info_set interdie_3d_rr_edges_to_create; - - for (size_t i = 0; i < grid.width() - 1; ++i) { - for (size_t j = 0; j < grid.height() - 1; ++j) { - - // In multi-die FPGAs with track-to-track connections between layers, we need to load CHANZ nodes - // These extra nodes can be driven from many tracks in the source layer and can drive multiple tracks in the destination layer, - // since these die-crossing connections have more delays. - if (grid.get_num_layers() > 1) { - build_inter_die_3d_rr_chan(rr_graph_builder, i, j, interdie_3d_links[i][j], - CHANX_COST_INDEX_START + num_seg_types_x + num_seg_types_y); - } - - for (int layer = 0; layer < (int)grid.get_num_layers(); ++layer) { - const auto& device_ctx = g_vpr_ctx.device(); - // Skip the current die if architecture file specifies that it doesn't require inter-cluster programmable resource routing - if (!device_ctx.inter_cluster_prog_routing_resources.at(layer)) { - continue; - } - - if (i > 0) { - int tracks_per_chan = ((is_global_graph) ? 1 : chan_width.x_list[j]); - build_rr_chan(rr_graph_builder, layer, i, j, e_rr_type::CHANX, track_to_pin_lookup_x, sb_conn_map, - switch_block_conn, - CHANX_COST_INDEX_START, - chan_width, grid, tracks_per_chan, - sblock_pattern, Fs / 3, chan_details_x, chan_details_y, - rr_edges_to_create, - wire_to_ipin_switch, - directionality); - - // Create the actual CHAN->CHAN edges - uniquify_edges(rr_edges_to_create); - alloc_and_load_edges(rr_graph_builder, rr_edges_to_create); - num_edges += rr_edges_to_create.size(); - - rr_edges_to_create.clear(); - } - if (j > 0) { - int tracks_per_chan = ((is_global_graph) ? 1 : chan_width.y_list[i]); - build_rr_chan(rr_graph_builder, layer, i, j, e_rr_type::CHANY, track_to_pin_lookup_y, sb_conn_map, - switch_block_conn, - CHANX_COST_INDEX_START + num_seg_types_x, - chan_width, grid, tracks_per_chan, - sblock_pattern, Fs / 3, chan_details_x, chan_details_y, - rr_edges_to_create, - wire_to_ipin_switch, - directionality); - - // Create the actual CHAN->CHAN edges - uniquify_edges(rr_edges_to_create); - alloc_and_load_edges(rr_graph_builder, rr_edges_to_create); - num_edges += rr_edges_to_create.size(); - rr_edges_to_create.clear(); - } - } + add_chan_chan_edges(rr_graph_builder, + num_seg_types_x, num_seg_types_y, + track_to_pin_lookup_x, track_to_pin_lookup_y, + chan_width, chan_details_x, chan_details_y, + sb_conn_map, switch_block_conn, interdie_3d_links, sblock_pattern, + Fs, wire_to_ipin_switch, directionality, is_global_graph, num_edges); + VTR_LOGV(route_verbosity > 1, "CHAN->CHAN type edge count:%d\n", num_edges); - if (grid.get_num_layers() > 1) { - add_inter_die_3d_edges(rr_graph_builder, i, j, - chan_details_x, chan_details_y, - interdie_3d_links[i][j], interdie_3d_rr_edges_to_create); - uniquify_edges(interdie_3d_rr_edges_to_create); - alloc_and_load_edges(rr_graph_builder, interdie_3d_rr_edges_to_create); - num_edges += interdie_3d_rr_edges_to_create.size(); - interdie_3d_rr_edges_to_create.clear(); - } - } - } - add_and_connect_non_3d_sg_links(rr_graph_builder, sg_links, sg_node_indices, chan_details_x, chan_details_y, num_seg_types_x, rr_edges_to_create); - uniquify_edges(rr_edges_to_create); - alloc_and_load_edges(rr_graph_builder, rr_edges_to_create); - num_edges += rr_edges_to_create.size(); - rr_edges_to_create.clear(); + add_and_connect_non_3d_sg_links(rr_graph_builder, + sg_links, sg_node_indices, + chan_details_x, chan_details_y, + num_seg_types_x, num_edges); + VTR_LOGV(route_verbosity > 1, "Non-3D scatter-gather edge count:%d\n", num_edges); - VTR_LOGV(route_verbosity > 1, "CHAN->CHAN type edge count:%d\n", num_edges); num_edges = 0; std::function update_chan_width = [](t_chan_width*) noexcept {}; @@ -1632,192 +1549,6 @@ void free_rr_graph() { invalidate_router_lookahead_cache(); } -/* Allocates/loads edges for nodes belonging to specified channel segment and initializes - * node properties such as cost, occupancy and capacity */ -static void build_rr_chan(RRGraphBuilder& rr_graph_builder, - const int layer, - const int x_coord, - const int y_coord, - const e_rr_type chan_type, - const t_track_to_pin_lookup& track_to_pin_lookup, - t_sb_connection_map* sb_conn_map, - const vtr::NdMatrix, 3>& switch_block_conn, - const int cost_index_offset, - const t_chan_width& nodes_per_chan, - const DeviceGrid& grid, - const int tracks_per_chan, - t_sblock_pattern& sblock_pattern, - const int Fs_per_side, - const t_chan_details& chan_details_x, - const t_chan_details& chan_details_y, - t_rr_edge_info_set& rr_edges_to_create, - const int wire_to_ipin_switch, - const e_directionality directionality) { - // this function builds both x and y-directed channel segments, so set up our coordinates based on channel type - - const auto& device_ctx = g_vpr_ctx.device(); - auto& mutable_device_ctx = g_vpr_ctx.mutable_device(); - - // Initially assumes CHANX - int seg_coord = x_coord; //The absolute coordinate of this segment within the channel - int chan_coord = y_coord; //The absolute coordinate of this channel within the device - int seg_dimension = device_ctx.grid.width() - 2; //-2 for no perim channels - int chan_dimension = device_ctx.grid.height() - 2; //-2 for no perim channels - const t_chan_details& from_chan_details = (chan_type == e_rr_type::CHANX) ? chan_details_x : chan_details_y; - const t_chan_details& opposite_chan_details = (chan_type == e_rr_type::CHANX) ? chan_details_y : chan_details_x; - e_rr_type opposite_chan_type = e_rr_type::CHANY; - if (chan_type == e_rr_type::CHANY) { - //Swap values since CHANX was assumed above - std::swap(seg_coord, chan_coord); - std::swap(seg_dimension, chan_dimension); - opposite_chan_type = e_rr_type::CHANX; - } - - const t_chan_seg_details* seg_details = from_chan_details[x_coord][y_coord].data(); - - // figure out if we're generating switch block edges based on a custom switch block description - bool custom_switch_block = false; - if (sb_conn_map != nullptr) { - VTR_ASSERT(sblock_pattern.empty() && switch_block_conn.empty()); - custom_switch_block = true; - } - - // Loads up all the routing resource nodes in the current channel segment - for (int track = 0; track < tracks_per_chan; ++track) { - if (seg_details[track].length() == 0) - continue; - - // Start and end coordinates of this segment along the length of the channel - // Note that these values are in the VPR coordinate system (and do not consider - // wire directionality), so start correspond to left/bottom and end corresponds to right/top - int start = get_seg_start(seg_details, track, chan_coord, seg_coord); - int end = get_seg_end(seg_details, track, start, chan_coord, seg_dimension); - - if (seg_coord > start) { - continue; // Only process segments which start at this location - } - VTR_ASSERT(seg_coord == start); - - const t_chan_seg_details* from_seg_details = nullptr; - if (chan_type == e_rr_type::CHANY) { - from_seg_details = chan_details_y[x_coord][start].data(); - } else { - from_seg_details = chan_details_x[start][y_coord].data(); - } - - RRNodeId node = rr_graph_builder.node_lookup().find_node(layer, x_coord, y_coord, chan_type, track); - - if (!node) { - continue; - } - - // Add the edges from this track to all it's connected pins into the list - get_track_to_pins(rr_graph_builder, layer, start, chan_coord, track, tracks_per_chan, node, rr_edges_to_create, - track_to_pin_lookup, seg_details, chan_type, seg_dimension, - wire_to_ipin_switch, directionality); - - // Add edges going from the current track into channel segments which are perpendicular to it - if (chan_coord > 0) { - const t_chan_seg_details* to_seg_details; - int max_opposite_chan_width; - if (chan_type == e_rr_type::CHANX) { - to_seg_details = chan_details_y[start][y_coord].data(); - max_opposite_chan_width = nodes_per_chan.y_max; - } else { - VTR_ASSERT(chan_type == e_rr_type::CHANY); - to_seg_details = chan_details_x[x_coord][start].data(); - max_opposite_chan_width = nodes_per_chan.x_max; - } - if (to_seg_details->length() > 0) { - get_track_to_tracks(rr_graph_builder, layer, chan_coord, start, track, chan_type, chan_coord, - opposite_chan_type, seg_dimension, max_opposite_chan_width, grid, - Fs_per_side, sblock_pattern, node, rr_edges_to_create, - from_seg_details, to_seg_details, opposite_chan_details, - directionality, - switch_block_conn, sb_conn_map); - } - } - - if (chan_coord < chan_dimension) { - const t_chan_seg_details* to_seg_details; - int max_opposite_chan_width = 0; - if (chan_type == e_rr_type::CHANX) { - to_seg_details = chan_details_y[start][y_coord + 1].data(); - max_opposite_chan_width = nodes_per_chan.y_max; - } else { - VTR_ASSERT(chan_type == e_rr_type::CHANY); - to_seg_details = chan_details_x[x_coord + 1][start].data(); - max_opposite_chan_width = nodes_per_chan.x_max; - } - if (to_seg_details->length() > 0) { - get_track_to_tracks(rr_graph_builder, layer, chan_coord, start, track, chan_type, chan_coord + 1, - opposite_chan_type, seg_dimension, max_opposite_chan_width, grid, - Fs_per_side, sblock_pattern, node, rr_edges_to_create, - from_seg_details, to_seg_details, opposite_chan_details, - directionality, switch_block_conn, sb_conn_map); - } - } - - // walk over the switch blocks along the source track and implement edges from this track to other tracks in the same channel (i.e. straight-through connections) - for (int target_seg = start - 1; target_seg <= end + 1; target_seg++) { - if (target_seg != start - 1 && target_seg != end + 1) { - // skip straight-through connections from midpoint if non-custom switch block. - // currently non-custom switch blocks don't properly describe connections from the mid-point of a wire segment - // to other segments in the same channel (i.e. straight-through connections) - if (!custom_switch_block) { - continue; - } - } - if (target_seg > 0 && target_seg < seg_dimension + 1) { - const t_chan_seg_details* to_seg_details; - // AA: Same channel width for straight through connections assuming uniform width distributions along the axis - int max_chan_width = 0; - if (chan_type == e_rr_type::CHANX) { - to_seg_details = chan_details_x[target_seg][y_coord].data(); - max_chan_width = nodes_per_chan.x_max; - } else { - VTR_ASSERT(chan_type == e_rr_type::CHANY); - to_seg_details = chan_details_y[x_coord][target_seg].data(); - max_chan_width = nodes_per_chan.y_max; - } - if (to_seg_details->length() > 0) { - get_track_to_tracks(rr_graph_builder, layer, chan_coord, start, track, chan_type, target_seg, - chan_type, seg_dimension, max_chan_width, grid, - Fs_per_side, sblock_pattern, node, rr_edges_to_create, - from_seg_details, to_seg_details, from_chan_details, - directionality, - switch_block_conn, sb_conn_map); - } - } - } - - // Edge arrays have now been built up. Do everything else. - // AA: The cost_index should be w.r.t the index of the segment to its **parallel** segment_inf vector. - // Note that when building channels, we use the indices w.r.t segment_inf_x and segment_inf_y as - // computed earlier in build_rr_graph so it's fine to use .index() for to get the correct index. - rr_graph_builder.set_node_cost_index(node, RRIndexedDataId(cost_index_offset + seg_details[track].index())); - rr_graph_builder.set_node_capacity(node, 1); // GLOBAL routing handled elsewhere - - if (chan_type == e_rr_type::CHANX) { - rr_graph_builder.set_node_coordinates(node, start, y_coord, end, y_coord); - } else { - VTR_ASSERT(chan_type == e_rr_type::CHANY); - rr_graph_builder.set_node_coordinates(node, x_coord, start, x_coord, end); - } - - rr_graph_builder.set_node_layer(node, layer, layer); - - int length = end - start + 1; - float R = length * seg_details[track].Rmetal(); - float C = length * seg_details[track].Cmetal(); - rr_graph_builder.set_node_rc_index(node, find_create_rr_rc_data(R, C, mutable_device_ctx.rr_rc_data)); - - rr_graph_builder.set_node_type(node, chan_type); - rr_graph_builder.set_node_track_num(node, track); - rr_graph_builder.set_node_direction(node, seg_details[track].direction()); - } -} - void alloc_and_load_edges(RRGraphBuilder& rr_graph_builder, const t_rr_edge_info_set& rr_edges_to_create) { rr_graph_builder.alloc_and_load_edges(&rr_edges_to_create); } diff --git a/vpr/src/route/rr_graph_generation/rr_graph2.cpp b/vpr/src/route/rr_graph_generation/rr_graph2.cpp index 577c661541..2bc4103da5 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph2.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph2.cpp @@ -16,120 +16,6 @@ constexpr short UN_SET = -1; /************************** Subroutines local to this module ****************/ -static void get_switch_type(bool is_from_sb, - bool is_to_sb, - short from_node_switch, - short to_node_switch, - const int switch_override, - short switch_types[2]); - -static int get_bidir_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, - const std::vector& conn_tracks, - const int layer, - const int to_chan, - const int to_seg, - const int to_sb, - const e_rr_type to_type, - const t_chan_seg_details* seg_details, - const bool from_is_sblock, - const int from_switch, - const int switch_override, - const enum e_directionality directionality, - RRNodeId from_rr_node, - t_rr_edge_info_set& rr_edges_to_create); - -static int get_unidir_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, - const int layer, - const int from_track, - const int to_chan, - const int to_seg, - const int to_sb, - const e_rr_type to_type, - const int max_chan_width, - const DeviceGrid& grid, - const enum e_side from_side, - const enum e_side to_side, - const int Fs_per_side, - t_sblock_pattern& sblock_pattern, - const int switch_override, - const t_chan_seg_details* seg_details, - bool* Fs_clipped, - RRNodeId from_rr_node, - t_rr_edge_info_set& rr_edges_to_create); - -/** - * @brief creates the RR graph edges corresponding to switch blocks permutation map - * - * @param rr_graph_builder RRGraphBuilder data structure which allows data modification on a routing resource graph - * @param tile_x x-coordinate of the switch block - * @param tile_y y-coordinate of the switch block - * @param layer layer-coordinate of the switch block - * @param from_side switch block connection source side - * @param from_wire switch block connection source wire index (ptc_num) within the channel - * @param from_rr_node switch block connection source wire RRNode index - * @param to_side switch block connection destination side - * @param to_x switch block connection destination x-coordinate - * @param to_y switch block connection destination y-coordinate - * @param to_chan_type switch block connection destination channel type (CHANX or CHANY) - * @param switch_override used to set the correct switch index for the RR graph edge - * @param sb_conn_map switch block permutation map - * @param rr_edges_to_create Total RR edges count - * @param edge_count number of RR edges that this function creates - */ -static void get_switchblocks_edges(RRGraphBuilder& rr_graph_builder, - const int tile_x, - const int tile_y, - const int layer, - const e_side from_side, - const int from_wire, - RRNodeId from_rr_node, - const e_side to_side, - const int to_x, - const int to_y, - const e_rr_type to_chan_type, - const int switch_override, - const t_sb_connection_map& sb_conn_map, - t_rr_edge_info_set& rr_edges_to_create, - int& edge_count); - -/** - * @brief Figures out the edges that should connect the given wire segment to the given channel segment, adds these edges to 'rr_edge_to_create' - * - * @param rr_graph_builder RRGraphBuilder data structure which allows data modification on a routing resource graph - * @param layer the channel segment layer-coordinate - * @param from_track source track index (ptc_num) within the channel - * @param to_chan destination coordinate (x or y) based on chan type - * @param to_seg destination segment coordinate (x or y) based on chan type - * @param to_chan_type destination wire segment channel type (CHANX or CHANY) - * @param from_side swtich block connection source side - * @param to_side swtich block connection destination side - * @param swtich_override used to set the correct switch index for the RR graph edge - * @param sb_conn_map switch block permutation map, created based on the architecture file - * @param from_rr_node the source wire segment RRNodeID - * @param rr_edges_to_create keeps the created edges - * - * @return the number of edges added to 'rr_edge_to_create' - */ - -static int get_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, - const int layer, - const int from_track, - const int to_chan, - const int to_seg, - const e_rr_type to_chan_type, - const e_side from_side, - const e_side to_side, - const int swtich_override, - const t_sb_connection_map& sb_conn_map, - RRNodeId from_rr_node, - t_rr_edge_info_set& rr_edges_to_create); - -static int vpr_to_phy_track(const int itrack, - const int chan_num, - const int seg_num, - const t_chan_seg_details* seg_details, - const e_directionality directionality); - static void label_incoming_wires(const int chan_num, const int seg_num, const int sb_seg, @@ -149,16 +35,6 @@ void dump_seg_details(t_seg_details* seg_details, int max_chan_width, const char* fname); -//Returns how the switch type for the switch block at the specified location should be created -// grid: The device grid -// from_chan_coord: The horizontal or vertical channel index (i.e. x-coord for CHANY, y-coord for CHANX) -// from_seg_coord: The horizontal or vertical location along the channel (i.e. y-coord for CHANY, x-coord for CHANX) -// from_chan_type: The from channel type -// to_chan_type: The to channel type -static int should_create_switchblock(const DeviceGrid& grid, int layer_num, int from_chan_coord, int from_seg_coord, e_rr_type from_chan_type, e_rr_type to_chan_type); - -static bool should_apply_switch_override(int switch_override); - /******************** Subroutine definitions *******************************/ std::vector get_seg_track_counts(int num_sets, @@ -781,581 +657,6 @@ void dump_track_to_pin_map(t_track_to_pin_lookup& track_to_pin_map, } } -int get_track_to_pins(RRGraphBuilder& rr_graph_builder, - int layer, - int seg, - int chan, - int track, - int tracks_per_chan, - RRNodeId from_rr_node, - t_rr_edge_info_set& rr_edges_to_create, - const t_track_to_pin_lookup& track_to_pin_lookup, - const t_chan_seg_details* seg_details, - e_rr_type chan_type, - int chan_length, - int wire_to_ipin_switch, - e_directionality directionality) { - const DeviceContext& device_ctx = g_vpr_ctx.device(); - - // End of this wire - int end = get_seg_end(seg_details, track, seg, chan, chan_length); - - int num_conn = 0; - - for (int j = seg; j <= end; j++) { - if (is_cblock(chan, j, track, seg_details)) { - for (int pass = 0; pass < 2; ++pass) { //pass == 0 => TOP/RIGHT, pass == 1 => BOTTOM/LEFT - e_side side; - int x, y; - if (e_rr_type::CHANX == chan_type) { - x = j; - y = chan + pass; - side = (0 == pass ? TOP : BOTTOM); - } else { - VTR_ASSERT(e_rr_type::CHANY == chan_type); - x = chan + pass; - y = j; - side = (0 == pass ? RIGHT : LEFT); - } - - /* PAJ - if the pointed to is an EMPTY then shouldn't look for ipins */ - t_physical_tile_type_ptr type = device_ctx.grid.get_physical_type({x, y, layer}); - if (type == device_ctx.EMPTY_PHYSICAL_TILE_TYPE) - continue; - - /* Move from logical (straight) to physical (twisted) track index - * - algorithm assigns ipin connections to same physical track index - * so that the logical track gets distributed uniformly */ - - int phy_track = vpr_to_phy_track(track, chan, j, seg_details, directionality); - phy_track %= tracks_per_chan; - - /* We need the type to find the ipin map for this type */ - - int width_offset = device_ctx.grid.get_width_offset({x, y, layer}); - int height_offset = device_ctx.grid.get_height_offset({x, y, layer}); - - const int max_conn = track_to_pin_lookup[type->index][phy_track][width_offset][height_offset][side].size(); - for (int iconn = 0; iconn < max_conn; iconn++) { - const int ipin = track_to_pin_lookup[type->index][phy_track][width_offset][height_offset][side][iconn]; - - // Check there is a connection and Fc map isn't wrong - RRNodeId to_node = rr_graph_builder.node_lookup().find_node(layer, x, y, e_rr_type::IPIN, ipin, side); - if (to_node) { - rr_edges_to_create.emplace_back(from_rr_node, to_node, wire_to_ipin_switch, false); - ++num_conn; - } - } - } - } - } - - return num_conn; -} - -/* - * Collects the edges fanning-out of the 'from' track which connect to the 'to' - * tracks, according to the switch block pattern. - * - * It returns the number of connections added, and updates edge_list_ptr to - * point at the head of the (extended) linked list giving the nodes to which - * this segment connects and the switch type used to connect to each. - * - * An edge is added from this segment to a y-segment if: - * (1) this segment should have a switch box at that location, or - * (2) the y-segment to which it would connect has a switch box, and the switch - * type of that y-segment is unbuffered (bidirectional pass transistor). - * - * For bidirectional: - * If the switch in each direction is a pass transistor (unbuffered), both - * switches are marked as being of the types of the larger (lower R) pass - * transistor. - */ -int get_track_to_tracks(RRGraphBuilder& rr_graph_builder, - const int layer, - const int from_chan, - const int from_seg, - const int from_track, - const e_rr_type from_type, - const int to_seg, - const e_rr_type to_type, - const int chan_len, - const int max_chan_width, - const DeviceGrid& grid, - const int Fs_per_side, - t_sblock_pattern& sblock_pattern, - RRNodeId from_rr_node, - t_rr_edge_info_set& rr_edges_to_create, - const t_chan_seg_details* from_seg_details, - const t_chan_seg_details* to_seg_details, - const t_chan_details& to_chan_details, - const e_directionality directionality, - const vtr::NdMatrix, 3>& switch_block_conn, - const t_sb_connection_map* sb_conn_map) { - int to_chan, to_sb; - std::vector conn_tracks; - bool Fs_clipped; - e_side to_side; - - // check whether a custom switch block will be used - bool custom_switch_block = false; - if (sb_conn_map != nullptr) { - custom_switch_block = true; - VTR_ASSERT(switch_block_conn.empty()); - } - - VTR_ASSERT_MSG(from_seg == get_seg_start(from_seg_details, from_track, from_chan, from_seg), "From segment location must be a the wire start point"); - - int from_switch = from_seg_details[from_track].arch_wire_switch(); - - //The absolute coordinate along the channel where the switch block at the - //beginning of the current wire segment is located - int start_sb_seg = from_seg - 1; - - //The absolute coordinate along the channel where the switch block at the - //end of the current wire segment is located - int end_sb_seg = get_seg_end(from_seg_details, from_track, from_seg, from_chan, chan_len); - - // Figure out the sides of SB the from_wire will use - e_side from_side_a, from_side_b; - if (e_rr_type::CHANX == from_type) { - from_side_a = RIGHT; - from_side_b = LEFT; - } else { - VTR_ASSERT(e_rr_type::CHANY == from_type); - from_side_a = TOP; - from_side_b = BOTTOM; - } - - // Set the loop bounds, so we iterate over the whole wire segment - int start = start_sb_seg; - int end = end_sb_seg; - - // If source and destination segments both lie along the same channel - // we clip the loop bounds to the switch blocks of interest and proceed normally - if (to_type == from_type) { - start = to_seg - 1; - end = to_seg; - } - - //Walk along the 'from' wire segment identifying if a switchblock is located - //at each coordinate and add any related fan-out connections to the 'from' wire segment - int num_conn = 0; - for (int sb_seg = start; sb_seg <= end; ++sb_seg) { - if (sb_seg < start_sb_seg || sb_seg > end_sb_seg) { - continue; - } - - // Figure out if we are at a sblock - bool from_is_sblock = is_sblock(from_chan, from_seg, sb_seg, from_track, - from_seg_details, directionality); - if (sb_seg == end_sb_seg || sb_seg == start_sb_seg) { - /* end of wire must be an sblock */ - from_is_sblock = true; - } - - int switch_override = should_create_switchblock(grid, layer, from_chan, sb_seg, from_type, to_type); - if (switch_override == NO_SWITCH) { - continue; //Do not create an SB here - } - - /* Get the coordinates of the current SB from the perspective of the destination channel. - * i.e. for segments laid in the x-direction, sb_seg corresponds to the x coordinate and from_chan to the y, - * but for segments in the y-direction, from_chan is the x coordinate and sb_seg is the y. So here we reverse - * the coordinates if necessary */ - if (from_type == to_type) { - //Same channel - to_chan = from_chan; - to_sb = sb_seg; - } else { - VTR_ASSERT(from_type != to_type); - //Different channels - to_chan = sb_seg; - to_sb = from_chan; - } - - /* to_chan_details may correspond to an x-directed or y-directed channel, depending on which - * channel type this function is used; so coordinates are reversed as necessary */ - if (to_type == e_rr_type::CHANX) { - to_seg_details = to_chan_details[to_seg][to_chan].data(); - } else { - to_seg_details = to_chan_details[to_chan][to_seg].data(); - } - - if (to_seg_details[0].length() == 0) - continue; - - // Figure out whether the switch block at the current sb_seg coordinate is *behind* - // the target channel segment (with respect to VPR coordinate system) - bool is_behind = false; - if (to_type == from_type) { - if (sb_seg == start) { - is_behind = true; - } else { - is_behind = false; - } - } else { - VTR_ASSERT((to_seg == from_chan) || (to_seg == (from_chan + 1))); - if (to_seg > from_chan) { - is_behind = true; - } - } - - /* Figure out which side of the SB the destination segment lies on */ - if (e_rr_type::CHANX == to_type) { - to_side = (is_behind ? RIGHT : LEFT); - } else { - VTR_ASSERT(e_rr_type::CHANY == to_type); - to_side = (is_behind ? TOP : BOTTOM); - } - - /* To get to the destination seg/chan, the source track can connect to the SB from - * one of two directions. If we're in CHANX, we can connect to it from the left or - * right, provided we're not at a track endpoint. And similarly for a source track - * in CHANY. */ - /* Do edges going from the right SB side (if we're in CHANX) or top (if we're in CHANY). - * However, can't connect to right (top) if already at rightmost (topmost) track end */ - if (sb_seg < end_sb_seg) { - if (custom_switch_block) { - if (Direction::DEC == from_seg_details[from_track].direction() || BI_DIRECTIONAL == directionality) { - num_conn += get_track_to_chan_seg(rr_graph_builder, layer, from_track, to_chan, to_seg, - to_type, from_side_a, to_side, - switch_override, - *sb_conn_map, from_rr_node, rr_edges_to_create); - } - } else { - if (BI_DIRECTIONAL == directionality) { - /* For bidir, the target segment might have an unbuffered (bidir pass transistor) - * switchbox, so we follow through regardless of whether the current segment has an SB */ - conn_tracks = switch_block_conn[from_side_a][to_side][from_track]; - num_conn += get_bidir_track_to_chan_seg(rr_graph_builder, conn_tracks, layer, - to_chan, to_seg, to_sb, to_type, - to_seg_details, from_is_sblock, from_switch, - switch_override, - directionality, from_rr_node, rr_edges_to_create); - } - if (UNI_DIRECTIONAL == directionality) { - /* No fanout if no SB. */ - /* Also, we are connecting from the top or right of SB so it - * makes the most sense to only get there from Direction::DEC wires. */ - if ((from_is_sblock) && (Direction::DEC == from_seg_details[from_track].direction())) { - num_conn += get_unidir_track_to_chan_seg(rr_graph_builder, layer, from_track, to_chan, - to_seg, to_sb, to_type, max_chan_width, grid, - from_side_a, to_side, Fs_per_side, - sblock_pattern, - switch_override, - to_seg_details, - &Fs_clipped, from_rr_node, rr_edges_to_create); - } - } - } - } - - /* Do the edges going from the left SB side (if we're in CHANX) or bottom (if we're in CHANY) - * However, can't connect to left (bottom) if already at leftmost (bottommost) track end */ - if (sb_seg > start_sb_seg) { - if (custom_switch_block) { - if (Direction::INC == from_seg_details[from_track].direction() || BI_DIRECTIONAL == directionality) { - num_conn += get_track_to_chan_seg(rr_graph_builder, layer, from_track, to_chan, to_seg, - to_type, from_side_b, to_side, - switch_override, - *sb_conn_map, from_rr_node, rr_edges_to_create); - } - } else { - if (BI_DIRECTIONAL == directionality) { - /* For bidir, the target segment might have an unbuffered (bidir pass transistor) - * switchbox, so we follow through regardless of whether the current segment has an SB */ - conn_tracks = switch_block_conn[from_side_b][to_side][from_track]; - num_conn += get_bidir_track_to_chan_seg(rr_graph_builder, conn_tracks, layer, - to_chan, to_seg, to_sb, to_type, - to_seg_details, from_is_sblock, from_switch, - switch_override, - directionality, from_rr_node, rr_edges_to_create); - } - if (UNI_DIRECTIONAL == directionality) { - /* No fanout if no SB. */ - /* Also, we are connecting from the bottom or left of SB so it - * makes the most sense to only get there from Direction::INC wires. */ - if ((from_is_sblock) - && (Direction::INC == from_seg_details[from_track].direction())) { - num_conn += get_unidir_track_to_chan_seg(rr_graph_builder, layer, from_track, to_chan, - to_seg, to_sb, to_type, max_chan_width, grid, - from_side_b, to_side, Fs_per_side, - sblock_pattern, - switch_override, - to_seg_details, - &Fs_clipped, from_rr_node, rr_edges_to_create); - } - } - } - } - } - - return num_conn; -} - -static int get_bidir_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, - const std::vector& conn_tracks, - const int layer, - const int to_chan, - const int to_seg, - const int to_sb, - const e_rr_type to_type, - const t_chan_seg_details* seg_details, - const bool from_is_sblock, - const int from_switch, - const int switch_override, - const enum e_directionality directionality, - RRNodeId from_rr_node, - t_rr_edge_info_set& rr_edges_to_create) { - int to_x, to_y; - short switch_types[2]; - - // x, y coords for get_rr_node lookups - if (e_rr_type::CHANX == to_type) { - to_x = to_seg; - to_y = to_chan; - } else { - VTR_ASSERT(e_rr_type::CHANY == to_type); - to_x = to_chan; - to_y = to_seg; - } - - // Go through the list of tracks we can connect to - int num_conn = 0; - for (int to_track : conn_tracks) { - RRNodeId to_node = rr_graph_builder.node_lookup().find_node(layer, to_x, to_y, to_type, to_track); - - if (!to_node) { - continue; - } - - /* Get the switches for any edges between the two tracks */ - int to_switch = seg_details[to_track].arch_wire_switch(); - - bool to_is_sblock = is_sblock(to_chan, to_seg, to_sb, to_track, seg_details, directionality); - get_switch_type(from_is_sblock, to_is_sblock, from_switch, to_switch, - switch_override, - switch_types); - - // There are up to two switch edges allowed from track to track - for (int i = 0; i < 2; ++i) { - /* If the switch_type entry is empty, skip it */ - if (UNDEFINED == switch_types[i]) { - continue; - } - - /* Add the edge to the list */ - rr_edges_to_create.emplace_back(from_rr_node, to_node, switch_types[i], false); - ++num_conn; - } - } - - return num_conn; -} - -static void get_switchblocks_edges(RRGraphBuilder& rr_graph_builder, - const int tile_x, - const int tile_y, - const int layer, - const e_side from_side, - const int from_wire, - RRNodeId from_rr_node, - const e_side to_side, - const int to_x, - const int to_y, - const e_rr_type to_chan_type, - const int switch_override, - const t_sb_connection_map& sb_conn_map, - t_rr_edge_info_set& rr_edges_to_create, - int& edge_count) { - const auto& device_ctx = g_vpr_ctx.device(); - - // Coordinate to index into the SB map - SwitchblockLookupKey sb_coord(tile_x, tile_y, layer, from_side, to_side); - if (sb_conn_map.contains(sb_coord)) { - // Reference to the connections vector which lists all destination wires for a given source wire - // at a specific coordinate sb_coord - const std::vector& sb_edges = sb_conn_map.at(sb_coord); - - // Go through the connections... - for (const t_switchblock_edge& sb_edge : sb_edges) { - if (sb_edge.from_wire != from_wire) continue; - - int to_wire = sb_edge.to_wire; - // Get the index of the switch connecting the two wires - int src_switch = sb_edge.switch_ind; - - RRNodeId to_node = rr_graph_builder.node_lookup().find_node(layer, to_x, to_y, to_chan_type, to_wire); - - if (!to_node) { - continue; - } - - // Apply any switch overrides - if (should_apply_switch_override(switch_override)) { - src_switch = switch_override; - } - - rr_edges_to_create.emplace_back(from_rr_node, to_node, src_switch, false); - ++edge_count; - - if (device_ctx.arch_switch_inf[src_switch].directionality() == BI_DIRECTIONAL) { - // Add reverse edge since bidirectional - rr_edges_to_create.emplace_back(to_node, from_rr_node, src_switch, false); - ++edge_count; - } - } - } -} - -static int get_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, - const int layer, - const int from_wire, - const int to_chan, - const int to_seg, - const e_rr_type to_chan_type, - const e_side from_side, - const e_side to_side, - const int switch_override, - const t_sb_connection_map& sb_conn_map, - RRNodeId from_rr_node, - t_rr_edge_info_set& rr_edges_to_create) { - int edge_count = 0; - int to_x, to_y; - int tile_x, tile_y; - - // Get x/y coordinates from seg/chan coordinates - if (e_rr_type::CHANX == to_chan_type) { - to_x = tile_x = to_seg; - to_y = tile_y = to_chan; - if (RIGHT == to_side) { - tile_x--; - } - } else { - VTR_ASSERT(e_rr_type::CHANY == to_chan_type); - to_x = tile_x = to_chan; - to_y = tile_y = to_seg; - if (TOP == to_side) { - tile_y--; - } - } - - get_switchblocks_edges(rr_graph_builder, - tile_x, - tile_y, - layer, - from_side, - from_wire, - from_rr_node, - to_side, - to_x, - to_y, - to_chan_type, - switch_override, - sb_conn_map, - rr_edges_to_create, - edge_count); - - return edge_count; -} - -static int get_unidir_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, - const int layer, - const int from_track, - const int to_chan, - const int to_seg, - const int to_sb, - const e_rr_type to_type, - const int max_chan_width, - const DeviceGrid& grid, - const enum e_side from_side, - const enum e_side to_side, - const int Fs_per_side, - t_sblock_pattern& sblock_pattern, - const int switch_override, - const t_chan_seg_details* seg_details, - bool* Fs_clipped, - RRNodeId from_rr_node, - t_rr_edge_info_set& rr_edges_to_create) { - int num_labels = 0; - std::vector mux_labels; - - // x, y coords for get_rr_node lookups - int to_x = (e_rr_type::CHANX == to_type ? to_seg : to_chan); - int to_y = (e_rr_type::CHANX == to_type ? to_chan : to_seg); - int sb_x = (e_rr_type::CHANX == to_type ? to_sb : to_chan); - int sb_y = (e_rr_type::CHANX == to_type ? to_chan : to_sb); - int max_len = (e_rr_type::CHANX == to_type ? grid.width() : grid.height()) - 2; //-2 for no perimeter channels - - enum Direction to_dir = Direction::DEC; - if (to_sb < to_seg) { - to_dir = Direction::INC; - } - - *Fs_clipped = false; - - /* get list of muxes to which we can connect */ - int dummy; - label_wire_muxes(to_chan, to_seg, seg_details, UNDEFINED, max_len, - to_dir, max_chan_width, false, mux_labels, &num_labels, &dummy); - - /* Can't connect if no muxes. */ - if (num_labels < 1) { - return 0; - } - - /* Check if Fs demand was too high. */ - if (Fs_per_side > num_labels) { - *Fs_clipped = true; - } - - /* Handle Fs > 3 by assigning consecutive muxes. */ - int count = 0; - for (int i = 0; i < Fs_per_side; ++i) { - /* Get the target label */ - for (int j = 0; j < 4; j = j + 2) { - /* Use the balanced labeling for passing and fringe wires */ - int to_mux = sblock_pattern[sb_x][sb_y][from_side][to_side][from_track][j]; - if (to_mux == UN_SET) - continue; - - int to_track = sblock_pattern[sb_x][sb_y][from_side][to_side][from_track][j + 1]; - if (to_track == UN_SET) { - to_track = mux_labels[(to_mux + i) % num_labels]; - sblock_pattern[sb_x][sb_y][from_side][to_side][from_track][j + 1] = to_track; - } - RRNodeId to_node = rr_graph_builder.node_lookup().find_node(layer, to_x, to_y, to_type, to_track); - - if (!to_node) { - continue; - } - - //Determine which switch to use - int iswitch = seg_details[to_track].arch_wire_switch(); - - //Apply any switch overrides - if (should_apply_switch_override(switch_override)) { - iswitch = switch_override; - } - VTR_ASSERT(iswitch != UNDEFINED); - - /* Add edge to list. */ - rr_edges_to_create.emplace_back(from_rr_node, to_node, iswitch, false); - ++count; - - const auto& device_ctx = g_vpr_ctx.device(); - if (device_ctx.arch_switch_inf[iswitch].directionality() == BI_DIRECTIONAL) { - // Add reverse edge since bidirectional - rr_edges_to_create.emplace_back(to_node, from_rr_node, iswitch, false); - ++count; - } - } - } - - return count; -} - bool is_sblock(const int chan, int wire_seg, const int sb_seg, const int track, const t_chan_seg_details* seg_details, const enum e_directionality directionality) { int fac = 1; if (UNI_DIRECTIONAL == directionality) { @@ -1380,112 +681,6 @@ bool is_sblock(const int chan, int wire_seg, const int sb_seg, const int track, return seg_details[track].sb(ofs); } -static void get_switch_type(bool is_from_sblock, - bool is_to_sblock, - short from_node_switch, - short to_node_switch, - const int switch_override, - short switch_types[2]) { - /* This routine looks at whether the from_node and to_node want a switch, * - * and what type of switch is used to connect *to* each type of node * - * (from_node_switch and to_node_switch). It decides what type of switch, * - * if any, should be used to go from from_node to to_node. If no switch * - * should be inserted (i.e. no connection), it returns NO_SWITCH. Its returned * - * values are in the switch_types array. It needs to return an array * - * because some topologies (e.g. bi-dir pass gates) result in two switches.*/ - - auto& device_ctx = g_vpr_ctx.device(); - - switch_types[0] = NO_SWITCH; - switch_types[1] = NO_SWITCH; - - if (switch_override == NO_SWITCH) { - return; //No switches - } - - if (should_apply_switch_override(switch_override)) { - //Use the override switches instead - from_node_switch = switch_override; - to_node_switch = switch_override; - } - - int used = 0; - bool forward_switch = false; - bool backward_switch = false; - - /* Connect forward if we are a sblock */ - if (is_from_sblock) { - switch_types[used] = to_node_switch; - ++used; - - forward_switch = true; - } - - /* Check for reverse switch */ - if (is_to_sblock) { - if (device_ctx.arch_switch_inf[from_node_switch].directionality() == e_directionality::BI_DIRECTIONAL) { - switch_types[used] = from_node_switch; - ++used; - - backward_switch = true; - } - } - - /* Take the larger switch if there are two of the same type */ - if (forward_switch - && backward_switch - && (device_ctx.arch_switch_inf[from_node_switch].type() == device_ctx.arch_switch_inf[to_node_switch].type())) { - //Sanity checks - VTR_ASSERT_SAFE_MSG(device_ctx.arch_switch_inf[from_node_switch].type() == device_ctx.arch_switch_inf[to_node_switch].type(), "Same switch type"); - VTR_ASSERT_MSG(device_ctx.arch_switch_inf[to_node_switch].directionality() == e_directionality::BI_DIRECTIONAL, "Bi-dir to switch"); - VTR_ASSERT_MSG(device_ctx.arch_switch_inf[from_node_switch].directionality() == e_directionality::BI_DIRECTIONAL, "Bi-dir from switch"); - - /* Take the smaller index unless the other - * switch is bigger (smaller R). */ - - int first_switch = std::min(to_node_switch, from_node_switch); - int second_switch = std::max(to_node_switch, from_node_switch); - - if (used < 2) { - VPR_FATAL_ERROR(VPR_ERROR_ROUTE, - "Expected 2 switches (forward and back) between RR nodes (found %d switches, min switch index: %d max switch index: %d)", - used, first_switch, second_switch); - } - - int switch_to_use = first_switch; - if (device_ctx.arch_switch_inf[second_switch].R < device_ctx.arch_switch_inf[first_switch].R) { - switch_to_use = second_switch; - } - - for (int i = 0; i < used; ++i) { - switch_types[i] = switch_to_use; - } - } -} - -static int vpr_to_phy_track(const int itrack, - const int chan_num, - const int seg_num, - const t_chan_seg_details* seg_details, - const e_directionality directionality) { - - // Assign in pairs if unidir. - int fac = 1; - if (UNI_DIRECTIONAL == directionality) { - fac = 2; - } - - int group_start = seg_details[itrack].group_start(); - int group_size = seg_details[itrack].group_size(); - - int vpr_offset_for_first_phy_track = (chan_num + seg_num - 1) % (group_size / fac); - int vpr_offset = (itrack - group_start) / fac; - int phy_offset = (vpr_offset_for_first_phy_track + vpr_offset) % (group_size / fac); - int phy_track = group_start + (fac * phy_offset) + (itrack - group_start) % fac; - - return phy_track; -} - t_sblock_pattern alloc_sblock_pattern_lookup(const DeviceGrid& grid, const t_chan_width& nodes_per_chan) { /* loading up the sblock connection pattern matrix. It's a huge matrix because @@ -1684,8 +879,8 @@ void load_sblock_pattern_lookup(const int i, } if (incoming_wire_label[side_cw][itrack] != UN_SET) { - int mux = get_simple_switch_block_track((enum e_side)side_cw, - (enum e_side)to_side, + int mux = get_simple_switch_block_track((e_side)side_cw, + to_side, incoming_wire_label[side_cw][ichan], switch_block_type, num_wire_muxes[to_side], @@ -1710,8 +905,8 @@ void load_sblock_pattern_lookup(const int i, } if (incoming_wire_label[side_ccw][itrack] != UN_SET) { - int mux = get_simple_switch_block_track((enum e_side)side_ccw, - (enum e_side)to_side, + int mux = get_simple_switch_block_track((e_side)side_ccw, + to_side, incoming_wire_label[side_ccw][ichan], switch_block_type, num_wire_muxes[to_side], @@ -1918,49 +1113,6 @@ static int find_label_of_track(const std::vector& wire_mux_on_track, return i_label; } -static int should_create_switchblock(const DeviceGrid& grid, int layer_num, int from_chan_coord, int from_seg_coord, e_rr_type from_chan_type, e_rr_type to_chan_type) { - //Convert the chan/seg indices to real x/y coordinates - int y_coord; - int x_coord; - if (from_chan_type == e_rr_type::CHANX) { - y_coord = from_chan_coord; - x_coord = from_seg_coord; - } else { - VTR_ASSERT(from_chan_type == e_rr_type::CHANY); - y_coord = from_seg_coord; - x_coord = from_chan_coord; - } - - t_physical_tile_type_ptr blk_type = grid.get_physical_type({x_coord, y_coord, layer_num}); - int width_offset = grid.get_width_offset({x_coord, y_coord, layer_num}); - int height_offset = grid.get_height_offset({x_coord, y_coord, layer_num}); - - e_sb_type sb_type = blk_type->switchblock_locations[width_offset][height_offset]; - int switch_override = blk_type->switchblock_switch_overrides[width_offset][height_offset]; - - if (sb_type == e_sb_type::FULL) { - return switch_override; - } else if (sb_type == e_sb_type::STRAIGHT && from_chan_type == to_chan_type) { - return switch_override; - } else if (sb_type == e_sb_type::TURNS && from_chan_type != to_chan_type) { - return switch_override; - } else if (sb_type == e_sb_type::HORIZONTAL && from_chan_type == e_rr_type::CHANX && to_chan_type == e_rr_type::CHANX) { - return switch_override; - } else if (sb_type == e_sb_type::VERTICAL && from_chan_type == e_rr_type::CHANY && to_chan_type == e_rr_type::CHANY) { - return switch_override; - } - - return NO_SWITCH; -} - -static bool should_apply_switch_override(int switch_override) { - if (switch_override != NO_SWITCH && switch_override != DEFAULT_SWITCH) { - VTR_ASSERT(switch_override >= 0); - return true; - } - return false; -} - inline int get_chan_width(enum e_side side, const t_chan_width& nodes_per_chan) { return (side == TOP || side == BOTTOM ? nodes_per_chan.y_max : nodes_per_chan.x_max); } diff --git a/vpr/src/route/rr_graph_generation/rr_graph2.h b/vpr/src/route/rr_graph_generation/rr_graph2.h index 14b56ed9c0..17bf1db617 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph2.h +++ b/vpr/src/route/rr_graph_generation/rr_graph2.h @@ -45,6 +45,7 @@ int get_seg_start(const t_chan_seg_details* seg_details, const int itrack, const int chan_num, const int seg_num); + int get_seg_end(const t_chan_seg_details* seg_details, const int itrack, const int istart, @@ -63,44 +64,6 @@ bool is_sblock(const int chan, const t_chan_seg_details* seg_details, const enum e_directionality directionality); -/// Adds the fan-out edges from wire segment at (chan, seg, track) to adjacent blocks along the wire's length -int get_track_to_pins(RRGraphBuilder& rr_graph_builder, - int layer, - int seg, - int chan, - int track, - int tracks_per_chan, - RRNodeId from_rr_node, - t_rr_edge_info_set& rr_edges_to_create, - const t_track_to_pin_lookup& track_to_pin_lookup, - const t_chan_seg_details* seg_details, - e_rr_type chan_type, - int chan_length, - int wire_to_ipin_switch, - e_directionality directionality); - -int get_track_to_tracks(RRGraphBuilder& rr_graph_builder, - const int layer, - const int from_chan, - const int from_seg, - const int from_track, - const e_rr_type from_type, - const int to_seg, - const e_rr_type to_type, - const int chan_len, - const int max_chan_width, - const DeviceGrid& grid, - const int Fs_per_side, - t_sblock_pattern& sblock_pattern, - RRNodeId from_rr_node, - t_rr_edge_info_set& rr_edges_to_create, - const t_chan_seg_details* from_seg_details, - const t_chan_seg_details* to_seg_details, - const t_chan_details& to_chan_details, - const e_directionality directionality, - const vtr::NdMatrix, 3>& switch_block_conn, - const t_sb_connection_map* sb_conn_map); - /** * @brief Identifies and labels all mux endpoints at a given channel segment coordinate. * diff --git a/vpr/src/route/rr_graph_generation/rr_graph_chan_chan_edges.cpp b/vpr/src/route/rr_graph_generation/rr_graph_chan_chan_edges.cpp new file mode 100644 index 0000000000..e5c30cfcd2 --- /dev/null +++ b/vpr/src/route/rr_graph_generation/rr_graph_chan_chan_edges.cpp @@ -0,0 +1,1168 @@ + +#include "rr_graph_chan_chan_edges.h" + +#include "rr_graph_builder.h" +#include "rr_types.h" +#include "rr_rc_data.h" +#include "rr_graph_sg.h" +#include "rr_graph2.h" +#include "build_switchblocks.h" +#include "build_scatter_gathers.h" +#include "globals.h" + +static void build_rr_chan(RRGraphBuilder& rr_graph_builder, + int layer, + int x_coord, + int y_coord, + e_rr_type chan_type, + const t_track_to_pin_lookup& track_to_pin_lookup, + t_sb_connection_map* sb_conn_map, + const vtr::NdMatrix, 3>& switch_block_conn, + int cost_index_offset, + const t_chan_width& nodes_per_chan, + int tracks_per_chan, + t_sblock_pattern& sblock_pattern, + int Fs_per_side, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + t_rr_edge_info_set& rr_edges_to_create, + int wire_to_ipin_switch, + e_directionality directionality); + +static int get_track_to_tracks(RRGraphBuilder& rr_graph_builder, + int layer, + int from_chan, + int from_seg, + int from_track, + e_rr_type from_type, + int to_seg, + e_rr_type to_type, + int chan_len, + int max_chan_width, + int Fs_per_side, + t_sblock_pattern& sblock_pattern, + RRNodeId from_rr_node, + t_rr_edge_info_set& rr_edges_to_create, + const t_chan_seg_details* from_seg_details, + const t_chan_seg_details* to_seg_details, + const t_chan_details& to_chan_details, + e_directionality directionality, + const vtr::NdMatrix, 3>& switch_block_conn, + const t_sb_connection_map* sb_conn_map); + +/** + * @brief Figures out the edges that should connect the given wire segment to the given channel segment, + * adds these edges to 'rr_edge_to_create' + * @return The number of edges added to 'rr_edge_to_create' + */ +static int get_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, + int layer, + int from_track, + int to_chan, + int to_seg, + e_rr_type to_chan_type, + e_side from_side, + e_side to_side, + int swtich_override, + const t_sb_connection_map& sb_conn_map, + RRNodeId from_rr_node, + t_rr_edge_info_set& rr_edges_to_create); + +/// @brief creates the RR graph edges corresponding to switch blocks permutation map +static void get_switchblocks_edges(RRGraphBuilder& rr_graph_builder, + int tile_x, + int tile_y, + int layer, + e_side from_side, + int from_wire, + RRNodeId from_rr_node, + e_side to_side, + int to_x, + int to_y, + e_rr_type to_chan_type, + int switch_override, + const t_sb_connection_map& sb_conn_map, + t_rr_edge_info_set& rr_edges_to_create, + int& edge_count); + +/// Adds the fan-out edges from wire segment at (chan, seg, track) to adjacent blocks along the wire's length +static int get_track_to_pins(RRGraphBuilder& rr_graph_builder, + int layer, + int seg, + int chan, + int track, + int tracks_per_chan, + RRNodeId from_rr_node, + t_rr_edge_info_set& rr_edges_to_create, + const t_track_to_pin_lookup& track_to_pin_lookup, + const t_chan_seg_details* seg_details, + e_rr_type chan_type, + int chan_length, + int wire_to_ipin_switch, + e_directionality directionality); + +//Returns how the switch type for the switch block at the specified location should be created +// from_chan_coord: The horizontal or vertical channel index (i.e. x-coord for CHANY, y-coord for CHANX) +// from_seg_coord: The horizontal or vertical location along the channel (i.e. y-coord for CHANY, x-coord for CHANX) +// from_chan_type: The from channel type +// to_chan_type: The to channel type +static int should_create_switchblock(int layer_num, + int from_chan_coord, + int from_seg_coord, + e_rr_type from_chan_type, + e_rr_type to_chan_type); + +static int get_unidir_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, + int layer, + int from_track, + int to_chan, + int to_seg, + int to_sb, + e_rr_type to_type, + int max_chan_width, + e_side from_side, + e_side to_side, + int Fs_per_side, + t_sblock_pattern& sblock_pattern, + int switch_override, + const t_chan_seg_details* seg_details, + bool* Fs_clipped, + RRNodeId from_rr_node, + t_rr_edge_info_set& rr_edges_to_create); + +static int get_bidir_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, + const std::vector& conn_tracks, + int layer, + int to_chan, + int to_seg, + int to_sb, + e_rr_type to_type, + const t_chan_seg_details* seg_details, + bool from_is_sblock, + int from_switch, + int switch_override, + e_directionality directionality, + RRNodeId from_rr_node, + t_rr_edge_info_set& rr_edges_to_create); + +static int vpr_to_phy_track(int itrack, + int chan_num, + int seg_num, + const t_chan_seg_details* seg_details, + e_directionality directionality); + +static void get_switch_type(bool is_from_sb, + bool is_to_sb, + short from_node_switch, + short to_node_switch, + int switch_override, + short switch_types[2]); + +static bool should_apply_switch_override(int switch_override); + +/* Allocates/loads edges for nodes belonging to specified channel segment and initializes + * node properties such as cost, occupancy and capacity */ +static void build_rr_chan(RRGraphBuilder& rr_graph_builder, + int layer, + int x_coord, + int y_coord, + e_rr_type chan_type, + const t_track_to_pin_lookup& track_to_pin_lookup, + t_sb_connection_map* sb_conn_map, + const vtr::NdMatrix, 3>& switch_block_conn, + int cost_index_offset, + const t_chan_width& nodes_per_chan, + int tracks_per_chan, + t_sblock_pattern& sblock_pattern, + int Fs_per_side, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + t_rr_edge_info_set& rr_edges_to_create, + int wire_to_ipin_switch, + e_directionality directionality) { + // this function builds both x and y-directed channel segments, so set up our coordinates based on channel type + + const auto& device_ctx = g_vpr_ctx.device(); + auto& mutable_device_ctx = g_vpr_ctx.mutable_device(); + + // Initially assumes CHANX + int seg_coord = x_coord; //The absolute coordinate of this segment within the channel + int chan_coord = y_coord; //The absolute coordinate of this channel within the device + int seg_dimension = device_ctx.grid.width() - 2; //-2 for no perim channels + int chan_dimension = device_ctx.grid.height() - 2; //-2 for no perim channels + const t_chan_details& from_chan_details = (chan_type == e_rr_type::CHANX) ? chan_details_x : chan_details_y; + const t_chan_details& opposite_chan_details = (chan_type == e_rr_type::CHANX) ? chan_details_y : chan_details_x; + e_rr_type opposite_chan_type = e_rr_type::CHANY; + if (chan_type == e_rr_type::CHANY) { + //Swap values since CHANX was assumed above + std::swap(seg_coord, chan_coord); + std::swap(seg_dimension, chan_dimension); + opposite_chan_type = e_rr_type::CHANX; + } + + const t_chan_seg_details* seg_details = from_chan_details[x_coord][y_coord].data(); + + // figure out if we're generating switch block edges based on a custom switch block description + bool custom_switch_block = false; + if (sb_conn_map != nullptr) { + VTR_ASSERT(sblock_pattern.empty() && switch_block_conn.empty()); + custom_switch_block = true; + } + + // Loads up all the routing resource nodes in the current channel segment + for (int track = 0; track < tracks_per_chan; ++track) { + if (seg_details[track].length() == 0) + continue; + + // Start and end coordinates of this segment along the length of the channel + // Note that these values are in the VPR coordinate system (and do not consider + // wire directionality), so start correspond to left/bottom and end corresponds to right/top + int start = get_seg_start(seg_details, track, chan_coord, seg_coord); + int end = get_seg_end(seg_details, track, start, chan_coord, seg_dimension); + + if (seg_coord > start) { + continue; // Only process segments which start at this location + } + VTR_ASSERT(seg_coord == start); + + const t_chan_seg_details* from_seg_details = nullptr; + if (chan_type == e_rr_type::CHANY) { + from_seg_details = chan_details_y[x_coord][start].data(); + } else { + from_seg_details = chan_details_x[start][y_coord].data(); + } + + RRNodeId node = rr_graph_builder.node_lookup().find_node(layer, x_coord, y_coord, chan_type, track); + + if (!node) { + continue; + } + + // Add the edges from this track to all it's connected pins into the list + get_track_to_pins(rr_graph_builder, layer, start, chan_coord, track, tracks_per_chan, node, rr_edges_to_create, + track_to_pin_lookup, seg_details, chan_type, seg_dimension, + wire_to_ipin_switch, directionality); + + // Add edges going from the current track into channel segments which are perpendicular to it + if (chan_coord > 0) { + const t_chan_seg_details* to_seg_details; + int max_opposite_chan_width; + if (chan_type == e_rr_type::CHANX) { + to_seg_details = chan_details_y[start][y_coord].data(); + max_opposite_chan_width = nodes_per_chan.y_max; + } else { + VTR_ASSERT(chan_type == e_rr_type::CHANY); + to_seg_details = chan_details_x[x_coord][start].data(); + max_opposite_chan_width = nodes_per_chan.x_max; + } + if (to_seg_details->length() > 0) { + get_track_to_tracks(rr_graph_builder, layer, chan_coord, start, track, chan_type, chan_coord, + opposite_chan_type, seg_dimension, max_opposite_chan_width, + Fs_per_side, sblock_pattern, node, rr_edges_to_create, + from_seg_details, to_seg_details, opposite_chan_details, + directionality, + switch_block_conn, sb_conn_map); + } + } + + if (chan_coord < chan_dimension) { + const t_chan_seg_details* to_seg_details; + int max_opposite_chan_width = 0; + if (chan_type == e_rr_type::CHANX) { + to_seg_details = chan_details_y[start][y_coord + 1].data(); + max_opposite_chan_width = nodes_per_chan.y_max; + } else { + VTR_ASSERT(chan_type == e_rr_type::CHANY); + to_seg_details = chan_details_x[x_coord + 1][start].data(); + max_opposite_chan_width = nodes_per_chan.x_max; + } + if (to_seg_details->length() > 0) { + get_track_to_tracks(rr_graph_builder, layer, chan_coord, start, track, chan_type, chan_coord + 1, + opposite_chan_type, seg_dimension, max_opposite_chan_width, + Fs_per_side, sblock_pattern, node, rr_edges_to_create, + from_seg_details, to_seg_details, opposite_chan_details, + directionality, switch_block_conn, sb_conn_map); + } + } + + // walk over the switch blocks along the source track and implement edges from this track to other tracks in the same channel (i.e. straight-through connections) + for (int target_seg = start - 1; target_seg <= end + 1; target_seg++) { + if (target_seg != start - 1 && target_seg != end + 1) { + // skip straight-through connections from midpoint if non-custom switch block. + // currently non-custom switch blocks don't properly describe connections from the mid-point of a wire segment + // to other segments in the same channel (i.e. straight-through connections) + if (!custom_switch_block) { + continue; + } + } + if (target_seg > 0 && target_seg < seg_dimension + 1) { + const t_chan_seg_details* to_seg_details; + // AA: Same channel width for straight through connections assuming uniform width distributions along the axis + int max_chan_width = 0; + if (chan_type == e_rr_type::CHANX) { + to_seg_details = chan_details_x[target_seg][y_coord].data(); + max_chan_width = nodes_per_chan.x_max; + } else { + VTR_ASSERT(chan_type == e_rr_type::CHANY); + to_seg_details = chan_details_y[x_coord][target_seg].data(); + max_chan_width = nodes_per_chan.y_max; + } + if (to_seg_details->length() > 0) { + get_track_to_tracks(rr_graph_builder, layer, chan_coord, start, track, chan_type, target_seg, + chan_type, seg_dimension, max_chan_width, + Fs_per_side, sblock_pattern, node, rr_edges_to_create, + from_seg_details, to_seg_details, from_chan_details, + directionality, + switch_block_conn, sb_conn_map); + } + } + } + + // Edge arrays have now been built up. Do everything else. + // AA: The cost_index should be w.r.t the index of the segment to its **parallel** segment_inf vector. + // Note that when building channels, we use the indices w.r.t segment_inf_x and segment_inf_y as + // computed earlier in build_rr_graph so it's fine to use .index() for to get the correct index. + rr_graph_builder.set_node_cost_index(node, RRIndexedDataId(cost_index_offset + seg_details[track].index())); + rr_graph_builder.set_node_capacity(node, 1); // GLOBAL routing handled elsewhere + + if (chan_type == e_rr_type::CHANX) { + rr_graph_builder.set_node_coordinates(node, start, y_coord, end, y_coord); + } else { + VTR_ASSERT(chan_type == e_rr_type::CHANY); + rr_graph_builder.set_node_coordinates(node, x_coord, start, x_coord, end); + } + + rr_graph_builder.set_node_layer(node, layer, layer); + + int length = end - start + 1; + float R = length * seg_details[track].Rmetal(); + float C = length * seg_details[track].Cmetal(); + rr_graph_builder.set_node_rc_index(node, find_create_rr_rc_data(R, C, mutable_device_ctx.rr_rc_data)); + + rr_graph_builder.set_node_type(node, chan_type); + rr_graph_builder.set_node_track_num(node, track); + rr_graph_builder.set_node_direction(node, seg_details[track].direction()); + } +} + +/* + * Collects the edges fanning-out of the 'from' track which connect to the 'to' + * tracks, according to the switch block pattern. + * + * It returns the number of connections added, and updates edge_list_ptr to + * point at the head of the (extended) linked list giving the nodes to which + * this segment connects and the switch type used to connect to each. + * + * An edge is added from this segment to a y-segment if: + * (1) this segment should have a switch box at that location, or + * (2) the y-segment to which it would connect has a switch box, and the switch + * type of that y-segment is unbuffered (bidirectional pass transistor). + * + * For bidirectional: + * If the switch in each direction is a pass transistor (unbuffered), both + * switches are marked as being of the types of the larger (lower R) pass + * transistor. + */ +static int get_track_to_tracks(RRGraphBuilder& rr_graph_builder, + int layer, + int from_chan, + int from_seg, + int from_track, + e_rr_type from_type, + int to_seg, + e_rr_type to_type, + int chan_len, + int max_chan_width, + int Fs_per_side, + t_sblock_pattern& sblock_pattern, + RRNodeId from_rr_node, + t_rr_edge_info_set& rr_edges_to_create, + const t_chan_seg_details* from_seg_details, + const t_chan_seg_details* to_seg_details, + const t_chan_details& to_chan_details, + e_directionality directionality, + const vtr::NdMatrix, 3>& switch_block_conn, + const t_sb_connection_map* sb_conn_map) { + int to_chan, to_sb; + std::vector conn_tracks; + bool Fs_clipped; + e_side to_side; + + // check whether a custom switch block will be used + bool custom_switch_block = false; + if (sb_conn_map != nullptr) { + custom_switch_block = true; + VTR_ASSERT(switch_block_conn.empty()); + } + + VTR_ASSERT_MSG(from_seg == get_seg_start(from_seg_details, from_track, from_chan, from_seg), + "From segment location must be a the wire start point"); + + int from_switch = from_seg_details[from_track].arch_wire_switch(); + + //The absolute coordinate along the channel where the switch block at the + //beginning of the current wire segment is located + int start_sb_seg = from_seg - 1; + + //The absolute coordinate along the channel where the switch block at the + //end of the current wire segment is located + int end_sb_seg = get_seg_end(from_seg_details, from_track, from_seg, from_chan, chan_len); + + // Figure out the sides of SB the from_wire will use + e_side from_side_a, from_side_b; + if (e_rr_type::CHANX == from_type) { + from_side_a = RIGHT; + from_side_b = LEFT; + } else { + VTR_ASSERT(e_rr_type::CHANY == from_type); + from_side_a = TOP; + from_side_b = BOTTOM; + } + + // Set the loop bounds, so we iterate over the whole wire segment + int start = start_sb_seg; + int end = end_sb_seg; + + // If source and destination segments both lie along the same channel + // we clip the loop bounds to the switch blocks of interest and proceed normally + if (to_type == from_type) { + start = to_seg - 1; + end = to_seg; + } + + //Walk along the 'from' wire segment identifying if a switchblock is located + //at each coordinate and add any related fan-out connections to the 'from' wire segment + int num_conn = 0; + for (int sb_seg = start; sb_seg <= end; ++sb_seg) { + if (sb_seg < start_sb_seg || sb_seg > end_sb_seg) { + continue; + } + + // Figure out if we are at a sblock + bool from_is_sblock = is_sblock(from_chan, from_seg, sb_seg, from_track, + from_seg_details, directionality); + if (sb_seg == end_sb_seg || sb_seg == start_sb_seg) { + // end of wire must be an sblock + from_is_sblock = true; + } + + int switch_override = should_create_switchblock(layer, from_chan, sb_seg, from_type, to_type); + if (switch_override == NO_SWITCH) { + continue; //Do not create an SB here + } + + // Get the coordinates of the current SB from the perspective of the destination channel. + // i.e. for segments laid in the x-direction, sb_seg corresponds to the x coordinate and from_chan to the y, + // but for segments in the y-direction, from_chan is the x coordinate and sb_seg is the y. So here we reverse + //the coordinates if necessary + if (from_type == to_type) { + // Same channel + to_chan = from_chan; + to_sb = sb_seg; + } else { + VTR_ASSERT(from_type != to_type); + // Different channels + to_chan = sb_seg; + to_sb = from_chan; + } + + // to_chan_details may correspond to an x-directed or y-directed channel, depending on which + // channel type this function is used; so coordinates are reversed as necessary + if (to_type == e_rr_type::CHANX) { + to_seg_details = to_chan_details[to_seg][to_chan].data(); + } else { + to_seg_details = to_chan_details[to_chan][to_seg].data(); + } + + if (to_seg_details[0].length() == 0) + continue; + + // Figure out whether the switch block at the current sb_seg coordinate is *behind* + // the target channel segment (with respect to VPR coordinate system) + bool is_behind = false; + if (to_type == from_type) { + if (sb_seg == start) { + is_behind = true; + } else { + is_behind = false; + } + } else { + VTR_ASSERT((to_seg == from_chan) || (to_seg == (from_chan + 1))); + if (to_seg > from_chan) { + is_behind = true; + } + } + + // Figure out which side of the SB the destination segment lies on + if (e_rr_type::CHANX == to_type) { + to_side = (is_behind ? RIGHT : LEFT); + } else { + VTR_ASSERT(e_rr_type::CHANY == to_type); + to_side = (is_behind ? TOP : BOTTOM); + } + + // To get to the destination seg/chan, the source track can connect to the SB from + // one of two directions. If we're in CHANX, we can connect to it from the left or + // right, provided we're not at a track endpoint. And similarly for a source track + // in CHANY. + // Do edges going from the right SB side (if we're in CHANX) or top (if we're in CHANY). + // However, can't connect to right (top) if already at rightmost (topmost) track end + if (sb_seg < end_sb_seg) { + if (custom_switch_block) { + if (Direction::DEC == from_seg_details[from_track].direction() || BI_DIRECTIONAL == directionality) { + num_conn += get_track_to_chan_seg(rr_graph_builder, layer, from_track, to_chan, to_seg, + to_type, from_side_a, to_side, + switch_override, + *sb_conn_map, from_rr_node, rr_edges_to_create); + } + } else { + if (BI_DIRECTIONAL == directionality) { + // For bidir, the target segment might have an unbuffered (bidir pass transistor) + // switchbox, so we follow through regardless of whether the current segment has an SB + conn_tracks = switch_block_conn[from_side_a][to_side][from_track]; + num_conn += get_bidir_track_to_chan_seg(rr_graph_builder, conn_tracks, layer, + to_chan, to_seg, to_sb, to_type, + to_seg_details, from_is_sblock, from_switch, + switch_override, + directionality, from_rr_node, rr_edges_to_create); + } + if (UNI_DIRECTIONAL == directionality) { + // No fanout if no SB. + // Also, we are connecting from the top or right of SB so it + // makes the most sense to only get there from Direction::DEC wires. + if ((from_is_sblock) && (Direction::DEC == from_seg_details[from_track].direction())) { + num_conn += get_unidir_track_to_chan_seg(rr_graph_builder, layer, from_track, to_chan, + to_seg, to_sb, to_type, max_chan_width, + from_side_a, to_side, Fs_per_side, + sblock_pattern, + switch_override, + to_seg_details, + &Fs_clipped, from_rr_node, rr_edges_to_create); + } + } + } + } + + // Do the edges going from the left SB side (if we're in CHANX) or bottom (if we're in CHANY) + // However, can't connect to left (bottom) if already at leftmost (bottommost) track end + if (sb_seg > start_sb_seg) { + if (custom_switch_block) { + if (Direction::INC == from_seg_details[from_track].direction() || BI_DIRECTIONAL == directionality) { + num_conn += get_track_to_chan_seg(rr_graph_builder, layer, from_track, to_chan, to_seg, + to_type, from_side_b, to_side, + switch_override, + *sb_conn_map, from_rr_node, rr_edges_to_create); + } + } else { + if (BI_DIRECTIONAL == directionality) { + // For bidir, the target segment might have an unbuffered (bidir pass transistor) + // switchbox, so we follow through regardless of whether the current segment has an SB + conn_tracks = switch_block_conn[from_side_b][to_side][from_track]; + num_conn += get_bidir_track_to_chan_seg(rr_graph_builder, conn_tracks, layer, + to_chan, to_seg, to_sb, to_type, + to_seg_details, from_is_sblock, from_switch, + switch_override, + directionality, from_rr_node, rr_edges_to_create); + } + if (UNI_DIRECTIONAL == directionality) { + // No fanout if no SB. + /* Also, we are connecting from the bottom or left of SB so it + * makes the most sense to only get there from Direction::INC wires. */ + if ((from_is_sblock) + && (Direction::INC == from_seg_details[from_track].direction())) { + num_conn += get_unidir_track_to_chan_seg(rr_graph_builder, layer, from_track, to_chan, + to_seg, to_sb, to_type, max_chan_width, + from_side_b, to_side, Fs_per_side, + sblock_pattern, + switch_override, + to_seg_details, + &Fs_clipped, from_rr_node, rr_edges_to_create); + } + } + } + } + } + + return num_conn; +} + +static int get_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, + int layer, + int from_wire, + int to_chan, + int to_seg, + e_rr_type to_chan_type, + e_side from_side, + e_side to_side, + int switch_override, + const t_sb_connection_map& sb_conn_map, + RRNodeId from_rr_node, + t_rr_edge_info_set& rr_edges_to_create) { + int edge_count = 0; + int to_x, to_y; + int tile_x, tile_y; + + // Get x/y coordinates from seg/chan coordinates + if (e_rr_type::CHANX == to_chan_type) { + to_x = tile_x = to_seg; + to_y = tile_y = to_chan; + if (RIGHT == to_side) { + tile_x--; + } + } else { + VTR_ASSERT(e_rr_type::CHANY == to_chan_type); + to_x = tile_x = to_chan; + to_y = tile_y = to_seg; + if (TOP == to_side) { + tile_y--; + } + } + + get_switchblocks_edges(rr_graph_builder, + tile_x, + tile_y, + layer, + from_side, + from_wire, + from_rr_node, + to_side, + to_x, + to_y, + to_chan_type, + switch_override, + sb_conn_map, + rr_edges_to_create, + edge_count); + + return edge_count; +} + +static void get_switchblocks_edges(RRGraphBuilder& rr_graph_builder, + int tile_x, + int tile_y, + int layer, + e_side from_side, + int from_wire, + RRNodeId from_rr_node, + e_side to_side, + int to_x, + int to_y, + e_rr_type to_chan_type, + int switch_override, + const t_sb_connection_map& sb_conn_map, + t_rr_edge_info_set& rr_edges_to_create, + int& edge_count) { + const DeviceContext& device_ctx = g_vpr_ctx.device(); + + // Coordinate to index into the SB map + SwitchblockLookupKey sb_coord(tile_x, tile_y, layer, from_side, to_side); + if (sb_conn_map.contains(sb_coord)) { + // Reference to the connections vector which lists all destination wires for a given source wire + // at a specific coordinate sb_coord + const std::vector& sb_edges = sb_conn_map.at(sb_coord); + + // Go through the connections... + for (const t_switchblock_edge& sb_edge : sb_edges) { + if (sb_edge.from_wire != from_wire) continue; + + int to_wire = sb_edge.to_wire; + // Get the index of the switch connecting the two wires + int src_switch = sb_edge.switch_ind; + + RRNodeId to_node = rr_graph_builder.node_lookup().find_node(layer, to_x, to_y, to_chan_type, to_wire); + + if (!to_node) { + continue; + } + + // Apply any switch overrides + if (should_apply_switch_override(switch_override)) { + src_switch = switch_override; + } + + rr_edges_to_create.emplace_back(from_rr_node, to_node, src_switch, false); + ++edge_count; + + if (device_ctx.arch_switch_inf[src_switch].directionality() == BI_DIRECTIONAL) { + // Add reverse edge since bidirectional + rr_edges_to_create.emplace_back(to_node, from_rr_node, src_switch, false); + ++edge_count; + } + } + } +} + +static int get_track_to_pins(RRGraphBuilder& rr_graph_builder, + int layer, + int seg, + int chan, + int track, + int tracks_per_chan, + RRNodeId from_rr_node, + t_rr_edge_info_set& rr_edges_to_create, + const t_track_to_pin_lookup& track_to_pin_lookup, + const t_chan_seg_details* seg_details, + e_rr_type chan_type, + int chan_length, + int wire_to_ipin_switch, + e_directionality directionality) { + const DeviceContext& device_ctx = g_vpr_ctx.device(); + + // End of this wire + int end = get_seg_end(seg_details, track, seg, chan, chan_length); + + int num_conn = 0; + + for (int j = seg; j <= end; j++) { + if (is_cblock(chan, j, track, seg_details)) { + for (int pass = 0; pass < 2; ++pass) { //pass == 0 => TOP/RIGHT, pass == 1 => BOTTOM/LEFT + e_side side; + int x, y; + if (e_rr_type::CHANX == chan_type) { + x = j; + y = chan + pass; + side = (0 == pass ? TOP : BOTTOM); + } else { + VTR_ASSERT(e_rr_type::CHANY == chan_type); + x = chan + pass; + y = j; + side = (0 == pass ? RIGHT : LEFT); + } + + /* PAJ - if the pointed to is an EMPTY then shouldn't look for ipins */ + t_physical_tile_type_ptr type = device_ctx.grid.get_physical_type({x, y, layer}); + if (type == device_ctx.EMPTY_PHYSICAL_TILE_TYPE) + continue; + + /* Move from logical (straight) to physical (twisted) track index + * - algorithm assigns ipin connections to same physical track index + * so that the logical track gets distributed uniformly */ + + int phy_track = vpr_to_phy_track(track, chan, j, seg_details, directionality); + phy_track %= tracks_per_chan; + + /* We need the type to find the ipin map for this type */ + + int width_offset = device_ctx.grid.get_width_offset({x, y, layer}); + int height_offset = device_ctx.grid.get_height_offset({x, y, layer}); + + const int max_conn = track_to_pin_lookup[type->index][phy_track][width_offset][height_offset][side].size(); + for (int iconn = 0; iconn < max_conn; iconn++) { + const int ipin = track_to_pin_lookup[type->index][phy_track][width_offset][height_offset][side][iconn]; + + // Check there is a connection and Fc map isn't wrong + RRNodeId to_node = rr_graph_builder.node_lookup().find_node(layer, x, y, e_rr_type::IPIN, ipin, side); + if (to_node) { + rr_edges_to_create.emplace_back(from_rr_node, to_node, wire_to_ipin_switch, false); + ++num_conn; + } + } + } + } + } + + return num_conn; +} + +static int should_create_switchblock(int layer_num, int from_chan_coord, int from_seg_coord, e_rr_type from_chan_type, e_rr_type to_chan_type) { + const DeviceGrid& grid = g_vpr_ctx.device().grid; + + // Convert the chan/seg indices to real x/y coordinates + int y_coord; + int x_coord; + if (from_chan_type == e_rr_type::CHANX) { + y_coord = from_chan_coord; + x_coord = from_seg_coord; + } else { + VTR_ASSERT(from_chan_type == e_rr_type::CHANY); + y_coord = from_seg_coord; + x_coord = from_chan_coord; + } + + t_physical_tile_type_ptr blk_type = grid.get_physical_type({x_coord, y_coord, layer_num}); + int width_offset = grid.get_width_offset({x_coord, y_coord, layer_num}); + int height_offset = grid.get_height_offset({x_coord, y_coord, layer_num}); + + e_sb_type sb_type = blk_type->switchblock_locations[width_offset][height_offset]; + int switch_override = blk_type->switchblock_switch_overrides[width_offset][height_offset]; + + if (sb_type == e_sb_type::FULL) { + return switch_override; + } else if (sb_type == e_sb_type::STRAIGHT && from_chan_type == to_chan_type) { + return switch_override; + } else if (sb_type == e_sb_type::TURNS && from_chan_type != to_chan_type) { + return switch_override; + } else if (sb_type == e_sb_type::HORIZONTAL && from_chan_type == e_rr_type::CHANX && to_chan_type == e_rr_type::CHANX) { + return switch_override; + } else if (sb_type == e_sb_type::VERTICAL && from_chan_type == e_rr_type::CHANY && to_chan_type == e_rr_type::CHANY) { + return switch_override; + } + + return NO_SWITCH; +} + +static int get_unidir_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, + int layer, + int from_track, + int to_chan, + int to_seg, + int to_sb, + e_rr_type to_type, + int max_chan_width, + e_side from_side, + e_side to_side, + int Fs_per_side, + t_sblock_pattern& sblock_pattern, + int switch_override, + const t_chan_seg_details* seg_details, + bool* Fs_clipped, + RRNodeId from_rr_node, + t_rr_edge_info_set& rr_edges_to_create) { + const DeviceContext& device_ctx = g_vpr_ctx.device(); + const DeviceGrid& grid = device_ctx.grid; + + int num_labels = 0; + std::vector mux_labels; + + // x, y coords for get_rr_node lookups + int to_x = (e_rr_type::CHANX == to_type ? to_seg : to_chan); + int to_y = (e_rr_type::CHANX == to_type ? to_chan : to_seg); + int sb_x = (e_rr_type::CHANX == to_type ? to_sb : to_chan); + int sb_y = (e_rr_type::CHANX == to_type ? to_chan : to_sb); + int max_len = (e_rr_type::CHANX == to_type ? grid.width() : grid.height()) - 2; //-2 for no perimeter channels + + enum Direction to_dir = Direction::DEC; + if (to_sb < to_seg) { + to_dir = Direction::INC; + } + + *Fs_clipped = false; + + /* get list of muxes to which we can connect */ + int dummy; + label_wire_muxes(to_chan, to_seg, seg_details, UNDEFINED, max_len, + to_dir, max_chan_width, false, mux_labels, &num_labels, &dummy); + + /* Can't connect if no muxes. */ + if (num_labels < 1) { + return 0; + } + + /* Check if Fs demand was too high. */ + if (Fs_per_side > num_labels) { + *Fs_clipped = true; + } + + // Handle Fs > 3 by assigning consecutive muxes. + int count = 0; + for (int i = 0; i < Fs_per_side; ++i) { + // Get the target label + for (int j = 0; j < 4; j = j + 2) { + // Use the balanced labeling for passing and fringe wires + int to_mux = sblock_pattern[sb_x][sb_y][from_side][to_side][from_track][j]; + if (to_mux < 0) { + continue; + } + + int to_track = sblock_pattern[sb_x][sb_y][from_side][to_side][from_track][j + 1]; + if (to_track < 0) { + to_track = mux_labels[(to_mux + i) % num_labels]; + sblock_pattern[sb_x][sb_y][from_side][to_side][from_track][j + 1] = to_track; + } + RRNodeId to_node = rr_graph_builder.node_lookup().find_node(layer, to_x, to_y, to_type, to_track); + + if (!to_node) { + continue; + } + + // Determine which switch to use + int iswitch = seg_details[to_track].arch_wire_switch(); + + // Apply any switch overrides + if (should_apply_switch_override(switch_override)) { + iswitch = switch_override; + } + VTR_ASSERT(iswitch != UNDEFINED); + + // Add edge to list. + rr_edges_to_create.emplace_back(from_rr_node, to_node, iswitch, false); + ++count; + + if (device_ctx.arch_switch_inf[iswitch].directionality() == BI_DIRECTIONAL) { + // Add reverse edge since bidirectional + rr_edges_to_create.emplace_back(to_node, from_rr_node, iswitch, false); + ++count; + } + } + } + + return count; +} + +static int get_bidir_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, + const std::vector& conn_tracks, + int layer, + int to_chan, + int to_seg, + int to_sb, + e_rr_type to_type, + const t_chan_seg_details* seg_details, + bool from_is_sblock, + int from_switch, + int switch_override, + e_directionality directionality, + RRNodeId from_rr_node, + t_rr_edge_info_set& rr_edges_to_create) { + int to_x, to_y; + short switch_types[2]; + + // x, y coords for get_rr_node lookups + if (e_rr_type::CHANX == to_type) { + to_x = to_seg; + to_y = to_chan; + } else { + VTR_ASSERT(e_rr_type::CHANY == to_type); + to_x = to_chan; + to_y = to_seg; + } + + // Go through the list of tracks we can connect to + int num_conn = 0; + for (int to_track : conn_tracks) { + RRNodeId to_node = rr_graph_builder.node_lookup().find_node(layer, to_x, to_y, to_type, to_track); + + if (!to_node) { + continue; + } + + // Get the switches for any edges between the two tracks + int to_switch = seg_details[to_track].arch_wire_switch(); + + bool to_is_sblock = is_sblock(to_chan, to_seg, to_sb, to_track, seg_details, directionality); + get_switch_type(from_is_sblock, to_is_sblock, from_switch, to_switch, + switch_override, + switch_types); + + // There are up to two switch edges allowed from track to track + for (int i = 0; i < 2; ++i) { + // If the switch_type entry is empty, skip it + if (UNDEFINED == switch_types[i]) { + continue; + } + + // Add the edge to the list + rr_edges_to_create.emplace_back(from_rr_node, to_node, switch_types[i], false); + ++num_conn; + } + } + + return num_conn; +} + +static int vpr_to_phy_track(int itrack, + int chan_num, + int seg_num, + const t_chan_seg_details* seg_details, + e_directionality directionality) { + + // Assign in pairs if unidir. + int fac = 1; + if (UNI_DIRECTIONAL == directionality) { + fac = 2; + } + + int group_start = seg_details[itrack].group_start(); + int group_size = seg_details[itrack].group_size(); + + int vpr_offset_for_first_phy_track = (chan_num + seg_num - 1) % (group_size / fac); + int vpr_offset = (itrack - group_start) / fac; + int phy_offset = (vpr_offset_for_first_phy_track + vpr_offset) % (group_size / fac); + int phy_track = group_start + (fac * phy_offset) + (itrack - group_start) % fac; + + return phy_track; +} + +static void get_switch_type(bool is_from_sblock, + bool is_to_sblock, + short from_node_switch, + short to_node_switch, + int switch_override, + short switch_types[2]) { + /* This routine looks at whether the from_node and to_node want a switch, * + * and what type of switch is used to connect *to* each type of node * + * (from_node_switch and to_node_switch). It decides what type of switch, * + * if any, should be used to go from from_node to to_node. If no switch * + * should be inserted (i.e. no connection), it returns NO_SWITCH. Its returned * + * values are in the switch_types array. It needs to return an array * + * because some topologies (e.g. bi-dir pass gates) result in two switches.*/ + + auto& device_ctx = g_vpr_ctx.device(); + + switch_types[0] = NO_SWITCH; + switch_types[1] = NO_SWITCH; + + if (switch_override == NO_SWITCH) { + return; //No switches + } + + if (should_apply_switch_override(switch_override)) { + //Use the override switches instead + from_node_switch = switch_override; + to_node_switch = switch_override; + } + + int used = 0; + bool forward_switch = false; + bool backward_switch = false; + + /* Connect forward if we are a sblock */ + if (is_from_sblock) { + switch_types[used] = to_node_switch; + ++used; + + forward_switch = true; + } + + /* Check for reverse switch */ + if (is_to_sblock) { + if (device_ctx.arch_switch_inf[from_node_switch].directionality() == e_directionality::BI_DIRECTIONAL) { + switch_types[used] = from_node_switch; + ++used; + + backward_switch = true; + } + } + + /* Take the larger switch if there are two of the same type */ + if (forward_switch + && backward_switch + && (device_ctx.arch_switch_inf[from_node_switch].type() == device_ctx.arch_switch_inf[to_node_switch].type())) { + //Sanity checks + VTR_ASSERT_SAFE_MSG(device_ctx.arch_switch_inf[from_node_switch].type() == device_ctx.arch_switch_inf[to_node_switch].type(), "Same switch type"); + VTR_ASSERT_MSG(device_ctx.arch_switch_inf[to_node_switch].directionality() == e_directionality::BI_DIRECTIONAL, "Bi-dir to switch"); + VTR_ASSERT_MSG(device_ctx.arch_switch_inf[from_node_switch].directionality() == e_directionality::BI_DIRECTIONAL, "Bi-dir from switch"); + + /* Take the smaller index unless the other + * switch is bigger (smaller R). */ + + int first_switch = std::min(to_node_switch, from_node_switch); + int second_switch = std::max(to_node_switch, from_node_switch); + + if (used < 2) { + VPR_FATAL_ERROR(VPR_ERROR_ROUTE, + "Expected 2 switches (forward and back) between RR nodes (found %d switches, min switch index: %d max switch index: %d)", + used, first_switch, second_switch); + } + + int switch_to_use = first_switch; + if (device_ctx.arch_switch_inf[second_switch].R < device_ctx.arch_switch_inf[first_switch].R) { + switch_to_use = second_switch; + } + + for (int i = 0; i < used; ++i) { + switch_types[i] = switch_to_use; + } + } +} + +static bool should_apply_switch_override(int switch_override) { + if (switch_override != NO_SWITCH && switch_override != DEFAULT_SWITCH) { + VTR_ASSERT(switch_override >= 0); + return true; + } + return false; +} + +void add_chan_chan_edges(RRGraphBuilder& rr_graph_builder, + size_t num_seg_types_x, + size_t num_seg_types_y, + const t_track_to_pin_lookup& track_to_pin_lookup_x, + const t_track_to_pin_lookup& track_to_pin_lookup_y, + const t_chan_width& chan_width, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + t_sb_connection_map* sb_conn_map, + const vtr::NdMatrix, 3>& switch_block_conn, + const vtr::NdMatrix, 2>& interdie_3d_links, + t_sblock_pattern& sblock_pattern, + int Fs, + int wire_to_ipin_switch, + e_directionality directionality, + bool is_global_graph, + int& num_edges) { + const DeviceContext& device_ctx = g_vpr_ctx.device(); + const DeviceGrid& grid = device_ctx.grid; + + VTR_ASSERT(Fs % 3 == 0); + num_edges = 0; + + t_rr_edge_info_set rr_edges_to_create; + t_rr_edge_info_set interdie_3d_rr_edges_to_create; + + for (size_t i = 0; i < grid.width() - 1; ++i) { + for (size_t j = 0; j < grid.height() - 1; ++j) { + + // In multi-die FPGAs with track-to-track connections between layers, we need to load CHANZ nodes + // These extra nodes can be driven from many tracks in the source layer and can drive multiple tracks in the destination layer, + // since these die-crossing connections have more delays. + if (grid.get_num_layers() > 1) { + build_inter_die_3d_rr_chan(rr_graph_builder, i, j, interdie_3d_links[i][j], + CHANX_COST_INDEX_START + num_seg_types_x + num_seg_types_y); + } + + for (int layer = 0; layer < (int)grid.get_num_layers(); ++layer) { + + // Skip the current die if architecture file specifies that it doesn't require inter-cluster programmable resource routing + if (!device_ctx.inter_cluster_prog_routing_resources.at(layer)) { + continue; + } + + if (i > 0) { + int tracks_per_chan = ((is_global_graph) ? 1 : chan_width.x_list[j]); + build_rr_chan(rr_graph_builder, layer, i, j, e_rr_type::CHANX, track_to_pin_lookup_x, sb_conn_map, + switch_block_conn, + CHANX_COST_INDEX_START, + chan_width, tracks_per_chan, + sblock_pattern, Fs / 3, chan_details_x, chan_details_y, + rr_edges_to_create, + wire_to_ipin_switch, + directionality); + + // Create the actual CHAN->CHAN edges + uniquify_edges(rr_edges_to_create); + rr_graph_builder.alloc_and_load_edges(&rr_edges_to_create); + num_edges += rr_edges_to_create.size(); + + rr_edges_to_create.clear(); + } + if (j > 0) { + int tracks_per_chan = ((is_global_graph) ? 1 : chan_width.y_list[i]); + build_rr_chan(rr_graph_builder, layer, i, j, e_rr_type::CHANY, track_to_pin_lookup_y, sb_conn_map, + switch_block_conn, + CHANX_COST_INDEX_START + num_seg_types_x, + chan_width, tracks_per_chan, + sblock_pattern, Fs / 3, chan_details_x, chan_details_y, + rr_edges_to_create, + wire_to_ipin_switch, + directionality); + + // Create the actual CHAN->CHAN edges + uniquify_edges(rr_edges_to_create); + rr_graph_builder.alloc_and_load_edges(&rr_edges_to_create); + num_edges += rr_edges_to_create.size(); + rr_edges_to_create.clear(); + } + } + + if (grid.get_num_layers() > 1) { + add_inter_die_3d_edges(rr_graph_builder, i, j, + chan_details_x, chan_details_y, + interdie_3d_links[i][j], interdie_3d_rr_edges_to_create); + uniquify_edges(interdie_3d_rr_edges_to_create); + rr_graph_builder.alloc_and_load_edges(&interdie_3d_rr_edges_to_create); + num_edges += interdie_3d_rr_edges_to_create.size(); + interdie_3d_rr_edges_to_create.clear(); + } + } + } +} \ No newline at end of file diff --git a/vpr/src/route/rr_graph_generation/rr_graph_chan_chan_edges.h b/vpr/src/route/rr_graph_generation/rr_graph_chan_chan_edges.h new file mode 100644 index 0000000000..fc35692bf4 --- /dev/null +++ b/vpr/src/route/rr_graph_generation/rr_graph_chan_chan_edges.h @@ -0,0 +1,26 @@ +#pragma once + +#include "rr_types.h" +#include "build_switchblocks.h" + +class RRGraphBuilder; +struct t_chan_width; +struct t_bottleneck_link; + +void add_chan_chan_edges(RRGraphBuilder& rr_graph_builder, + size_t num_seg_types_x, + size_t num_seg_types_y, + const t_track_to_pin_lookup& track_to_pin_lookup_x, + const t_track_to_pin_lookup& track_to_pin_lookup_y, + const t_chan_width& chan_width, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + t_sb_connection_map* sb_conn_map, + const vtr::NdMatrix, 3>& switch_block_conn, + const vtr::NdMatrix, 2>& interdie_3d_links, + t_sblock_pattern& sblock_pattern, + int Fs, + int wire_to_ipin_switch, + e_directionality directionality, + bool is_global_graph, + int& num_edges); diff --git a/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.cpp b/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.cpp index 4834b1d450..e40de0a411 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.cpp @@ -658,12 +658,13 @@ void add_opin_chan_edges(RRGraphBuilder& rr_graph_builder, const std::vector& directs, const std::vector& clb_to_clb_directs, e_directionality directionality, - t_rr_edge_info_set& rr_edges_to_create, int& num_edges, int& rr_edges_before_directs, bool* Fc_clipped) { const DeviceGrid& grid = g_vpr_ctx.device().grid; + t_rr_edge_info_set rr_edges_to_create; + // These are data structures used by the unidir opin mapping. They are used // to spread connections evenly for each segment type among the available // wire start points diff --git a/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.h b/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.h index eadaa2ed82..73deea1f77 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.h +++ b/vpr/src/route/rr_graph_generation/rr_graph_opin_chan_edges.h @@ -37,7 +37,6 @@ void add_opin_chan_edges(RRGraphBuilder& rr_graph_builder, const std::vector& directs, const std::vector& clb_to_clb_directs, e_directionality directionality, - t_rr_edge_info_set& rr_edges_to_create, int& num_edges, int& rr_edges_before_directs, bool* Fc_clipped); diff --git a/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp b/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp index 85974def4e..b8d5956624 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph_sg.cpp @@ -264,11 +264,14 @@ void add_and_connect_non_3d_sg_links(RRGraphBuilder& rr_graph_builder, const t_chan_details& chan_details_x, const t_chan_details& chan_details_y, size_t num_seg_types_x, - t_rr_edge_info_set& non_3d_sg_rr_edges_to_create) { + int& num_edges) { // Each SG link should have a corresponding RR node index VTR_ASSERT(sg_links.size() == sg_node_indices.size()); const size_t num_links = sg_links.size(); + t_rr_edge_info_set rr_edges_to_create; + num_edges = 0; + for (size_t i = 0; i < num_links; i++) { const t_bottleneck_link& link = sg_links[i]; @@ -320,7 +323,7 @@ void add_and_connect_non_3d_sg_links(RRGraphBuilder& rr_graph_builder, gather_chan_type, gather_wire.wire_switchpoint.wire); // Record deferred edge creation (gather_node --> sg_node) - non_3d_sg_rr_edges_to_create.emplace_back(gather_node, node_id, link.arch_wire_switch, false); + rr_edges_to_create.emplace_back(gather_node, node_id, link.arch_wire_switch, false); } // Step 7: Add outgoing edges to scatter (fanout) channel wires @@ -339,7 +342,11 @@ void add_and_connect_non_3d_sg_links(RRGraphBuilder& rr_graph_builder, // Determine which architecture switch this edge should use int switch_index = chan_details[chan_loc.x][chan_loc.y][scatter_wire.wire_switchpoint.wire].arch_wire_switch(); // Record deferred edge creation (sg_node --> scatter_node) - non_3d_sg_rr_edges_to_create.emplace_back(node_id, scatter_node, switch_index, false); + rr_edges_to_create.emplace_back(node_id, scatter_node, switch_index, false); } } + + uniquify_edges(rr_edges_to_create); + rr_graph_builder.alloc_and_load_edges(&rr_edges_to_create); + num_edges += rr_edges_to_create.size(); } diff --git a/vpr/src/route/rr_graph_generation/rr_graph_sg.h b/vpr/src/route/rr_graph_generation/rr_graph_sg.h index 4116f8bce0..a6cb0058d1 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_sg.h +++ b/vpr/src/route/rr_graph_generation/rr_graph_sg.h @@ -67,7 +67,7 @@ void add_edges_opin_chanz_per_block(const RRGraphView& rr_graph, * @param chan_details_x Channel details for CHANX segments. * @param chan_details_y Channel details for CHANY segments. * @param num_seg_types_x Number of segment types in the X direction. - * @param non_3d_sg_rr_edges_to_create Set collecting RR edges to create later. + * @param num_edges Total number of edges added to RR graph. */ void add_and_connect_non_3d_sg_links(RRGraphBuilder& rr_graph_builder, const std::vector& sg_links, @@ -75,4 +75,4 @@ void add_and_connect_non_3d_sg_links(RRGraphBuilder& rr_graph_builder, const t_chan_details& chan_details_x, const t_chan_details& chan_details_y, size_t num_seg_types_x, - t_rr_edge_info_set& non_3d_sg_rr_edges_to_create); + int& num_edges); From 63cbe06bcbc3adec68188d7e1dc98e509008dbbc Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Wed, 5 Nov 2025 17:26:01 -0500 Subject: [PATCH 29/32] add rr_chanz_segment_width to DeviceContext --- vpr/src/base/vpr_context.h | 2 ++ vpr/src/route/rr_graph_generation/rr_graph.cpp | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/vpr/src/base/vpr_context.h b/vpr/src/base/vpr_context.h index 6a49a91fd6..241a586135 100644 --- a/vpr/src/base/vpr_context.h +++ b/vpr/src/base/vpr_context.h @@ -267,6 +267,8 @@ struct DeviceContext : public Context { vtr::NdMatrix rr_chanx_segment_width; /// Stores the number of CHANY wire segments in each routing channel segment at [layer][x][y] vtr::NdMatrix rr_chany_segment_width; + /// Stores the number of CHANZ wire segments along Z-axis at each (x, y) location. + vtr::NdMatrix rr_chanz_segment_width; /// Stores the maximum channel segment width in each horizontal channel std::vector rr_chanx_width; diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index 6c093570fc..0c6b3c4d69 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -1017,6 +1017,7 @@ static void alloc_and_init_channel_width() { vtr::NdMatrix& chanx_width = mutable_device_ctx.rr_chanx_segment_width; vtr::NdMatrix& chany_width = mutable_device_ctx.rr_chany_segment_width; + vtr::NdMatrix& chanz_width = mutable_device_ctx.rr_chanz_segment_width; chanx_width.resize({grid.get_num_layers(), grid.width(), grid.height()}); chany_width.resize({grid.get_num_layers(), grid.width(), grid.height()}); @@ -1024,6 +1025,11 @@ static void alloc_and_init_channel_width() { chanx_width.fill(0); chany_width.fill(0); + if (grid.get_num_layers() > 1) { + chanz_width.resize({grid.width(), grid.height()}); + chanz_width.fill(0); + } + for (RRNodeId node_id : rr_graph.nodes()) { e_rr_type rr_type = rr_graph.node_type(node_id); @@ -1039,6 +1045,10 @@ static void alloc_and_init_channel_width() { for (int y = rr_graph.node_ylow(node_id); y <= rr_graph.node_yhigh(node_id); y++) { chany_width[layer][x][y] += rr_graph.node_capacity(node_id); } + } else if (rr_type == e_rr_type::CHANZ) { + int x = rr_graph.node_xlow(node_id); + int y = rr_graph.node_ylow(node_id); + chanz_width[x][y]++; } } From 5d477c148850466085ea6294922805cc2544635d Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Wed, 5 Nov 2025 17:39:18 -0500 Subject: [PATCH 30/32] calculate acc_tile_num_inter_die_conn_ using pre-computed chanz width --- vpr/src/place/net_cost_handler.cpp | 57 ++++-------------------------- vpr/src/place/net_cost_handler.h | 10 +----- 2 files changed, 8 insertions(+), 59 deletions(-) diff --git a/vpr/src/place/net_cost_handler.cpp b/vpr/src/place/net_cost_handler.cpp index 9bcdde45e0..859f56bda9 100644 --- a/vpr/src/place/net_cost_handler.cpp +++ b/vpr/src/place/net_cost_handler.cpp @@ -176,59 +176,16 @@ void NetCostHandler::alloc_and_load_chan_w_factors_for_place_cost_() { }); if (is_multi_layer_) { - alloc_and_load_for_fast_vertical_cost_update_(); + // Calculate prefix sum of the inter-die connectivity up to and including the channel at (x, y). + acc_tile_num_inter_die_conn_ = vtr::PrefixSum2D(grid_width, + grid_height, + [&](size_t x, size_t y) { + return device_ctx.rr_chanz_segment_width[x][y]; + }); } } -void NetCostHandler::alloc_and_load_for_fast_vertical_cost_update_() { - const auto& device_ctx = g_vpr_ctx.device(); - const auto& rr_graph = device_ctx.rr_graph; - - const size_t grid_height = device_ctx.grid.height(); - const size_t grid_width = device_ctx.grid.width(); - - vtr::NdMatrix tile_num_inter_die_conn({grid_width, grid_height}, 0.); - - /* - * Step 1: iterate over the rr-graph, recording how many edges go between layers at each (x,y) location - * in the device. We count all these edges, regardless of which layers they connect. Then we divide by - * the number of layers - 1 to get the average cross-layer edge count per (x,y) location -- this mirrors - * what we do for the horizontal and vertical channels where we assume the channel width doesn't change - * along the length of the channel. It lets us be more memory-efficient for 3D devices, and could be revisited - * if someday we have architectures with widely varying connectivity between different layers in a stack. - */ - - /* To calculate the accumulative number of inter-die connections we first need to get the number of - * inter-die connection per location. To be able to work for the cases that RR Graph is read instead - * of being made from the architecture file, we calculate this number by iterating over the RR graph. Once - * tile_num_inter_die_conn is populated, we can start populating acc_tile_num_inter_die_conn_. - */ - - for (const RRNodeId node : rr_graph.nodes()) { - if (rr_graph.node_type(node) == e_rr_type::CHANZ) { - int x = rr_graph.node_xlow(node); - int y = rr_graph.node_ylow(node); - VTR_ASSERT_SAFE(x == rr_graph.node_xhigh(node) && y == rr_graph.node_yhigh(node)); - tile_num_inter_die_conn[x][y]++; - } - } - - int num_layers = device_ctx.grid.get_num_layers(); - for (size_t x = 0; x < device_ctx.grid.width(); x++) { - for (size_t y = 0; y < device_ctx.grid.height(); y++) { - tile_num_inter_die_conn[x][y] /= (num_layers - 1); - } - } - - // Step 2: Calculate prefix sum of the inter-die connectivity up to and including the channel at (x, y). - acc_tile_num_inter_die_conn_ = vtr::PrefixSum2D(grid_width, - grid_height, - [&](size_t x, size_t y) { - return (int)tile_num_inter_die_conn[x][y]; - }); -} - -std::pair NetCostHandler::comp_bb_cost(e_cost_methods method) { +std::pair NetCostHandler::comp_bb_cost(e_cost_methods method) const { return comp_bb_cost_functor_(method); } diff --git a/vpr/src/place/net_cost_handler.h b/vpr/src/place/net_cost_handler.h index b36fe9fc6e..0f6b882c2d 100644 --- a/vpr/src/place/net_cost_handler.h +++ b/vpr/src/place/net_cost_handler.h @@ -68,7 +68,7 @@ class NetCostHandler { * * @note The returned estimated wirelength is valid only when method == CHECK */ - std::pair comp_bb_cost(e_cost_methods method); + std::pair comp_bb_cost(e_cost_methods method) const; /** * @brief Find all the nets and pins affected by this swap and update costs. @@ -302,14 +302,6 @@ class NetCostHandler { */ void alloc_and_load_chan_w_factors_for_place_cost_(); - /** - * @brief Allocates and loads acc_tile_num_inter_die_conn_ which contains the accumulative number of inter-die - * conntections. - * - * @details This is only useful for multi-die FPGAs. - */ - void alloc_and_load_for_fast_vertical_cost_update_(); - /** * @brief Calculate the new connection delay and timing cost of all the * sink pins affected by moving a specific pin to a new location. Also From eadc8fe997d3328d58f77dac602b9fcea2bd8985 Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Thu, 6 Nov 2025 11:58:18 -0500 Subject: [PATCH 31/32] update expected_delay_cost before VTR_ASSERT --- .../router_lookahead/router_lookahead_map.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/vpr/src/route/router_lookahead/router_lookahead_map.cpp b/vpr/src/route/router_lookahead/router_lookahead_map.cpp index fe798cb54f..ce0e987e3d 100644 --- a/vpr/src/route/router_lookahead/router_lookahead_map.cpp +++ b/vpr/src/route/router_lookahead/router_lookahead_map.cpp @@ -319,10 +319,10 @@ std::pair MapLookahead::get_expected_delay_and_cong(RRNodeId from_ e_rr_type from_type = rr_graph.node_type(from_node); if (from_type == e_rr_type::SOURCE || from_type == e_rr_type::OPIN) { - //When estimating costs from a SOURCE/OPIN we look-up to find which wire types (and the - //cost to reach them) in src_opin_delays. Once we know what wire types are - //reachable, we query the f_wire_cost_map (i.e. the wire lookahead) to get the final - //delay to reach the sink. + // When estimating costs from a SOURCE/OPIN we look-up to find which wire types (and the + // cost to reach them) in src_opin_delays. Once we know what wire types are + // reachable, we query the f_wire_cost_map (i.e. the wire lookahead) to get the final + // delay to reach the sink. t_physical_tile_type_ptr from_tile_type = device_ctx.grid.get_physical_type({rr_graph.node_xlow(from_node), rr_graph.node_ylow(from_node), @@ -335,7 +335,7 @@ std::pair MapLookahead::get_expected_delay_and_cong(RRNodeId from_ // get_cost_from_src_opin iterates over all routing segments passed to it (the first argument) and returns // the minimum cost among them. In the following for loop, we iterate over each layer and pass it the // routing segments on that layer reachable from the OPIN/SOURCE to segments on that layer. This for loop then calculates and returns - // the minimum cost from the given OPIN/SOURCE to the specified SINK considering routing options across all layers. + // the minimum cost from the given OPIN/SOURCE to the specified SINK considering routing options across all layers. for (size_t layer_num = 0; layer_num < device_ctx.grid.get_num_layers(); layer_num++) { const auto [this_delay_cost, this_cong_cost] = util::get_cost_from_src_opin(src_opin_delays[from_layer_num][from_tile_index][from_ptc][layer_num], delta_x, @@ -389,6 +389,9 @@ std::pair MapLookahead::get_expected_delay_and_cong(RRNodeId from_ delta_y, to_layer_num); + expected_delay_cost = cost_entry.delay * params.criticality; + expected_cong_cost = cost_entry.congestion * (1 - params.criticality); + VTR_ASSERT_SAFE_MSG(std::isfinite(expected_delay_cost), vtr::string_fmt("Lookahead failed to estimate cost from %s: %s", rr_node_arch_name(from_node, is_flat_).c_str(), @@ -399,8 +402,6 @@ std::pair MapLookahead::get_expected_delay_and_cong(RRNodeId from_ is_flat_) .c_str()) .c_str()); - expected_delay_cost = cost_entry.delay * params.criticality; - expected_cong_cost = cost_entry.congestion * (1 - params.criticality); } else if (from_type == e_rr_type::IPIN) { // Change if you're allowing route-throughs return std::make_pair(0., device_ctx.rr_indexed_data[RRIndexedDataId(SINK_COST_INDEX)].base_cost); } else { // Change this if you want to investigate route-throughs From 2657db0034c7afb95e183872564240e9747a66f5 Mon Sep 17 00:00:00 2001 From: Soheil Shahrouz Date: Thu, 6 Nov 2025 19:41:25 -0500 Subject: [PATCH 32/32] add sg and z segment to 3d_k4_n4_90nm --- .../multi_die/simple_arch/3d_k4_N4_90nm.xml | 41 ++++++++++++++----- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/vtr_flow/arch/multi_die/simple_arch/3d_k4_N4_90nm.xml b/vtr_flow/arch/multi_die/simple_arch/3d_k4_N4_90nm.xml index 500df33875..1cafe857d2 100644 --- a/vtr_flow/arch/multi_die/simple_arch/3d_k4_N4_90nm.xml +++ b/vtr_flow/arch/multi_die/simple_arch/3d_k4_N4_90nm.xml @@ -26,10 +26,10 @@ - io.outpad io.inpad io.clock - io.outpad io.inpad io.clock - io.outpad io.inpad io.clock - io.outpad io.inpad io.clock + io.outpad io.inpad io.clock + io.outpad io.inpad io.clock + io.outpad io.inpad io.clock + io.outpad io.inpad io.clock @@ -41,9 +41,11 @@ - + + + - clb.I clb.clk + clb.I clb.clk - clb.O + clb.O @@ -91,7 +93,6 @@ - @@ -99,9 +100,8 @@ - + - 1 1 1 @@ -221,4 +221,25 @@ + + + + + + + + + + + + + + + + + + + + +