From 998ba664b9fefef3b541af619c21c0da24363df1 Mon Sep 17 00:00:00 2001 From: Amir Poolad Date: Thu, 6 Nov 2025 15:20:24 -0500 Subject: [PATCH 01/21] Add interposer crossing wire cutting --- libs/librrgraph/src/base/rr_graph_builder.h | 4 + libs/librrgraph/src/base/rr_graph_storage.cpp | 54 ++++- libs/librrgraph/src/base/rr_graph_storage.h | 7 + libs/librrgraph/src/base/rr_graph_view.cpp | 2 - libs/librrgraph/src/base/rr_graph_view.h | 9 +- .../rr_graph_generation/interposer_cut.cpp | 205 ++++++++++++++++++ .../rr_graph_generation/interposer_cut.h | 10 + .../route/rr_graph_generation/rr_graph.cpp | 12 + vpr/src/route/rr_graph_generation/rr_graph.h | 2 +- .../rr_graph_generation/rr_node_indices.cpp | 196 ++++++++--------- 10 files changed, 385 insertions(+), 116 deletions(-) create mode 100644 vpr/src/route/rr_graph_generation/interposer_cut.cpp create mode 100644 vpr/src/route/rr_graph_generation/interposer_cut.h diff --git a/libs/librrgraph/src/base/rr_graph_builder.h b/libs/librrgraph/src/base/rr_graph_builder.h index daf42742275..3bd10e749f3 100644 --- a/libs/librrgraph/src/base/rr_graph_builder.h +++ b/libs/librrgraph/src/base/rr_graph_builder.h @@ -352,6 +352,10 @@ class RRGraphBuilder { node_storage_.alloc_and_load_edges(rr_edges_to_create); } + inline void remove_edges(std::vector& rr_edges_to_remove) { + node_storage_.remove_edges(rr_edges_to_remove); + } + /** @brief Overrides the associated switch for a given edge by * updating the edge to use the passed in switch. */ inline void override_edge_switch(RREdgeId edge_id, RRSwitchId switch_id) { diff --git a/libs/librrgraph/src/base/rr_graph_storage.cpp b/libs/librrgraph/src/base/rr_graph_storage.cpp index 1e15f127b8d..ace814b04e5 100644 --- a/libs/librrgraph/src/base/rr_graph_storage.cpp +++ b/libs/librrgraph/src/base/rr_graph_storage.cpp @@ -2,8 +2,10 @@ #include "rr_graph_storage.h" #include "physical_types.h" #include "rr_graph_fwd.h" +#include "vtr_assert.h" #include "vtr_error.h" #include "librrgraph_types.h" +#include "vtr_util.h" #include #include @@ -57,6 +59,33 @@ void t_rr_graph_storage::alloc_and_load_edges(const t_rr_edge_info_set* rr_edges } } +void t_rr_graph_storage::remove_edges(std::vector& rr_edges_to_remove) { + size_t starting_edge_count = edge_dest_node_.size(); + + vtr::uniquify(rr_edges_to_remove); + + size_t edge_list_end = edge_dest_node_.size() - 1; + for (auto it = rr_edges_to_remove.rbegin(); it != rr_edges_to_remove.rend(); ++it) { + RREdgeId erase_idx = *it; + + edge_dest_node_[erase_idx] = edge_dest_node_[RREdgeId(edge_list_end)]; + edge_src_node_[erase_idx] = edge_src_node_[RREdgeId(edge_list_end)]; + edge_switch_[erase_idx] = edge_switch_[RREdgeId(edge_list_end)]; + edge_remapped_[erase_idx] = edge_remapped_[RREdgeId(edge_list_end)]; + + edge_list_end--; + + } + + edge_dest_node_.erase(edge_dest_node_.begin() + edge_list_end + 1, edge_dest_node_.end()); + edge_src_node_.erase(edge_src_node_.begin() + edge_list_end + 1, edge_src_node_.end()); + edge_switch_.erase(edge_switch_.begin() + edge_list_end + 1, edge_switch_.end()); + edge_remapped_.erase(edge_remapped_.begin() + edge_list_end + 1, edge_remapped_.end()); + + VTR_ASSERT(edge_dest_node_.size() == (starting_edge_count - rr_edges_to_remove.size())); +} + + void t_rr_graph_storage::assign_first_edges() { VTR_ASSERT(node_first_edge_.empty()); @@ -68,31 +97,34 @@ void t_rr_graph_storage::assign_first_edges() { edge_src_node_.end())); size_t node_id = 0; - size_t first_id = 0; - size_t second_id = 0; + size_t first_edge_id = 0; + size_t second_edge_id = 0; + size_t num_edges = edge_src_node_.size(); VTR_ASSERT(edge_dest_node_.size() == num_edges); VTR_ASSERT(edge_switch_.size() == num_edges); VTR_ASSERT(edge_remapped_.size() == num_edges); + while (true) { - VTR_ASSERT(first_id < num_edges); - VTR_ASSERT(second_id < num_edges); - size_t current_node_id = size_t(edge_src_node_[RREdgeId(second_id)]); + VTR_ASSERT(first_edge_id < num_edges); + VTR_ASSERT(second_edge_id < num_edges); + + size_t current_node_id = size_t(edge_src_node_[RREdgeId(second_edge_id)]); if (node_id < current_node_id) { // All edges belonging to node_id are assigned. while (node_id < current_node_id) { // Store any edges belongs to node_id. VTR_ASSERT(node_id < node_first_edge_.size()); - node_first_edge_[RRNodeId(node_id)] = RREdgeId(first_id); - first_id = second_id; + node_first_edge_[RRNodeId(node_id)] = RREdgeId(first_edge_id); + first_edge_id = second_edge_id; node_id += 1; } VTR_ASSERT(node_id == current_node_id); - node_first_edge_[RRNodeId(node_id)] = RREdgeId(second_id); + node_first_edge_[RRNodeId(node_id)] = RREdgeId(second_edge_id); } else { - second_id += 1; - if (second_id == num_edges) { + second_edge_id += 1; + if (second_edge_id == num_edges) { break; } } @@ -100,7 +132,7 @@ void t_rr_graph_storage::assign_first_edges() { // All remaining nodes have no edges, set as such. for (size_t inode = node_id + 1; inode < node_first_edge_.size(); ++inode) { - node_first_edge_[RRNodeId(inode)] = RREdgeId(second_id); + node_first_edge_[RRNodeId(inode)] = RREdgeId(second_edge_id); } VTR_ASSERT_SAFE(verify_first_edges()); diff --git a/libs/librrgraph/src/base/rr_graph_storage.h b/libs/librrgraph/src/base/rr_graph_storage.h index ab1c844cd19..ba4882a60f3 100644 --- a/libs/librrgraph/src/base/rr_graph_storage.h +++ b/libs/librrgraph/src/base/rr_graph_storage.h @@ -400,6 +400,11 @@ class t_rr_graph_storage { return vtr::StrongIdRange(first_edge(id), last_edge(id)); } + + inline vtr::StrongIdRange all_edges() const { + return vtr::StrongIdRange(RREdgeId(0), RREdgeId(edge_src_node_.size())); + } + /** @brief Retrieve the RREdgeId for iedge'th edge in RRNodeId. * * This method should generally not be used, and instead first_edge and @@ -776,6 +781,8 @@ class t_rr_graph_storage { /** @brief Adds a batch of edges.*/ void alloc_and_load_edges(const t_rr_edge_info_set* rr_edges_to_create); + void remove_edges(std::vector& rr_edges_to_remove); + /* Edge finalization methods */ /** @brief Counts the number of rr switches needed based on fan in to support mux diff --git a/libs/librrgraph/src/base/rr_graph_view.cpp b/libs/librrgraph/src/base/rr_graph_view.cpp index f23762c3e7d..0b8b04b13ef 100644 --- a/libs/librrgraph/src/base/rr_graph_view.cpp +++ b/libs/librrgraph/src/base/rr_graph_view.cpp @@ -129,5 +129,3 @@ bool RRGraphView::validate_in_edges() const { } return true; } - - diff --git a/libs/librrgraph/src/base/rr_graph_view.h b/libs/librrgraph/src/base/rr_graph_view.h index ca825d15642..8f9d82a0b6f 100644 --- a/libs/librrgraph/src/base/rr_graph_view.h +++ b/libs/librrgraph/src/base/rr_graph_view.h @@ -65,9 +65,11 @@ #include "metadata_storage.h" #include "rr_node.h" #include "physical_types.h" +#include "rr_node_types.h" #include "rr_spatial_lookup.h" #include "vtr_geometry.h" #include "rr_graph_utils.h" +#include "vtr_range.h" class RRGraphView { /* -- Constructors -- */ @@ -584,7 +586,7 @@ class RRGraphView { * @example * RRGraphView rr_graph; // A dummy rr_graph for a short example * RRNodeId node; // A dummy node for a short example - * for (RREdgeId edge : rr_graph.edges(node)) { + * for (t_edge_size edge : rr_graph.edges(node)) { * // Do something with the edge * } */ @@ -592,6 +594,11 @@ class RRGraphView { return vtr::make_range(edge_idx_iterator(0), edge_idx_iterator(num_edges(id))); } + inline vtr::StrongIdRange all_edges() const { + return node_storage_.all_edges(); + } + + /** * @brief Return ID range for outgoing edges. */ diff --git a/vpr/src/route/rr_graph_generation/interposer_cut.cpp b/vpr/src/route/rr_graph_generation/interposer_cut.cpp new file mode 100644 index 00000000000..02d6c5d86e8 --- /dev/null +++ b/vpr/src/route/rr_graph_generation/interposer_cut.cpp @@ -0,0 +1,205 @@ +#include +#include +#include +#include + +#include "device_grid.h" +#include "rr_graph_builder.h" +#include "rr_graph_fwd.h" +#include "rr_graph_view.h" +#include "rr_node_types.h" +#include "rr_spatial_lookup.h" +#include "vtr_assert.h" +#include "vtr_log.h" + +#include "interposer_cut.h" + +static bool should_cut_edge(int src_start_loc, int sink_start_loc, int cut_loc) { + int src_delta = src_start_loc - cut_loc; + int sink_delta = sink_start_loc - cut_loc; + + // Same sign means that both sink and source are on the same side of this cut + if ((src_delta < 0 && sink_delta < 0) || (src_delta >= 0 && sink_delta >= 0)) { + return false; + } else { + return true; + } +} + +static bool should_cut_node(int src_start_loc, int sink_start_loc, int cut_loc) { + int src_delta = src_start_loc - cut_loc; + int sink_delta = sink_start_loc - cut_loc; + + // Same sign means that both sink and source are on the same side of this cut + if ((src_delta <= 0 && sink_delta <= 0) || (src_delta > 0 && sink_delta > 0)) { + return false; + } else { + return true; + } +} + +static short node_xstart(const RRGraphView& rr_graph, RRNodeId node) { + // Return early for OPIN and IPIN types (Some BIDIR pins would trigger the assertion below) + if (rr_graph.node_type(node) == e_rr_type::OPIN || rr_graph.node_type(node) == e_rr_type::IPIN) { + VTR_ASSERT(rr_graph.node_xlow(node) == rr_graph.node_xhigh(node)); + return rr_graph.node_xlow(node); + } + + switch (rr_graph.node_direction(node)) { + case Direction::DEC: + return rr_graph.node_xhigh(node); + break; + + case Direction::INC: + return rr_graph.node_xlow(node); + break; + + case Direction::NONE: + VTR_ASSERT(rr_graph.node_xlow(node) == rr_graph.node_xhigh(node)); + return (rr_graph.node_xlow(node)); + break; + + case Direction::BIDIR: + VTR_ASSERT_MSG(false, "Bidir node has no starting point"); + break; + + default: + VTR_ASSERT(false); + break; + } +} + +static short node_ystart(const RRGraphView& rr_graph, RRNodeId node) { + // Return early for OPIN and IPIN types (Some BIDIR pins would trigger the assertion below) + if (rr_graph.node_type(node) == e_rr_type::OPIN || rr_graph.node_type(node) == e_rr_type::IPIN) { + return rr_graph.node_ylow(node); + } + + switch (rr_graph.node_direction(node)) { + case Direction::DEC: + return rr_graph.node_yhigh(node); + break; + + case Direction::INC: + return rr_graph.node_ylow(node); + break; + + case Direction::NONE: + VTR_ASSERT(rr_graph.node_ylow(node) == rr_graph.node_yhigh(node)); + return (rr_graph.node_ylow(node)); + break; + + case Direction::BIDIR: + VTR_ASSERT_MSG(false, "Bidir node has no starting point"); + break; + + default: + VTR_ASSERT(false); + break; + } +} + +std::vector mark_interposer_cut_edges_for_removal(const RRGraphView& rr_graph, const DeviceGrid& grid) { + std::vector edges_to_be_removed; + + // Loop over all RREdgeIds and mark ones that cross a cutline to be removed + + for (RREdgeId edge_id : rr_graph.all_edges()) { + RRNodeId src_node = rr_graph.edge_src_node(edge_id); + RRNodeId sink_node = rr_graph.edge_sink_node(edge_id); + + if (src_node == RRNodeId(5866) && sink_node == RRNodeId(5604)) { + VTR_LOG("HI\n"); + } + + // TODO: ignoring chanz nodes for now + if (rr_graph.node_type(src_node) == e_rr_type::CHANZ || rr_graph.node_type(sink_node) == e_rr_type::CHANZ) { + continue; + } + + VTR_ASSERT(rr_graph.node_layer_low(src_node) == rr_graph.node_layer_low(sink_node)); + VTR_ASSERT(rr_graph.node_layer_low(src_node) == rr_graph.node_layer_high(src_node)); + VTR_ASSERT(rr_graph.node_layer_low(sink_node) == rr_graph.node_layer_high(sink_node)); + + int layer = rr_graph.node_layer_low(src_node); + + for (int cut_loc_y : grid.get_horizontal_interposer_cuts()[layer]) { + int src_start_loc_y = node_ystart(rr_graph, src_node); + int sink_start_loc_y = node_ystart(rr_graph, sink_node); + + if (should_cut_edge(src_start_loc_y, sink_start_loc_y, cut_loc_y)) { + edges_to_be_removed.push_back(edge_id); + } + } + + for (int cut_loc_x : grid.get_vertical_interposer_cuts()[layer]) { + int src_start_loc_x = node_xstart(rr_graph, src_node); + int sink_start_loc_x = node_xstart(rr_graph, sink_node); + + if (should_cut_edge(src_start_loc_x, sink_start_loc_x, cut_loc_x)) { + edges_to_be_removed.push_back(edge_id); + } + } + } + + return edges_to_be_removed; +} + +// TODO: workshop a better name +void update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(const RRGraphView& rr_graph, const DeviceGrid& grid, RRGraphBuilder& rr_graph_builder, const std::vector>& sg_node_indices) { + VTR_ASSERT(std::is_sorted(sg_node_indices.begin(), sg_node_indices.end())); + + RRSpatialLookup& spatial_lookup = rr_graph_builder.node_lookup(); + size_t num_sg = 0; + for (size_t layer = 0; layer < grid.get_num_layers(); layer++) { + for (int cut_loc_y : grid.get_horizontal_interposer_cuts()[layer]) { + for (size_t x_loc = 0; x_loc < grid.width(); x_loc++) { + std::vector channel_nodes = spatial_lookup.find_channel_nodes(layer, x_loc, cut_loc_y, e_rr_type::CHANY); + for (RRNodeId node : channel_nodes) { + + bool is_sg_node = std::ranges::binary_search(std::views::keys(sg_node_indices), node, [](RRNodeId l, RRNodeId r) {return size_t(l) < size_t(r);}); + if (is_sg_node) { + num_sg++; + continue; + } + + + int x_high = rr_graph.node_xhigh(node); + int x_low = rr_graph.node_xlow(node); + VTR_ASSERT(x_high == x_low); + int y_high = rr_graph.node_yhigh(node); + int y_low = rr_graph.node_ylow(node); + int ptc_num = rr_graph.node_ptc_num(node); + + + // No need to cut 1-length wires + if (y_high == y_low) { + continue; + } + + if (!should_cut_node(y_low, y_high, cut_loc_y)) { + continue; + } + + if (rr_graph.node_direction(node) == Direction::INC) { + // Anything above cut_loc_y shouldn't exist + rr_graph_builder.set_node_coordinates(node, x_low, y_low, x_high, cut_loc_y); + + // Do a loop from cut_loc_y to y_high and remove node from spatial lookup + for (int y_loc = cut_loc_y + 1; y_loc <= y_high; y_loc++) { + spatial_lookup.remove_node(node, layer, x_low, y_loc, e_rr_type::CHANY, ptc_num); + } + } else if (rr_graph.node_direction(node) == Direction::DEC) { + // Anything below cut_loc_y shouldn't exist + rr_graph_builder.set_node_coordinates(node, x_low, cut_loc_y + 1, x_high, y_high); + + // Do a loop from y_low to cut_loc_y and remove node from spatial lookup + for (int y_loc = y_low; y_loc <= cut_loc_y; y_loc++) { + spatial_lookup.remove_node(node, layer, x_low, y_loc, e_rr_type::CHANY, ptc_num); + } + } + } + } + } + } +} diff --git a/vpr/src/route/rr_graph_generation/interposer_cut.h b/vpr/src/route/rr_graph_generation/interposer_cut.h new file mode 100644 index 00000000000..97d49c354e5 --- /dev/null +++ b/vpr/src/route/rr_graph_generation/interposer_cut.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include "rr_graph_fwd.h" +#include "rr_graph_view.h" +#include "device_grid.h" + +std::vector mark_interposer_cut_edges_for_removal(const RRGraphView& rr_graph, const DeviceGrid& grid); + +void update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(const RRGraphView& rr_graph, const DeviceGrid& grid, RRGraphBuilder& rr_graph_builder, const std::vector>& sg_node_indices); \ No newline at end of file diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index 05b972646e7..91410189ac1 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -8,6 +8,7 @@ #include "get_parallel_segs.h" #include "physical_types.h" #include "physical_types_util.h" +#include "rr_graph_fwd.h" #include "rr_graph_view.h" #include "rr_rc_data.h" #include "switchblock_types.h" @@ -46,6 +47,8 @@ #include "rr_types.h" #include "rr_node_indices.h" +#include "interposer_cut.h" + //#define VERBOSE //used for getting the exact count of each edge type and printing it to std out. @@ -1667,6 +1670,12 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder } } + std::vector interposer_edges = mark_interposer_cut_edges_for_removal(rr_graph, grid); + rr_graph_builder.remove_edges(interposer_edges); + + update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(rr_graph, grid, rr_graph_builder, sg_node_indices); + + 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); @@ -2118,6 +2127,7 @@ static void add_and_connect_non_3d_sg_links(RRGraphBuilder& rr_graph_builder, chan_loc.y, gather_chan_type, gather_wire.wire_switchpoint.wire); + VTR_ASSERT(gather_node.is_valid()); // 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); } @@ -2135,6 +2145,8 @@ static void add_and_connect_non_3d_sg_links(RRGraphBuilder& rr_graph_builder, chan_loc.y, scatter_chan_type, scatter_wire.wire_switchpoint.wire); + + VTR_ASSERT(scatter_node.is_valid()); // 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) diff --git a/vpr/src/route/rr_graph_generation/rr_graph.h b/vpr/src/route/rr_graph_generation/rr_graph.h index 4aca0d82b76..75b82851bf7 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.h +++ b/vpr/src/route/rr_graph_generation/rr_graph.h @@ -17,7 +17,7 @@ enum { RR_GRAPH_NO_WARN = 0x00, RR_GRAPH_WARN_FC_CLIPPED = 0x01, RR_GRAPH_WARN_CHAN_X_WIDTH_CHANGED = 0x02, - RR_GRAPH_WARN_CHAN_Y_WIDTH_CHANGED = 0x03 + RR_GRAPH_WARN_CHAN_Y_WIDTH_CHANGED = 0x04 }; void create_rr_graph(e_graph_type graph_type, 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 3932fefd1e6..ba1cb38d0eb 100644 --- a/vpr/src/route/rr_graph_generation/rr_node_indices.cpp +++ b/vpr/src/route/rr_graph_generation/rr_node_indices.cpp @@ -7,6 +7,8 @@ #include "physical_types.h" #include "physical_types_util.h" #include "rr_graph2.h" +#include "rr_graph_fwd.h" +#include "rr_node_types.h" #include "vpr_utils.h" /** @@ -496,111 +498,104 @@ bool verify_rr_node_indices(const DeviceGrid& grid, const t_rr_graph_storage& rr_nodes, bool is_flat) { std::unordered_map rr_node_counts; + for (t_physical_tile_loc tile_loc : grid.all_locations()) { + 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 || rr_type == e_rr_type::CHANZ) { + nodes_from_lookup = rr_graph.node_lookup().find_channel_nodes(tile_loc.layer_num, tile_loc.x, tile_loc.y, rr_type); + } else { + nodes_from_lookup = rr_graph.node_lookup().find_grid_nodes_at_all_sides(tile_loc.layer_num, tile_loc.x, tile_loc.y, rr_type); + } - 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 || rr_type == e_rr_type::CHANZ) { - 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]++; + 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) != 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 (l < rr_graph.node_layer_low(inode) && l > rr_graph.node_layer_high(inode)) { + if (tile_loc.layer_num < rr_graph.node_layer_low(inode) && tile_loc.layer_num > rr_graph.node_layer_high(inode)) { VPR_ERROR(VPR_ERROR_ROUTE, "RR node layer 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::CHANZ) { - VTR_ASSERT_MSG(rr_graph.node_xlow(inode) == rr_graph.node_xhigh(inode), "CHANZ should move only along layers"); - VTR_ASSERT_MSG(rr_graph.node_ylow(inode) == rr_graph.node_yhigh(inode), "CHANZ should move only along layers"); - - 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 (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_xlow(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 || rr_graph.node_type(inode) == e_rr_type::MUX) { - // 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, + 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 (tile_loc.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), + tile_loc.y, + describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); + } + + if (!rr_graph.x_in_node_range(tile_loc.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), + tile_loc.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 (tile_loc.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), + tile_loc.x, + describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); + } + + if (!rr_graph.y_in_node_range(tile_loc.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), + tile_loc.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::CHANZ) { + VTR_ASSERT_MSG(rr_graph.node_xlow(inode) == rr_graph.node_xhigh(inode), "CHANZ should move only along layers"); + VTR_ASSERT_MSG(rr_graph.node_ylow(inode) == rr_graph.node_yhigh(inode), "CHANZ should move only along layers"); + + if (tile_loc.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), + tile_loc.x, + describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); + } + + if (tile_loc.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_xlow(inode), + tile_loc.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 || rr_graph.node_type(inode) == e_rr_type::MUX) { + // Sources have co-ordinates covering the entire block they are in, but not sinks + if (!rr_graph.x_in_node_range(tile_loc.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), + tile_loc.x, + describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); + } + + if (!rr_graph.y_in_node_range(tile_loc.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), + tile_loc.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", @@ -616,10 +611,10 @@ bool verify_rr_node_indices(const DeviceGrid& grid, * 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, + 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", @@ -630,8 +625,6 @@ bool verify_rr_node_indices(const DeviceGrid& grid, * VTR_ASSERT(rr_node.side() == side); * } */ - } - } } } } @@ -648,6 +641,7 @@ static void check_rr_node_counts(const std::unordered_map& rr_nod const DeviceGrid& grid, const vtr::vector& rr_indexed_data, bool is_flat) { + 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(), From 25467890f98a59c0d22644ace400d43e0b539c49 Mon Sep 17 00:00:00 2001 From: Amir Poolad Date: Mon, 10 Nov 2025 14:48:04 -0500 Subject: [PATCH 02/21] Fix edge cutting --- .../rr_graph_generation/interposer_cut.cpp | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/vpr/src/route/rr_graph_generation/interposer_cut.cpp b/vpr/src/route/rr_graph_generation/interposer_cut.cpp index 02d6c5d86e8..f034131172e 100644 --- a/vpr/src/route/rr_graph_generation/interposer_cut.cpp +++ b/vpr/src/route/rr_graph_generation/interposer_cut.cpp @@ -14,19 +14,7 @@ #include "interposer_cut.h" -static bool should_cut_edge(int src_start_loc, int sink_start_loc, int cut_loc) { - int src_delta = src_start_loc - cut_loc; - int sink_delta = sink_start_loc - cut_loc; - - // Same sign means that both sink and source are on the same side of this cut - if ((src_delta < 0 && sink_delta < 0) || (src_delta >= 0 && sink_delta >= 0)) { - return false; - } else { - return true; - } -} - -static bool should_cut_node(int src_start_loc, int sink_start_loc, int cut_loc) { +static bool should_cut(int src_start_loc, int sink_start_loc, int cut_loc) { int src_delta = src_start_loc - cut_loc; int sink_delta = sink_start_loc - cut_loc; @@ -127,7 +115,7 @@ std::vector mark_interposer_cut_edges_for_removal(const RRGraphView& r int src_start_loc_y = node_ystart(rr_graph, src_node); int sink_start_loc_y = node_ystart(rr_graph, sink_node); - if (should_cut_edge(src_start_loc_y, sink_start_loc_y, cut_loc_y)) { + if (should_cut(src_start_loc_y, sink_start_loc_y, cut_loc_y)) { edges_to_be_removed.push_back(edge_id); } } @@ -136,7 +124,7 @@ std::vector mark_interposer_cut_edges_for_removal(const RRGraphView& r int src_start_loc_x = node_xstart(rr_graph, src_node); int sink_start_loc_x = node_xstart(rr_graph, sink_node); - if (should_cut_edge(src_start_loc_x, sink_start_loc_x, cut_loc_x)) { + if (should_cut(src_start_loc_x, sink_start_loc_x, cut_loc_x)) { edges_to_be_removed.push_back(edge_id); } } @@ -177,7 +165,7 @@ void update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(con continue; } - if (!should_cut_node(y_low, y_high, cut_loc_y)) { + if (!should_cut(y_low, y_high, cut_loc_y)) { continue; } From 21d5080d1cc9014f41f9a420d19971e1b1cca565 Mon Sep 17 00:00:00 2001 From: Amir Poolad Date: Tue, 11 Nov 2025 16:48:10 -0500 Subject: [PATCH 03/21] Fix integration with scatter-gather patterns --- .../rr_graph_generation/interposer_cut.cpp | 142 ++++++++++++------ .../route/rr_graph_generation/rr_graph.cpp | 12 +- 2 files changed, 108 insertions(+), 46 deletions(-) diff --git a/vpr/src/route/rr_graph_generation/interposer_cut.cpp b/vpr/src/route/rr_graph_generation/interposer_cut.cpp index f034131172e..1347730b1ec 100644 --- a/vpr/src/route/rr_graph_generation/interposer_cut.cpp +++ b/vpr/src/route/rr_graph_generation/interposer_cut.cpp @@ -133,59 +133,113 @@ std::vector mark_interposer_cut_edges_for_removal(const RRGraphView& r return edges_to_be_removed; } +static void cut_chan_y_node(RRNodeId node, int cut_loc_y, const RRGraphView& rr_graph, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup, const std::vector>& sg_node_indices) { + bool is_sg_node = std::ranges::binary_search(std::views::keys(sg_node_indices), node, [](RRNodeId l, RRNodeId r) {return size_t(l) < size_t(r);}); + if (is_sg_node) { + return; + } + + int x_high = rr_graph.node_xhigh(node); + int x_low = rr_graph.node_xlow(node); + + int y_high = rr_graph.node_yhigh(node); + int y_low = rr_graph.node_ylow(node); + + int layer = rr_graph.node_layer_low(node); + + int ptc_num = rr_graph.node_ptc_num(node); + + // No need to cut 1-length wires + if (y_high == y_low) { + return; + } + + if (!should_cut(y_low, y_high, cut_loc_y)) { + return; + } + + if (rr_graph.node_direction(node) == Direction::INC) { + // Anything above cut_loc_y shouldn't exist + rr_graph_builder.set_node_coordinates(node, x_low, y_low, x_high, cut_loc_y); + + // Do a loop from cut_loc_y to y_high and remove node from spatial lookup + for (int y_loc = cut_loc_y + 1; y_loc <= y_high; y_loc++) { + spatial_lookup.remove_node(node, layer, x_low, y_loc, e_rr_type::CHANY, ptc_num); + } + } else if (rr_graph.node_direction(node) == Direction::DEC) { + // Anything below cut_loc_y shouldn't exist + rr_graph_builder.set_node_coordinates(node, x_low, cut_loc_y + 1, x_high, y_high); + + // Do a loop from y_low to cut_loc_y and remove node from spatial lookup + for (int y_loc = y_low; y_loc <= cut_loc_y; y_loc++) { + spatial_lookup.remove_node(node, layer, x_low, y_loc, e_rr_type::CHANY, ptc_num); + } + } +} + +static void cut_chan_x_node(RRNodeId node, int cut_loc_x, const RRGraphView& rr_graph, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup, const std::vector>& sg_node_indices) { + bool is_sg_node = std::ranges::binary_search(std::views::keys(sg_node_indices), node, [](RRNodeId l, RRNodeId r) {return size_t(l) < size_t(r);}); + if (is_sg_node) { + return; + } + + int x_high = rr_graph.node_xhigh(node); + int x_low = rr_graph.node_xlow(node); + + int y_high = rr_graph.node_yhigh(node); + int y_low = rr_graph.node_ylow(node); + + int layer = rr_graph.node_layer_low(node); + + int ptc_num = rr_graph.node_ptc_num(node); + + // No need to cut 1-length wires + if (x_high == x_low) { + return; + } + + if (!should_cut(x_low, x_high, cut_loc_x)) { + return; + } + + if (rr_graph.node_direction(node) == Direction::INC) { + // Anything to the right of cut_loc_x shouldn't exist + rr_graph_builder.set_node_coordinates(node, x_low, y_low, cut_loc_x, y_high); + + // Do a loop from cut_loc_x to x_high and remove node from spatial lookup + for (int x_loc = cut_loc_x + 1; x_loc <= x_high; x_loc++) { + spatial_lookup.remove_node(node, layer, x_loc, y_low, e_rr_type::CHANX, ptc_num); + } + } else if (rr_graph.node_direction(node) == Direction::DEC) { + // Anything to the left of cut_loc_x shouldn't exist + rr_graph_builder.set_node_coordinates(node, cut_loc_x + 1, y_low, x_high, y_high); + + // Do a loop from x_low to cut_loc_x - 1 and remove node from spatial lookup + for (int x_loc = x_low; x_loc <= cut_loc_x; x_loc++) { + spatial_lookup.remove_node(node, layer, x_loc, y_low, e_rr_type::CHANX, ptc_num); + } + } +} + // TODO: workshop a better name void update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(const RRGraphView& rr_graph, const DeviceGrid& grid, RRGraphBuilder& rr_graph_builder, const std::vector>& sg_node_indices) { VTR_ASSERT(std::is_sorted(sg_node_indices.begin(), sg_node_indices.end())); - RRSpatialLookup& spatial_lookup = rr_graph_builder.node_lookup(); - size_t num_sg = 0; for (size_t layer = 0; layer < grid.get_num_layers(); layer++) { for (int cut_loc_y : grid.get_horizontal_interposer_cuts()[layer]) { for (size_t x_loc = 0; x_loc < grid.width(); x_loc++) { std::vector channel_nodes = spatial_lookup.find_channel_nodes(layer, x_loc, cut_loc_y, e_rr_type::CHANY); for (RRNodeId node : channel_nodes) { - - bool is_sg_node = std::ranges::binary_search(std::views::keys(sg_node_indices), node, [](RRNodeId l, RRNodeId r) {return size_t(l) < size_t(r);}); - if (is_sg_node) { - num_sg++; - continue; - } - - - int x_high = rr_graph.node_xhigh(node); - int x_low = rr_graph.node_xlow(node); - VTR_ASSERT(x_high == x_low); - int y_high = rr_graph.node_yhigh(node); - int y_low = rr_graph.node_ylow(node); - int ptc_num = rr_graph.node_ptc_num(node); - - - // No need to cut 1-length wires - if (y_high == y_low) { - continue; - } - - if (!should_cut(y_low, y_high, cut_loc_y)) { - continue; - } - - if (rr_graph.node_direction(node) == Direction::INC) { - // Anything above cut_loc_y shouldn't exist - rr_graph_builder.set_node_coordinates(node, x_low, y_low, x_high, cut_loc_y); - - // Do a loop from cut_loc_y to y_high and remove node from spatial lookup - for (int y_loc = cut_loc_y + 1; y_loc <= y_high; y_loc++) { - spatial_lookup.remove_node(node, layer, x_low, y_loc, e_rr_type::CHANY, ptc_num); - } - } else if (rr_graph.node_direction(node) == Direction::DEC) { - // Anything below cut_loc_y shouldn't exist - rr_graph_builder.set_node_coordinates(node, x_low, cut_loc_y + 1, x_high, y_high); - - // Do a loop from y_low to cut_loc_y and remove node from spatial lookup - for (int y_loc = y_low; y_loc <= cut_loc_y; y_loc++) { - spatial_lookup.remove_node(node, layer, x_low, y_loc, e_rr_type::CHANY, ptc_num); - } - } + cut_chan_y_node(node, cut_loc_y, rr_graph, rr_graph_builder, spatial_lookup, sg_node_indices); + } + } + } + + for (int cut_loc_x : grid.get_vertical_interposer_cuts()[layer]) { + for (size_t y_loc = 0; y_loc < grid.height(); y_loc++) { + std::vector channel_nodes = spatial_lookup.find_channel_nodes(layer, cut_loc_x, y_loc, e_rr_type::CHANX); + for (RRNodeId node : channel_nodes) { + cut_chan_x_node(node, cut_loc_x, rr_graph, rr_graph_builder, spatial_lookup, sg_node_indices); } } } diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index 91410189ac1..73d918ef6c8 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -2127,7 +2127,11 @@ static void add_and_connect_non_3d_sg_links(RRGraphBuilder& rr_graph_builder, chan_loc.y, gather_chan_type, gather_wire.wire_switchpoint.wire); - VTR_ASSERT(gather_node.is_valid()); + // TODO: Some of the nodes that the scatter-gather patterns want to connect to have been cut because they were crossing the die + // For now we're ignoring those, but a proper fix should be investigated. + if (gather_node == RRNodeId::INVALID()) { + continue; + } // 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); } @@ -2146,7 +2150,11 @@ static void add_and_connect_non_3d_sg_links(RRGraphBuilder& rr_graph_builder, scatter_chan_type, scatter_wire.wire_switchpoint.wire); - VTR_ASSERT(scatter_node.is_valid()); + // TODO: Some of the nodes that the scatter-gather patterns want to connect to have been cut because they were crossing the die + // For now we're ignoring those, but a proper fix should be investigated. + if (scatter_node == RRNodeId::INVALID()) { + continue; + } // 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) From 72e8933cbc8c9c09fc10ab344eb211d7eddc90d3 Mon Sep 17 00:00:00 2001 From: Amir Poolad Date: Wed, 12 Nov 2025 13:54:30 -0500 Subject: [PATCH 04/21] Add doxygen to interposer cut functions --- .../rr_graph_generation/interposer_cut.cpp | 81 ++++++++++++------- .../rr_graph_generation/interposer_cut.h | 13 +++ 2 files changed, 66 insertions(+), 28 deletions(-) diff --git a/vpr/src/route/rr_graph_generation/interposer_cut.cpp b/vpr/src/route/rr_graph_generation/interposer_cut.cpp index 1347730b1ec..be08167a263 100644 --- a/vpr/src/route/rr_graph_generation/interposer_cut.cpp +++ b/vpr/src/route/rr_graph_generation/interposer_cut.cpp @@ -14,9 +14,12 @@ #include "interposer_cut.h" -static bool should_cut(int src_start_loc, int sink_start_loc, int cut_loc) { - int src_delta = src_start_loc - cut_loc; - int sink_delta = sink_start_loc - cut_loc; +/** + * @brief Takes location of a source and a sink and determines wether it crosses cut_loc or not. For example, the interval (1, 4) is cut by 3, while it is not cut by 5 or 0. + */ +static bool should_cut(int src_loc, int sink_loc, int cut_loc) { + int src_delta = src_loc - cut_loc; + int sink_delta = sink_loc - cut_loc; // Same sign means that both sink and source are on the same side of this cut if ((src_delta <= 0 && sink_delta <= 0) || (src_delta > 0 && sink_delta > 0)) { @@ -26,6 +29,9 @@ static bool should_cut(int src_start_loc, int sink_start_loc, int cut_loc) { } } +/** + * @brief Calculates the starting x point of node based on it's directionality. + */ static short node_xstart(const RRGraphView& rr_graph, RRNodeId node) { // Return early for OPIN and IPIN types (Some BIDIR pins would trigger the assertion below) if (rr_graph.node_type(node) == e_rr_type::OPIN || rr_graph.node_type(node) == e_rr_type::IPIN) { @@ -57,6 +63,9 @@ static short node_xstart(const RRGraphView& rr_graph, RRNodeId node) { } } +/** + * @brief Calculates the starting y point of node based on it's directionality. + */ static short node_ystart(const RRGraphView& rr_graph, RRNodeId node) { // Return early for OPIN and IPIN types (Some BIDIR pins would trigger the assertion below) if (rr_graph.node_type(node) == e_rr_type::OPIN || rr_graph.node_type(node) == e_rr_type::IPIN) { @@ -133,11 +142,16 @@ std::vector mark_interposer_cut_edges_for_removal(const RRGraphView& r return edges_to_be_removed; } -static void cut_chan_y_node(RRNodeId node, int cut_loc_y, const RRGraphView& rr_graph, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup, const std::vector>& sg_node_indices) { - bool is_sg_node = std::ranges::binary_search(std::views::keys(sg_node_indices), node, [](RRNodeId l, RRNodeId r) {return size_t(l) < size_t(r);}); - if (is_sg_node) { - return; - } +/** + * @brief Update a CHANY node's bounding box in RRGraph and SpatialLookup entries if it crosses cut_loc_y + * + * @param node CHANY RR graph node that might cross the interposer cut line + * @param cut_loc_y Y location of horizontal interposer cut line + * @param sg_node_indices List of scatter-gather node IDs. We do not want to cut these nodes as they're allowed to cross an interposer cut line. + * @note This function is very similar to cut_chan_x_node. If you're modifying this you probably also want to modify that function too. + */ +static void cut_chan_y_node(RRNodeId node, int cut_loc_y, const RRGraphView& rr_graph, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup) { + VTR_ASSERT_SAFE(rr_graph.node_type(node) == e_rr_type::CHANY); int x_high = rr_graph.node_xhigh(node); int x_low = rr_graph.node_xlow(node); @@ -149,11 +163,6 @@ static void cut_chan_y_node(RRNodeId node, int cut_loc_y, const RRGraphView& rr_ int ptc_num = rr_graph.node_ptc_num(node); - // No need to cut 1-length wires - if (y_high == y_low) { - return; - } - if (!should_cut(y_low, y_high, cut_loc_y)) { return; } @@ -167,21 +176,28 @@ static void cut_chan_y_node(RRNodeId node, int cut_loc_y, const RRGraphView& rr_ spatial_lookup.remove_node(node, layer, x_low, y_loc, e_rr_type::CHANY, ptc_num); } } else if (rr_graph.node_direction(node) == Direction::DEC) { - // Anything below cut_loc_y shouldn't exist + // Anything below cut_loc_y (inclusive) shouldn't exist rr_graph_builder.set_node_coordinates(node, x_low, cut_loc_y + 1, x_high, y_high); // Do a loop from y_low to cut_loc_y and remove node from spatial lookup for (int y_loc = y_low; y_loc <= cut_loc_y; y_loc++) { spatial_lookup.remove_node(node, layer, x_low, y_loc, e_rr_type::CHANY, ptc_num); } + } else { + VTR_ASSERT_MSG(false, "Bidirectional routing is not supported for interposer architectures."); } } -static void cut_chan_x_node(RRNodeId node, int cut_loc_x, const RRGraphView& rr_graph, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup, const std::vector>& sg_node_indices) { - bool is_sg_node = std::ranges::binary_search(std::views::keys(sg_node_indices), node, [](RRNodeId l, RRNodeId r) {return size_t(l) < size_t(r);}); - if (is_sg_node) { - return; - } +/** + * @brief Update a CHANX node's bounding box in RRGraph and SpatialLookup entries if it crosses cut_loc_x + * + * @param node CHANX RR graph node that might cross the interposer cut line + * @param cut_loc_y X location of vertical interposer cut line + * @param sg_node_indices List of scatter-gather node IDs. We do not want to cut these nodes as they're allowed to cross an interposer cut line. + * @note This function is very similar to cut_chan_y_node. If you're modifying this you probably also want to modify that function too. + */ +static void cut_chan_x_node(RRNodeId node, int cut_loc_x, const RRGraphView& rr_graph, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup) { + VTR_ASSERT_SAFE(rr_graph.node_type(node) == e_rr_type::CHANX); int x_high = rr_graph.node_xhigh(node); int x_low = rr_graph.node_xlow(node); @@ -193,11 +209,6 @@ static void cut_chan_x_node(RRNodeId node, int cut_loc_x, const RRGraphView& rr_ int ptc_num = rr_graph.node_ptc_num(node); - // No need to cut 1-length wires - if (x_high == x_low) { - return; - } - if (!should_cut(x_low, x_high, cut_loc_x)) { return; } @@ -211,26 +222,35 @@ static void cut_chan_x_node(RRNodeId node, int cut_loc_x, const RRGraphView& rr_ spatial_lookup.remove_node(node, layer, x_loc, y_low, e_rr_type::CHANX, ptc_num); } } else if (rr_graph.node_direction(node) == Direction::DEC) { - // Anything to the left of cut_loc_x shouldn't exist + // Anything to the left of cut_loc_x (inclusive) shouldn't exist rr_graph_builder.set_node_coordinates(node, cut_loc_x + 1, y_low, x_high, y_high); // Do a loop from x_low to cut_loc_x - 1 and remove node from spatial lookup for (int x_loc = x_low; x_loc <= cut_loc_x; x_loc++) { spatial_lookup.remove_node(node, layer, x_loc, y_low, e_rr_type::CHANX, ptc_num); } + } else { + VTR_ASSERT_MSG(false, "Bidirectional routing is not supported for interposer architectures."); } } -// TODO: workshop a better name void update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(const RRGraphView& rr_graph, const DeviceGrid& grid, RRGraphBuilder& rr_graph_builder, const std::vector>& sg_node_indices) { + + constexpr auto node_indice_compare = [](RRNodeId l, RRNodeId r) noexcept { return size_t(l) < size_t(r); }; VTR_ASSERT(std::is_sorted(sg_node_indices.begin(), sg_node_indices.end())); + RRSpatialLookup& spatial_lookup = rr_graph_builder.node_lookup(); for (size_t layer = 0; layer < grid.get_num_layers(); layer++) { for (int cut_loc_y : grid.get_horizontal_interposer_cuts()[layer]) { for (size_t x_loc = 0; x_loc < grid.width(); x_loc++) { std::vector channel_nodes = spatial_lookup.find_channel_nodes(layer, x_loc, cut_loc_y, e_rr_type::CHANY); for (RRNodeId node : channel_nodes) { - cut_chan_y_node(node, cut_loc_y, rr_graph, rr_graph_builder, spatial_lookup, sg_node_indices); + bool is_sg_node = std::ranges::binary_search(std::views::keys(sg_node_indices), node, node_indice_compare); + if (is_sg_node) { + continue; + } + + cut_chan_y_node(node, cut_loc_y, rr_graph, rr_graph_builder, spatial_lookup); } } } @@ -239,7 +259,12 @@ void update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(con for (size_t y_loc = 0; y_loc < grid.height(); y_loc++) { std::vector channel_nodes = spatial_lookup.find_channel_nodes(layer, cut_loc_x, y_loc, e_rr_type::CHANX); for (RRNodeId node : channel_nodes) { - cut_chan_x_node(node, cut_loc_x, rr_graph, rr_graph_builder, spatial_lookup, sg_node_indices); + bool is_sg_node = std::ranges::binary_search(std::views::keys(sg_node_indices), node, node_indice_compare); + if (is_sg_node) { + continue; + } + + cut_chan_x_node(node, cut_loc_x, rr_graph, rr_graph_builder, spatial_lookup); } } } diff --git a/vpr/src/route/rr_graph_generation/interposer_cut.h b/vpr/src/route/rr_graph_generation/interposer_cut.h index 97d49c354e5..53ef25a7467 100644 --- a/vpr/src/route/rr_graph_generation/interposer_cut.h +++ b/vpr/src/route/rr_graph_generation/interposer_cut.h @@ -5,6 +5,19 @@ #include "rr_graph_view.h" #include "device_grid.h" +/** + * @brief Goes through all edges in the RR Graph and returns a list of the edges that cross an interposer cut line. + * + * @return std::vector List of all edges that cross an interposer cut line. + */ std::vector mark_interposer_cut_edges_for_removal(const RRGraphView& rr_graph, const DeviceGrid& grid); +/** + * @brief Shortens the channel nodes that cross an interposer cut line + * + * @param rr_graph RRGraphView, used to read the RR Graph. + * @param grid Device grid, used to access interposer cut locations. + * @param rr_graph_builder RRGraphBuilder, to modify the RRGraph. + * @param sg_node_indices list of scatter-gather node IDs. We do not want to cut these nodes as they're allowed to cross an interposer cut line. + */ void update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(const RRGraphView& rr_graph, const DeviceGrid& grid, RRGraphBuilder& rr_graph_builder, const std::vector>& sg_node_indices); \ No newline at end of file From bc9a40a459379fd94433b27da204aa7274e390b5 Mon Sep 17 00:00:00 2001 From: Amir Poolad Date: Wed, 12 Nov 2025 14:29:15 -0500 Subject: [PATCH 05/21] Fix some code duplication issues --- .../rr_graph_generation/interposer_cut.cpp | 126 +++++++++--------- 1 file changed, 61 insertions(+), 65 deletions(-) diff --git a/vpr/src/route/rr_graph_generation/interposer_cut.cpp b/vpr/src/route/rr_graph_generation/interposer_cut.cpp index be08167a263..f9d304b1959 100644 --- a/vpr/src/route/rr_graph_generation/interposer_cut.cpp +++ b/vpr/src/route/rr_graph_generation/interposer_cut.cpp @@ -4,6 +4,7 @@ #include #include "device_grid.h" +#include "interposer_types.h" #include "rr_graph_builder.h" #include "rr_graph_fwd.h" #include "rr_graph_view.h" @@ -143,31 +144,11 @@ std::vector mark_interposer_cut_edges_for_removal(const RRGraphView& r } /** - * @brief Update a CHANY node's bounding box in RRGraph and SpatialLookup entries if it crosses cut_loc_y - * - * @param node CHANY RR graph node that might cross the interposer cut line - * @param cut_loc_y Y location of horizontal interposer cut line - * @param sg_node_indices List of scatter-gather node IDs. We do not want to cut these nodes as they're allowed to cross an interposer cut line. - * @note This function is very similar to cut_chan_x_node. If you're modifying this you probably also want to modify that function too. - */ -static void cut_chan_y_node(RRNodeId node, int cut_loc_y, const RRGraphView& rr_graph, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup) { - VTR_ASSERT_SAFE(rr_graph.node_type(node) == e_rr_type::CHANY); - - int x_high = rr_graph.node_xhigh(node); - int x_low = rr_graph.node_xlow(node); - - int y_high = rr_graph.node_yhigh(node); - int y_low = rr_graph.node_ylow(node); - - int layer = rr_graph.node_layer_low(node); - - int ptc_num = rr_graph.node_ptc_num(node); - - if (!should_cut(y_low, y_high, cut_loc_y)) { - return; - } - - if (rr_graph.node_direction(node) == Direction::INC) { + * @brief Update a CHANY node's bounding box in RRGraph and SpatialLookup entries. This function assumes that the channel node actually crosses the cut location and might not function correctly otherwise. + * This is a low level function, you should use cut_channel_node that wraps this up in a nicer API. + */ +static void cut_chan_y_node(RRNodeId node, int x_low, int y_low, int x_high, int y_high, int layer, int ptc_num, int cut_loc_y, Direction node_direction, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup) { + if (node_direction == Direction::INC) { // Anything above cut_loc_y shouldn't exist rr_graph_builder.set_node_coordinates(node, x_low, y_low, x_high, cut_loc_y); @@ -175,7 +156,7 @@ static void cut_chan_y_node(RRNodeId node, int cut_loc_y, const RRGraphView& rr_ for (int y_loc = cut_loc_y + 1; y_loc <= y_high; y_loc++) { spatial_lookup.remove_node(node, layer, x_low, y_loc, e_rr_type::CHANY, ptc_num); } - } else if (rr_graph.node_direction(node) == Direction::DEC) { + } else if (node_direction == Direction::DEC) { // Anything below cut_loc_y (inclusive) shouldn't exist rr_graph_builder.set_node_coordinates(node, x_low, cut_loc_y + 1, x_high, y_high); @@ -189,31 +170,11 @@ static void cut_chan_y_node(RRNodeId node, int cut_loc_y, const RRGraphView& rr_ } /** - * @brief Update a CHANX node's bounding box in RRGraph and SpatialLookup entries if it crosses cut_loc_x - * - * @param node CHANX RR graph node that might cross the interposer cut line - * @param cut_loc_y X location of vertical interposer cut line - * @param sg_node_indices List of scatter-gather node IDs. We do not want to cut these nodes as they're allowed to cross an interposer cut line. - * @note This function is very similar to cut_chan_y_node. If you're modifying this you probably also want to modify that function too. - */ -static void cut_chan_x_node(RRNodeId node, int cut_loc_x, const RRGraphView& rr_graph, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup) { - VTR_ASSERT_SAFE(rr_graph.node_type(node) == e_rr_type::CHANX); - - int x_high = rr_graph.node_xhigh(node); - int x_low = rr_graph.node_xlow(node); - - int y_high = rr_graph.node_yhigh(node); - int y_low = rr_graph.node_ylow(node); - - int layer = rr_graph.node_layer_low(node); - - int ptc_num = rr_graph.node_ptc_num(node); - - if (!should_cut(x_low, x_high, cut_loc_x)) { - return; - } - - if (rr_graph.node_direction(node) == Direction::INC) { + * @brief Update a CHANX node's bounding box in RRGraph and SpatialLookup entries. This function assumes that the channel node actually crosses the cut location and might not function correctly otherwise. + * This is a low level function, you should use cut_channel_node that wraps this up in a nicer API. + */ +static void cut_chan_x_node(RRNodeId node, int x_low, int y_low, int x_high, int y_high, int layer, int ptc_num, int cut_loc_x, Direction node_direction, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup) { + if (node_direction == Direction::INC) { // Anything to the right of cut_loc_x shouldn't exist rr_graph_builder.set_node_coordinates(node, x_low, y_low, cut_loc_x, y_high); @@ -221,7 +182,7 @@ static void cut_chan_x_node(RRNodeId node, int cut_loc_x, const RRGraphView& rr_ for (int x_loc = cut_loc_x + 1; x_loc <= x_high; x_loc++) { spatial_lookup.remove_node(node, layer, x_loc, y_low, e_rr_type::CHANX, ptc_num); } - } else if (rr_graph.node_direction(node) == Direction::DEC) { + } else if (node_direction == Direction::DEC) { // Anything to the left of cut_loc_x (inclusive) shouldn't exist rr_graph_builder.set_node_coordinates(node, cut_loc_x + 1, y_low, x_high, y_high); @@ -234,9 +195,54 @@ static void cut_chan_x_node(RRNodeId node, int cut_loc_x, const RRGraphView& rr_ } } +/** + * @brief Update a CHANX or CHANY node's bounding box in RRGraph and SpatialLookup entries if it crosses cut_loc + * + * @param node Channel segment RR graph node that might cross the interposer cut line + * @param cut_loc location of vertical interposer cut line + * @param interposer_cut_type Type of the interposer cut line (Horizontal or vertical) + * @param sg_node_indices Sorted list of scatter-gather node IDs. We do not want to cut these nodes as they're allowed to cross an interposer cut line. + * @note This function is very similar to cut_chan_y_node. If you're modifying this you probably also want to modify that function too. + */ +static void cut_channel_node(RRNodeId node, int cut_loc, e_interposer_cut_type interposer_cut_type, const RRGraphView& rr_graph, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup, const std::vector>& sg_node_indices) { + constexpr auto node_indice_compare = [](RRNodeId l, RRNodeId r) noexcept { return size_t(l) < size_t(r); }; + bool is_sg_node = std::ranges::binary_search(std::views::keys(sg_node_indices), node, node_indice_compare); + if (is_sg_node) { + return; + } + + int x_high = rr_graph.node_xhigh(node); + int x_low = rr_graph.node_xlow(node); + + int y_high = rr_graph.node_yhigh(node); + int y_low = rr_graph.node_ylow(node); + + int layer = rr_graph.node_layer_low(node); + int ptc_num = rr_graph.node_ptc_num(node); + Direction node_direction = rr_graph.node_direction(node); + e_rr_type node_type = rr_graph.node_type(node); + + if (interposer_cut_type == e_interposer_cut_type::HORZ) { + VTR_ASSERT(node_type == e_rr_type::CHANY); + if (!should_cut(y_low, y_high, cut_loc)) { + return; + } + } else if (interposer_cut_type == e_interposer_cut_type::VERT) { + VTR_ASSERT(node_type == e_rr_type::CHANX); + if (!should_cut(x_low, x_high, cut_loc)) { + return; + } + } + + if (interposer_cut_type == e_interposer_cut_type::HORZ) { + cut_chan_y_node(node, x_low, y_low, x_high, y_high, layer, ptc_num, cut_loc, node_direction, rr_graph_builder, spatial_lookup); + } else if (interposer_cut_type == e_interposer_cut_type::VERT) { + cut_chan_x_node(node, x_low, y_low, x_high, y_high, layer, ptc_num, cut_loc, node_direction, rr_graph_builder, spatial_lookup); + } +} + void update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(const RRGraphView& rr_graph, const DeviceGrid& grid, RRGraphBuilder& rr_graph_builder, const std::vector>& sg_node_indices) { - constexpr auto node_indice_compare = [](RRNodeId l, RRNodeId r) noexcept { return size_t(l) < size_t(r); }; VTR_ASSERT(std::is_sorted(sg_node_indices.begin(), sg_node_indices.end())); RRSpatialLookup& spatial_lookup = rr_graph_builder.node_lookup(); @@ -245,12 +251,7 @@ void update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(con for (size_t x_loc = 0; x_loc < grid.width(); x_loc++) { std::vector channel_nodes = spatial_lookup.find_channel_nodes(layer, x_loc, cut_loc_y, e_rr_type::CHANY); for (RRNodeId node : channel_nodes) { - bool is_sg_node = std::ranges::binary_search(std::views::keys(sg_node_indices), node, node_indice_compare); - if (is_sg_node) { - continue; - } - - cut_chan_y_node(node, cut_loc_y, rr_graph, rr_graph_builder, spatial_lookup); + cut_channel_node(node, cut_loc_y, e_interposer_cut_type::HORZ, rr_graph, rr_graph_builder, spatial_lookup, sg_node_indices); } } } @@ -259,12 +260,7 @@ void update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(con for (size_t y_loc = 0; y_loc < grid.height(); y_loc++) { std::vector channel_nodes = spatial_lookup.find_channel_nodes(layer, cut_loc_x, y_loc, e_rr_type::CHANX); for (RRNodeId node : channel_nodes) { - bool is_sg_node = std::ranges::binary_search(std::views::keys(sg_node_indices), node, node_indice_compare); - if (is_sg_node) { - continue; - } - - cut_chan_x_node(node, cut_loc_x, rr_graph, rr_graph_builder, spatial_lookup); + cut_channel_node(node, cut_loc_x, e_interposer_cut_type::VERT, rr_graph, rr_graph_builder, spatial_lookup, sg_node_indices); } } } From b6f592a9afb5210d3fa73297814083856bed2b52 Mon Sep 17 00:00:00 2001 From: Amir Poolad Date: Wed, 12 Nov 2025 15:01:21 -0500 Subject: [PATCH 06/21] Remove experimental interposer status from documentation --- doc/src/arch/reference.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/src/arch/reference.rst b/doc/src/arch/reference.rst index 5322fe473b9..ef349c6fad2 100644 --- a/doc/src/arch/reference.rst +++ b/doc/src/arch/reference.rst @@ -589,7 +589,6 @@ Grid Layout Example .. note:: Exactly one of the ``x`` or ``y`` attributes must be specified. - .. note:: Interposers are experimental and are currently not supported by VPR and using the related tags will not actually result in any changes to the flow. Defines an interposer cut for modelling 2.5D interposer-based architectures. An interposer cut will cut all connections at location 'loc' along the axis 'dim' Leaving the two sides completely unconnected. To reconnect the two sides, this tag can have multiple tags as children to specify the connection between the two sides. @@ -2751,7 +2750,7 @@ The number of any additional wires or muxes created by scatter-gather specificat Overview of how scatter-gather patterns work. First, connections from a switchblock location are selected according to the specification. These selected connection are then muxed and passed through the scatter-gather node, which is typically a wire segment. The scatter-gather node then fans out or scatters in another switchblock location. -.. note:: Scatter-Gather patterns are only supported for 3D architectures where the scatter-gather links are unidirectional. They are not currently supported in 2D architectures or with bidirectional sg_links. +.. note:: Scatter-Gather patterns are only supported for 3D architectures where the scatter-gather links are uni-directional and uni-directional 2D architectures. Bidirectional sg_links are not currently supported. When instantiated, a scatter-gather pattern gathers connections from a switchblock and passes the connection through a multiplexer and the scatter-gather node which is typically a wire segment, then scatters or fans out somewhere else in the device. These patterns can be used to define 3D switchblocks. An example is shown below: From 349d67272e9eaa03788c23dd64564a6a9639e556 Mon Sep 17 00:00:00 2001 From: Amir Poolad Date: Wed, 12 Nov 2025 15:05:21 -0500 Subject: [PATCH 07/21] Fix issue with interposers and 3D connection blocks --- vpr/src/route/rr_graph_generation/interposer_cut.cpp | 7 +++++-- vpr/src/route/rr_graph_generation/rr_graph.cpp | 9 +++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/vpr/src/route/rr_graph_generation/interposer_cut.cpp b/vpr/src/route/rr_graph_generation/interposer_cut.cpp index f9d304b1959..8237c9a7d84 100644 --- a/vpr/src/route/rr_graph_generation/interposer_cut.cpp +++ b/vpr/src/route/rr_graph_generation/interposer_cut.cpp @@ -110,12 +110,15 @@ std::vector mark_interposer_cut_edges_for_removal(const RRGraphView& r VTR_LOG("HI\n"); } - // TODO: ignoring chanz nodes for now + // TODO: ignoring ChanZ nodes for now if (rr_graph.node_type(src_node) == e_rr_type::CHANZ || rr_graph.node_type(sink_node) == e_rr_type::CHANZ) { continue; } - VTR_ASSERT(rr_graph.node_layer_low(src_node) == rr_graph.node_layer_low(sink_node)); + // Currently 3D connection block edges cross layers. We don't want to cut these edges. + if (rr_graph.node_layer_low(src_node) != rr_graph.node_layer_low(sink_node)) { + continue; + } VTR_ASSERT(rr_graph.node_layer_low(src_node) == rr_graph.node_layer_high(src_node)); VTR_ASSERT(rr_graph.node_layer_low(sink_node) == rr_graph.node_layer_high(sink_node)); diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index 73d918ef6c8..f654475ba65 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -1670,11 +1670,12 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder } } - std::vector interposer_edges = mark_interposer_cut_edges_for_removal(rr_graph, grid); - rr_graph_builder.remove_edges(interposer_edges); - - update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(rr_graph, grid, rr_graph_builder, sg_node_indices); + if (!grid.get_horizontal_interposer_cuts().empty() || !grid.get_vertical_interposer_cuts().empty()) { + std::vector interposer_edges = mark_interposer_cut_edges_for_removal(rr_graph, grid); + rr_graph_builder.remove_edges(interposer_edges); + update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(rr_graph, grid, rr_graph_builder, sg_node_indices); + } 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); From e659e23e2785a605a26bd87d24943e915030c46d Mon Sep 17 00:00:00 2001 From: Amir Poolad Date: Thu, 13 Nov 2025 10:52:29 -0500 Subject: [PATCH 08/21] Address PR comments --- libs/librrgraph/src/base/rr_graph_builder.h | 9 +++++- libs/librrgraph/src/base/rr_graph_storage.cpp | 11 +++++++ libs/librrgraph/src/base/rr_graph_storage.h | 12 ++++++- libs/librrgraph/src/base/rr_graph_view.h | 4 +++ .../rr_graph_generation/interposer_cut.cpp | 31 ++++++++----------- .../rr_graph_generation/rr_node_indices.cpp | 6 ++-- 6 files changed, 50 insertions(+), 23 deletions(-) diff --git a/libs/librrgraph/src/base/rr_graph_builder.h b/libs/librrgraph/src/base/rr_graph_builder.h index 3bd10e749f3..3ba04b3dc02 100644 --- a/libs/librrgraph/src/base/rr_graph_builder.h +++ b/libs/librrgraph/src/base/rr_graph_builder.h @@ -351,7 +351,14 @@ class RRGraphBuilder { inline void alloc_and_load_edges(const t_rr_edge_info_set* rr_edges_to_create) { node_storage_.alloc_and_load_edges(rr_edges_to_create); } - + + /** @brief Removes a given list of RREdgeIds for the RR Graph. + * This method does not preserve the order of edges. If you're + * calling it after partition_edges has been called, you need + * to call it again. + * + * @param rr_edges_to_remove list of RREdgeIds to be removed + */ inline void remove_edges(std::vector& rr_edges_to_remove) { node_storage_.remove_edges(rr_edges_to_remove); } diff --git a/libs/librrgraph/src/base/rr_graph_storage.cpp b/libs/librrgraph/src/base/rr_graph_storage.cpp index ace814b04e5..23de8a52b26 100644 --- a/libs/librrgraph/src/base/rr_graph_storage.cpp +++ b/libs/librrgraph/src/base/rr_graph_storage.cpp @@ -62,21 +62,32 @@ void t_rr_graph_storage::alloc_and_load_edges(const t_rr_edge_info_set* rr_edges void t_rr_graph_storage::remove_edges(std::vector& rr_edges_to_remove) { size_t starting_edge_count = edge_dest_node_.size(); + // Sort and make sure all edge indices are unique vtr::uniquify(rr_edges_to_remove); + VTR_ASSERT_SAFE(std::is_sorted(rr_edges_to_remove.begin(), rr_edges_to_remove.end())); + // Index of the last edge size_t edge_list_end = edge_dest_node_.size() - 1; + + // Iterate backwards through the list of indices we want to remove. for (auto it = rr_edges_to_remove.rbegin(); it != rr_edges_to_remove.rend(); ++it) { RREdgeId erase_idx = *it; + // Copy what's at the end of the list to the index we wanted to remove edge_dest_node_[erase_idx] = edge_dest_node_[RREdgeId(edge_list_end)]; edge_src_node_[erase_idx] = edge_src_node_[RREdgeId(edge_list_end)]; edge_switch_[erase_idx] = edge_switch_[RREdgeId(edge_list_end)]; edge_remapped_[erase_idx] = edge_remapped_[RREdgeId(edge_list_end)]; + // At this point we have no copies of what was at erase_idx and two copies of + // what was at the end of the list. If we make the list one element shorter, + // we end up with a list that has removed the element at erase_idx. edge_list_end--; } + // We have a new index to the end of the list, call erase on the elements past that index + // to update the std::vector and shrink the actual data structures. edge_dest_node_.erase(edge_dest_node_.begin() + edge_list_end + 1, edge_dest_node_.end()); edge_src_node_.erase(edge_src_node_.begin() + edge_list_end + 1, edge_src_node_.end()); edge_switch_.erase(edge_switch_.begin() + edge_list_end + 1, edge_switch_.end()); diff --git a/libs/librrgraph/src/base/rr_graph_storage.h b/libs/librrgraph/src/base/rr_graph_storage.h index ba4882a60f3..7d06795f498 100644 --- a/libs/librrgraph/src/base/rr_graph_storage.h +++ b/libs/librrgraph/src/base/rr_graph_storage.h @@ -400,7 +400,10 @@ class t_rr_graph_storage { return vtr::StrongIdRange(first_edge(id), last_edge(id)); } - + /** @brief Returns a range of all edges in the RR Graph. + * This method does not depend on the edges begin correctly + * sorted and can be used before partition_edges is called. + */ inline vtr::StrongIdRange all_edges() const { return vtr::StrongIdRange(RREdgeId(0), RREdgeId(edge_src_node_.size())); } @@ -781,6 +784,13 @@ class t_rr_graph_storage { /** @brief Adds a batch of edges.*/ void alloc_and_load_edges(const t_rr_edge_info_set* rr_edges_to_create); + /** @brief Removes a given list of RREdgeIds for the RR Graph. + * This method does not preserve the order of edges. If you're + * calling it after partition_edges has been called, you need + * to call it again. + * + * @param rr_edges_to_remove list of RREdgeIds to be removed + */ void remove_edges(std::vector& rr_edges_to_remove); /* Edge finalization methods */ diff --git a/libs/librrgraph/src/base/rr_graph_view.h b/libs/librrgraph/src/base/rr_graph_view.h index 8f9d82a0b6f..91ccc9fc2ee 100644 --- a/libs/librrgraph/src/base/rr_graph_view.h +++ b/libs/librrgraph/src/base/rr_graph_view.h @@ -594,6 +594,10 @@ class RRGraphView { return vtr::make_range(edge_idx_iterator(0), edge_idx_iterator(num_edges(id))); } + /** @brief Returns a range of all edges in the RR Graph. + * This method does not depend on the edges begin correctly + * sorted and can be used before partition_edges is called. + */ inline vtr::StrongIdRange all_edges() const { return node_storage_.all_edges(); } diff --git a/vpr/src/route/rr_graph_generation/interposer_cut.cpp b/vpr/src/route/rr_graph_generation/interposer_cut.cpp index 8237c9a7d84..1ed58cc8d5b 100644 --- a/vpr/src/route/rr_graph_generation/interposer_cut.cpp +++ b/vpr/src/route/rr_graph_generation/interposer_cut.cpp @@ -10,8 +10,8 @@ #include "rr_graph_view.h" #include "rr_node_types.h" #include "rr_spatial_lookup.h" +#include "vpr_error.h" #include "vtr_assert.h" -#include "vtr_log.h" #include "interposer_cut.h" @@ -43,23 +43,20 @@ static short node_xstart(const RRGraphView& rr_graph, RRNodeId node) { switch (rr_graph.node_direction(node)) { case Direction::DEC: return rr_graph.node_xhigh(node); - break; case Direction::INC: return rr_graph.node_xlow(node); - break; case Direction::NONE: VTR_ASSERT(rr_graph.node_xlow(node) == rr_graph.node_xhigh(node)); return (rr_graph.node_xlow(node)); - break; case Direction::BIDIR: - VTR_ASSERT_MSG(false, "Bidir node has no starting point"); + VPR_FATAL_ERROR(VPR_ERROR_ROUTE, "Bidir node has no starting point."); break; default: - VTR_ASSERT(false); + VPR_FATAL_ERROR(VPR_ERROR_ROUTE, "Invalid RR node direction."); break; } } @@ -76,23 +73,20 @@ static short node_ystart(const RRGraphView& rr_graph, RRNodeId node) { switch (rr_graph.node_direction(node)) { case Direction::DEC: return rr_graph.node_yhigh(node); - break; case Direction::INC: return rr_graph.node_ylow(node); - break; case Direction::NONE: VTR_ASSERT(rr_graph.node_ylow(node) == rr_graph.node_yhigh(node)); return (rr_graph.node_ylow(node)); - break; case Direction::BIDIR: - VTR_ASSERT_MSG(false, "Bidir node has no starting point"); + VPR_FATAL_ERROR(VPR_ERROR_ROUTE, "Bidir node has no starting point."); break; default: - VTR_ASSERT(false); + VPR_FATAL_ERROR(VPR_ERROR_ROUTE, "Invalid RR node direction."); break; } } @@ -106,10 +100,6 @@ std::vector mark_interposer_cut_edges_for_removal(const RRGraphView& r RRNodeId src_node = rr_graph.edge_src_node(edge_id); RRNodeId sink_node = rr_graph.edge_sink_node(edge_id); - if (src_node == RRNodeId(5866) && sink_node == RRNodeId(5604)) { - VTR_LOG("HI\n"); - } - // TODO: ignoring ChanZ nodes for now if (rr_graph.node_type(src_node) == e_rr_type::CHANZ || rr_graph.node_type(sink_node) == e_rr_type::CHANZ) { continue; @@ -147,7 +137,10 @@ std::vector mark_interposer_cut_edges_for_removal(const RRGraphView& r } /** - * @brief Update a CHANY node's bounding box in RRGraph and SpatialLookup entries. This function assumes that the channel node actually crosses the cut location and might not function correctly otherwise. + * @brief Update a CHANY node's bounding box in RRGraph and SpatialLookup entries. + * This function assumes that the channel node actually crosses the cut location and + * might not function correctly otherwise. + * * This is a low level function, you should use cut_channel_node that wraps this up in a nicer API. */ static void cut_chan_y_node(RRNodeId node, int x_low, int y_low, int x_high, int y_high, int layer, int ptc_num, int cut_loc_y, Direction node_direction, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup) { @@ -173,7 +166,10 @@ static void cut_chan_y_node(RRNodeId node, int x_low, int y_low, int x_high, int } /** - * @brief Update a CHANX node's bounding box in RRGraph and SpatialLookup entries. This function assumes that the channel node actually crosses the cut location and might not function correctly otherwise. + * @brief Update a CHANX node's bounding box in RRGraph and SpatialLookup entries. + * This function assumes that the channel node actually crosses the cut location and + * might not function correctly otherwise. + * * This is a low level function, you should use cut_channel_node that wraps this up in a nicer API. */ static void cut_chan_x_node(RRNodeId node, int x_low, int y_low, int x_high, int y_high, int layer, int ptc_num, int cut_loc_x, Direction node_direction, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup) { @@ -205,7 +201,6 @@ static void cut_chan_x_node(RRNodeId node, int x_low, int y_low, int x_high, int * @param cut_loc location of vertical interposer cut line * @param interposer_cut_type Type of the interposer cut line (Horizontal or vertical) * @param sg_node_indices Sorted list of scatter-gather node IDs. We do not want to cut these nodes as they're allowed to cross an interposer cut line. - * @note This function is very similar to cut_chan_y_node. If you're modifying this you probably also want to modify that function too. */ static void cut_channel_node(RRNodeId node, int cut_loc, e_interposer_cut_type interposer_cut_type, const RRGraphView& rr_graph, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup, const std::vector>& sg_node_indices) { constexpr auto node_indice_compare = [](RRNodeId l, RRNodeId r) noexcept { return size_t(l) < size_t(r); }; 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 ba1cb38d0eb..696f2d08e55 100644 --- a/vpr/src/route/rr_graph_generation/rr_node_indices.cpp +++ b/vpr/src/route/rr_graph_generation/rr_node_indices.cpp @@ -86,7 +86,7 @@ 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 (const t_physical_tile_loc grid_loc : grid.all_locations()) { + for (const t_physical_tile_loc& grid_loc : grid.all_locations()) { //Process each block from its root location if (grid.is_root_location(grid_loc)) { t_physical_tile_type_ptr physical_type = grid.get_physical_type(grid_loc); @@ -458,7 +458,7 @@ void alloc_and_load_intra_cluster_rr_node_indices(RRGraphBuilder& rr_graph_build const vtr::vector>& pin_chains_num, int* index) { - for (const t_physical_tile_loc grid_loc : grid.all_locations()) { + for (const t_physical_tile_loc& grid_loc : grid.all_locations()) { // Process each block from its root location if (grid.is_root_location(grid_loc)) { @@ -498,7 +498,7 @@ bool verify_rr_node_indices(const DeviceGrid& grid, const t_rr_graph_storage& rr_nodes, bool is_flat) { std::unordered_map rr_node_counts; - for (t_physical_tile_loc tile_loc : grid.all_locations()) { + for (const t_physical_tile_loc& tile_loc : grid.all_locations()) { for (e_rr_type rr_type : RR_TYPES) { // Get the list of nodes at a specific location (x, y) std::vector nodes_from_lookup; From e9876b39cfabcf3db8a00faacedad8dc9802618a Mon Sep 17 00:00:00 2001 From: Amir Poolad Date: Thu, 13 Nov 2025 10:56:13 -0500 Subject: [PATCH 09/21] Change RR Graph warning enum to be clearer This commit makes the bit mask much more obvious that it should be one-hot encoded. --- vpr/src/route/rr_graph_generation/rr_graph.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/vpr/src/route/rr_graph_generation/rr_graph.h b/vpr/src/route/rr_graph_generation/rr_graph.h index 75b82851bf7..fd4fefdc1e3 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.h +++ b/vpr/src/route/rr_graph_generation/rr_graph.h @@ -11,13 +11,15 @@ #include "rr_graph_type.h" #include "clb2clb_directs.h" -/* Warnings about the routing graph that can be returned. - * This is to avoid output messages during a value sweep */ +/** @brief Warnings about the routing graph that can be returned. + * This is to avoid output messages during a value sweep. + * @note This enum is used as a bitmask and should be one-hot encoded. + */ enum { RR_GRAPH_NO_WARN = 0x00, - RR_GRAPH_WARN_FC_CLIPPED = 0x01, - RR_GRAPH_WARN_CHAN_X_WIDTH_CHANGED = 0x02, - RR_GRAPH_WARN_CHAN_Y_WIDTH_CHANGED = 0x04 + RR_GRAPH_WARN_FC_CLIPPED = 0x01 << 0, + RR_GRAPH_WARN_CHAN_X_WIDTH_CHANGED = 0x01 << 1, + RR_GRAPH_WARN_CHAN_Y_WIDTH_CHANGED = 0x01 << 2 }; void create_rr_graph(e_graph_type graph_type, From 2d6de4feb997676e5308bb1611b58960594784af Mon Sep 17 00:00:00 2001 From: Amir Poolad Date: Mon, 17 Nov 2025 13:36:20 -0500 Subject: [PATCH 10/21] Address PR comments on RR Graph changes --- doc/src/arch/reference.rst | 2 +- libs/librrgraph/src/base/rr_graph_storage.cpp | 2 + libs/librrgraph/src/base/rr_graph_view.h | 2 + .../rr_graph_generation/interposer_cut.cpp | 12 ++-- .../rr_graph_generation/interposer_cut.h | 2 +- .../route/rr_graph_generation/rr_graph.cpp | 6 +- .../rr_graph_generation/rr_node_indices.cpp | 62 +++++++++---------- 7 files changed, 47 insertions(+), 41 deletions(-) diff --git a/doc/src/arch/reference.rst b/doc/src/arch/reference.rst index ef349c6fad2..9ef24a8df97 100644 --- a/doc/src/arch/reference.rst +++ b/doc/src/arch/reference.rst @@ -2750,7 +2750,7 @@ The number of any additional wires or muxes created by scatter-gather specificat Overview of how scatter-gather patterns work. First, connections from a switchblock location are selected according to the specification. These selected connection are then muxed and passed through the scatter-gather node, which is typically a wire segment. The scatter-gather node then fans out or scatters in another switchblock location. -.. note:: Scatter-Gather patterns are only supported for 3D architectures where the scatter-gather links are uni-directional and uni-directional 2D architectures. Bidirectional sg_links are not currently supported. +.. note:: Scatter-Gather patterns are only supported for uni-directional 3D and uni-directional 2D architectures. Bidirectional sg_links are not currently supported. When instantiated, a scatter-gather pattern gathers connections from a switchblock and passes the connection through a multiplexer and the scatter-gather node which is typically a wire segment, then scatters or fans out somewhere else in the device. These patterns can be used to define 3D switchblocks. An example is shown below: diff --git a/libs/librrgraph/src/base/rr_graph_storage.cpp b/libs/librrgraph/src/base/rr_graph_storage.cpp index 23de8a52b26..683800b958f 100644 --- a/libs/librrgraph/src/base/rr_graph_storage.cpp +++ b/libs/librrgraph/src/base/rr_graph_storage.cpp @@ -60,6 +60,8 @@ void t_rr_graph_storage::alloc_and_load_edges(const t_rr_edge_info_set* rr_edges } void t_rr_graph_storage::remove_edges(std::vector& rr_edges_to_remove) { + VTR_ASSERT(!edges_read_); + size_t starting_edge_count = edge_dest_node_.size(); // Sort and make sure all edge indices are unique diff --git a/libs/librrgraph/src/base/rr_graph_view.h b/libs/librrgraph/src/base/rr_graph_view.h index 91ccc9fc2ee..b3e9a7cae13 100644 --- a/libs/librrgraph/src/base/rr_graph_view.h +++ b/libs/librrgraph/src/base/rr_graph_view.h @@ -589,6 +589,8 @@ class RRGraphView { * for (t_edge_size edge : rr_graph.edges(node)) { * // Do something with the edge * } + * + * @note Iterating on the range returned by this function will not give you an RREdgeId, but instead gives you the index among a node's outgoing edges */ inline edge_idx_range edges(const RRNodeId& id) const { return vtr::make_range(edge_idx_iterator(0), edge_idx_iterator(num_edges(id))); diff --git a/vpr/src/route/rr_graph_generation/interposer_cut.cpp b/vpr/src/route/rr_graph_generation/interposer_cut.cpp index 1ed58cc8d5b..60840ab6dca 100644 --- a/vpr/src/route/rr_graph_generation/interposer_cut.cpp +++ b/vpr/src/route/rr_graph_generation/interposer_cut.cpp @@ -137,12 +137,12 @@ std::vector mark_interposer_cut_edges_for_removal(const RRGraphView& r } /** - * @brief Update a CHANY node's bounding box in RRGraph and SpatialLookup entries. - * This function assumes that the channel node actually crosses the cut location and - * might not function correctly otherwise. - * - * This is a low level function, you should use cut_channel_node that wraps this up in a nicer API. - */ + * @brief Update a CHANY node's bounding box in RRGraph and SpatialLookup entries. + * This function assumes that the channel node actually crosses the cut location and + * might not function correctly otherwise. + * + * This is a low level function, you should use cut_channel_node that wraps this up in a nicer API. + */ static void cut_chan_y_node(RRNodeId node, int x_low, int y_low, int x_high, int y_high, int layer, int ptc_num, int cut_loc_y, Direction node_direction, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup) { if (node_direction == Direction::INC) { // Anything above cut_loc_y shouldn't exist diff --git a/vpr/src/route/rr_graph_generation/interposer_cut.h b/vpr/src/route/rr_graph_generation/interposer_cut.h index 53ef25a7467..1db110db992 100644 --- a/vpr/src/route/rr_graph_generation/interposer_cut.h +++ b/vpr/src/route/rr_graph_generation/interposer_cut.h @@ -20,4 +20,4 @@ std::vector mark_interposer_cut_edges_for_removal(const RRGraphView& r * @param rr_graph_builder RRGraphBuilder, to modify the RRGraph. * @param sg_node_indices list of scatter-gather node IDs. We do not want to cut these nodes as they're allowed to cross an interposer cut line. */ -void update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(const RRGraphView& rr_graph, const DeviceGrid& grid, RRGraphBuilder& rr_graph_builder, const std::vector>& sg_node_indices); \ No newline at end of file +void update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(const RRGraphView& rr_graph, const DeviceGrid& grid, RRGraphBuilder& rr_graph_builder, const std::vector>& sg_node_indices); diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index f654475ba65..c51164765bc 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -1669,14 +1669,16 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder } } } - + + // If there are any interposer cuts, remove the edges and shorten the wires that cross interposer cut lines. if (!grid.get_horizontal_interposer_cuts().empty() || !grid.get_vertical_interposer_cuts().empty()) { std::vector interposer_edges = mark_interposer_cut_edges_for_removal(rr_graph, grid); rr_graph_builder.remove_edges(interposer_edges); update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(rr_graph, grid, rr_graph_builder, sg_node_indices); } - + + // Add 2D scatter-gather link edges (the nodes have already been created at this point). These links are mostly used for interposer-crossing connections, but could also be used for other things. 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); 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 696f2d08e55..78970d42084 100644 --- a/vpr/src/route/rr_graph_generation/rr_node_indices.cpp +++ b/vpr/src/route/rr_graph_generation/rr_node_indices.cpp @@ -518,12 +518,12 @@ bool verify_rr_node_indices(const DeviceGrid& grid, describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); } - if (tile_loc.layer_num < rr_graph.node_layer_low(inode) && tile_loc.layer_num > rr_graph.node_layer_high(inode)) { - VPR_ERROR(VPR_ERROR_ROUTE, "RR node layer 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 (tile_loc.layer_num < rr_graph.node_layer_low(inode) && tile_loc.layer_num > rr_graph.node_layer_high(inode)) { + VPR_ERROR(VPR_ERROR_ROUTE, "RR node layer 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"); @@ -596,35 +596,35 @@ bool verify_rr_node_indices(const DeviceGrid& grid, } 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()); - * } - */ + * 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); - * } - */ + * 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); + * } + */ } } } From 16f26ce6652d360626a67df2fc4a1402a3f48b30 Mon Sep 17 00:00:00 2001 From: Amir Poolad Date: Mon, 17 Nov 2025 13:39:51 -0500 Subject: [PATCH 11/21] Add doxygen to interposer_cut.h --- vpr/src/route/rr_graph_generation/interposer_cut.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/vpr/src/route/rr_graph_generation/interposer_cut.h b/vpr/src/route/rr_graph_generation/interposer_cut.h index 1db110db992..93d50a7f790 100644 --- a/vpr/src/route/rr_graph_generation/interposer_cut.h +++ b/vpr/src/route/rr_graph_generation/interposer_cut.h @@ -1,5 +1,13 @@ #pragma once +/** + * @file interposer_cut.h + * @brief This file implements functions that: + * (1) Marks all edges that cross an interposer cut for removal + * (2) Makes the channel nodes that cross an interposer cut shorter to have them not cross the interposer anymore + * Using these two functions and combined with 2D scatter-gather patterns, you can model and implement 2.5D FPGA RR Graphs. + */ + #include #include "rr_graph_fwd.h" #include "rr_graph_view.h" From ea396cd662d6d8f7714be63eb0893ae5fa94bb27 Mon Sep 17 00:00:00 2001 From: Amir Poolad Date: Mon, 17 Nov 2025 13:40:55 -0500 Subject: [PATCH 12/21] Fix formatting --- vpr/src/route/rr_graph_generation/interposer_cut.cpp | 12 ++++++------ vpr/src/route/rr_graph_generation/rr_graph.cpp | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/vpr/src/route/rr_graph_generation/interposer_cut.cpp b/vpr/src/route/rr_graph_generation/interposer_cut.cpp index 60840ab6dca..5d5b4c95071 100644 --- a/vpr/src/route/rr_graph_generation/interposer_cut.cpp +++ b/vpr/src/route/rr_graph_generation/interposer_cut.cpp @@ -166,12 +166,12 @@ static void cut_chan_y_node(RRNodeId node, int x_low, int y_low, int x_high, int } /** - * @brief Update a CHANX node's bounding box in RRGraph and SpatialLookup entries. - * This function assumes that the channel node actually crosses the cut location and - * might not function correctly otherwise. - * - * This is a low level function, you should use cut_channel_node that wraps this up in a nicer API. - */ + * @brief Update a CHANX node's bounding box in RRGraph and SpatialLookup entries. + * This function assumes that the channel node actually crosses the cut location and + * might not function correctly otherwise. + * + * This is a low level function, you should use cut_channel_node that wraps this up in a nicer API. + */ static void cut_chan_x_node(RRNodeId node, int x_low, int y_low, int x_high, int y_high, int layer, int ptc_num, int cut_loc_x, Direction node_direction, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup) { if (node_direction == Direction::INC) { // Anything to the right of cut_loc_x shouldn't exist diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index c51164765bc..a1cc8876b1b 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -1669,7 +1669,7 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder } } } - + // If there are any interposer cuts, remove the edges and shorten the wires that cross interposer cut lines. if (!grid.get_horizontal_interposer_cuts().empty() || !grid.get_vertical_interposer_cuts().empty()) { std::vector interposer_edges = mark_interposer_cut_edges_for_removal(rr_graph, grid); @@ -1677,7 +1677,7 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(rr_graph, grid, rr_graph_builder, sg_node_indices); } - + // Add 2D scatter-gather link edges (the nodes have already been created at this point). These links are mostly used for interposer-crossing connections, but could also be used for other things. 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); From 4d954190b959bb8b6d36e4e853fd56c87d8a3158 Mon Sep 17 00:00:00 2001 From: Amir Poolad Date: Mon, 17 Nov 2025 13:47:10 -0500 Subject: [PATCH 13/21] Add .clangd to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 890ad1ac450..599c0f1854a 100644 --- a/.gitignore +++ b/.gitignore @@ -160,3 +160,4 @@ cmake-build-release # Clangd # compile_commands.json +.clangd \ No newline at end of file From e2cee0c32087a61d29ea2f9a336e544c80c22bc0 Mon Sep 17 00:00:00 2001 From: Amir Poolad Date: Mon, 17 Nov 2025 16:59:33 -0500 Subject: [PATCH 14/21] Make remove_edges use ranges --- libs/librrgraph/src/base/rr_graph_storage.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libs/librrgraph/src/base/rr_graph_storage.cpp b/libs/librrgraph/src/base/rr_graph_storage.cpp index 683800b958f..8494f8caf64 100644 --- a/libs/librrgraph/src/base/rr_graph_storage.cpp +++ b/libs/librrgraph/src/base/rr_graph_storage.cpp @@ -9,6 +9,7 @@ #include #include +#include void t_rr_graph_storage::reserve_edges(size_t num_edges) { edge_src_node_.reserve(num_edges); @@ -67,14 +68,16 @@ void t_rr_graph_storage::remove_edges(std::vector& rr_edges_to_remove) // Sort and make sure all edge indices are unique vtr::uniquify(rr_edges_to_remove); VTR_ASSERT_SAFE(std::is_sorted(rr_edges_to_remove.begin(), rr_edges_to_remove.end())); + + // Make sure the edge indices are valid + VTR_ASSERT(static_cast(rr_edges_to_remove.back()) <= edge_dest_node_.size()); // Index of the last edge size_t edge_list_end = edge_dest_node_.size() - 1; // Iterate backwards through the list of indices we want to remove. - for (auto it = rr_edges_to_remove.rbegin(); it != rr_edges_to_remove.rend(); ++it) { - RREdgeId erase_idx = *it; - + + for (RREdgeId erase_idx : std::ranges::reverse_view(rr_edges_to_remove)) { // Copy what's at the end of the list to the index we wanted to remove edge_dest_node_[erase_idx] = edge_dest_node_[RREdgeId(edge_list_end)]; edge_src_node_[erase_idx] = edge_src_node_[RREdgeId(edge_list_end)]; From 4573aa9c0f3850d5cdb6858193d4c5c71b9ed921 Mon Sep 17 00:00:00 2001 From: Amir Poolad Date: Mon, 17 Nov 2025 17:00:01 -0500 Subject: [PATCH 15/21] Pass RRNodeIds by value --- libs/librrgraph/src/base/rr_graph_view.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/librrgraph/src/base/rr_graph_view.h b/libs/librrgraph/src/base/rr_graph_view.h index b3e9a7cae13..ca87ef4ea1a 100644 --- a/libs/librrgraph/src/base/rr_graph_view.h +++ b/libs/librrgraph/src/base/rr_graph_view.h @@ -592,7 +592,7 @@ class RRGraphView { * * @note Iterating on the range returned by this function will not give you an RREdgeId, but instead gives you the index among a node's outgoing edges */ - inline edge_idx_range edges(const RRNodeId& id) const { + inline edge_idx_range edges(RRNodeId id) const { return vtr::make_range(edge_idx_iterator(0), edge_idx_iterator(num_edges(id))); } @@ -608,7 +608,7 @@ class RRGraphView { /** * @brief Return ID range for outgoing edges. */ - inline edge_idx_range node_out_edges(const RRNodeId& id) const { + inline edge_idx_range node_out_edges(RRNodeId id) const { return vtr::make_range(edge_idx_iterator(0), edge_idx_iterator(num_edges(id))); } From 6b39edc5d5a62b5f66cef73465f36bfc1f263ff0 Mon Sep 17 00:00:00 2001 From: Amir Poolad Date: Mon, 17 Nov 2025 17:00:38 -0500 Subject: [PATCH 16/21] Add newline to 2D scatter-gather comment --- vpr/src/route/rr_graph_generation/rr_graph.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index a1cc8876b1b..711bd73016a 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -49,6 +49,7 @@ #include "interposer_cut.h" + //#define VERBOSE //used for getting the exact count of each edge type and printing it to std out. @@ -1678,7 +1679,8 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(rr_graph, grid, rr_graph_builder, sg_node_indices); } - // Add 2D scatter-gather link edges (the nodes have already been created at this point). These links are mostly used for interposer-crossing connections, but could also be used for other things. + // Add 2D scatter-gather link edges (the nodes have already been created at this point). + // These links are mostly used for interposer-crossing connections, but could also be used for other things. 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); From 0fc6d07332f4451e7bb5fc9332648698d66b5a08 Mon Sep 17 00:00:00 2001 From: Amir Poolad Date: Mon, 17 Nov 2025 17:00:58 -0500 Subject: [PATCH 17/21] Rename interposer_cut to rr_graph_interposer --- .../route/rr_graph_generation/rr_graph.cpp | 3 +- ...rposer_cut.cpp => rr_graph_interposer.cpp} | 63 ++++++++++++------- ...interposer_cut.h => rr_graph_interposer.h} | 0 3 files changed, 41 insertions(+), 25 deletions(-) rename vpr/src/route/rr_graph_generation/{interposer_cut.cpp => rr_graph_interposer.cpp} (83%) rename vpr/src/route/rr_graph_generation/{interposer_cut.h => rr_graph_interposer.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 711bd73016a..d5e0c99d9ff 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_intra_cluster.h" #include "rr_graph_tile_nodes.h" #include "rr_graph_3d.h" +#include "rr_graph_interposer.h" #include "rr_graph_timing_params.h" #include "check_rr_graph.h" #include "echo_files.h" @@ -47,8 +48,6 @@ #include "rr_types.h" #include "rr_node_indices.h" -#include "interposer_cut.h" - //#define VERBOSE //used for getting the exact count of each edge type and printing it to std out. diff --git a/vpr/src/route/rr_graph_generation/interposer_cut.cpp b/vpr/src/route/rr_graph_generation/rr_graph_interposer.cpp similarity index 83% rename from vpr/src/route/rr_graph_generation/interposer_cut.cpp rename to vpr/src/route/rr_graph_generation/rr_graph_interposer.cpp index 5d5b4c95071..d1b473aed84 100644 --- a/vpr/src/route/rr_graph_generation/interposer_cut.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph_interposer.cpp @@ -13,10 +13,11 @@ #include "vpr_error.h" #include "vtr_assert.h" -#include "interposer_cut.h" +#include "rr_graph_interposer.h" /** - * @brief Takes location of a source and a sink and determines wether it crosses cut_loc or not. For example, the interval (1, 4) is cut by 3, while it is not cut by 5 or 0. + * @brief Takes location of a source and a sink and determines wether it crosses cut_loc or not. + * For example, the interval (1, 4) is cut by 3, while it is not cut by 5 or 0. */ static bool should_cut(int src_loc, int sink_loc, int cut_loc) { int src_delta = src_loc - cut_loc; @@ -34,22 +35,27 @@ static bool should_cut(int src_loc, int sink_loc, int cut_loc) { * @brief Calculates the starting x point of node based on it's directionality. */ static short node_xstart(const RRGraphView& rr_graph, RRNodeId node) { + e_rr_type node_type = rr_graph.node_type(node); + Direction node_direction = rr_graph.node_direction(node); + short node_xlow = rr_graph.node_xlow(node); + short node_xhigh = rr_graph.node_xhigh(node); + // Return early for OPIN and IPIN types (Some BIDIR pins would trigger the assertion below) - if (rr_graph.node_type(node) == e_rr_type::OPIN || rr_graph.node_type(node) == e_rr_type::IPIN) { - VTR_ASSERT(rr_graph.node_xlow(node) == rr_graph.node_xhigh(node)); - return rr_graph.node_xlow(node); + if (is_pin(node_type)) { + VTR_ASSERT(node_xlow == node_xhigh); + return node_xlow; } - switch (rr_graph.node_direction(node)) { + switch (node_direction) { case Direction::DEC: - return rr_graph.node_xhigh(node); + return node_xhigh; case Direction::INC: - return rr_graph.node_xlow(node); + return node_xlow; case Direction::NONE: - VTR_ASSERT(rr_graph.node_xlow(node) == rr_graph.node_xhigh(node)); - return (rr_graph.node_xlow(node)); + VTR_ASSERT(node_xlow == node_xhigh); + return (node_xlow); case Direction::BIDIR: VPR_FATAL_ERROR(VPR_ERROR_ROUTE, "Bidir node has no starting point."); @@ -65,21 +71,26 @@ static short node_xstart(const RRGraphView& rr_graph, RRNodeId node) { * @brief Calculates the starting y point of node based on it's directionality. */ static short node_ystart(const RRGraphView& rr_graph, RRNodeId node) { + e_rr_type node_type = rr_graph.node_type(node); + Direction node_direction = rr_graph.node_direction(node); + short node_ylow = rr_graph.node_ylow(node); + short node_yhigh = rr_graph.node_yhigh(node); + // Return early for OPIN and IPIN types (Some BIDIR pins would trigger the assertion below) - if (rr_graph.node_type(node) == e_rr_type::OPIN || rr_graph.node_type(node) == e_rr_type::IPIN) { - return rr_graph.node_ylow(node); + if (is_pin(node_type)) { + return node_ylow; } - switch (rr_graph.node_direction(node)) { + switch (node_direction) { case Direction::DEC: - return rr_graph.node_yhigh(node); + return node_yhigh; case Direction::INC: - return rr_graph.node_ylow(node); + return node_ylow; case Direction::NONE: - VTR_ASSERT(rr_graph.node_ylow(node) == rr_graph.node_yhigh(node)); - return (rr_graph.node_ylow(node)); + VTR_ASSERT(node_ylow == node_yhigh); + return (node_ylow); case Direction::BIDIR: VPR_FATAL_ERROR(VPR_ERROR_ROUTE, "Bidir node has no starting point."); @@ -143,7 +154,8 @@ std::vector mark_interposer_cut_edges_for_removal(const RRGraphView& r * * This is a low level function, you should use cut_channel_node that wraps this up in a nicer API. */ -static void cut_chan_y_node(RRNodeId node, int x_low, int y_low, int x_high, int y_high, int layer, int ptc_num, int cut_loc_y, Direction node_direction, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup) { +static void cut_chan_y_node(RRNodeId node, int x_low, int y_low, int x_high, int y_high, int layer, int ptc_num, int cut_loc_y, + Direction node_direction, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup) { if (node_direction == Direction::INC) { // Anything above cut_loc_y shouldn't exist rr_graph_builder.set_node_coordinates(node, x_low, y_low, x_high, cut_loc_y); @@ -172,7 +184,8 @@ static void cut_chan_y_node(RRNodeId node, int x_low, int y_low, int x_high, int * * This is a low level function, you should use cut_channel_node that wraps this up in a nicer API. */ -static void cut_chan_x_node(RRNodeId node, int x_low, int y_low, int x_high, int y_high, int layer, int ptc_num, int cut_loc_x, Direction node_direction, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup) { +static void cut_chan_x_node(RRNodeId node, int x_low, int y_low, int x_high, int y_high, int layer, int ptc_num, int cut_loc_x, + Direction node_direction, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup) { if (node_direction == Direction::INC) { // Anything to the right of cut_loc_x shouldn't exist rr_graph_builder.set_node_coordinates(node, x_low, y_low, cut_loc_x, y_high); @@ -202,7 +215,8 @@ static void cut_chan_x_node(RRNodeId node, int x_low, int y_low, int x_high, int * @param interposer_cut_type Type of the interposer cut line (Horizontal or vertical) * @param sg_node_indices Sorted list of scatter-gather node IDs. We do not want to cut these nodes as they're allowed to cross an interposer cut line. */ -static void cut_channel_node(RRNodeId node, int cut_loc, e_interposer_cut_type interposer_cut_type, const RRGraphView& rr_graph, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup, const std::vector>& sg_node_indices) { +static void cut_channel_node(RRNodeId node, int cut_loc, e_interposer_cut_type interposer_cut_type, const RRGraphView& rr_graph, RRGraphBuilder& rr_graph_builder, + RRSpatialLookup& spatial_lookup, const std::vector>& sg_node_indices) { constexpr auto node_indice_compare = [](RRNodeId l, RRNodeId r) noexcept { return size_t(l) < size_t(r); }; bool is_sg_node = std::ranges::binary_search(std::views::keys(sg_node_indices), node, node_indice_compare); if (is_sg_node) { @@ -239,7 +253,8 @@ static void cut_channel_node(RRNodeId node, int cut_loc, e_interposer_cut_type i } } -void update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(const RRGraphView& rr_graph, const DeviceGrid& grid, RRGraphBuilder& rr_graph_builder, const std::vector>& sg_node_indices) { +void update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(const RRGraphView& rr_graph, const DeviceGrid& grid, RRGraphBuilder& rr_graph_builder, + const std::vector>& sg_node_indices) { VTR_ASSERT(std::is_sorted(sg_node_indices.begin(), sg_node_indices.end())); @@ -249,7 +264,8 @@ void update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(con for (size_t x_loc = 0; x_loc < grid.width(); x_loc++) { std::vector channel_nodes = spatial_lookup.find_channel_nodes(layer, x_loc, cut_loc_y, e_rr_type::CHANY); for (RRNodeId node : channel_nodes) { - cut_channel_node(node, cut_loc_y, e_interposer_cut_type::HORZ, rr_graph, rr_graph_builder, spatial_lookup, sg_node_indices); + cut_channel_node(node, cut_loc_y, e_interposer_cut_type::HORZ, + rr_graph, rr_graph_builder, spatial_lookup, sg_node_indices); } } } @@ -258,7 +274,8 @@ void update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(con for (size_t y_loc = 0; y_loc < grid.height(); y_loc++) { std::vector channel_nodes = spatial_lookup.find_channel_nodes(layer, cut_loc_x, y_loc, e_rr_type::CHANX); for (RRNodeId node : channel_nodes) { - cut_channel_node(node, cut_loc_x, e_interposer_cut_type::VERT, rr_graph, rr_graph_builder, spatial_lookup, sg_node_indices); + cut_channel_node(node, cut_loc_x, e_interposer_cut_type::VERT, + rr_graph, rr_graph_builder, spatial_lookup, sg_node_indices); } } } diff --git a/vpr/src/route/rr_graph_generation/interposer_cut.h b/vpr/src/route/rr_graph_generation/rr_graph_interposer.h similarity index 100% rename from vpr/src/route/rr_graph_generation/interposer_cut.h rename to vpr/src/route/rr_graph_generation/rr_graph_interposer.h From dda2e4304be10b66dadefe4a35d3f5c5f5108e99 Mon Sep 17 00:00:00 2001 From: Amir Poolad Date: Mon, 17 Nov 2025 17:06:33 -0500 Subject: [PATCH 18/21] Add static function declarations to rr_graph_interposer.cpp --- .../rr_graph_interposer.cpp | 75 ++++++++++++------- 1 file changed, 47 insertions(+), 28 deletions(-) diff --git a/vpr/src/route/rr_graph_generation/rr_graph_interposer.cpp b/vpr/src/route/rr_graph_generation/rr_graph_interposer.cpp index d1b473aed84..68ee21e5867 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_interposer.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph_interposer.cpp @@ -15,10 +15,57 @@ #include "rr_graph_interposer.h" +// Static function declarations + /** * @brief Takes location of a source and a sink and determines wether it crosses cut_loc or not. * For example, the interval (1, 4) is cut by 3, while it is not cut by 5 or 0. */ +static bool should_cut(int src_loc, int sink_loc, int cut_loc); + +/** + * @brief Calculates the starting x point of node based on it's directionality. + */ +static short node_xstart(const RRGraphView& rr_graph, RRNodeId node); + +/** + * @brief Calculates the starting y point of node based on it's directionality. + */ +static short node_ystart(const RRGraphView& rr_graph, RRNodeId node); + +/** + * @brief Update a CHANY node's bounding box in RRGraph and SpatialLookup entries. + * This function assumes that the channel node actually crosses the cut location and + * might not function correctly otherwise. + * + * This is a low level function, you should use cut_channel_node that wraps this up in a nicer API. + */ +static void cut_chan_y_node(RRNodeId node, int x_low, int y_low, int x_high, int y_high, int layer, int ptc_num, int cut_loc_y, + Direction node_direction, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup); + +/** + * @brief Update a CHANX node's bounding box in RRGraph and SpatialLookup entries. + * This function assumes that the channel node actually crosses the cut location and + * might not function correctly otherwise. + * + * This is a low level function, you should use cut_channel_node that wraps this up in a nicer API. + */ +static void cut_chan_x_node(RRNodeId node, int x_low, int y_low, int x_high, int y_high, int layer, int ptc_num, int cut_loc_x, + Direction node_direction, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup); + +/** + * @brief Update a CHANX or CHANY node's bounding box in RRGraph and SpatialLookup entries if it crosses cut_loc + * + * @param node Channel segment RR graph node that might cross the interposer cut line + * @param cut_loc location of vertical interposer cut line + * @param interposer_cut_type Type of the interposer cut line (Horizontal or vertical) + * @param sg_node_indices Sorted list of scatter-gather node IDs. We do not want to cut these nodes as they're allowed to cross an interposer cut line. + */ +static void cut_channel_node(RRNodeId node, int cut_loc, e_interposer_cut_type interposer_cut_type, const RRGraphView& rr_graph, RRGraphBuilder& rr_graph_builder, + RRSpatialLookup& spatial_lookup, const std::vector>& sg_node_indices); + +// Function definitions + static bool should_cut(int src_loc, int sink_loc, int cut_loc) { int src_delta = src_loc - cut_loc; int sink_delta = sink_loc - cut_loc; @@ -31,9 +78,6 @@ static bool should_cut(int src_loc, int sink_loc, int cut_loc) { } } -/** - * @brief Calculates the starting x point of node based on it's directionality. - */ static short node_xstart(const RRGraphView& rr_graph, RRNodeId node) { e_rr_type node_type = rr_graph.node_type(node); Direction node_direction = rr_graph.node_direction(node); @@ -67,9 +111,6 @@ static short node_xstart(const RRGraphView& rr_graph, RRNodeId node) { } } -/** - * @brief Calculates the starting y point of node based on it's directionality. - */ static short node_ystart(const RRGraphView& rr_graph, RRNodeId node) { e_rr_type node_type = rr_graph.node_type(node); Direction node_direction = rr_graph.node_direction(node); @@ -147,13 +188,6 @@ std::vector mark_interposer_cut_edges_for_removal(const RRGraphView& r return edges_to_be_removed; } -/** - * @brief Update a CHANY node's bounding box in RRGraph and SpatialLookup entries. - * This function assumes that the channel node actually crosses the cut location and - * might not function correctly otherwise. - * - * This is a low level function, you should use cut_channel_node that wraps this up in a nicer API. - */ static void cut_chan_y_node(RRNodeId node, int x_low, int y_low, int x_high, int y_high, int layer, int ptc_num, int cut_loc_y, Direction node_direction, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup) { if (node_direction == Direction::INC) { @@ -177,13 +211,6 @@ static void cut_chan_y_node(RRNodeId node, int x_low, int y_low, int x_high, int } } -/** - * @brief Update a CHANX node's bounding box in RRGraph and SpatialLookup entries. - * This function assumes that the channel node actually crosses the cut location and - * might not function correctly otherwise. - * - * This is a low level function, you should use cut_channel_node that wraps this up in a nicer API. - */ static void cut_chan_x_node(RRNodeId node, int x_low, int y_low, int x_high, int y_high, int layer, int ptc_num, int cut_loc_x, Direction node_direction, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup) { if (node_direction == Direction::INC) { @@ -207,14 +234,6 @@ static void cut_chan_x_node(RRNodeId node, int x_low, int y_low, int x_high, int } } -/** - * @brief Update a CHANX or CHANY node's bounding box in RRGraph and SpatialLookup entries if it crosses cut_loc - * - * @param node Channel segment RR graph node that might cross the interposer cut line - * @param cut_loc location of vertical interposer cut line - * @param interposer_cut_type Type of the interposer cut line (Horizontal or vertical) - * @param sg_node_indices Sorted list of scatter-gather node IDs. We do not want to cut these nodes as they're allowed to cross an interposer cut line. - */ static void cut_channel_node(RRNodeId node, int cut_loc, e_interposer_cut_type interposer_cut_type, const RRGraphView& rr_graph, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup, const std::vector>& sg_node_indices) { constexpr auto node_indice_compare = [](RRNodeId l, RRNodeId r) noexcept { return size_t(l) < size_t(r); }; From 61ebf99193bf6c9f4ebb184210dc70cc8348169c Mon Sep 17 00:00:00 2001 From: Amir Poolad Date: Mon, 17 Nov 2025 17:07:03 -0500 Subject: [PATCH 19/21] Add std::pair include --- vpr/src/route/rr_graph_generation/rr_graph_interposer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/vpr/src/route/rr_graph_generation/rr_graph_interposer.cpp b/vpr/src/route/rr_graph_generation/rr_graph_interposer.cpp index 68ee21e5867..f0c57ad95f7 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_interposer.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph_interposer.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include From 561b5fbcabc456925a5009946d366a0f31233c23 Mon Sep 17 00:00:00 2001 From: Amir Poolad Date: Mon, 17 Nov 2025 17:11:55 -0500 Subject: [PATCH 20/21] Fix formatting issues --- .../route/rr_graph_generation/rr_graph.cpp | 1 - .../rr_graph_interposer.cpp | 74 +++++++++++++++---- .../rr_graph_generation/rr_graph_interposer.h | 5 +- 3 files changed, 65 insertions(+), 15 deletions(-) diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index d5e0c99d9ff..03a8516b396 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -48,7 +48,6 @@ #include "rr_types.h" #include "rr_node_indices.h" - //#define VERBOSE //used for getting the exact count of each edge type and printing it to std out. diff --git a/vpr/src/route/rr_graph_generation/rr_graph_interposer.cpp b/vpr/src/route/rr_graph_generation/rr_graph_interposer.cpp index f0c57ad95f7..5499b105490 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_interposer.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph_interposer.cpp @@ -41,8 +41,17 @@ static short node_ystart(const RRGraphView& rr_graph, RRNodeId node); * * This is a low level function, you should use cut_channel_node that wraps this up in a nicer API. */ -static void cut_chan_y_node(RRNodeId node, int x_low, int y_low, int x_high, int y_high, int layer, int ptc_num, int cut_loc_y, - Direction node_direction, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup); +static void cut_chan_y_node(RRNodeId node, + int x_low, + int y_low, + int x_high, + int y_high, + int layer, + int ptc_num, + int cut_loc_y, + Direction node_direction, + RRGraphBuilder& rr_graph_builder, + RRSpatialLookup& spatial_lookup); /** * @brief Update a CHANX node's bounding box in RRGraph and SpatialLookup entries. @@ -51,8 +60,17 @@ static void cut_chan_y_node(RRNodeId node, int x_low, int y_low, int x_high, int * * This is a low level function, you should use cut_channel_node that wraps this up in a nicer API. */ -static void cut_chan_x_node(RRNodeId node, int x_low, int y_low, int x_high, int y_high, int layer, int ptc_num, int cut_loc_x, - Direction node_direction, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup); +static void cut_chan_x_node(RRNodeId node, + int x_low, + int y_low, + int x_high, + int y_high, + int layer, + int ptc_num, + int cut_loc_x, + Direction node_direction, + RRGraphBuilder& rr_graph_builder, + RRSpatialLookup& spatial_lookup); /** * @brief Update a CHANX or CHANY node's bounding box in RRGraph and SpatialLookup entries if it crosses cut_loc @@ -62,8 +80,13 @@ static void cut_chan_x_node(RRNodeId node, int x_low, int y_low, int x_high, int * @param interposer_cut_type Type of the interposer cut line (Horizontal or vertical) * @param sg_node_indices Sorted list of scatter-gather node IDs. We do not want to cut these nodes as they're allowed to cross an interposer cut line. */ -static void cut_channel_node(RRNodeId node, int cut_loc, e_interposer_cut_type interposer_cut_type, const RRGraphView& rr_graph, RRGraphBuilder& rr_graph_builder, - RRSpatialLookup& spatial_lookup, const std::vector>& sg_node_indices); +static void cut_channel_node(RRNodeId node, + int cut_loc, + e_interposer_cut_type interposer_cut_type, + const RRGraphView& rr_graph, + RRGraphBuilder& rr_graph_builder, + RRSpatialLookup& spatial_lookup, + const std::vector>& sg_node_indices); // Function definitions @@ -189,8 +212,17 @@ std::vector mark_interposer_cut_edges_for_removal(const RRGraphView& r return edges_to_be_removed; } -static void cut_chan_y_node(RRNodeId node, int x_low, int y_low, int x_high, int y_high, int layer, int ptc_num, int cut_loc_y, - Direction node_direction, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup) { +static void cut_chan_y_node(RRNodeId node, + int x_low, + int y_low, + int x_high, + int y_high, + int layer, + int ptc_num, + int cut_loc_y, + Direction node_direction, + RRGraphBuilder& rr_graph_builder, + RRSpatialLookup& spatial_lookup) { if (node_direction == Direction::INC) { // Anything above cut_loc_y shouldn't exist rr_graph_builder.set_node_coordinates(node, x_low, y_low, x_high, cut_loc_y); @@ -212,8 +244,17 @@ static void cut_chan_y_node(RRNodeId node, int x_low, int y_low, int x_high, int } } -static void cut_chan_x_node(RRNodeId node, int x_low, int y_low, int x_high, int y_high, int layer, int ptc_num, int cut_loc_x, - Direction node_direction, RRGraphBuilder& rr_graph_builder, RRSpatialLookup& spatial_lookup) { +static void cut_chan_x_node(RRNodeId node, + int x_low, + int y_low, + int x_high, + int y_high, + int layer, + int ptc_num, + int cut_loc_x, + Direction node_direction, + RRGraphBuilder& rr_graph_builder, + RRSpatialLookup& spatial_lookup) { if (node_direction == Direction::INC) { // Anything to the right of cut_loc_x shouldn't exist rr_graph_builder.set_node_coordinates(node, x_low, y_low, cut_loc_x, y_high); @@ -235,8 +276,13 @@ static void cut_chan_x_node(RRNodeId node, int x_low, int y_low, int x_high, int } } -static void cut_channel_node(RRNodeId node, int cut_loc, e_interposer_cut_type interposer_cut_type, const RRGraphView& rr_graph, RRGraphBuilder& rr_graph_builder, - RRSpatialLookup& spatial_lookup, const std::vector>& sg_node_indices) { +static void cut_channel_node(RRNodeId node, + int cut_loc, + e_interposer_cut_type interposer_cut_type, + const RRGraphView& rr_graph, + RRGraphBuilder& rr_graph_builder, + RRSpatialLookup& spatial_lookup, + const std::vector>& sg_node_indices) { constexpr auto node_indice_compare = [](RRNodeId l, RRNodeId r) noexcept { return size_t(l) < size_t(r); }; bool is_sg_node = std::ranges::binary_search(std::views::keys(sg_node_indices), node, node_indice_compare); if (is_sg_node) { @@ -273,7 +319,9 @@ static void cut_channel_node(RRNodeId node, int cut_loc, e_interposer_cut_type i } } -void update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(const RRGraphView& rr_graph, const DeviceGrid& grid, RRGraphBuilder& rr_graph_builder, +void update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(const RRGraphView& rr_graph, + const DeviceGrid& grid, + RRGraphBuilder& rr_graph_builder, const std::vector>& sg_node_indices) { VTR_ASSERT(std::is_sorted(sg_node_indices.begin(), sg_node_indices.end())); diff --git a/vpr/src/route/rr_graph_generation/rr_graph_interposer.h b/vpr/src/route/rr_graph_generation/rr_graph_interposer.h index 93d50a7f790..b4349afa388 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_interposer.h +++ b/vpr/src/route/rr_graph_generation/rr_graph_interposer.h @@ -28,4 +28,7 @@ std::vector mark_interposer_cut_edges_for_removal(const RRGraphView& r * @param rr_graph_builder RRGraphBuilder, to modify the RRGraph. * @param sg_node_indices list of scatter-gather node IDs. We do not want to cut these nodes as they're allowed to cross an interposer cut line. */ -void update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(const RRGraphView& rr_graph, const DeviceGrid& grid, RRGraphBuilder& rr_graph_builder, const std::vector>& sg_node_indices); +void update_interposer_crossing_nodes_in_spatial_lookup_and_rr_graph_storage(const RRGraphView& rr_graph, + const DeviceGrid& grid, + RRGraphBuilder& rr_graph_builder, + const std::vector>& sg_node_indices); From b57b08fdd3304ab6f2f4191013d1870f794d8adc Mon Sep 17 00:00:00 2001 From: Amir Poolad Date: Mon, 17 Nov 2025 17:46:20 -0500 Subject: [PATCH 21/21] Fix bug with checking if device has interposer cuts --- libs/libarchfpga/src/device_grid.cpp | 16 ++++++++++++++++ libs/libarchfpga/src/device_grid.h | 5 +++++ vpr/src/route/rr_graph_generation/rr_graph.cpp | 2 +- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/libs/libarchfpga/src/device_grid.cpp b/libs/libarchfpga/src/device_grid.cpp index f0644873a43..6873ffff6fb 100644 --- a/libs/libarchfpga/src/device_grid.cpp +++ b/libs/libarchfpga/src/device_grid.cpp @@ -89,3 +89,19 @@ void DeviceGrid::count_instances() { } } } + +bool DeviceGrid::has_interposer_cuts() const { + for (const std::vector& layer_h_cuts : horizontal_interposer_cuts_) { + if (!layer_h_cuts.empty()) { + return true; + } + } + + for (const std::vector& layer_v_cuts : vertical_interposer_cuts_) { + if (!layer_v_cuts.empty()) { + return true; + } + } + + return false; +} diff --git a/libs/libarchfpga/src/device_grid.h b/libs/libarchfpga/src/device_grid.h index 5a5f1c01054..74f3f18b88c 100644 --- a/libs/libarchfpga/src/device_grid.h +++ b/libs/libarchfpga/src/device_grid.h @@ -211,6 +211,11 @@ class DeviceGrid { return vertical_interposer_cuts_; } + /// Returns if the grid has any interposer cuts. You should use this function instead of + /// checking if get_horizontal/vertical_interposer_cuts is empty, since the return value + /// of those functions might look something like this: {{}} which is technically not empty. + bool has_interposer_cuts() const; + private: /// @brief Counts the number of each tile type on each layer and store it in instance_counts_. /// It is called in the constructor. diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index 03a8516b396..c4bbed47df5 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -1670,7 +1670,7 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder } // If there are any interposer cuts, remove the edges and shorten the wires that cross interposer cut lines. - if (!grid.get_horizontal_interposer_cuts().empty() || !grid.get_vertical_interposer_cuts().empty()) { + if (grid.has_interposer_cuts()) { std::vector interposer_edges = mark_interposer_cut_edges_for_removal(rr_graph, grid); rr_graph_builder.remove_edges(interposer_edges);