Skip to content

Commit fff2dc5

Browse files
refactor chan node adjacency checks
1 parent a39be3e commit fff2dc5

File tree

4 files changed

+199
-95
lines changed

4 files changed

+199
-95
lines changed

libs/librrgraph/src/base/rr_graph_utils.cpp

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "vpr_error.h"
44
#include "rr_graph_obj.h"
55
#include "rr_graph_builder.h"
6+
#include "rr_graph_view.h"
67

78
/*
89
* @brief Walk backwards from origin SINK, and insert all cluster-edge IPINs to which origin is connected to sink_ipins
@@ -255,3 +256,130 @@ bool inter_layer_connections_limited_to_opin(const RRGraphView& rr_graph) {
255256

256257
return limited_to_opin;
257258
}
259+
260+
bool chanx_chany_nodes_are_adjacent(const RRGraphView& rr_graph, RRNodeId node1, RRNodeId node2) {
261+
e_rr_type type1 = rr_graph.node_type(node1);
262+
e_rr_type type2 = rr_graph.node_type(node2);
263+
VTR_ASSERT((type1 == e_rr_type::CHANX && type2 == e_rr_type::CHANY) || (type1 == e_rr_type::CHANY && type2 == e_rr_type::CHANX));
264+
265+
// Make sure node1 is CHANX for consistency
266+
if (type1 == e_rr_type::CHANY) {
267+
std::swap(node1, node2);
268+
std::swap(type1, type2);
269+
}
270+
271+
RRNodeId chanx_node = node1;
272+
RRNodeId chany_node = node2;
273+
274+
// Check vertical (Y) adjacency
275+
if (rr_graph.node_ylow(chany_node) > rr_graph.node_ylow(chanx_node) + 1 ||
276+
rr_graph.node_yhigh(chany_node) < rr_graph.node_ylow(chanx_node)) {
277+
return false;
278+
}
279+
280+
// Check horizontal (X) adjacency
281+
if (rr_graph.node_xlow(chanx_node) > rr_graph.node_xlow(chany_node) + 1 ||
282+
rr_graph.node_xhigh(chanx_node) < rr_graph.node_xlow(chany_node)) {
283+
return false;
284+
}
285+
286+
return true;
287+
}
288+
289+
bool chanxy_chanz_adjacent(const RRGraphView& rr_graph, RRNodeId node1, RRNodeId node2) {
290+
e_rr_type type1 = rr_graph.node_type(node1);
291+
e_rr_type type2 = rr_graph.node_type(node2);
292+
293+
// Ensure one is CHANZ, the other is CHANX or CHANY
294+
VTR_ASSERT((type1 == e_rr_type::CHANZ && (type2 == e_rr_type::CHANX || type2 == e_rr_type::CHANY))
295+
|| (type2 == e_rr_type::CHANZ && (type1 == e_rr_type::CHANX || type1 == e_rr_type::CHANY)));
296+
297+
// Make sure chanz_node is second for unified handling
298+
if (type1 == e_rr_type::CHANZ) {
299+
std::swap(node1, node2);
300+
std::swap(type1, type2);
301+
}
302+
303+
// node1 is CHANX or CHANY, node2 is CHANZ
304+
RRNodeId chanxy_node = node1;
305+
RRNodeId chanz_node = node2;
306+
e_rr_type chanxy_node_type = type1;
307+
308+
int chanz_x = rr_graph.node_xlow(chanz_node);
309+
int chanz_y = rr_graph.node_ylow(chanz_node);
310+
VTR_ASSERT_SAFE(chanz_x == rr_graph.node_xhigh(chanz_node));
311+
VTR_ASSERT_SAFE(chanz_y == rr_graph.node_yhigh(chanz_node));
312+
313+
if (chanxy_node_type == e_rr_type::CHANX) {
314+
// CHANX runs horizontally: match Y, overlap X
315+
return chanz_y == rr_graph.node_ylow(chanxy_node)
316+
&& chanz_x >= rr_graph.node_xlow(chanxy_node) - 1
317+
&& chanz_x <= rr_graph.node_xhigh(chanxy_node) + 1;
318+
} else {
319+
// CHANY runs vertically: match X, overlap Y
320+
return chanz_x == rr_graph.node_xlow(chanxy_node)
321+
&& chanz_y >= rr_graph.node_ylow(chanxy_node) - 1
322+
&& chanz_y <= rr_graph.node_yhigh(chanxy_node) + 1;
323+
}
324+
}
325+
326+
bool chan_same_type_are_adjacent(const RRGraphView& rr_graph, RRNodeId node1, RRNodeId node2) {
327+
e_rr_type type = rr_graph.node_type(node1);
328+
VTR_ASSERT(type == rr_graph.node_type(node2));
329+
330+
int xlow1 = rr_graph.node_xlow(node1);
331+
int xhigh1 = rr_graph.node_xhigh(node1);
332+
int ylow1 = rr_graph.node_ylow(node1);
333+
int yhigh1 = rr_graph.node_yhigh(node1);
334+
int layer1 = rr_graph.node_layer(node1);
335+
336+
int xlow2 = rr_graph.node_xlow(node2);
337+
int xhigh2 = rr_graph.node_xhigh(node2);
338+
int ylow2 = rr_graph.node_ylow(node2);
339+
int yhigh2 = rr_graph.node_yhigh(node2);
340+
int layer2 = rr_graph.node_layer(node2);
341+
342+
if (type == e_rr_type::CHANX) {
343+
if (ylow1 != ylow2) {
344+
return false;
345+
}
346+
347+
// Adjacent ends or overlapping segments
348+
if (xhigh1 == xlow2 - 1 || xhigh2 == xlow1 - 1) {
349+
return true;
350+
}
351+
352+
for (int x = xlow1; x <= xhigh1; ++x) {
353+
if (x >= xlow2 && x <= xhigh2) {
354+
return true;
355+
}
356+
}
357+
return false;
358+
359+
} else if (type == e_rr_type::CHANY) {
360+
if (xlow1 != xlow2) {
361+
return false;
362+
}
363+
364+
if (yhigh1 == ylow2 - 1 || yhigh2 == ylow1 - 1) {
365+
return true;
366+
}
367+
368+
for (int y = ylow1; y <= yhigh1; ++y) {
369+
if (y >= ylow2 && y <= yhigh2) {
370+
return true;
371+
}
372+
}
373+
return false;
374+
375+
} else if (type == e_rr_type::CHANZ) {
376+
// Same X/Y span, adjacent layer
377+
bool same_xy = (xlow1 == xlow2 && xhigh1 == xhigh2 && ylow1 == ylow2 && yhigh1 == yhigh2);
378+
bool adjacent_layer = std::abs(layer1 - layer2) == 1;
379+
return same_xy && adjacent_layer;
380+
} else {
381+
VTR_ASSERT_MSG(false, "Unexpected RR node type in chan_same_type_are_adjacent().\n");
382+
}
383+
384+
return false; // unreachable
385+
}

libs/librrgraph/src/base/rr_graph_utils.h

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,14 @@
55
* @brief This file includes the most-utilized functions that manipulate the RRGraph object.
66
*/
77

