Skip to content

Conversation

soheilshahrouz
Copy link
Contributor

This PR includes the following changes:

  1. Creates nodes and edges in RR graph based on scatter-gather patterns specifed in the architecture file.
  2. Updates router lookahead map to handle CHANZ nodes properly.
  3. Computes indexed data for CHANZ nodes.
  4. Removes 3-d (with above and under) switch blocks from code

soheilshahrouz and others added 30 commits September 5, 2025 12:44
@soheilshahrouz soheilshahrouz changed the title [WIP] Scatter-gather patterns for 3D architectures Scatter-gather patterns for 3D architectures Sep 18, 2025
Copy link
Contributor

@AlexandreSinger AlexandreSinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gave a quick review.

@soheilshahrouz I love the cleanups you do, but man you got to split them across PRs; there's so much to review!

Copy link
Contributor

@AmirhosseinPoolad AmirhosseinPoolad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only reviewed until vpr/src/route/DecompNetlistRouter.tpp

Copy link
Contributor

@AmirhosseinPoolad AmirhosseinPoolad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed from DecompNetlistRouter to build_scatter_gathers.cpp.

Comment on lines +158 to +159
// TODO: handle CHANZ nodes

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO remaining in final code


int from_layer_num = rr_graph.node_layer(from_node);
int to_layer_num = rr_graph.node_layer(to_node);
// TODO: handle CHANZ nodes that span multiple layers
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO again. Not saying that you have to fix these right now, but a reminder that it is there. I sometimes forget about my TODOs so I'm just making sure that it's intended.

const auto& grid = device_ctx.grid;

const size_t num_layers = grid.get_num_layers();
const size_t chan_type_dim_size = (num_layers == 1) ? 2 : 3;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add comment explaining this.

