diff --git a/libs/libarchfpga/src/physical_types.cpp b/libs/libarchfpga/src/physical_types.cpp
index 9b72cb9575..6032bcb6d2 100644
--- a/libs/libarchfpga/src/physical_types.cpp
+++ b/libs/libarchfpga/src/physical_types.cpp
@@ -252,7 +252,71 @@ const t_port* t_logical_block_type::get_port_by_pin(int pin) const {
return nullptr;
}
-/**
+/*
+ * t_pb_type
+ */
+
+int t_pb_type::get_max_primitives() const {
+ int max_size;
+
+ if (modes == nullptr) {
+ max_size = 1;
+ } else {
+ max_size = 0;
+ int temp_size = 0;
+ for (int i = 0; i < num_modes; i++) {
+ for (int j = 0; j < modes[i].num_pb_type_children; j++) {
+ temp_size += modes[i].pb_type_children[j].num_pb * modes[i].pb_type_children[j].get_max_primitives();
+ }
+ if (temp_size > max_size) {
+ max_size = temp_size;
+ }
+ }
+ }
+
+ return max_size;
+}
+
+/* finds maximum number of nets that can be contained in pb_type, this is bounded by the number of driving pins */
+int t_pb_type::get_max_nets() const {
+ int max_nets;
+ if (modes == nullptr) {
+ max_nets = num_output_pins;
+ } else {
+ max_nets = 0;
+
+ for (int i = 0; i < num_modes; i++) {
+ int temp_nets = 0;
+ for (int j = 0; j < modes[i].num_pb_type_children; j++) {
+ temp_nets += modes[i].pb_type_children[j].num_pb * modes[i].pb_type_children[j].get_max_nets();
+ }
+
+ if (temp_nets > max_nets) {
+ max_nets = temp_nets;
+ }
+ }
+ }
+
+ if (is_root()) {
+ max_nets += num_input_pins + num_output_pins + num_clock_pins;
+ }
+
+ return max_nets;
+}
+
+int t_pb_type::get_max_depth() const {
+ int max_depth = depth;
+
+ for (int i = 0; i < num_modes; i++) {
+ for (int j = 0; j < modes[i].num_pb_type_children; j++) {
+ int temp_depth = modes[i].pb_type_children[j].get_max_depth();
+ max_depth = std::max(max_depth, temp_depth);
+ }
+ }
+ return max_depth;
+}
+
+/*
* t_pb_graph_node
*/
diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h
index c2459721d9..27b787f7c6 100644
--- a/libs/libarchfpga/src/physical_types.h
+++ b/libs/libarchfpga/src/physical_types.h
@@ -725,6 +725,11 @@ struct t_physical_tile_type {
///@brief Is this t_physical_tile_type an empty type?
bool is_empty() const;
+ ///@brief Returns true if the physical tile type can implement either a .input or .output block type
+ inline bool is_io() const {
+ return is_input_type || is_output_type;
+ }
+
///@brief Returns the relative pin index within a sub tile that corresponds to the pin within the given port and its index in the port
int find_pin(std::string_view port_name, int pin_index_in_port) const;
@@ -1087,6 +1092,10 @@ struct t_pb_type {
inline bool is_primitive() const {
return num_modes == 0;
}
+
+ int get_max_primitives() const;
+ int get_max_depth() const;
+ int get_max_nets() const;
};
/** Describes an operational mode of a clustered logic block
diff --git a/libs/libarchfpga/src/physical_types_util.cpp b/libs/libarchfpga/src/physical_types_util.cpp
index 2ecc7fbd41..74ad3aa6f1 100644
--- a/libs/libarchfpga/src/physical_types_util.cpp
+++ b/libs/libarchfpga/src/physical_types_util.cpp
@@ -637,21 +637,6 @@ bool is_pin_conencted_to_layer(t_physical_tile_type_ptr type, int ipin, int from
return false;
}
-// TODO: Remove is_input_type / is_output_type / is_io_type as part of
-// https://github.com/verilog-to-routing/vtr-verilog-to-routing/issues/1193
-bool is_input_type(t_physical_tile_type_ptr type) {
- return type->is_input_type;
-}
-
-bool is_output_type(t_physical_tile_type_ptr type) {
- return type->is_output_type;
-}
-
-bool is_io_type(t_physical_tile_type_ptr type) {
- return is_input_type(type)
- || is_output_type(type);
-}
-
std::string block_type_pin_index_to_name(t_physical_tile_type_ptr type, int pin_physical_num, bool is_flat) {
int max_ptc = get_tile_pin_max_ptc(type, is_flat);
VTR_ASSERT(pin_physical_num < max_ptc);
diff --git a/libs/libarchfpga/src/physical_types_util.h b/libs/libarchfpga/src/physical_types_util.h
index a081683fae..84cad62a84 100644
--- a/libs/libarchfpga/src/physical_types_util.h
+++ b/libs/libarchfpga/src/physical_types_util.h
@@ -120,13 +120,6 @@ bool is_opin(int ipin, t_physical_tile_type_ptr type);
///@brief Returns true if the specified pin is located at "from_layer" and it is connected to "to_layer"
bool is_pin_conencted_to_layer(t_physical_tile_type_ptr type, int ipin, int from_layer, int to_layer, int num_of_avail_layer);
-///@brief Returns true if the given physical tile type can implement a .input block type
-bool is_input_type(t_physical_tile_type_ptr type);
-///@brief Returns true if the given physical tile type can implement a .output block type
-bool is_output_type(t_physical_tile_type_ptr type);
-///@brief Returns true if the given physical tile type can implement either a .input or .output block type
-bool is_io_type(t_physical_tile_type_ptr type);
-
/**
* @brief Returns the corresponding physical pin based on the input parameters:
*
diff --git a/vpr/src/base/ShowSetup.cpp b/vpr/src/base/ShowSetup.cpp
index fa81fa9f1a..ccf900f8ef 100644
--- a/vpr/src/base/ShowSetup.cpp
+++ b/vpr/src/base/ShowSetup.cpp
@@ -135,7 +135,7 @@ ClusteredNetlistStats::ClusteredNetlistStats() {
auto logical_block = cluster_ctx.clb_nlist.block_type(blk_id);
auto physical_tile = pick_physical_type(logical_block);
num_blocks_type[logical_block->index]++;
- if (is_io_type(physical_tile)) {
+ if (physical_tile->is_io()) {
for (int j = 0; j < logical_block->pb_type->num_pins; j++) {
int physical_pin = get_physical_pin(physical_tile, logical_block, j);
diff --git a/vpr/src/base/check_netlist.cpp b/vpr/src/base/check_netlist.cpp
index 3d777f3ec4..d8ad7fab6f 100644
--- a/vpr/src/base/check_netlist.cpp
+++ b/vpr/src/base/check_netlist.cpp
@@ -110,8 +110,7 @@ static int check_connections_to_global_clb_pins(ClusterNetId net_id, int verbosi
int log_index = cluster_ctx.clb_nlist.pin_logical_index(pin_id);
int pin_index = get_physical_pin(physical_type, logical_type, log_index);
- if (physical_type->is_ignored_pin[pin_index] != net_is_ignored
- && !is_io_type(physical_type)) {
+ if (physical_type->is_ignored_pin[pin_index] != net_is_ignored && !physical_type->is_io()) {
VTR_LOGV_WARN(verbosity > 2,
"Global net '%s' connects to non-global architecture pin '%s' (netlist pin '%s')\n",
cluster_ctx.clb_nlist.net_name(net_id).c_str(),
diff --git a/vpr/src/base/read_route.cpp b/vpr/src/base/read_route.cpp
index 0b8231925e..3ede11a9f9 100644
--- a/vpr/src/base/read_route.cpp
+++ b/vpr/src/base/read_route.cpp
@@ -296,7 +296,7 @@ static void process_nodes(const Netlist<>& net_list, std::ifstream& fp, ClusterN
/* Verify types and ptc*/
if (tokens[2] == "SOURCE" || tokens[2] == "SINK" || tokens[2] == "OPIN" || tokens[2] == "IPIN") {
const auto& type = device_ctx.grid.get_physical_type({x, y, layer_num});
- if (tokens[4 + offset] == "Pad:" && !is_io_type(type)) {
+ if (tokens[4 + offset] == "Pad:" && !type->is_io()) {
vpr_throw(VPR_ERROR_ROUTE, filename, lineno,
"Node %d is of the wrong type", inode);
}
@@ -319,7 +319,7 @@ static void process_nodes(const Netlist<>& net_list, std::ifstream& fp, ClusterN
if (tokens[6 + offset] != "Switch:") {
/*This is an opin or ipin, process its pin nums*/
auto type = device_ctx.grid.get_physical_type({x, y, layer_num});
- if (!is_io_type(type) && (tokens[2] == "IPIN" || tokens[2] == "OPIN")) {
+ if (!type->is_io() && (tokens[2] == "IPIN" || tokens[2] == "OPIN")) {
int pin_num = rr_graph.node_pin_num(RRNodeId(inode));
int width_offset = device_ctx.grid.get_width_offset({x, y, layer_num});
int height_offset = device_ctx.grid.get_height_offset({x, y, layer_num});
@@ -592,10 +592,13 @@ void print_route(const Netlist<>& net_list,
fprintf(fp, "to (%d,%d,%d) ", rr_graph.node_xhigh(inode),
rr_graph.node_yhigh(inode), layer_num);
+ t_physical_tile_type_ptr physical_tile = device_ctx.grid.get_physical_type({ilow, jlow, layer_num});
+
switch (rr_type) {
case e_rr_type::IPIN:
case e_rr_type::OPIN:
- if (is_io_type(device_ctx.grid.get_physical_type({ilow, jlow, layer_num}))) {
+
+ if (physical_tile->is_io()) {
fprintf(fp, " Pad: ");
} else { /* IO Pad. */
fprintf(fp, " Pin: ");
@@ -609,7 +612,7 @@ void print_route(const Netlist<>& net_list,
case e_rr_type::SOURCE:
case e_rr_type::SINK:
- if (is_io_type(device_ctx.grid.get_physical_type({ilow, jlow, layer_num}))) {
+ if (physical_tile->is_io()) {
fprintf(fp, " Pad: ");
} else { /* IO Pad. */
fprintf(fp, " Class: ");
@@ -625,8 +628,7 @@ void print_route(const Netlist<>& net_list,
fprintf(fp, "%d ", rr_graph.node_ptc_num(inode));
- auto physical_tile = device_ctx.grid.get_physical_type({ilow, jlow, layer_num});
- if (!is_io_type(physical_tile) && (rr_type == e_rr_type::IPIN || rr_type == e_rr_type::OPIN)) {
+ if (!physical_tile->is_io() && (rr_type == e_rr_type::IPIN || rr_type == e_rr_type::OPIN)) {
int pin_num = rr_graph.node_pin_num(inode);
int xoffset = device_ctx.grid.get_width_offset({ilow, jlow, layer_num});
int yoffset = device_ctx.grid.get_height_offset({ilow, jlow, layer_num});
diff --git a/vpr/src/base/stats.cpp b/vpr/src/base/stats.cpp
index 109147e337..08927b500e 100644
--- a/vpr/src/base/stats.cpp
+++ b/vpr/src/base/stats.cpp
@@ -91,10 +91,7 @@ void routing_stats(const Netlist<>& net_list,
auto type = device_ctx.grid.get_physical_type({i, j, layer_num});
int width_offset = device_ctx.grid.get_width_offset({i, j, layer_num});
int height_offset = device_ctx.grid.get_height_offset({i, j, layer_num});
- if (width_offset == 0
- && height_offset == 0
- && !is_io_type(type)
- && type != device_ctx.EMPTY_PHYSICAL_TILE_TYPE) {
+ if (width_offset == 0 && height_offset == 0 && !type->is_io() && !type->is_empty()) {
if (type->area == UNDEFINED) {
area += grid_logic_tile_area * type->width * type->height;
} else {
@@ -111,7 +108,7 @@ void routing_stats(const Netlist<>& net_list,
for (ClusterBlockId blk_id : cluster_ctx.clb_nlist.blocks()) {
t_pl_loc block_loc = block_locs[blk_id].loc;
auto type = physical_tile_type(block_loc);
- if (!is_io_type(type)) {
+ if (!type->is_io()) {
if (type->area == UNDEFINED) {
used_area += grid_logic_tile_area * type->width * type->height;
} else {
@@ -473,7 +470,7 @@ void print_lambda() {
t_pl_loc block_loc = block_locs[blk_id].loc;
auto type = physical_tile_type(block_loc);
VTR_ASSERT(type != nullptr);
- if (!is_io_type(type)) {
+ if (!type->is_io()) {
for (int ipin = 0; ipin < type->num_pins; ipin++) {
if (get_pin_type_from_pin_physical_num(type, ipin) == RECEIVER) {
ClusterNetId net_id = cluster_ctx.clb_nlist.block_net(blk_id, ipin);
diff --git a/vpr/src/pack/appack_max_dist_th_manager.cpp b/vpr/src/pack/appack_max_dist_th_manager.cpp
index 9f9a39815a..c5c9b685b7 100644
--- a/vpr/src/pack/appack_max_dist_th_manager.cpp
+++ b/vpr/src/pack/appack_max_dist_th_manager.cpp
@@ -100,7 +100,7 @@ void APPackMaxDistThManager::auto_set_max_distance_thresholds(const std::vector<
// Find which type(s) this logical block type looks like.
bool has_memory = has_memory_pbs(lb_ty.pb_type);
bool is_logic_block_type = (lb_ty.index == logic_block_type->index);
- bool is_io_block = is_io_type(pick_physical_type(&lb_ty));
+ bool is_io_block = pick_physical_type(&lb_ty)->is_io();
// Update the max distance threshold based on the type. If the logical
// block type looks like many block types at the same time (for example
diff --git a/vpr/src/place/initial_placement.cpp b/vpr/src/place/initial_placement.cpp
index 3dc8650a3e..bcf6e3b709 100644
--- a/vpr/src/place/initial_placement.cpp
+++ b/vpr/src/place/initial_placement.cpp
@@ -1012,10 +1012,10 @@ static inline void fix_IO_block_types(const t_pl_macro& pl_macro,
vtr::vector_map& block_locs) {
const auto& device_ctx = g_vpr_ctx.device();
- //If the user marked the IO block pad_loc_type as RANDOM, that means it should be randomly
- //placed and then stay fixed to that location, which is why the macro members are marked as fixed.
- const auto& type = device_ctx.grid.get_physical_type({loc.x, loc.y, loc.layer});
- if (is_io_type(type) && pad_loc_type == e_pad_loc_type::RANDOM) {
+ // If the user marked the IO block pad_loc_type as RANDOM, that means it should be randomly
+ // placed and then stay fixed to that location, which is why the macro members are marked as fixed.
+ const t_physical_tile_type_ptr type = device_ctx.grid.get_physical_type({loc.x, loc.y, loc.layer});
+ if (type->is_io() && pad_loc_type == e_pad_loc_type::RANDOM) {
for (const t_pl_macro_member& pl_macro_member : pl_macro.members) {
block_locs[pl_macro_member.blk_index].is_fixed = true;
}
diff --git a/vpr/src/route/route_common.cpp b/vpr/src/route/route_common.cpp
index 43501cd04a..3f6d574b60 100644
--- a/vpr/src/route/route_common.cpp
+++ b/vpr/src/route/route_common.cpp
@@ -358,7 +358,7 @@ static t_clb_opins_used alloc_and_load_clb_opins_used_locally() {
clb_opins_used_locally[blk_id].resize((int)type->class_inf.size());
- if (is_io_type(type)) continue;
+ if (type->is_io()) continue;
const auto [pin_low, pin_high] = get_pin_range_for_block(blk_id);
diff --git a/vpr/src/route/router_lookahead_map.cpp b/vpr/src/route/router_lookahead_map.cpp
index b8782a45c5..b9dde54cd9 100644
--- a/vpr/src/route/router_lookahead_map.cpp
+++ b/vpr/src/route/router_lookahead_map.cpp
@@ -89,7 +89,7 @@ static void compute_tiles_lookahead(std::unordered_map cost
* @param physical_tile
* @param det_routing_arch
diff --git a/vpr/src/route/build_switchblocks.cpp b/vpr/src/route/rr_graph_generation/build_switchblocks.cpp
similarity index 100%
rename from vpr/src/route/build_switchblocks.cpp
rename to vpr/src/route/rr_graph_generation/build_switchblocks.cpp
diff --git a/vpr/src/route/build_switchblocks.h b/vpr/src/route/rr_graph_generation/build_switchblocks.h
similarity index 100%
rename from vpr/src/route/build_switchblocks.h
rename to vpr/src/route/rr_graph_generation/build_switchblocks.h
diff --git a/vpr/src/route/cb_metrics.cpp b/vpr/src/route/rr_graph_generation/cb_metrics.cpp
similarity index 100%
rename from vpr/src/route/cb_metrics.cpp
rename to vpr/src/route/rr_graph_generation/cb_metrics.cpp
diff --git a/vpr/src/route/cb_metrics.h b/vpr/src/route/rr_graph_generation/cb_metrics.h
similarity index 100%
rename from vpr/src/route/cb_metrics.h
rename to vpr/src/route/rr_graph_generation/cb_metrics.h
diff --git a/vpr/src/route/clock_connection_builders.cpp b/vpr/src/route/rr_graph_generation/clock_connection_builders.cpp
similarity index 100%
rename from vpr/src/route/clock_connection_builders.cpp
rename to vpr/src/route/rr_graph_generation/clock_connection_builders.cpp
diff --git a/vpr/src/route/clock_connection_builders.h b/vpr/src/route/rr_graph_generation/clock_connection_builders.h
similarity index 100%
rename from vpr/src/route/clock_connection_builders.h
rename to vpr/src/route/rr_graph_generation/clock_connection_builders.h
diff --git a/vpr/src/route/clock_fwd.h b/vpr/src/route/rr_graph_generation/clock_fwd.h
similarity index 100%
rename from vpr/src/route/clock_fwd.h
rename to vpr/src/route/rr_graph_generation/clock_fwd.h
diff --git a/vpr/src/route/clock_network_builders.cpp b/vpr/src/route/rr_graph_generation/clock_network_builders.cpp
similarity index 100%
rename from vpr/src/route/clock_network_builders.cpp
rename to vpr/src/route/rr_graph_generation/clock_network_builders.cpp
diff --git a/vpr/src/route/clock_network_builders.h b/vpr/src/route/rr_graph_generation/clock_network_builders.h
similarity index 100%
rename from vpr/src/route/clock_network_builders.h
rename to vpr/src/route/rr_graph_generation/clock_network_builders.h
diff --git a/vpr/src/route/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp
similarity index 99%
rename from vpr/src/route/rr_graph.cpp
rename to vpr/src/route/rr_graph_generation/rr_graph.cpp
index 3f77949d96..b993ed7ded 100644
--- a/vpr/src/route/rr_graph.cpp
+++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp
@@ -33,6 +33,7 @@
#include "edge_groups.h"
#include "rr_graph_builder.h"
#include "rr_types.h"
+#include "rr_node_indices.h"
//#define VERBOSE
//used for getting the exact count of each edge type and printing it to std out.
diff --git a/vpr/src/route/rr_graph.h b/vpr/src/route/rr_graph_generation/rr_graph.h
similarity index 100%
rename from vpr/src/route/rr_graph.h
rename to vpr/src/route/rr_graph_generation/rr_graph.h
diff --git a/vpr/src/route/rr_graph2.cpp b/vpr/src/route/rr_graph_generation/rr_graph2.cpp
similarity index 77%
rename from vpr/src/route/rr_graph2.cpp
rename to vpr/src/route/rr_graph_generation/rr_graph2.cpp
index acb094fa8d..0295a8cca3 100644
--- a/vpr/src/route/rr_graph2.cpp
+++ b/vpr/src/route/rr_graph_generation/rr_graph2.cpp
@@ -1,6 +1,5 @@
#include
-#include "describe_rr_node.h"
#include "physical_types_util.h"
#include "vpr_utils.h"
#include "vtr_util.h"
@@ -25,52 +24,8 @@ static void get_switch_type(bool is_from_sb,
const int switch_override,
short switch_types[2]);
-static void load_chan_rr_indices(const int max_chan_width,
- const DeviceGrid& grid,
- const int chan_len,
- const int num_chans,
- const e_rr_type type,
- const t_chan_details& chan_details,
- RRGraphBuilder& rr_graph_builder,
- int* index);
-
-/**
- * @brief Assigns and loads rr_node indices for block-level routing resources (SOURCE, SINK, IPIN, OPIN).
- *
- * This function walks through the device grid and assigns unique rr_node indices to the routing resources
- * associated with each block (tiles).
- *
- * For SINKs and SOURCEs, it uses side 0 by convention (since they have no geometric side). For IPINs and OPINs,
- * it determines the correct sides based on the tile's position in the grid, following special rules for
- * edge and corner tiles.
- *
- * The index counter is passed and updated as rr_nodes are added.
- */
-static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder,
- const DeviceGrid& grid,
- int* index);
-
-static void add_pins_spatial_lookup(RRGraphBuilder& rr_graph_builder,
- t_physical_tile_type_ptr physical_type_ptr,
- const std::vector& pin_num_vec,
- int layer,
- int root_x,
- int root_y,
- int* index,
- const std::vector& wanted_sides);
-
-static void add_classes_spatial_lookup(RRGraphBuilder& rr_graph_builder,
- t_physical_tile_type_ptr physical_type_ptr,
- const std::vector& class_num_vec,
- int layer,
- int x,
- int y,
- int block_width,
- int block_height,
- int* index);
-
static int get_bidir_track_to_chan_seg(RRGraphBuilder& rr_graph_builder,
- const std::vector conn_tracks,
+ const std::vector& conn_tracks,
const int layer,
const int to_chan,
const int to_seg,
@@ -1092,57 +1047,6 @@ void dump_track_to_pin_map(t_track_to_pin_lookup& track_to_pin_map,
}
}
-static void load_chan_rr_indices(const int max_chan_width,
- const DeviceGrid& grid,
- const int chan_len,
- const int num_chans,
- const e_rr_type type,
- const t_chan_details& chan_details,
- RRGraphBuilder& rr_graph_builder,
- int* index) {
- const auto& device_ctx = g_vpr_ctx.device();
-
- for (int layer = 0; layer < grid.get_num_layers(); layer++) {
- // Skip the current die if architecture file specifies that it doesn't require global resource routing
- if (!device_ctx.inter_cluster_prog_routing_resources.at(layer)) {
- continue;
- }
-
- for (int chan = 0; chan < num_chans - 1; ++chan) {
- for (int seg = 1; seg < chan_len - 1; ++seg) {
- // Assign an inode to the starts of tracks
- const int x = (type == e_rr_type::CHANX) ? seg : chan;
- const int y = (type == e_rr_type::CHANX) ? chan : seg;
- const t_chan_seg_details* seg_details = chan_details[x][y].data();
-
- // Reserve nodes in lookup to save memory
- rr_graph_builder.node_lookup().reserve_nodes(layer, x, y, type, max_chan_width);
-
- for (int track = 0; track < max_chan_width; ++track) {
- /* TODO: May let the length() == 0 case go through, to model muxes */
- if (seg_details[track].length() <= 0)
- continue;
-
- int start = get_seg_start(seg_details, track, chan, seg);
- int node_start_x = (type == e_rr_type::CHANX) ? start : chan;
- int node_start_y = (type == e_rr_type::CHANX) ? chan : start;
-
- // If the start of the wire doesn't have an RRNodeId, assign one to it.
- RRNodeId inode = rr_graph_builder.node_lookup().find_node(layer, node_start_x, node_start_y, type, track);
- if (!inode) {
- inode = RRNodeId(*index);
- ++(*index);
- rr_graph_builder.node_lookup().add_node(inode, layer, node_start_x, node_start_y, type, track);
- }
-
- // Assign RRNodeId of start of wire to current position
- rr_graph_builder.node_lookup().add_node(inode, layer, x, y, type, track);
- }
- }
- }
- }
-}
-
static bool is_sb_conn_layer_crossing(enum e_side src_side, enum e_side dest_side) {
if (src_side < NUM_2D_SIDES && dest_side < NUM_2D_SIDES) {
return false;
@@ -1213,471 +1117,6 @@ vtr::NdMatrix get_number_track_to_track_inter_die_conn(t_sb_connection_m
return extra_nodes_per_switchblocks;
}
-void alloc_and_load_inter_die_rr_node_indices(RRGraphBuilder& rr_graph_builder,
- const t_chan_width& nodes_per_chan,
- const DeviceGrid& grid,
- const vtr::NdMatrix& extra_nodes_per_switchblock,
- int* index) {
- /*
- * In case of multi-die FPGAs, we add extra nodes (could have used either CHANX or CHANY; we chose to use all CHANX) to
- * support inter-die communication coming from switch blocks (connection between two tracks in different layers)
- * The extra nodes have the following attribute:
- * 1) type = CHANX
- * 2) length = 0 (xhigh = xlow, yhigh = ylow)
- * 3) ptc = [max_chanx_width:max_chanx_width+number_of_connection-1]
- * 4) direction = NONE
- */
- const auto& device_ctx = g_vpr_ctx.device();
-
- for (int layer = 0; layer < grid.get_num_layers(); layer++) {
- /* Skip the current die if architecture file specifies that it doesn't have global resource routing */
- if (!device_ctx.inter_cluster_prog_routing_resources.at(layer)) {
- continue;
- }
-
- for (size_t y = 0; y < grid.height() - 1; ++y) {
- for (size_t x = 1; x < grid.width() - 1; ++x) {
- // count how many track-to-track connection go from current layer to other layers
- int conn_count = extra_nodes_per_switchblock[x][y];
-
- // skip if no connection is required
- if (conn_count == 0) {
- continue;
- }
-
- // reserve extra nodes for inter-die track-to-track connection
- rr_graph_builder.node_lookup().reserve_nodes(layer, x, y, e_rr_type::CHANX, conn_count + nodes_per_chan.max);
- for (int rr_node_offset = 0; rr_node_offset < conn_count; rr_node_offset++) {
- RRNodeId inode = rr_graph_builder.node_lookup().find_node(layer, x, y, e_rr_type::CHANX, nodes_per_chan.max + rr_node_offset);
- if (!inode) {
- inode = RRNodeId(*index);
- ++(*index);
- rr_graph_builder.node_lookup().add_node(inode, layer, x, y, e_rr_type::CHANX, nodes_per_chan.max + rr_node_offset);
- }
- }
- }
- }
- }
-}
-
-/* As the rr_indices builders modify a local copy of indices, use the local copy in the builder
- * TODO: these building functions should only talk to a RRGraphBuilder object
- */
-static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder,
- const DeviceGrid& grid,
- int* index) {
- //Walk through the grid assigning indices to SOURCE/SINK IPIN/OPIN
- for (int layer = 0; layer < grid.get_num_layers(); layer++) {
- for (int x = 0; x < (int)grid.width(); x++) {
- for (int y = 0; y < (int)grid.height(); y++) {
- //Process each block from its root location
- if (grid.is_root_location({x, y, layer})) {
- t_physical_tile_type_ptr physical_type = grid.get_physical_type({x, y, layer});
-
- //Assign indices for SINKs and SOURCEs
- // Note that SINKS/SOURCES have no side, so we always use side 0
- std::vector class_num_vec = get_tile_root_classes(physical_type);
- std::vector pin_num_vec = get_tile_root_pins(physical_type);
-
- add_classes_spatial_lookup(rr_graph_builder,
- physical_type,
- class_num_vec,
- layer,
- x,
- y,
- physical_type->width,
- physical_type->height,
- index);
-
- /* Limited sides for grids
- * The wanted side depends on the location of the grid.
- * In particular for perimeter grid,
- * -------------------------------------------------------
- * Grid location | IPIN side
- * -------------------------------------------------------
- * TOP | BOTTOM
- * -------------------------------------------------------
- * RIGHT | LEFT
- * -------------------------------------------------------
- * BOTTOM | TOP
- * -------------------------------------------------------
- * LEFT | RIGHT
- * -------------------------------------------------------
- * TOP-LEFT | BOTTOM & RIGHT
- * -------------------------------------------------------
- * TOP-RIGHT | BOTTOM & LEFT
- * -------------------------------------------------------
- * BOTTOM-LEFT | TOP & RIGHT
- * -------------------------------------------------------
- * BOTTOM-RIGHT | TOP & LEFT
- * -------------------------------------------------------
- * Other | First come first fit
- * -------------------------------------------------------
- *
- * Special for IPINs:
- * If there are multiple wanted sides, first come first fit is applied
- * This guarantee that there is only a unique rr_node
- * for the same input pin on multiple sides, and thus avoid multiple driver problems
- */
- std::vector wanted_sides;
- if ((int)grid.height() - 1 == y) { /* TOP side */
- wanted_sides.push_back(BOTTOM);
- }
- if ((int)grid.width() - 1 == x) { /* RIGHT side */
- wanted_sides.push_back(LEFT);
- }
- if (0 == y) { /* BOTTOM side */
- wanted_sides.push_back(TOP);
- }
- if (0 == x) { /* LEFT side */
- wanted_sides.push_back(RIGHT);
- }
-
- /* If wanted sides is empty still, this block does not have specific wanted sides,
- * Deposit all the sides
- */
- if (wanted_sides.empty()) {
- for (e_side side : TOTAL_2D_SIDES) {
- wanted_sides.push_back(side);
- }
- }
-
- add_pins_spatial_lookup(rr_graph_builder,
- physical_type,
- pin_num_vec,
- layer,
- x,
- y,
- index,
- wanted_sides);
- }
- }
- }
- }
-}
-
-static void add_pins_spatial_lookup(RRGraphBuilder& rr_graph_builder,
- t_physical_tile_type_ptr physical_type_ptr,
- const std::vector& pin_num_vec,
- int layer,
- int root_x,
- int root_y,
- int* index,
- const std::vector& wanted_sides) {
- for (e_side side : wanted_sides) {
- for (int width_offset = 0; width_offset < physical_type_ptr->width; ++width_offset) {
- int x_tile = root_x + width_offset;
- for (int height_offset = 0; height_offset < physical_type_ptr->height; ++height_offset) {
- int y_tile = root_y + height_offset;
- //only nodes on the tile may be located in a location other than the root-location
- rr_graph_builder.node_lookup().reserve_nodes(layer, x_tile, y_tile, e_rr_type::OPIN, physical_type_ptr->num_pins, side);
- rr_graph_builder.node_lookup().reserve_nodes(layer, x_tile, y_tile, e_rr_type::IPIN, physical_type_ptr->num_pins, side);
- }
- }
- }
-
- for (const int pin_num : pin_num_vec) {
- bool assigned_to_rr_node = false;
- const auto [x_offset, y_offset, pin_sides] = get_pin_coordinates(physical_type_ptr, pin_num, wanted_sides);
- e_pin_type pin_type = get_pin_type_from_pin_physical_num(physical_type_ptr, pin_num);
- for (int pin_coord_idx = 0; pin_coord_idx < (int)pin_sides.size(); pin_coord_idx++) {
- int x_tile = root_x + x_offset[pin_coord_idx];
- int y_tile = root_y + y_offset[pin_coord_idx];
- e_side side = pin_sides[pin_coord_idx];
- if (pin_type == DRIVER) {
- rr_graph_builder.node_lookup().add_node(RRNodeId(*index), layer, x_tile, y_tile, e_rr_type::OPIN, pin_num, side);
- assigned_to_rr_node = true;
- } else {
- VTR_ASSERT(pin_type == RECEIVER);
- rr_graph_builder.node_lookup().add_node(RRNodeId(*index), layer, x_tile, y_tile, e_rr_type::IPIN, pin_num, side);
- assigned_to_rr_node = true;
- }
- }
- /* A pin may locate on multiple sides of a tile.
- * Instead of allocating multiple rr_nodes for the pin,
- * we just create a rr_node and make it indexable on these sides
- * As such, we can avoid redundant rr_node to be allocated
- * and multiple nets to be mapped to the pin
- *
- * Considering that some pin could be just dangling, we do not need
- * to create a void rr_node for it.
- * As such, we only allocate a rr node when the pin is indeed located
- * on at least one side
- */
- if (assigned_to_rr_node) {
- ++(*index);
- }
- }
-}
-
-static void add_classes_spatial_lookup(RRGraphBuilder& rr_graph_builder,
- t_physical_tile_type_ptr physical_type_ptr,
- const std::vector& class_num_vec,
- int layer,
- int root_x,
- int root_y,
- int block_width,
- int block_height,
- int* index) {
- for (int x_tile = root_x; x_tile < (root_x + block_width); x_tile++) {
- for (int y_tile = root_y; y_tile < (root_y + block_height); y_tile++) {
- rr_graph_builder.node_lookup().reserve_nodes(layer, x_tile, y_tile, e_rr_type::SOURCE, class_num_vec.size(), TOTAL_2D_SIDES[0]);
- rr_graph_builder.node_lookup().reserve_nodes(layer, x_tile, y_tile, e_rr_type::SINK, class_num_vec.size(), TOTAL_2D_SIDES[0]);
- }
- }
-
- for (const int class_num : class_num_vec) {
- e_pin_type class_type = get_class_type_from_class_physical_num(physical_type_ptr, class_num);
- e_rr_type node_type = e_rr_type::SINK;
- if (class_type == DRIVER) {
- node_type = e_rr_type::SOURCE;
- } else {
- VTR_ASSERT(class_type == RECEIVER);
- }
-
- for (int x_offset = 0; x_offset < block_width; x_offset++) {
- for (int y_offset = 0; y_offset < block_height; y_offset++) {
- int curr_x = root_x + x_offset;
- int curr_y = root_y + y_offset;
-
- rr_graph_builder.node_lookup().add_node(RRNodeId(*index), layer, curr_x, curr_y, node_type, class_num);
- }
- }
-
- ++(*index);
- }
-}
-
-void alloc_and_load_rr_node_indices(RRGraphBuilder& rr_graph_builder,
- const t_chan_width& nodes_per_chan,
- const DeviceGrid& grid,
- int* index,
- const t_chan_details& chan_details_x,
- const t_chan_details& chan_details_y) {
- /* Alloc the lookup table */
- for (e_rr_type rr_type : RR_TYPES) {
- rr_graph_builder.node_lookup().resize_nodes(grid.get_num_layers(), grid.width(), grid.height(), rr_type, NUM_2D_SIDES);
- }
-
- /* Assign indices for block nodes */
- load_block_rr_indices(rr_graph_builder, grid, index);
-
- /* Load the data for x and y channels */
- load_chan_rr_indices(nodes_per_chan.x_max, grid, grid.width(), grid.height(),
- e_rr_type::CHANX, chan_details_x, rr_graph_builder, index);
- load_chan_rr_indices(nodes_per_chan.y_max, grid, grid.height(), grid.width(),
- e_rr_type::CHANY, chan_details_y, rr_graph_builder, index);
-}
-
-void alloc_and_load_intra_cluster_rr_node_indices(RRGraphBuilder& rr_graph_builder,
- const DeviceGrid& grid,
- const vtr::vector& pin_chains,
- const vtr::vector>& pin_chains_num,
- int* index) {
- for (int layer = 0; layer < grid.get_num_layers(); layer++) {
- for (int x = 0; x < (int)grid.width(); x++) {
- for (int y = 0; y < (int)grid.height(); y++) {
- //Process each block from its root location
- if (grid.is_root_location({x, y, layer})) {
- t_physical_tile_type_ptr physical_type = grid.get_physical_type({x, y, layer});
- //Assign indices for SINKs and SOURCEs
- // Note that SINKS/SOURCES have no side, so we always use side 0
- std::vector class_num_vec;
- std::vector pin_num_vec;
- class_num_vec = get_cluster_netlist_intra_tile_classes_at_loc(layer, x, y, physical_type);
- pin_num_vec = get_cluster_netlist_intra_tile_pins_at_loc(layer,
- x,
- y,
- pin_chains,
- pin_chains_num,
- physical_type);
- add_classes_spatial_lookup(rr_graph_builder,
- physical_type,
- class_num_vec,
- layer,
- x,
- y,
- physical_type->width,
- physical_type->height,
- index);
-
- std::vector wanted_sides;
- wanted_sides.push_back(e_side::TOP);
- add_pins_spatial_lookup(rr_graph_builder,
- physical_type,
- pin_num_vec,
- layer,
- x,
- y,
- index,
- wanted_sides);
- }
- }
- }
- }
-}
-
-bool verify_rr_node_indices(const DeviceGrid& grid,
- const RRGraphView& rr_graph,
- const vtr::vector& rr_indexed_data,
- const t_rr_graph_storage& rr_nodes,
- bool is_flat) {
- std::unordered_map rr_node_counts;
-
- int width = grid.width();
- int height = grid.height();
- int layer = grid.get_num_layers();
-
- for (int l = 0; l < layer; ++l) {
- for (int x = 0; x < width; ++x) {
- for (int y = 0; y < height; ++y) {
- for (e_rr_type rr_type : RR_TYPES) {
- /* Get the list of nodes at a specific location (x, y) */
- std::vector nodes_from_lookup;
- if (rr_type == e_rr_type::CHANX || rr_type == e_rr_type::CHANY) {
- nodes_from_lookup = rr_graph.node_lookup().find_channel_nodes(l, x, y, rr_type);
- } else {
- nodes_from_lookup = rr_graph.node_lookup().find_grid_nodes_at_all_sides(l, x, y, rr_type);
- }
-
- for (RRNodeId inode : nodes_from_lookup) {
- rr_node_counts[inode]++;
-
- if (rr_graph.node_type(inode) != rr_type) {
- VPR_ERROR(VPR_ERROR_ROUTE, "RR node type does not match between rr_nodes and rr_node_indices (%s/%s): %s",
- rr_node_typename[rr_graph.node_type(inode)],
- rr_node_typename[rr_type],
- describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str());
- }
-
- if (rr_graph.node_type(inode) == e_rr_type::CHANX) {
- VTR_ASSERT_MSG(rr_graph.node_ylow(inode) == rr_graph.node_yhigh(inode), "CHANX should be horizontal");
- if (y != rr_graph.node_ylow(inode)) {
- VPR_ERROR(VPR_ERROR_ROUTE, "RR node y position does not agree between rr_nodes (%d) and rr_node_indices (%d): %s",
- rr_graph.node_ylow(inode),
- y,
- describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str());
- }
-
- if (!rr_graph.x_in_node_range(x, inode)) {
- VPR_ERROR(VPR_ERROR_ROUTE, "RR node x positions do not agree between rr_nodes (%d <-> %d) and rr_node_indices (%d): %s",
- rr_graph.node_xlow(inode),
- rr_graph.node_xlow(inode),
- x,
- describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str());
- }
- } else if (rr_graph.node_type(inode) == e_rr_type::CHANY) {
- VTR_ASSERT_MSG(rr_graph.node_xlow(inode) == rr_graph.node_xhigh(inode), "CHANY should be vertical");
-
- if (x != rr_graph.node_xlow(inode)) {
- VPR_ERROR(VPR_ERROR_ROUTE, "RR node x position does not agree between rr_nodes (%d) and rr_node_indices (%d): %s",
- rr_graph.node_xlow(inode),
- x,
- describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str());
- }
-
- if (!rr_graph.y_in_node_range(y, inode)) {
- VPR_ERROR(VPR_ERROR_ROUTE, "RR node y positions do not agree between rr_nodes (%d <-> %d) and rr_node_indices (%d): %s",
- rr_graph.node_ylow(inode),
- rr_graph.node_ylow(inode),
- y,
- describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str());
- }
- } else if (rr_graph.node_type(inode) == e_rr_type::SOURCE || rr_graph.node_type(inode) == e_rr_type::SINK) {
- // Sources have co-ordinates covering the entire block they are in, but not sinks
- if (!rr_graph.x_in_node_range(x, inode)) {
- VPR_ERROR(VPR_ERROR_ROUTE, "RR node x positions do not agree between rr_nodes (%d <-> %d) and rr_node_indices (%d): %s",
- rr_graph.node_xlow(inode),
- rr_graph.node_xlow(inode),
- x,
- describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str());
- }
-
- if (!rr_graph.y_in_node_range(y, inode)) {
- VPR_ERROR(VPR_ERROR_ROUTE, "RR node y positions do not agree between rr_nodes (%d <-> %d) and rr_node_indices (%d): %s",
- rr_graph.node_ylow(inode),
- rr_graph.node_ylow(inode),
- y,
- describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str());
- }
- } else {
- VTR_ASSERT(rr_graph.node_type(inode) == e_rr_type::IPIN || rr_graph.node_type(inode) == e_rr_type::OPIN);
- /* As we allow a pin to be indexable on multiple sides,
- * This check code should be invalid
- * if (rr_node.xlow() != x) {
- * VPR_ERROR(VPR_ERROR_ROUTE, "RR node xlow does not match between rr_nodes and rr_node_indices (%d/%d): %s",
- * rr_node.xlow(),
- * x,
- * describe_rr_node(rr_graph, grid, rr_indexed_data, inode).c_str());
- * }
- *
- * if (rr_node.ylow() != y) {
- * VPR_ERROR(VPR_ERROR_ROUTE, "RR node ylow does not match between rr_nodes and rr_node_indices (%d/%d): %s",
- * rr_node.ylow(),
- * y,
- * describe_rr_node(rr_graph, grid, rr_indexed_data, inode).c_str());
- * }
- */
- }
-
- if (rr_type == e_rr_type::IPIN || rr_type == e_rr_type::OPIN) {
- /* As we allow a pin to be indexable on multiple sides,
- * This check code should be invalid
- * if (rr_node.side() != side) {
- * VPR_ERROR(VPR_ERROR_ROUTE, "RR node xlow does not match between rr_nodes and rr_node_indices (%s/%s): %s",
- * TOTAL_2D_SIDE_STRINGS[rr_node.side()],
- * TOTAL_2D_SIDE_STRINGS[side],
- * describe_rr_node(rr_graph, grid, rr_indexed_data, inode).c_str());
- * } else {
- * VTR_ASSERT(rr_node.side() == side);
- * }
- */
- }
- }
- }
- }
- }
- }
-
- if (rr_node_counts.size() != rr_nodes.size()) {
- VPR_ERROR(VPR_ERROR_ROUTE, "Mismatch in number of unique RR nodes in rr_nodes (%zu) and rr_node_indices (%zu)",
- rr_nodes.size(),
- rr_node_counts.size());
- }
-
- for (auto kv : rr_node_counts) {
- RRNodeId inode = kv.first;
- int count = kv.second;
-
- auto& rr_node = rr_nodes[size_t(inode)];
-
- if (rr_graph.node_type(inode) == e_rr_type::SOURCE || rr_graph.node_type(inode) == e_rr_type::SINK) {
- int rr_width = (rr_graph.node_xhigh(rr_node.id()) - rr_graph.node_xlow(rr_node.id()) + 1);
- int rr_height = (rr_graph.node_yhigh(rr_node.id()) - rr_graph.node_ylow(rr_node.id()) + 1);
- int rr_area = rr_width * rr_height;
- if (count != rr_area) {
- VPR_ERROR(VPR_ERROR_ROUTE, "Mismatch between RR node size (%d) and count within rr_node_indices (%d): %s",
- rr_area,
- rr_node.length(),
- count,
- describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str());
- }
- /* As we allow a pin to be indexable on multiple sides,
- * This check code should not be applied to input and output pins
- */
- } else if ((e_rr_type::OPIN != rr_graph.node_type(inode)) && (e_rr_type::IPIN != rr_graph.node_type(inode))) {
- if (count != rr_node.length() + 1) {
- VPR_ERROR(VPR_ERROR_ROUTE, "Mismatch between RR node length (%d) and count within rr_node_indices (%d, should be length + 1): %s",
- rr_node.length(),
- count,
- describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str());
- }
- }
- }
-
- return true;
-}
-
int get_track_to_pins(RRGraphBuilder& rr_graph_builder,
int layer,
int seg,
@@ -2008,41 +1447,8 @@ int get_track_to_tracks(RRGraphBuilder& rr_graph_builder,
return num_conn;
}
-void alloc_and_load_tile_rr_node_indices(RRGraphBuilder& rr_graph_builder,
- t_physical_tile_type_ptr physical_tile,
- int layer,
- int x,
- int y,
- int* num_rr_nodes) {
- std::vector wanted_sides{TOP, BOTTOM, LEFT, RIGHT};
- auto class_num_range = get_flat_tile_primitive_classes(physical_tile);
- auto pin_num_vec = get_flat_tile_pins(physical_tile);
-
- std::vector class_num_vec(class_num_range.total_num());
- std::iota(class_num_vec.begin(), class_num_vec.end(), class_num_range.low);
-
- add_classes_spatial_lookup(rr_graph_builder,
- physical_tile,
- class_num_vec,
- layer,
- x,
- y,
- physical_tile->width,
- physical_tile->height,
- num_rr_nodes);
-
- add_pins_spatial_lookup(rr_graph_builder,
- physical_tile,
- pin_num_vec,
- layer,
- x,
- y,
- num_rr_nodes,
- wanted_sides);
-}
-
static int get_bidir_track_to_chan_seg(RRGraphBuilder& rr_graph_builder,
- const std::vector conn_tracks,
+ const std::vector& conn_tracks,
const int layer,
const int to_chan,
const int to_seg,
diff --git a/vpr/src/route/rr_graph2.h b/vpr/src/route/rr_graph_generation/rr_graph2.h
similarity index 75%
rename from vpr/src/route/rr_graph2.h
rename to vpr/src/route/rr_graph_generation/rr_graph2.h
index 05e723470e..c4b2456999 100644
--- a/vpr/src/route/rr_graph2.h
+++ b/vpr/src/route/rr_graph_generation/rr_graph2.h
@@ -14,62 +14,6 @@
/******************* Subroutines exported by rr_graph2.c *********************/
-/**
- * @brief Allocates and populates data structures for efficient rr_node index lookups.
- *
- * This function sets up the `rr_node_indices` structure, which maps a physical location
- * and type to the index of the first corresponding rr_node.
- */
-void alloc_and_load_rr_node_indices(RRGraphBuilder& rr_graph_builder,
- const t_chan_width& nodes_per_chan,
- const DeviceGrid& grid,
- int* index,
- const t_chan_details& chan_details_x,
- const t_chan_details& chan_details_y);
-
-/**
- * @brief Allocates extra nodes within the RR graph to support 3D custom switch blocks for multi-die FPGAs
- *
- * @param rr_graph_builder RRGraphBuilder data structure which allows data modification on a routing resource graph
- * @param nodes_per_chan number of tracks per channel (x, y)
- * @param grid device grid
- * @param extra_nodes_per_switchblock keeps how many extra length-0 CHANX node is required for each unique (x,y) location within the grid.
- * Number of these extra nodes are exactly the same for all layers. Hence, we only keep it for one layer. ([0..grid.width-1][0..grid.height-1)
- * @param index RRNodeId that should be assigned to add a new RR node to the RR graph
- */
-void alloc_and_load_inter_die_rr_node_indices(RRGraphBuilder& rr_graph_builder,
- const t_chan_width& nodes_per_chan,
- const DeviceGrid& grid,
- const vtr::NdMatrix& extra_nodes_per_switchblock,
- int* index);
-
-void alloc_and_load_tile_rr_node_indices(RRGraphBuilder& rr_graph_builder,
- t_physical_tile_type_ptr physical_tile,
- int layer,
- int x,
- int y,
- int* num_rr_nodes);
-
-void alloc_and_load_intra_cluster_rr_node_indices(RRGraphBuilder& rr_graph_builder,
- const DeviceGrid& grid,
- const vtr::vector& pin_chains,
- const vtr::vector>& pin_chains_num,
- int* index);
-
-/**
- * Validate the node look-up matches all the node-level information
- * in the storage of a routing resource graph
- * This function will check the following aspects:
- * - The type of each node matches its type that is indexed in the node look-up
- * - For bounding box (xlow, ylow, xhigh, yhigh) of each node is indexable in the node look-up
- * - The number of unique indexable nodes in the node look up matches the number of nodes in the storage
- * This ensures that every node in the storage is indexable and there are no hidden nodes in the look-up
- */
-bool verify_rr_node_indices(const DeviceGrid& grid,
- const RRGraphView& rr_graph,
- const vtr::vector& rr_indexed_data,
- const t_rr_graph_storage& rr_nodes,
- bool is_flat);
/**
* @brief goes through 3D custom switch blocks and counts how many connections are crossing dice for each switch block.
*
diff --git a/vpr/src/route/rr_graph_area.cpp b/vpr/src/route/rr_graph_generation/rr_graph_area.cpp
similarity index 100%
rename from vpr/src/route/rr_graph_area.cpp
rename to vpr/src/route/rr_graph_generation/rr_graph_area.cpp
diff --git a/vpr/src/route/rr_graph_area.h b/vpr/src/route/rr_graph_generation/rr_graph_area.h
similarity index 100%
rename from vpr/src/route/rr_graph_area.h
rename to vpr/src/route/rr_graph_generation/rr_graph_area.h
diff --git a/vpr/src/route/rr_graph_clock.cpp b/vpr/src/route/rr_graph_generation/rr_graph_clock.cpp
similarity index 100%
rename from vpr/src/route/rr_graph_clock.cpp
rename to vpr/src/route/rr_graph_generation/rr_graph_clock.cpp
diff --git a/vpr/src/route/rr_graph_clock.h b/vpr/src/route/rr_graph_generation/rr_graph_clock.h
similarity index 100%
rename from vpr/src/route/rr_graph_clock.h
rename to vpr/src/route/rr_graph_generation/rr_graph_clock.h
diff --git a/vpr/src/route/rr_graph_indexed_data.cpp b/vpr/src/route/rr_graph_generation/rr_graph_indexed_data.cpp
similarity index 100%
rename from vpr/src/route/rr_graph_indexed_data.cpp
rename to vpr/src/route/rr_graph_generation/rr_graph_indexed_data.cpp
diff --git a/vpr/src/route/rr_graph_indexed_data.h b/vpr/src/route/rr_graph_generation/rr_graph_indexed_data.h
similarity index 100%
rename from vpr/src/route/rr_graph_indexed_data.h
rename to vpr/src/route/rr_graph_generation/rr_graph_indexed_data.h
diff --git a/vpr/src/route/rr_graph_sbox.cpp b/vpr/src/route/rr_graph_generation/rr_graph_sbox.cpp
similarity index 100%
rename from vpr/src/route/rr_graph_sbox.cpp
rename to vpr/src/route/rr_graph_generation/rr_graph_sbox.cpp
diff --git a/vpr/src/route/rr_graph_sbox.h b/vpr/src/route/rr_graph_generation/rr_graph_sbox.h
similarity index 100%
rename from vpr/src/route/rr_graph_sbox.h
rename to vpr/src/route/rr_graph_generation/rr_graph_sbox.h
diff --git a/vpr/src/route/rr_graph_timing_params.cpp b/vpr/src/route/rr_graph_generation/rr_graph_timing_params.cpp
similarity index 100%
rename from vpr/src/route/rr_graph_timing_params.cpp
rename to vpr/src/route/rr_graph_generation/rr_graph_timing_params.cpp
diff --git a/vpr/src/route/rr_graph_timing_params.h b/vpr/src/route/rr_graph_generation/rr_graph_timing_params.h
similarity index 100%
rename from vpr/src/route/rr_graph_timing_params.h
rename to vpr/src/route/rr_graph_generation/rr_graph_timing_params.h
diff --git a/vpr/src/route/rr_graph_generation/rr_node_indices.cpp b/vpr/src/route/rr_graph_generation/rr_node_indices.cpp
new file mode 100644
index 0000000000..99c1a729e6
--- /dev/null
+++ b/vpr/src/route/rr_graph_generation/rr_node_indices.cpp
@@ -0,0 +1,613 @@
+
+#include "rr_node_indices.h"
+
+#include "describe_rr_node.h"
+#include "globals.h"
+#include "physical_types_util.h"
+#include "vpr_utils.h"
+
+/**
+ * @brief Assigns and loads rr_node indices for block-level routing resources (SOURCE, SINK, IPIN, OPIN).
+ *
+ * This function walks through the device grid and assigns unique rr_node indices to the routing resources
+ * associated with each block (tiles).
+ *
+ * For SINKs and SOURCEs, it uses side 0 by convention (since they have no geometric side). For IPINs and OPINs,
+ * it determines the correct sides based on the tile's position in the grid, following special rules for
+ * edge and corner tiles.
+ *
+ * The index counter is passed and updated as rr_nodes are added.
+ */
+static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder,
+ const DeviceGrid& grid,
+ int* index);
+
+/**
+ * @brief Populates the lookup indices for channel (CHANX or CHANY) RR nodes.
+ *
+ * This function builds part of the RR spatial lookup structure, specifically
+ * the RR nodes associated with routing channels (CHANX or CHANY).
+ *
+ * @param max_chan_width Maximum channel width (number of tracks).
+ * @param grid Device grid layout.
+ * @param chan_len Length of the channel being processed.
+ * @param num_chans Total number of channels in the direction being processed.
+ * @param type RR node type: should be CHANX or CHANY.
+ * @param chan_details Channel details used to determine segment and track information.
+ * @param node_lookup Spatial RR node lookup to be filled by this function.
+ * @param index The next available RR node index.
+ */
+static void load_chan_rr_indices(const int max_chan_width,
+ const DeviceGrid& grid,
+ const int chan_len,
+ const int num_chans,
+ const e_rr_type type,
+ const t_chan_details& chan_details,
+ RRSpatialLookup& node_lookup,
+ int* index);
+
+static void add_classes_spatial_lookup(RRGraphBuilder& rr_graph_builder,
+ t_physical_tile_type_ptr physical_type_ptr,
+ const std::vector& class_num_vec,
+ int layer,
+ int x,
+ int y,
+ int block_width,
+ int block_height,
+ int* index);
+
+static void add_pins_spatial_lookup(RRGraphBuilder& rr_graph_builder,
+ t_physical_tile_type_ptr physical_type_ptr,
+ const std::vector& pin_num_vec,
+ int layer,
+ int root_x,
+ int root_y,
+ int* index,
+ const std::vector& wanted_sides);
+
+/* As the rr_indices builders modify a local copy of indices, use the local copy in the builder
+ * TODO: these building functions should only talk to a RRGraphBuilder object
+ */
+static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder,
+ const DeviceGrid& grid,
+ int* index) {
+ // Walk through the grid assigning indices to SOURCE/SINK IPIN/OPIN
+ for (int layer = 0; layer < grid.get_num_layers(); layer++) {
+ for (int x = 0; x < (int)grid.width(); x++) {
+ for (int y = 0; y < (int)grid.height(); y++) {
+ //Process each block from its root location
+ if (grid.is_root_location({x, y, layer})) {
+ t_physical_tile_type_ptr physical_type = grid.get_physical_type({x, y, layer});
+
+ // Assign indices for SINKs and SOURCEs
+ // Note that SINKS/SOURCES have no side, so we always use side 0
+ std::vector class_num_vec = get_tile_root_classes(physical_type);
+ std::vector pin_num_vec = get_tile_root_pins(physical_type);
+
+ add_classes_spatial_lookup(rr_graph_builder,
+ physical_type,
+ class_num_vec,
+ layer,
+ x,
+ y,
+ physical_type->width,
+ physical_type->height,
+ index);
+
+ /* Limited sides for grids
+ * The wanted side depends on the location of the grid.
+ * In particular for perimeter grid,
+ * -------------------------------------------------------
+ * Grid location | IPIN side
+ * -------------------------------------------------------
+ * TOP | BOTTOM
+ * -------------------------------------------------------
+ * RIGHT | LEFT
+ * -------------------------------------------------------
+ * BOTTOM | TOP
+ * -------------------------------------------------------
+ * LEFT | RIGHT
+ * -------------------------------------------------------
+ * TOP-LEFT | BOTTOM & RIGHT
+ * -------------------------------------------------------
+ * TOP-RIGHT | BOTTOM & LEFT
+ * -------------------------------------------------------
+ * BOTTOM-LEFT | TOP & RIGHT
+ * -------------------------------------------------------
+ * BOTTOM-RIGHT | TOP & LEFT
+ * -------------------------------------------------------
+ * Other | First come first fit
+ * -------------------------------------------------------
+ *
+ * Special for IPINs:
+ * If there are multiple wanted sides, first come first fit is applied
+ * This guarantee that there is only a unique rr_node
+ * for the same input pin on multiple sides, and thus avoid multiple driver problems
+ */
+ std::vector wanted_sides;
+ if ((int)grid.height() - 1 == y) { // TOP side
+ wanted_sides.push_back(BOTTOM);
+ }
+ if ((int)grid.width() - 1 == x) { // RIGHT side
+ wanted_sides.push_back(LEFT);
+ }
+ if (0 == y) { // BOTTOM side
+ wanted_sides.push_back(TOP);
+ }
+ if (0 == x) { // LEFT side
+ wanted_sides.push_back(RIGHT);
+ }
+
+ // If wanted sides is empty still, this block does not have specific wanted sides, Deposit all the sides
+ if (wanted_sides.empty()) {
+ for (e_side side : TOTAL_2D_SIDES) {
+ wanted_sides.push_back(side);
+ }
+ }
+
+ add_pins_spatial_lookup(rr_graph_builder,
+ physical_type,
+ pin_num_vec,
+ layer,
+ x,
+ y,
+ index,
+ wanted_sides);
+ }
+ }
+ }
+ }
+}
+
+static void load_chan_rr_indices(const int max_chan_width,
+ const DeviceGrid& grid,
+ const int chan_len,
+ const int num_chans,
+ const e_rr_type type,
+ const t_chan_details& chan_details,
+ RRSpatialLookup& node_lookup,
+ int* index) {
+ const auto& device_ctx = g_vpr_ctx.device();
+
+ for (int layer = 0; layer < grid.get_num_layers(); layer++) {
+ // Skip the current die if architecture file specifies that it doesn't require global resource routing
+ if (!device_ctx.inter_cluster_prog_routing_resources.at(layer)) {
+ continue;
+ }
+
+ for (int chan = 0; chan < num_chans - 1; ++chan) {
+ for (int seg = 1; seg < chan_len - 1; ++seg) {
+ // Assign an inode to the starts of tracks
+ const int x = (type == e_rr_type::CHANX) ? seg : chan;
+ const int y = (type == e_rr_type::CHANX) ? chan : seg;
+ const t_chan_seg_details* seg_details = chan_details[x][y].data();
+
+ // Reserve nodes in lookup to save memory
+ node_lookup.reserve_nodes(layer, x, y, type, max_chan_width);
+
+ for (int track = 0; track < max_chan_width; ++track) {
+ /* TODO: May let the length() == 0 case go through, to model muxes */
+ if (seg_details[track].length() <= 0)
+ continue;
+
+ int start = get_seg_start(seg_details, track, chan, seg);
+ int node_start_x = (type == e_rr_type::CHANX) ? start : chan;
+ int node_start_y = (type == e_rr_type::CHANX) ? chan : start;
+
+ // If the start of the wire doesn't have an RRNodeId, assign one to it.
+ RRNodeId inode = node_lookup.find_node(layer, node_start_x, node_start_y, type, track);
+ if (!inode) {
+ inode = RRNodeId(*index);
+ ++(*index);
+ node_lookup.add_node(inode, layer, node_start_x, node_start_y, type, track);
+ }
+
+ // Assign RRNodeId of start of wire to current position
+ node_lookup.add_node(inode, layer, x, y, type, track);
+ }
+ }
+ }
+ }
+}
+
+static void add_classes_spatial_lookup(RRGraphBuilder& rr_graph_builder,
+ t_physical_tile_type_ptr physical_type_ptr,
+ const std::vector& class_num_vec,
+ int layer,
+ int root_x,
+ int root_y,
+ int block_width,
+ int block_height,
+ int* index) {
+ for (int x_tile = root_x; x_tile < (root_x + block_width); x_tile++) {
+ for (int y_tile = root_y; y_tile < (root_y + block_height); y_tile++) {
+ rr_graph_builder.node_lookup().reserve_nodes(layer, x_tile, y_tile, e_rr_type::SOURCE, class_num_vec.size(), TOTAL_2D_SIDES[0]);
+ rr_graph_builder.node_lookup().reserve_nodes(layer, x_tile, y_tile, e_rr_type::SINK, class_num_vec.size(), TOTAL_2D_SIDES[0]);
+ }
+ }
+
+ for (const int class_num : class_num_vec) {
+ e_pin_type class_type = get_class_type_from_class_physical_num(physical_type_ptr, class_num);
+ e_rr_type node_type = e_rr_type::SINK;
+ if (class_type == DRIVER) {
+ node_type = e_rr_type::SOURCE;
+ } else {
+ VTR_ASSERT(class_type == RECEIVER);
+ }
+
+ for (int x_offset = 0; x_offset < block_width; x_offset++) {
+ for (int y_offset = 0; y_offset < block_height; y_offset++) {
+ int curr_x = root_x + x_offset;
+ int curr_y = root_y + y_offset;
+
+ rr_graph_builder.node_lookup().add_node(RRNodeId(*index), layer, curr_x, curr_y, node_type, class_num);
+ }
+ }
+
+ ++(*index);
+ }
+}
+
+static void add_pins_spatial_lookup(RRGraphBuilder& rr_graph_builder,
+ t_physical_tile_type_ptr physical_type_ptr,
+ const std::vector& pin_num_vec,
+ int layer,
+ int root_x,
+ int root_y,
+ int* index,
+ const std::vector& wanted_sides) {
+ for (e_side side : wanted_sides) {
+ for (int width_offset = 0; width_offset < physical_type_ptr->width; ++width_offset) {
+ int x_tile = root_x + width_offset;
+ for (int height_offset = 0; height_offset < physical_type_ptr->height; ++height_offset) {
+ int y_tile = root_y + height_offset;
+ // only nodes on the tile may be located in a location other than the root-location
+ rr_graph_builder.node_lookup().reserve_nodes(layer, x_tile, y_tile, e_rr_type::OPIN, physical_type_ptr->num_pins, side);
+ rr_graph_builder.node_lookup().reserve_nodes(layer, x_tile, y_tile, e_rr_type::IPIN, physical_type_ptr->num_pins, side);
+ }
+ }
+ }
+
+ for (const int pin_num : pin_num_vec) {
+ bool assigned_to_rr_node = false;
+ const auto [x_offset, y_offset, pin_sides] = get_pin_coordinates(physical_type_ptr, pin_num, wanted_sides);
+ e_pin_type pin_type = get_pin_type_from_pin_physical_num(physical_type_ptr, pin_num);
+ for (int pin_coord_idx = 0; pin_coord_idx < (int)pin_sides.size(); pin_coord_idx++) {
+ int x_tile = root_x + x_offset[pin_coord_idx];
+ int y_tile = root_y + y_offset[pin_coord_idx];
+ e_side side = pin_sides[pin_coord_idx];
+ if (pin_type == DRIVER) {
+ rr_graph_builder.node_lookup().add_node(RRNodeId(*index), layer, x_tile, y_tile, e_rr_type::OPIN, pin_num, side);
+ assigned_to_rr_node = true;
+ } else {
+ VTR_ASSERT(pin_type == RECEIVER);
+ rr_graph_builder.node_lookup().add_node(RRNodeId(*index), layer, x_tile, y_tile, e_rr_type::IPIN, pin_num, side);
+ assigned_to_rr_node = true;
+ }
+ }
+ /* A pin may locate on multiple sides of a tile.
+ * Instead of allocating multiple rr_nodes for the pin,
+ * we just create a rr_node and make it indexable on these sides
+ * As such, we can avoid redundant rr_node to be allocated
+ * and multiple nets to be mapped to the pin
+ *
+ * Considering that some pin could be just dangling, we do not need
+ * to create a void rr_node for it.
+ * As such, we only allocate a rr node when the pin is indeed located
+ * on at least one side
+ */
+ if (assigned_to_rr_node) {
+ ++(*index);
+ }
+ }
+}
+
+void alloc_and_load_rr_node_indices(RRGraphBuilder& rr_graph_builder,
+ const t_chan_width& nodes_per_chan,
+ const DeviceGrid& grid,
+ int* index,
+ const t_chan_details& chan_details_x,
+ const t_chan_details& chan_details_y) {
+ // Alloc the lookup table
+ for (e_rr_type rr_type : RR_TYPES) {
+ rr_graph_builder.node_lookup().resize_nodes(grid.get_num_layers(), grid.width(), grid.height(), rr_type, NUM_2D_SIDES);
+ }
+
+ // Assign indices for block nodes
+ load_block_rr_indices(rr_graph_builder, grid, index);
+
+ // Load the data for x and y channels
+ load_chan_rr_indices(nodes_per_chan.x_max, grid, grid.width(), grid.height(),
+ e_rr_type::CHANX, chan_details_x, rr_graph_builder.node_lookup(), index);
+ load_chan_rr_indices(nodes_per_chan.y_max, grid, grid.height(), grid.width(),
+ e_rr_type::CHANY, chan_details_y, rr_graph_builder.node_lookup(), index);
+}
+
+void alloc_and_load_inter_die_rr_node_indices(RRGraphBuilder& rr_graph_builder,
+ const t_chan_width& nodes_per_chan,
+ const DeviceGrid& grid,
+ const vtr::NdMatrix& extra_nodes_per_switchblock,
+ int* index) {
+ /*
+ * In case of multi-die FPGAs, we add extra nodes (could have used either CHANX or CHANY; we chose to use all CHANX) to
+ * support inter-die communication coming from switch blocks (connection between two tracks in different layers)
+ * The extra nodes have the following attribute:
+ * 1) type = CHANX
+ * 2) length = 0 (xhigh = xlow, yhigh = ylow)
+ * 3) ptc = [max_chanx_width:max_chanx_width+number_of_connection-1]
+ * 4) direction = NONE
+ */
+ const auto& device_ctx = g_vpr_ctx.device();
+
+ for (int layer = 0; layer < grid.get_num_layers(); layer++) {
+ // Skip the current die if architecture file specifies that it doesn't have global resource routing
+ if (!device_ctx.inter_cluster_prog_routing_resources.at(layer)) {
+ continue;
+ }
+
+ for (size_t y = 0; y < grid.height() - 1; ++y) {
+ for (size_t x = 1; x < grid.width() - 1; ++x) {
+ // count how many track-to-track connection go from current layer to other layers
+ int conn_count = extra_nodes_per_switchblock[x][y];
+
+ // skip if no connection is required
+ if (conn_count == 0) {
+ continue;
+ }
+
+ // reserve extra nodes for inter-die track-to-track connection
+ rr_graph_builder.node_lookup().reserve_nodes(layer, x, y, e_rr_type::CHANX, conn_count + nodes_per_chan.max);
+ for (int rr_node_offset = 0; rr_node_offset < conn_count; rr_node_offset++) {
+ RRNodeId inode = rr_graph_builder.node_lookup().find_node(layer, x, y, e_rr_type::CHANX, nodes_per_chan.max + rr_node_offset);
+ if (!inode) {
+ inode = RRNodeId(*index);
+ ++(*index);
+ rr_graph_builder.node_lookup().add_node(inode, layer, x, y, e_rr_type::CHANX, nodes_per_chan.max + rr_node_offset);
+ }
+ }
+ }
+ }
+ }
+}
+
+void alloc_and_load_tile_rr_node_indices(RRGraphBuilder& rr_graph_builder,
+ t_physical_tile_type_ptr physical_tile,
+ int layer,
+ int x,
+ int y,
+ int* num_rr_nodes) {
+ std::vector wanted_sides{TOP, BOTTOM, LEFT, RIGHT};
+ auto class_num_range = get_flat_tile_primitive_classes(physical_tile);
+ auto pin_num_vec = get_flat_tile_pins(physical_tile);
+
+ std::vector class_num_vec(class_num_range.total_num());
+ std::iota(class_num_vec.begin(), class_num_vec.end(), class_num_range.low);
+
+ add_classes_spatial_lookup(rr_graph_builder,
+ physical_tile,
+ class_num_vec,
+ layer,
+ x,
+ y,
+ physical_tile->width,
+ physical_tile->height,
+ num_rr_nodes);
+
+ add_pins_spatial_lookup(rr_graph_builder,
+ physical_tile,
+ pin_num_vec,
+ layer,
+ x,
+ y,
+ num_rr_nodes,
+ wanted_sides);
+}
+
+void alloc_and_load_intra_cluster_rr_node_indices(RRGraphBuilder& rr_graph_builder,
+ const DeviceGrid& grid,
+ const vtr::vector& pin_chains,
+ const vtr::vector>& pin_chains_num,
+ int* index) {
+ for (int layer = 0; layer < grid.get_num_layers(); layer++) {
+ for (int x = 0; x < (int)grid.width(); x++) {
+ for (int y = 0; y < (int)grid.height(); y++) {
+ // Process each block from its root location
+ if (grid.is_root_location({x, y, layer})) {
+ t_physical_tile_type_ptr physical_type = grid.get_physical_type({x, y, layer});
+ // Assign indices for SINKs and SOURCEs
+ // Note that SINKS/SOURCES have no side, so we always use side 0
+ std::vector class_num_vec;
+ std::vector pin_num_vec;
+ class_num_vec = get_cluster_netlist_intra_tile_classes_at_loc(layer, x, y, physical_type);
+ pin_num_vec = get_cluster_netlist_intra_tile_pins_at_loc(layer,
+ x,
+ y,
+ pin_chains,
+ pin_chains_num,
+ physical_type);
+ add_classes_spatial_lookup(rr_graph_builder,
+ physical_type,
+ class_num_vec,
+ layer,
+ x,
+ y,
+ physical_type->width,
+ physical_type->height,
+ index);
+
+ std::vector wanted_sides;
+ wanted_sides.push_back(e_side::TOP);
+ add_pins_spatial_lookup(rr_graph_builder,
+ physical_type,
+ pin_num_vec,
+ layer,
+ x,
+ y,
+ index,
+ wanted_sides);
+ }
+ }
+ }
+ }
+}
+
+bool verify_rr_node_indices(const DeviceGrid& grid,
+ const RRGraphView& rr_graph,
+ const vtr::vector& rr_indexed_data,
+ const t_rr_graph_storage& rr_nodes,
+ bool is_flat) {
+ std::unordered_map rr_node_counts;
+
+ int width = grid.width();
+ int height = grid.height();
+ int layer = grid.get_num_layers();
+
+ for (int l = 0; l < layer; ++l) {
+ for (int x = 0; x < width; ++x) {
+ for (int y = 0; y < height; ++y) {
+ for (e_rr_type rr_type : RR_TYPES) {
+ // Get the list of nodes at a specific location (x, y)
+ std::vector nodes_from_lookup;
+ if (rr_type == e_rr_type::CHANX || rr_type == e_rr_type::CHANY) {
+ nodes_from_lookup = rr_graph.node_lookup().find_channel_nodes(l, x, y, rr_type);
+ } else {
+ nodes_from_lookup = rr_graph.node_lookup().find_grid_nodes_at_all_sides(l, x, y, rr_type);
+ }
+
+ for (RRNodeId inode : nodes_from_lookup) {
+ rr_node_counts[inode]++;
+
+ if (rr_graph.node_type(inode) != rr_type) {
+ VPR_ERROR(VPR_ERROR_ROUTE, "RR node type does not match between rr_nodes and rr_node_indices (%s/%s): %s",
+ rr_node_typename[rr_graph.node_type(inode)],
+ rr_node_typename[rr_type],
+ describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str());
+ }
+
+ if (rr_graph.node_type(inode) == e_rr_type::CHANX) {
+ VTR_ASSERT_MSG(rr_graph.node_ylow(inode) == rr_graph.node_yhigh(inode), "CHANX should be horizontal");
+ if (y != rr_graph.node_ylow(inode)) {
+ VPR_ERROR(VPR_ERROR_ROUTE, "RR node y position does not agree between rr_nodes (%d) and rr_node_indices (%d): %s",
+ rr_graph.node_ylow(inode),
+ y,
+ describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str());
+ }
+
+ if (!rr_graph.x_in_node_range(x, inode)) {
+ VPR_ERROR(VPR_ERROR_ROUTE, "RR node x positions do not agree between rr_nodes (%d <-> %d) and rr_node_indices (%d): %s",
+ rr_graph.node_xlow(inode),
+ rr_graph.node_xlow(inode),
+ x,
+ describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str());
+ }
+ } else if (rr_graph.node_type(inode) == e_rr_type::CHANY) {
+ VTR_ASSERT_MSG(rr_graph.node_xlow(inode) == rr_graph.node_xhigh(inode), "CHANY should be vertical");
+
+ if (x != rr_graph.node_xlow(inode)) {
+ VPR_ERROR(VPR_ERROR_ROUTE, "RR node x position does not agree between rr_nodes (%d) and rr_node_indices (%d): %s",
+ rr_graph.node_xlow(inode),
+ x,
+ describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str());
+ }
+
+ if (!rr_graph.y_in_node_range(y, inode)) {
+ VPR_ERROR(VPR_ERROR_ROUTE, "RR node y positions do not agree between rr_nodes (%d <-> %d) and rr_node_indices (%d): %s",
+ rr_graph.node_ylow(inode),
+ rr_graph.node_ylow(inode),
+ y,
+ describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str());
+ }
+ } else if (rr_graph.node_type(inode) == e_rr_type::SOURCE || rr_graph.node_type(inode) == e_rr_type::SINK) {
+ // Sources have co-ordinates covering the entire block they are in, but not sinks
+ if (!rr_graph.x_in_node_range(x, inode)) {
+ VPR_ERROR(VPR_ERROR_ROUTE, "RR node x positions do not agree between rr_nodes (%d <-> %d) and rr_node_indices (%d): %s",
+ rr_graph.node_xlow(inode),
+ rr_graph.node_xlow(inode),
+ x,
+ describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str());
+ }
+
+ if (!rr_graph.y_in_node_range(y, inode)) {
+ VPR_ERROR(VPR_ERROR_ROUTE, "RR node y positions do not agree between rr_nodes (%d <-> %d) and rr_node_indices (%d): %s",
+ rr_graph.node_ylow(inode),
+ rr_graph.node_ylow(inode),
+ y,
+ describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str());
+ }
+ } else {
+ VTR_ASSERT(rr_graph.node_type(inode) == e_rr_type::IPIN || rr_graph.node_type(inode) == e_rr_type::OPIN);
+ /* As we allow a pin to be indexable on multiple sides,
+ * This check code should be invalid
+ * if (rr_node.xlow() != x) {
+ * VPR_ERROR(VPR_ERROR_ROUTE, "RR node xlow does not match between rr_nodes and rr_node_indices (%d/%d): %s",
+ * rr_node.xlow(),
+ * x,
+ * describe_rr_node(rr_graph, grid, rr_indexed_data, inode).c_str());
+ * }
+ *
+ * if (rr_node.ylow() != y) {
+ * VPR_ERROR(VPR_ERROR_ROUTE, "RR node ylow does not match between rr_nodes and rr_node_indices (%d/%d): %s",
+ * rr_node.ylow(),
+ * y,
+ * describe_rr_node(rr_graph, grid, rr_indexed_data, inode).c_str());
+ * }
+ */
+ }
+
+ if (rr_type == e_rr_type::IPIN || rr_type == e_rr_type::OPIN) {
+ /* As we allow a pin to be indexable on multiple sides,
+ * This check code should be invalid
+ * if (rr_node.side() != side) {
+ * VPR_ERROR(VPR_ERROR_ROUTE, "RR node xlow does not match between rr_nodes and rr_node_indices (%s/%s): %s",
+ * TOTAL_2D_SIDE_STRINGS[rr_node.side()],
+ * TOTAL_2D_SIDE_STRINGS[side],
+ * describe_rr_node(rr_graph, grid, rr_indexed_data, inode).c_str());
+ * } else {
+ * VTR_ASSERT(rr_node.side() == side);
+ * }
+ */
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (rr_node_counts.size() != rr_nodes.size()) {
+ VPR_ERROR(VPR_ERROR_ROUTE, "Mismatch in number of unique RR nodes in rr_nodes (%zu) and rr_node_indices (%zu)",
+ rr_nodes.size(),
+ rr_node_counts.size());
+ }
+
+ for (auto kv : rr_node_counts) {
+ RRNodeId inode = kv.first;
+ int count = kv.second;
+
+ const t_rr_node& rr_node = rr_nodes[size_t(inode)];
+
+ if (rr_graph.node_type(inode) == e_rr_type::SOURCE || rr_graph.node_type(inode) == e_rr_type::SINK) {
+ int rr_width = (rr_graph.node_xhigh(rr_node.id()) - rr_graph.node_xlow(rr_node.id()) + 1);
+ int rr_height = (rr_graph.node_yhigh(rr_node.id()) - rr_graph.node_ylow(rr_node.id()) + 1);
+ int rr_area = rr_width * rr_height;
+ if (count != rr_area) {
+ VPR_ERROR(VPR_ERROR_ROUTE, "Mismatch between RR node size (%d) and count within rr_node_indices (%d): %s",
+ rr_area,
+ rr_node.length(),
+ count,
+ describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str());
+ }
+ // As we allow a pin to be indexable on multiple sides,
+ // This check code should not be applied to input and output pins
+
+ } else if ((e_rr_type::OPIN != rr_graph.node_type(inode)) && (e_rr_type::IPIN != rr_graph.node_type(inode))) {
+ if (count != rr_node.length() + 1) {
+ VPR_ERROR(VPR_ERROR_ROUTE, "Mismatch between RR node length (%d) and count within rr_node_indices (%d, should be length + 1): %s",
+ rr_node.length(),
+ count,
+ describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str());
+ }
+ }
+ }
+
+ return true;
+}
diff --git a/vpr/src/route/rr_graph_generation/rr_node_indices.h b/vpr/src/route/rr_graph_generation/rr_node_indices.h
new file mode 100644
index 0000000000..76373c1cc7
--- /dev/null
+++ b/vpr/src/route/rr_graph_generation/rr_node_indices.h
@@ -0,0 +1,88 @@
+#pragma once
+
+#include "rr_graph_builder.h"
+#include "rr_graph_view.h"
+#include "device_grid.h"
+#include "rr_types.h"
+#include "rr_graph_type.h"
+#include "rr_graph_utils.h"
+#include "clustered_netlist_fwd.h"
+
+/**
+ * @brief Allocates and populates data structures for efficient rr_node index lookups.
+ *
+ * This function sets up the `rr_node_indices` structure, which maps a physical location
+ * and type to the index of the first corresponding rr_node.
+ *
+ * @param rr_graph_builder Reference to the RRGraphBuilder used to construct and populate RR node spatial lookups.
+ * @param nodes_per_chan Specifies the maximum number of routing tracks per channel in the x and y directions.
+ * @param grid The device grid representing the physical layout of tiles in the FPGA fabric.
+ * @param index Pointer to the global RR node index counter; incremented as new RR nodes are assigned.
+ * @param chan_details_x Channel details describing segment and track properties for CHANX (horizontal) routing tracks.
+ * @param chan_details_y Channel details describing segment and track properties for CHANY (vertical) routing tracks.
+ */
+void alloc_and_load_rr_node_indices(RRGraphBuilder& rr_graph_builder,
+ const t_chan_width& nodes_per_chan,
+ const DeviceGrid& grid,
+ int* index,
+ const t_chan_details& chan_details_x,
+ const t_chan_details& chan_details_y);
+
+/**
+ * @brief Allocates extra nodes within the RR graph to support 3D custom switch blocks for multi-die FPGAs
+ *
+ * @param rr_graph_builder RRGraphBuilder data structure which allows data modification on a routing resource graph
+ * @param nodes_per_chan number of tracks per channel (x, y)
+ * @param grid The device grid representing the physical layout of tiles in the FPGA fabric.
+ * @param extra_nodes_per_switchblock keeps how many extra length-0 CHANX node is required for each unique (x,y) location within the grid.
+ * Number of these extra nodes are exactly the same for all layers. Hence, we only keep it for one layer. ([0..grid.width-1][0..grid.height-1)
+ * @param index Pointer to the global RR node index counter; incremented as new RR nodes are assigned.
+ */
+void alloc_and_load_inter_die_rr_node_indices(RRGraphBuilder& rr_graph_builder,
+ const t_chan_width& nodes_per_chan,
+ const DeviceGrid& grid,
+ const vtr::NdMatrix& extra_nodes_per_switchblock,
+ int* index);
+
+/**
+ * @brief Allocates and loads RR node indices for a specific tile.
+ *
+ * This function assigns RR node IDs to all classes (SOURCE/SINK) and pins (IPIN/OPIN)
+ * associated with a given physical tile at a specific grid location and layer.
+ * It is primarily used in scenarios where a standalone tile's routing resources
+ * need to be initialized independently.
+ *
+ * @param rr_graph_builder Reference to the RR graph builder with spatial lookup.
+ * @param physical_tile Pointer to the physical tile type being processed.
+ * @param layer Layer index of the tile in the device grid.
+ * @param x X-coordinate of the tile's root position in the grid.
+ * @param y Y-coordinate of the tile's root position in the grid.
+ * @param num_rr_nodes Pointer to the global RR node index counter (will be incremented).
+ */
+void alloc_and_load_tile_rr_node_indices(RRGraphBuilder& rr_graph_builder,
+ t_physical_tile_type_ptr physical_tile,
+ int layer,
+ int x,
+ int y,
+ int* num_rr_nodes);
+
+void alloc_and_load_intra_cluster_rr_node_indices(RRGraphBuilder& rr_graph_builder,
+ const DeviceGrid& grid,
+ const vtr::vector& pin_chains,
+ const vtr::vector>& pin_chains_num,
+ int* index);
+
+/**
+ * Validate the node look-up matches all the node-level information
+ * in the storage of a routing resource graph
+ * This function will check the following aspects:
+ * - The type of each node matches its type that is indexed in the node look-up
+ * - For bounding box (xlow, ylow, xhigh, yhigh) of each node is indexable in the node look-up
+ * - The number of unique indexable nodes in the node look up matches the number of nodes in the storage
+ * This ensures that every node in the storage is indexable and there are no hidden nodes in the look-up
+ */
+bool verify_rr_node_indices(const DeviceGrid& grid,
+ const RRGraphView& rr_graph,
+ const vtr::vector& rr_indexed_data,
+ const t_rr_graph_storage& rr_nodes,
+ bool is_flat);
diff --git a/vpr/src/route/rr_types.h b/vpr/src/route/rr_graph_generation/rr_types.h
similarity index 99%
rename from vpr/src/route/rr_types.h
rename to vpr/src/route/rr_graph_generation/rr_types.h
index 8e093faca7..620427a2d1 100644
--- a/vpr/src/route/rr_types.h
+++ b/vpr/src/route/rr_graph_generation/rr_types.h
@@ -1,5 +1,6 @@
#ifndef RR_TYPES_H
#define RR_TYPES_H
+
#include
#include "vtr_ndmatrix.h"
@@ -14,7 +15,7 @@
typedef std::vector, 5>> t_pin_to_track_lookup;
-/* AA: t_pin_to_track_lookup is alloacted first and is then converted to t_track_to_pin lookup by simply redefining the accessing order.
+/* AA: t_pin_to_track_lookup is alloacted first and is then converted to t_track_to_pin lookup by simply redefining the accessing order.
* As a result, the matrix should be accessed as follow as a result after allocation in rr_graph.cpp: alloc_track_to_pin_lookup (used by unidir and bidir)
* [0..device_ctx.physical_tile_types.size()-1][0..max_chan_width-1][0..width][0..height][0..layer-1][0..3]
*
diff --git a/vpr/src/util/vpr_utils.cpp b/vpr/src/util/vpr_utils.cpp
index 34c2156b98..82b019676f 100644
--- a/vpr/src/util/vpr_utils.cpp
+++ b/vpr/src/util/vpr_utils.cpp
@@ -729,66 +729,6 @@ static bool pb_type_contains_blif_model(const t_pb_type* pb_type, const std::reg
return false;
}
-int get_max_primitives_in_pb_type(t_pb_type* pb_type) {
- int max_size;
- if (pb_type->modes == nullptr) {
- max_size = 1;
- } else {
- max_size = 0;
- int temp_size = 0;
- for (int i = 0; i < pb_type->num_modes; i++) {
- for (int j = 0; j < pb_type->modes[i].num_pb_type_children; j++) {
- temp_size += pb_type->modes[i].pb_type_children[j].num_pb
- * get_max_primitives_in_pb_type(
- &pb_type->modes[i].pb_type_children[j]);
- }
- if (temp_size > max_size) {
- max_size = temp_size;
- }
- }
- }
- return max_size;
-}
-
-/* finds maximum number of nets that can be contained in pb_type, this is bounded by the number of driving pins */
-int get_max_nets_in_pb_type(const t_pb_type* pb_type) {
- int max_nets;
- if (pb_type->modes == nullptr) {
- max_nets = pb_type->num_output_pins;
- } else {
- max_nets = 0;
- for (int i = 0; i < pb_type->num_modes; i++) {
- int temp_nets = 0;
- for (int j = 0; j < pb_type->modes[i].num_pb_type_children; j++) {
- temp_nets += pb_type->modes[i].pb_type_children[j].num_pb
- * get_max_nets_in_pb_type(
- &pb_type->modes[i].pb_type_children[j]);
- }
- if (temp_nets > max_nets) {
- max_nets = temp_nets;
- }
- }
- }
- if (pb_type->is_root()) {
- max_nets += pb_type->num_input_pins + pb_type->num_output_pins
- + pb_type->num_clock_pins;
- }
- return max_nets;
-}
-
-int get_max_depth_of_pb_type(t_pb_type* pb_type) {
- int max_depth = pb_type->depth;
- for (int i = 0; i < pb_type->num_modes; i++) {
- for (int j = 0; j < pb_type->modes[i].num_pb_type_children; j++) {
- int temp_depth = get_max_depth_of_pb_type(&pb_type->modes[i].pb_type_children[j]);
- if (temp_depth > max_depth) {
- max_depth = temp_depth;
- }
- }
- }
- return max_depth;
-}
-
/**
* given an atom block and physical primitive type, is the mapping legal
*/
diff --git a/vpr/src/util/vpr_utils.h b/vpr/src/util/vpr_utils.h
index 762efd36c5..b6828859bd 100644
--- a/vpr/src/util/vpr_utils.h
+++ b/vpr/src/util/vpr_utils.h
@@ -1,5 +1,4 @@
-#ifndef VPR_UTILS_H
-#define VPR_UTILS_H
+#pragma once
#include "arch_util.h"
#include "atom_netlist.h"
@@ -181,9 +180,6 @@ InstPort parse_inst_port(const std::string& str);
//Returns the block type which is most likely the logic block
t_logical_block_type_ptr infer_logic_block_type(const DeviceGrid& grid);
-int get_max_primitives_in_pb_type(t_pb_type* pb_type);
-int get_max_depth_of_pb_type(t_pb_type* pb_type);
-int get_max_nets_in_pb_type(const t_pb_type* pb_type);
bool primitive_type_feasible(AtomBlockId blk_id, const t_pb_type* cur_pb_type);
t_pb_graph_pin* get_pb_graph_node_pin_from_model_port_pin(const t_model_ports* model_port, const int model_pin, const t_pb_graph_node* pb_graph_node);
/// @brief Gets the pb_graph_node pin at the given pin index for the given
@@ -287,13 +283,6 @@ std::vector get_cluster_netlist_intra_tile_classes_at_loc(int layer,
/**
* @brief Returns the list of pins inside the tile located at (layer, i, j), except for the ones which are on a chain
- * @param layer
- * @param i
- * @param j
- * @param pin_chains
- * @param pin_chains_num
- * @param physical_type
- * @return
*/
std::vector get_cluster_netlist_intra_tile_pins_at_loc(const int layer,
const int i,
@@ -362,5 +351,3 @@ class PortPinToBlockPinConverter {
*/
std::vector>>> blk_pin_from_port_pin_;
};
-
-#endif