8-
/* Include header files which include data structures used by
9-
* the function declaration
10-
*/
118
#include <vector>
129
#include "rr_graph_builder.h"
1310
#include "rr_graph_fwd.h"
1411
#include "rr_node_types.h"
15-
#include "rr_graph_view.h"
1612
#include "device_grid.h"
1713

14+
class RRGraphView;
15+
1816
struct t_pin_chain_node {
1917
int pin_physical_num = OPEN;
2018
int nxt_node_idx = OPEN;
@@ -93,8 +91,36 @@ int seg_index_of_sblock(const RRGraphView& rr_graph, int from_node, int to_node)
9391
* if that is the case. Can be used for multiple purposes. For example, to determine which type of bounding
9492
* box to be used to estimate the wire-length of a net.
9593
*
96-
* @param rr_graph
94+
* @param rr_graph The routing resource graph
9795
*
9896
* @return limited_to_opin
9997
*/
10098
bool inter_layer_connections_limited_to_opin(const RRGraphView& rr_graph);
99+
100+
/**
101+
* @brief Check if a CHANX and a CHANY node are adjacent, regardless of their order.
102+
*
103+
* This function checks spatial adjacency between a CHANX and CHANY node without assuming
104+
* any particular input order. If the node types are not one CHANX and one CHANY, an error is thrown.
105+
*
106+
* @param rr_graph The routing resource graph
107+
* @param node1 One of the nodes (CHANX or CHANY)
108+
* @param node2 The other node (CHANX or CHANY)
109+
* @return true if the nodes are spatially adjacent, false otherwise
110+
*/
111+
bool chanx_chany_nodes_are_adjacent(const RRGraphView& rr_graph, RRNodeId node1, RRNodeId node2);
112+
113+
/**
114+
* @brief Check if a CHANX or CHANY node is adjacent to a CHANZ node.
115+
*
116+
* @param rr_graph The routing resource graph
117+
* @param node1 One of the RR nodes (CHANX, CHANY, or CHANZ)
118+
* @param node2 The other RR node
119+
* @return true if spatially adjacent, false otherwise
120+
*
121+
* @note Exactly one node must be CHANZ; the other must be CHANX or CHANY.
122+
*/
123+
bool chanxy_chanz_adjacent(const RRGraphView& rr_graph, RRNodeId node1, RRNodeId node2);
124+
125+
bool chan_same_type_are_adjacent(const RRGraphView& rr_graph, RRNodeId node1, RRNodeId node2);
126+

libs/librrgraph/src/base/rr_graph_view.h

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
#include "physical_types.h"
6060
#include "rr_spatial_lookup.h"
6161
#include "vtr_geometry.h"
62+
#include "rr_graph_utils.h"
6263

6364
class RRGraphView {
6465
/* -- Constructors -- */
@@ -262,19 +263,37 @@ class RRGraphView {
262263
&& (node_xhigh(node) == -1) && (node_yhigh(node) == -1));
263264
}
264265

265-
/** @brief Check if two routing resource nodes are adjacent (must be a CHANX and a CHANY).
266-
* @note This function performs error checking by determining whether two nodes are physically adjacent based on their geometry.
267-
* It does not verify the routing edges to confirm if a connection is feasible within the current routing graph.
266+
/**
267+
* @brief Check if two CHANX, CHANY, or CHANZ nodes are spatially adjacent.
268+
* @param node1 First routing resource node
269+
* @param node2 Second routing resource node
270+
* @return true if the nodes are adjacent, false otherwise
268271
*/
269-
inline bool nodes_are_adjacent(RRNodeId chanx_node, RRNodeId chany_node) const {
270-
VTR_ASSERT(node_type(chanx_node) == e_rr_type::CHANX && node_type(chany_node) == e_rr_type::CHANY);
271-
if (node_ylow(chany_node) > node_ylow(chanx_node) + 1 || // verifies that chany_node is not more than one unit above chanx_node
272-
node_yhigh(chany_node) < node_ylow(chanx_node)) // verifies that chany_node is not more than one unit beneath chanx_node
273-
return false;
274-
if (node_xlow(chanx_node) > node_xlow(chany_node) + 1 || // verifies that chany_node is not more than one unit to the left of chanx_node
275-
node_xhigh(chanx_node) < node_xlow(chany_node)) // verifies that chany_node is not more than one unit to the right of chanx_node
276-
return false;
277-
return true;
272+
inline bool chan_nodes_are_adjacent(RRNodeId node1, RRNodeId node2) const {
273+
e_rr_type type1 = node_type(node1);
274+
e_rr_type type2 = node_type(node2);
275+
VTR_ASSERT(type1 == e_rr_type::CHANX || type1 == e_rr_type::CHANY || type1 == e_rr_type::CHANZ);
276+
VTR_ASSERT(type2 == e_rr_type::CHANX || type2 == e_rr_type::CHANY || type2 == e_rr_type::CHANZ);
277+
278+
if ((type1 == e_rr_type::CHANX && type2 == e_rr_type::CHANY)
279+
|| (type1 == e_rr_type::CHANY && type2 == e_rr_type::CHANX)) {
280+
return chanx_chany_nodes_are_adjacent(*this, node1, node2);
281+
}
282+
283+
// CHANX/CHANY to CHANZ (in any order)
284+
if ((type1 == e_rr_type::CHANZ || type2 == e_rr_type::CHANZ) &&
285+
(type1 == e_rr_type::CHANX || type1 == e_rr_type::CHANY ||
286+
type2 == e_rr_type::CHANX || type2 == e_rr_type::CHANY)) {
287+
return chanxy_chanz_adjacent(*this, node1, node2);
288+
}
289+
290+
// Same-type channel nodes (CHANX–CHANX, CHANY–CHANY, CHANZ–CHANZ)
291+
if (type1 == type2) {
292+
return chan_same_type_are_adjacent(*this, node1, node2);
293+
}
294+
295+
VTR_ASSERT_MSG(false, "Invalid CHAN node combination passed to chan_nodes_are_adjacent()");
296+
return false;
278297
}
279298

280299
/**

vpr/src/route/check_route.cpp

Lines changed: 9 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,6 @@ static void check_net_for_stubs(const Netlist<>& net_list,
8484
ParentNetId net,
8585
bool is_flat);
8686

87-
/**
88-
* @brief Returns true if the given CHANX or CHANY node is adjacent to the given CHANZ node.
89-
* @note Only performs geometric adjacency check; does not validate routing connectivity.
90-
*/
91-
static bool chanxy_chanz_adjacent(RRNodeId chanxy_node, RRNodeId chanz_node);
92-
9387
/************************ Subroutine definitions ****************************/
9488

9589
void check_route(const Netlist<>& net_list,
@@ -420,27 +414,9 @@ static bool check_adjacent(RRNodeId from_node, RRNodeId to_node, bool is_flat) {
420414

421415
case e_rr_type::CHANX:
422416
if (to_type == e_rr_type::IPIN) {
423-
num_adj += 1; //adjacent
424-
} else if (to_type == e_rr_type::CHANX) {
425-
from_xhigh = rr_graph.node_xhigh(from_node);
426-
to_xhigh = rr_graph.node_xhigh(to_node);
427-
if (from_ylow == to_ylow) {
428-
/*For Fs > 3, can connect to overlapping wire segment */
429-
if (to_xhigh == from_xlow - 1 || from_xhigh == to_xlow - 1) {
430-
num_adj++;
431-
} else { // Overlapping
432-
for (int i = from_xlow; i <= from_xhigh; i++) {
433-
if (i >= to_xlow && i <= to_xhigh) {
434-
num_adj++;
435-
break;
436-
}
437-
}
438-
}
439-
}
440-
} else if (to_type == e_rr_type::CHANY) {
441-
num_adj += rr_graph.nodes_are_adjacent(from_node, to_node);
442-
} else if (to_type == e_rr_type::CHANZ) {
443-
num_adj += chanxy_chanz_adjacent(from_node, to_node);
417+
num_adj += 1; // adjacent
418+
} else if (to_type == e_rr_type::CHANX || to_type == e_rr_type::CHANY || to_type == e_rr_type::CHANZ) {
419+
num_adj += rr_graph.chan_nodes_are_adjacent(from_node, to_node);
444420
} else {
445421
VPR_FATAL_ERROR(VPR_ERROR_ROUTE,
446422
"in check_adjacent: %d and %d are not adjacent", from_node, to_node);
@@ -449,39 +425,18 @@ static bool check_adjacent(RRNodeId from_node, RRNodeId to_node, bool is_flat) {
449425

450426
case e_rr_type::CHANY:
451427
if (to_type == e_rr_type::IPIN) {
452-
num_adj += 1; //adjacent
453-
} else if (to_type == e_rr_type::CHANY) {
454-
from_yhigh = rr_graph.node_yhigh(from_node);
455-
to_yhigh = rr_graph.node_yhigh(to_node);
456-
if (from_xlow == to_xlow) {
457-
if (to_yhigh == from_ylow - 1 || from_yhigh == to_ylow - 1) {
458-
num_adj++;
459-
} else { // Overlapping
460-
for (int j = from_ylow; j <= from_yhigh; j++) {
461-
if (j >= to_ylow && j <= to_yhigh) {
462-
num_adj++;
463-
break;
464-
}
465-
}
466-
}
467-
}
468-
} else if (to_type == e_rr_type::CHANX) {
469-
num_adj += rr_graph.nodes_are_adjacent(to_node, from_node);
470-
} else if (to_type == e_rr_type::CHANZ) {
471-
num_adj += chanxy_chanz_adjacent(from_node, to_node);
428+
num_adj += 1; // adjacent
429+
} else if (to_type == e_rr_type::CHANX || to_type == e_rr_type::CHANY || to_type == e_rr_type::CHANZ) {
430+
num_adj += rr_graph.chan_nodes_are_adjacent(from_node, to_node);
472431
} else {
473432
VPR_FATAL_ERROR(VPR_ERROR_ROUTE,
474433
"in check_adjacent: %d and %d are not adjacent", from_node, to_node);
475434
}
476435
break;
477436

478437
case e_rr_type::CHANZ:
479-
if (to_type == e_rr_type::CHANX || to_type == e_rr_type::CHANY) {
480-
num_adj += chanxy_chanz_adjacent(to_node, from_node);
481-
} else if (to_type == e_rr_type::CHANZ) {
482-
if (from_xlow == to_xlow && from_xhigh == to_xhigh && from_ylow == to_ylow && from_yhigh == to_yhigh && std::abs(from_layer - to_layer) == 1) {
483-
num_adj++;
484-
}
438+
if (to_type == e_rr_type::CHANX || to_type == e_rr_type::CHANY || to_type == e_rr_type::CHANZ) {
439+
num_adj += rr_graph.chan_nodes_are_adjacent(from_node, to_node);
485440
} else {
486441
VPR_FATAL_ERROR(VPR_ERROR_ROUTE,
487442
"in check_adjacent: %d and %d are not adjacent", from_node, to_node);
@@ -501,7 +456,7 @@ static bool check_adjacent(RRNodeId from_node, RRNodeId to_node, bool is_flat) {
501456

502457
VPR_ERROR(VPR_ERROR_ROUTE,
503458
"in check_adjacent: num_adj = %d. Expected 0 or 1.\n", num_adj);
504-
return false; //Should not reach here once thrown
459+
return false; // Should not reach here once thrown
505460
}
506461

507462
void recompute_occupancy_from_scratch(const Netlist<>& net_list, bool is_flat) {
@@ -872,30 +827,6 @@ void check_net_for_stubs(const Netlist<>& net_list,
872827
}
873828
}
874829

875-
static bool chanxy_chanz_adjacent(RRNodeId chanxy_node, RRNodeId chanz_node) {
876-
const RRGraphView& rr_graph = g_vpr_ctx.device().rr_graph;
877-
VTR_ASSERT(rr_graph.node_type(chanz_node) == e_rr_type::CHANZ);
878-
e_rr_type chanxy_node_type = rr_graph.node_type(chanxy_node);
879-
VTR_ASSERT(chanxy_node_type == e_rr_type::CHANX || chanxy_node_type == e_rr_type::CHANY);
880-
881-
int chanz_x = rr_graph.node_xlow(chanz_node);
882-
int chanz_y = rr_graph.node_ylow(chanz_node);
883-
VTR_ASSERT_SAFE(chanz_x == rr_graph.node_xhigh(chanz_node));
884-
VTR_ASSERT_SAFE(chanz_y == rr_graph.node_yhigh(chanz_node));
885-
886-
if (chanxy_node_type == e_rr_type::CHANX) {
887-
// CHANX runs horizontally, so y must match and x must overlap
888-
return chanz_y == rr_graph.node_ylow(chanxy_node)
889-
&& chanz_x >= rr_graph.node_xlow(chanxy_node) - 1
890-
&& chanz_x <= rr_graph.node_xhigh(chanxy_node) + 1;
891-
} else {
892-
// CHANY runs vertically, so x must match and y must overlap
893-
return chanz_x == rr_graph.node_xlow(chanxy_node)
894-
&& chanz_y >= rr_graph.node_ylow(chanxy_node) - 1
895-
&& chanz_y <= rr_graph.node_yhigh(chanxy_node) + 1;
896-
}
897-
}
898-
899830
bool StubFinder::CheckNet(ParentNetId net) {
900831
auto& route_ctx = g_vpr_ctx.mutable_routing();
901832
stub_nodes_.clear();

0 commit comments

Comments
 (0)