if (is_chanxy(from_type) || is_chanz(from_type)) {
int from_layer_num = rr_graph.node_layer(from_node);
int to_layer_num = rr_graph.node_layer(to_node);
// TODO: handle CHANZ nodes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO. Again, just reminding that it exists.

Copy link
Contributor

@AmirhosseinPoolad AmirhosseinPoolad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More comments until 'switchblock_scatter_gather_common_utils.cpp'

const t_chan_details& chan_details_x,
const t_chan_details& chan_details_y,
std::vector<t_chan_loc>& correct_channels) {
correct_channels.clear();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're clearing this vector at the start of the function, why not just have it as return value then?

t_physical_tile_loc chan_loc;
e_rr_type chan_type;

index_into_correct_chan(loc, side, chan_details_x, chan_details_y, chan_loc, chan_type);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name for these two functions are way to similar, I thought it was recursive at first glance. I think 'index_to_correct_channels' should have sg or scatter_gather somewhere in the name to differentiate it better.

for (const t_wire_switchpoints& wire_switchpoints : wire_switchpoints_vec) {
auto wire_type = vtr::string_view(wire_switchpoints.segment_name);

if (wire_type_sizes.find(wire_type) == wire_type_sizes.end()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer using contains from c++20

const t_chan_seg_details* chan_details = (chan_type == e_rr_type::CHANX) ? chan_details_x[chan_loc.x][chan_loc.y].data() : chan_details_y[chan_loc.x][chan_loc.y].data();

for (const t_wire_switchpoints& wire_switchpoints : wire_switchpoints_vec) {
auto wire_type = vtr::string_view(wire_switchpoints.segment_name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have a vtr::string_view? Maybe it's from when the project was not using C++17? Anyway I don't see why we need to use it now. Also, auto.

int wire_switchpoint = get_switchpoint_of_wire(chan_type, chan_details[iwire], seg_coord, chan_side);

// Check if this wire belongs to one of the specified switchpoints; add it to our 'wires' vector if so
if (wire_switchpoint != valid_switchpoint) continue;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The loop seems backwards to me. You're going through all valid switchpoints then all wires, meaning that you do all the processing for the wire only to throw it away because in the outer loop we were looking for switchpoint number 1 instead of 2, even though switchpoint 2 might also be valid in the next iteration of the outer loop.

index_to_correct_channels(sg_pattern.scatter_pattern, scatter_loc, chan_details_x, chan_details_y, scatter_channels);

if (gather_channels.empty() || scatter_channels.empty()) {
continue;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably at least warn the user here that there's an ill formed pattern.

Comment on lines +209 to +219
auto gather_wire_candidates = find_candidate_wires(gather_channels,
sg_pattern.gather_pattern.from_switchpoint_set,
chan_details_x, chan_details_y,
wire_type_sizes_x, wire_type_sizes_y,
/*is_dest=*/false);

auto scatter_wire_candidates = find_candidate_wires(scatter_channels,
sg_pattern.scatter_pattern.to_switchpoint_set,
chan_details_x, chan_details_y,
wire_type_sizes_x, wire_type_sizes_y,
/*is_dest=*/true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

auto

bottleneck_fanout = std::min<int>(bottleneck_fanout, scatter_wire_candidates.size());

if (bottleneck_fanin == 0 || bottleneck_fanout == 0) {
continue;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto here, maybe we should warn the user. There's a potential problem of printing way too much stuff that should be considered.

t_wire_switchpoint wire_switchpoint; ///< Wire index and its valid switchpoint
};

/// Represents a scatter/gather bottleneck connection between two locations.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we referred to this as the "scatter-gather node" in the docs. I don't have an issue with the name bottleneck but I think you should say in the comments that the bottleneck connection is the same thing as scatter-gather node in the docs.

const float R_minW_pmos,
const int wire_to_arch_ipin_switch,
int* wire_to_rr_ipin_switch) {
RRSwitchId* wire_to_rr_ipin_switch) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you pass this by reference instead?

Copy link
Contributor

@AmirhosseinPoolad AmirhosseinPoolad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And that concludes the review! Thanks for the PR Soheil.

Comment on lines +48329 to +48354

<!-- Specify a scatter-gather pattern for 3D connections. -->
<scatter_gather_list>
<sg_pattern name="name" type="unidir">
<gather>
<!-- Gather 30 connections from the end of 'wire' nodes at all four sides of a switchblock location -->
<wireconn num_conns="7" from_type="L4" from_switchpoint="1" side="rltb"/>
</gather>

<scatter>
<!-- Scatter 30 connections to the start of 'wire' nodes at all four sides of a switchblock location -->
<wireconn num_conns="7" to_type="L4" to_switchpoint="0" side="rtl"/>
</scatter>

<sg_link_list>
<!-- Link going up one layer, using the 'sw' multiplexer to gather connections from the bottom layer and using the 'wire' node/wire to move up one layer -->
<sg_link name="L_UP" z_offset="1" x_offset="0" y_offset="0" mux="seg4_inter_die_driver" seg_type="L4"/>
<!-- Link going down one layer, using the 'sw' multiplexer to gather connections from the top layer and using the 'wire' node/wire to down up one layer -->
<sg_link name="L_DOWN" z_offset="-1" mux="seg4_inter_die_driver" seg_type="L4"/>
</sg_link_list>

<!-- Instantiate 10 'L_UP' sg_links per switchblock location everywhere on the device -->
<sg_location type="EVERYWHERE" num="1" sg_link_name="L_UP"/>
<sg_location type="EVERYWHERE" num="1" sg_link_name="L_DOWN"/>
</sg_pattern>
</scatter_gather_list>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments here should be removed

@vaughnbetz
Copy link
Contributor

@soheilshahrouz is working on the interposer branch; target is to merge this by the end of the week.
Testing: CI passes.
3D switch block architectures have been updated: removed above/below and changed to scatter-gather patterns. They are in CI and pass. These archs use 12 wires at each switch block, and have a mux and demux size of 30. They route and are within the tolerance for Fmax and wire lengths. Only a few circuits in these strong tests.

TO DO: run the weekly test with the full titan design set and check Fmax, runtime, wire length vs. 2D. Also confirm the designs have to use multiple layers (devices full enough for at least some).

@vaughnbetz
Copy link
Contributor

Docs: add segment type documentation to explain Z axis.
Remove the "nothing will change" line from scatter-gather.
Longer term: make a tutorial on 3D architectures.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lang-cpp C/C++ code libarchfpga Library for handling FPGA Architecture descriptions VPR VPR FPGA Placement & Routing Tool
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants