-
Notifications
You must be signed in to change notification settings - Fork 415
Refactor rt node #1508
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor rt node #1508
Conversation
…lly checked in last commit)
Hi Vaughn, |
if (tokens[8 + offset] == "Net_pin_index:") { | ||
net_pin_id = atoi(tokens[9 + offset].c_str()); | ||
} else { | ||
vpr_throw(VPR_ERROR_ROUTE, filename, lineno, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To help users with old .route files, please add something like: "Is this an old .route file without that information? If so, re-generate the routing."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added message in the vpr_throw.
vpr/src/base/vpr_types.h
Outdated
* different pins, node index cannot uniquely identify * | ||
* each sink, so the net pin index guarentees an unique * | ||
* identification for each sink-type node. For non-sink- * | ||
* type nodes and for sink-type nodes with no associated * |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should say what SINK node wouldn't have such an index (special SINKs like the source of a clock tree which don't correspond to an actual netlist connection).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added comment. Also added the same comments for rt_node.
@@ -190,8 +190,7 @@ static void check_sink(int inode, ClusterNetId net_id, bool* pin_done) { | |||
int ptc_num = device_ctx.rr_nodes[inode].ptc_num(); | |||
int ifound = 0; | |||
|
|||
for (int iblk = 0; iblk < type->capacity; iblk++) { | |||
ClusterBlockId bnum = place_ctx.grid_blocks[i][j].blocks[iblk]; /* Hardcoded to one cluster_ctx block*/ | |||
for (auto bnum : place_ctx.grid_blocks[i][j].blocks) { | |||
unsigned int ipin = 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still baffled by the need for this code. It degenerates to a count of the pins connected, along with a check that some block on the net is at the (i,j) specified.
If you check out https://docs.verilogtorouting.org/en/latest/api/vpr/netlist/ you can see how the netlist works. We are storing a net_pin_index on each connection (SINK in the traceback). So if you pass that net_pin_index (which you now store) into check_sink, we can use it here. I think the code is basically:
pin_id = cluster_ctx.clb_nlist.net_pin (net_id, net_pin_index); // Gets a pin on the netlist corresponding to this connection on the netlist.
for (auto bnum: place_ctr.grid_blocks[i][j].blocks) { // Look through all blocks at the sink (i,j)
if (cluster_ctx.clb_nlist.pin_block(pin_id) == bnum) { // One should match the block at the end of this netlist connection
VPR_ASSERT (!pin_done[net_pin_index]); // Shouldn't have found a routed connection to it before
pin_done[net_pin_index] = true; // Mark that now we have found a routed connection to it
break;
}
}
if (!pin_done[net_pin_index]) {
VPR_FATAL_ERROR (... same message ...)
}
if
@@ -19,6 +19,10 @@ class Connection_based_routing_resources { | |||
// each net maps SINK node index -> PIN index for net | |||
// only need to be built once at the start since the SINK nodes never change | |||
// the reverse lookup of route_ctx.net_rr_terminals | |||
// be careful: it is possible for multiple sinks to share the same node index in some cases. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably say a single SINK can map to multiple PIN index on a net (multiple connections) in some unusual cases. Hence use of this data structure is discouraged (instead use the pin index on a net stored in the rt_node) and this data structure will likely be removed in the future.
[What still uses this? Just the breadth-first router? If so, we should note that in the comment and it's a good reason for deleting the breadth-first router in the future.]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, nothing uses this anymore, not even the BF router. There is just one function that does a sanity check of the map, called by an assertion in route_timing.cpp, which no longer uses this anyways.
I can go ahead and remove this altogether.
vpr/src/route/route_common.cpp
Outdated
@@ -86,7 +86,7 @@ static int num_linked_f_pointer_allocated = 0; | |||
* */ | |||
|
|||
/******************** Subroutines local to route_common.c *******************/ | |||
static t_trace_branch traceback_branch(int node, std::unordered_set<int>& main_branch_visited); | |||
static t_trace_branch traceback_branch(int node, int target_pin, std::unordered_set<int>& main_branch_visited); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd use a more descriptive variable name: target_net_pin_index would be better I think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, while I'm at it, I also changed the parameter name in update_traceback, which is the routine a level above this.
vpr/src/route/route_tree_timing.cpp
Outdated
@@ -316,6 +331,7 @@ add_subtree_to_route_tree(t_heap* hptr, t_rt_node** sink_rt_node_ptr) { | |||
|
|||
rt_node->u.child_list = linked_rt_edge; | |||
rt_node->inode = inode; | |||
rt_node->ipin = OPEN; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Explain why: not valid for non-SINK nodes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -347,6 +363,7 @@ add_subtree_to_route_tree(t_heap* hptr, t_rt_node** sink_rt_node_ptr) { | |||
|
|||
//Expand (recursively) each of the main-branch nodes adding any | |||
//non-configurably connected nodes | |||
//Sink is not included, so no need to pass in the node's ipin value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any pin index passed in, so I don't understand the comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My apologies, I sort of put this in as a reminder for myself that there is no need to pass in any net pin info to this function. But I agree it's confusing. I am taking it out.
vpr/src/route/route_tree_timing.h
Outdated
@@ -19,7 +19,7 @@ void free_route_tree(t_rt_node* rt_node); | |||
void print_route_tree(const t_rt_node* rt_node); | |||
void print_route_tree(const t_rt_node* rt_node, int depth); | |||
|
|||
t_rt_node* update_route_tree(t_heap* hptr, SpatialRouteTreeLookup* spatial_rt_lookup); | |||
t_rt_node* update_route_tree(t_heap* hptr, int target_pin, SpatialRouteTreeLookup* spatial_rt_lookup); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename target_pin to target_net_pin_index, and if you know what the routine does, write a comment above the function name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I never added a comment because the description for these functions are in the .cpp. But I've just added to the comment to describe what the target_net_pin_index parameter means before the function definition in the .cpp. If you think it's a good convention to add it in the .h as well, I can do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your call; you can keep following the .cpp convention for these files if you like.
vpr/src/route/route_tree_type.h
Outdated
@@ -27,6 +27,13 @@ struct t_linked_rt_edge { | |||
* parent_switch: Index of the switch type driving this node (by its * | |||
* parent). * | |||
* inode: index (ID) of the rr_node that corresponds to this rt_node. * | |||
* ipin: Net pin index associated with the rt_node. This value ranges from * |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
net_pin_index would be a better name than ipin, both here and in t_trace, in retrospect. The comment is good; you could change the member name too (here and in t_trace) if you have the energy for it :).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed and done.
vpr/src/timing/net_delay.cpp
Outdated
inode_to_Tdel_map[node->inode] = node->Tdel; // add to the map, process current node | ||
/* This routine recursively traverses the route tree, and copies the Tdel of the sink_type nodes * | ||
* into the map. */ | ||
if (node->ipin != OPEN) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment that this means non-SINK.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, done.
Hi Vaughn, |
Code format failed Helen; can you run make format? |
Thanks for the QoR checks; those look good. |
Great news Helen -- thanks. |
Everything looks good (except the spurious pylint failure. Merging. |
[Edited]
In this pull request, I have refactored the rt_node and traceback structures, adding a new member in the structure to keep track of the net pin index (ranging from 1 to fanout) of sinks. I've also updated all parts of the code to properly store and access this new member.
Description
Related Issue
#1475
Motivation and Context
As part of a Stratix IV architecture experiment, we tried forcing a greedy and false pin-equivalence to the M9K, M144K, and DSP inputs (meaning that although equivalence is set to "full" on the top level input pins, the local routing of these blocks is still partially fully connected).
When running benchmarks with this experiment, VPR failed in routing because it was attempting to delete the same node twice from the route tree. This happened because the the clustered netlist builder for logic blocks mapped the same net to multiple pins in a port, resulting in multiple rt nodes being created with the same rr node index. However, the code is inconsistent: when building up the route tree from traceback, only one rt_node is created for each rr node index found in the traceback, so edges are created between the same two nodes multiple times; this is problematic during deletion.
This never happened in the past because pin equivalence had always been applied to the LABs. The LABs have proper pin equivalence set up in the architecture capture. In a fully equivalent port, each pin should be mapped to a unique port, so the clustered netlist builder doesn't connect a net more than once to a port if it goes to multiple equivalent inputs in this case.
While investigating the case, I found multiple other issues that would arise if multiple sink-type rt nodes share the same rr node index. Several parts of the routing code need to use the net pin index of a node, but the rt_node structure only retains the node's rr node index value, so the rr node index is translated into its corresponding net pin index through the rr_sink_node_to_pin mapping, which could only map a rr-node index to ONE of its corresponding net pin indices.
If the architecture capture is modified properly with true equivalent ports to the DSP and ram blocks, this problem can be avoided. However, this is still a bug that we should address. If we one day take different speed paths to the same sink for different target_pins, we want to associate the route tree branch with the target_pin we were trying to route to (and hence make sure we get the branch with the timing we expect).
One way to fix this problem is to make rr_sink_node_to_pin a multimap, but that still makes it difficult to determine which pin a particular rt_node corresponds to if its node index maps to several net pin indices.
The best way to fix this once and for all is to have net pin index stored in the rt_node structure as well, so no more mapping is required.
How Has This Been Tested?
Types of changes
Checklist: