33#include < algorithm>
44#include < utility>
55#include < vector>
6+ #include < ranges>
7+
68#include " alloc_and_load_rr_indexed_data.h"
79#include " build_scatter_gathers.h"
810#include " get_parallel_segs.h"
@@ -84,6 +86,15 @@ static vtr::NdMatrix<std::vector<int>, 4> alloc_and_load_pin_to_track_map(const
8486 const e_directionality directionality,
8587 const std::vector<t_segment_inf>& seg_inf,
8688 const std::vector<int >& sets_per_seg_type);
89+
90+ static void add_edges_opin_chanz (RRGraphBuilder& rr_graph_builder,
91+ const RRGraphView& rr_graph,
92+ int layer, int x, int y,
93+ const std::vector<vtr::Matrix<int >>& Fc_out,
94+ const t_unified_to_parallel_seg_index& seg_index_map,
95+ int num_seg_types,
96+ t_rr_edge_info_set& rr_edges_to_create,
97+ const std::vector<t_bottleneck_link>& interdie_3d_links);
8798/* *
8899 * @brief This routine calculates pin connections to tracks for a specific type and a specific segment based on the Fc value
89100 * 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<vtr::Matrix<int>> alloc_and_load_actual_fc(const std::vector<t_physi
12931304
12941305 *Fc_clipped = false ;
12951306
1296- // Unidir tracks formed in pairs, otherwise no effect.
1297- int fac = 1 ;
1298- if (UNI_DIRECTIONAL == directionality) {
1299- fac = 2 ;
1300- }
1301-
1302- VTR_ASSERT ((nodes_per_chan->x_max % fac) == 0 && (nodes_per_chan->y_max % fac) == 0 );
1307+ // VTR_ASSERT((nodes_per_chan->x_max % fac) == 0 && (nodes_per_chan->y_max % fac) == 0);
13031308
13041309 for (const t_physical_tile_type& type : types) { // Skip EMPTY
13051310 int itype = type.index ;
@@ -1316,63 +1321,72 @@ std::vector<vtr::Matrix<int>> alloc_and_load_actual_fc(const std::vector<t_physi
13161321 for (int ipin : fc_spec.pins ) {
13171322 Fc[itype][ipin][iseg] = 0 ;
13181323 }
1319- } else {
1320- // General case indicating that this pin connects to general-purpose routing
1321-
1322- // Calculate how many connections there should be across all the pins in this fc_spec
1323- int total_connections = 0 ;
1324- if (fc_spec.fc_value_type == e_fc_value_type::FRACTIONAL) {
1325- float conns_per_pin = fac * sets_per_seg_type[iseg] * fc_spec.fc_value ;
1326- float flt_total_connections = conns_per_pin * fc_spec.pins .size ();
1327- total_connections = vtr::nint (flt_total_connections); // Round to integer
1328- } else {
1329- VTR_ASSERT (fc_spec.fc_value_type == e_fc_value_type::ABSOLUTE);
1324+ continue ;
1325+ }
13301326
1331- if (std::fmod (fc_spec.fc_value , fac) != 0 . && segment_inf[iseg].parallel_axis != e_parallel_axis::Z_AXIS) {
1332- VPR_FATAL_ERROR (VPR_ERROR_ROUTE, " Absolute Fc value must be a multiple of %d (was %f) between block pin '%s' and wire segment '%s'" ,
1333- fac, fc_spec.fc_value ,
1334- block_type_pin_index_to_name (&type, fc_spec.pins [0 ], is_flat).c_str (),
1335- segment_inf[iseg].name .c_str ());
1336- }
1327+ // General case indicating that this pin connects to general-purpose routing
13371328
1338- if (fc_spec.fc_value < fac && segment_inf[iseg].parallel_axis != e_parallel_axis::Z_AXIS) {
1339- VPR_FATAL_ERROR (VPR_ERROR_ROUTE, " Absolute Fc value must be at least %d (was %f) between block pin '%s' to wire segment %s" ,
1340- fac, fc_spec.fc_value ,
1341- block_type_pin_index_to_name (&type, fc_spec.pins [0 ], is_flat).c_str (),
1342- segment_inf[iseg].name .c_str ());
1343- }
1329+ // Unidir tracks formed in pairs, otherwise no effect.
1330+ int fac = 1 ;
1331+ if (directionality == UNI_DIRECTIONAL && segment_inf[iseg].parallel_axis != e_parallel_axis::Z_AXIS) {
1332+ fac = 2 ;
1333+ }
1334+
1335+ // Calculate how many connections there should be across all the pins in this fc_spec
1336+ int total_connections = 0 ;
1337+ if (fc_spec.fc_value_type == e_fc_value_type::FRACTIONAL) {
1338+ float conns_per_pin = fac * sets_per_seg_type[iseg] * fc_spec.fc_value ;
1339+ float flt_total_connections = conns_per_pin * fc_spec.pins .size ();
1340+ total_connections = vtr::nint (flt_total_connections); // Round to integer
1341+ } else {
1342+ VTR_ASSERT (fc_spec.fc_value_type == e_fc_value_type::ABSOLUTE);
13441343
1345- total_connections = vtr::nint (fc_spec.fc_value ) * fc_spec.pins .size ();
1344+ if (std::fmod (fc_spec.fc_value , fac) != 0 . && segment_inf[iseg].parallel_axis != e_parallel_axis::Z_AXIS) {
1345+ VPR_FATAL_ERROR (VPR_ERROR_ROUTE, " Absolute Fc value must be a multiple of %d (was %f) between block pin '%s' and wire segment '%s'" ,
1346+ fac, fc_spec.fc_value ,
1347+ block_type_pin_index_to_name (&type, fc_spec.pins [0 ], is_flat).c_str (),
1348+ segment_inf[iseg].name .c_str ());
13461349 }
13471350
1348- // Ensure that there are at least fac connections, this ensures that low Fc ports
1349- // targeting small sets of segs get connection(s), even if flt_total_connections < fac.
1350- total_connections = std::max (total_connections, fac);
1351-
1352- // Ensure total evenly divides fac by adding the remainder
1353- total_connections += (total_connections % fac);
1354-
1355- VTR_ASSERT (total_connections > 0 );
1356- VTR_ASSERT (total_connections % fac == 0 );
1357-
1358- // We walk through all the pins this fc_spec applies to, adding fac connections
1359- // to each pin, until we run out of connections. This should distribute the connections
1360- // as evenly as possible (if total_connections % pins.size() != 0, there will be
1361- // some inevitable imbalance).
1362- int connections_remaining = total_connections;
1363- while (connections_remaining != 0 ) {
1364- // Add one set of connections to each pin
1365- for (int ipin : fc_spec.pins ) {
1366- if (connections_remaining >= fac) {
1367- Fc[itype][ipin][iseg] += fac;
1368- connections_remaining -= fac;
1369- } else {
1370- VTR_ASSERT (connections_remaining == 0 );
1371- break ;
1372- }
1351+ if (fc_spec.fc_value < fac && segment_inf[iseg].parallel_axis != e_parallel_axis::Z_AXIS) {
1352+ VPR_FATAL_ERROR (VPR_ERROR_ROUTE, " Absolute Fc value must be at least %d (was %f) between block pin '%s' to wire segment %s" ,
1353+ fac, fc_spec.fc_value ,
1354+ block_type_pin_index_to_name (&type, fc_spec.pins [0 ], is_flat).c_str (),
1355+ segment_inf[iseg].name .c_str ());
1356+ }
1357+
1358+ total_connections = vtr::nint (fc_spec.fc_value ) * fc_spec.pins .size ();
1359+ }
1360+
1361+ // Ensure that there are at least fac connections, this ensures that low Fc ports
1362+ // targeting small sets of segs get connection(s), even if flt_total_connections < fac.
1363+ total_connections = std::max (total_connections, fac);
1364+
1365+ // Ensure total evenly divides fac by adding the remainder
1366+ total_connections += (total_connections % fac);
1367+
1368+ VTR_ASSERT (total_connections > 0 );
1369+ VTR_ASSERT (total_connections % fac == 0 );
1370+
1371+ // We walk through all the pins this fc_spec applies to, adding fac connections
1372+ // to each pin, until we run out of connections. This should distribute the connections
1373+ // as evenly as possible (if total_connections % pins.size() != 0, there will be
1374+ // some inevitable imbalance).
1375+ int connections_remaining = total_connections;
1376+ while (connections_remaining != 0 ) {
1377+ // Add one set of connections to each pin
1378+ for (int ipin : fc_spec.pins ) {
1379+ if (connections_remaining >= fac) {
1380+ Fc[itype][ipin][iseg] += fac;
1381+ connections_remaining -= fac;
1382+ } else {
1383+ VTR_ASSERT (connections_remaining == 0 );
1384+ break ;
13731385 }
13741386 }
1387+ }
13751388
1389+ if (segment_inf[iseg].parallel_axis != e_parallel_axis::Z_AXIS) {
13761390 for (int ipin : fc_spec.pins ) {
13771391 // It is possible that we may want more connections that wires of this type exist;
13781392 // clip to the maximum number of wires
@@ -1515,13 +1529,21 @@ static std::function<void(t_chan_width*)> alloc_and_load_rr_graph(RRGraphBuilder
15151529 *Fc_clipped = true ;
15161530 }
15171531 }
1518-
1519- // Create the actual OPIN->CHANX/CHANY edges
1520- uniquify_edges (rr_edges_to_create);
1521- alloc_and_load_edges (rr_graph_builder, rr_edges_to_create);
1522- num_edges += rr_edges_to_create.size ();
1523- rr_edges_to_create.clear ();
15241532 }
1533+
1534+ add_edges_opin_chanz (rr_graph_builder, rr_graph,
1535+ layer, i, j,
1536+ Fc_out,
1537+ seg_index_map,
1538+ num_seg_types,
1539+ rr_edges_to_create,
1540+ interdie_3d_links[i][j]);
1541+
1542+ // Create the actual OPIN->CHANX/CHANY edges
1543+ uniquify_edges (rr_edges_to_create);
1544+ alloc_and_load_edges (rr_graph_builder, rr_edges_to_create);
1545+ num_edges += rr_edges_to_create.size ();
1546+ rr_edges_to_create.clear ();
15251547 }
15261548 }
15271549 }
@@ -2800,6 +2822,57 @@ static vtr::NdMatrix<std::vector<int>, 4> alloc_and_load_track_to_pin_lookup(vtr
28002822 return track_to_pin_lookup;
28012823}
28022824
2825+ static void add_edges_opin_chanz (RRGraphBuilder& rr_graph_builder,
2826+ const RRGraphView& rr_graph,
2827+ int layer, int x, int y,
2828+ const std::vector<vtr::Matrix<int >>& Fc_out,
2829+ const t_unified_to_parallel_seg_index& seg_index_map,
2830+ int num_seg_types,
2831+ t_rr_edge_info_set& rr_edges_to_create,
2832+ const std::vector<t_bottleneck_link>& interdie_3d_links) {
2833+ const RRSpatialLookup& node_lookup = rr_graph.node_lookup ();
2834+ const DeviceGrid& grid = g_vpr_ctx.device ().grid ;
2835+
2836+ t_physical_tile_type_ptr type = grid.get_physical_type ({x, y, layer});
2837+
2838+ std::vector<RRNodeId> opin_nodes = node_lookup.find_grid_nodes_at_all_sides (layer, x, y, e_rr_type::OPIN);
2839+ std::ranges::stable_sort (opin_nodes, std::less<>{}, [](RRNodeId id) noexcept { return size_t (id); });
2840+ // Remove adjacent duplicates
2841+ auto [unique_end, _] = std::ranges::unique (opin_nodes);
2842+ opin_nodes.erase (unique_end, opin_nodes.end ());
2843+
2844+ std::vector<std::pair<RRNodeId, short >> selected_chanz_nodes;
2845+
2846+ for (int iseg = 0 ; iseg < num_seg_types; iseg++) {
2847+ int seg_index = get_parallel_seg_index (iseg, seg_index_map, e_parallel_axis::Z_AXIS);
2848+ if (seg_index < 0 ) {
2849+ continue ;
2850+ }
2851+
2852+ selected_chanz_nodes.clear ();
2853+ for (size_t track_num = 0 ; track_num < interdie_3d_links.size (); track_num++) {
2854+ const t_bottleneck_link& bottleneck_link = interdie_3d_links[track_num];
2855+ if (bottleneck_link.parallel_segment_index == seg_index && bottleneck_link.gather_loc .layer_num == layer) {
2856+ RRNodeId node_id = node_lookup.find_node (layer, x, y, e_rr_type::CHANZ, track_num);
2857+ selected_chanz_nodes.push_back ({node_id, bottleneck_link.arch_wire_switch });
2858+ }
2859+ }
2860+
2861+ int chanz_idx = 0 ;
2862+ for (RRNodeId opin_node_id : opin_nodes) {
2863+ int pin_number = rr_graph.node_pin_num (opin_node_id);
2864+ int fc = Fc_out[type->index ][pin_number][iseg];
2865+
2866+ for (int i = 0 ; i < fc; i++) {
2867+ RRNodeId chanz_node_id = selected_chanz_nodes[chanz_idx % selected_chanz_nodes.size ()].first ;
2868+ short switch_id = selected_chanz_nodes[chanz_idx % selected_chanz_nodes.size ()].second ;
2869+ chanz_idx++;
2870+ rr_edges_to_create.emplace_back (opin_node_id, chanz_node_id, switch_id, false );
2871+ }
2872+ }
2873+ }
2874+ }
2875+
28032876static void build_unidir_rr_opins (RRGraphBuilder& rr_graph_builder,
28042877 const RRGraphView& rr_graph,
28052878 const int layer,
@@ -2824,7 +2897,6 @@ static void build_unidir_rr_opins(RRGraphBuilder& rr_graph_builder,
28242897 *Fc_clipped = false ;
28252898
28262899 t_physical_tile_type_ptr type = grid.get_physical_type ({i, j, layer});
2827-
28282900 int width_offset = grid.get_width_offset ({i, j, layer});
28292901 int height_offset = grid.get_height_offset ({i, j, layer});
28302902
0 commit comments