From 4db0aef33770a41ee0f0d55c9ef09cdba04a0a33 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 20 Oct 2025 16:01:34 -0700 Subject: [PATCH 01/14] [TestRWRoute] Initial testSLRCrossingNonTimingDriven for Versal Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/TestRWRoute.java | 70 ++++++++++--------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java index 197ae2d6d..85736e054 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java @@ -401,48 +401,54 @@ void testSingleConnectionHelper(String partName, @ParameterizedTest @CsvSource({ + // Versal + // One SLR crossing + // Perfect + "xcv80,SLICE_X54Y331,SLICE_X54Y406,500", + + // US+ // One SLR crossing // (Too) Close - "SLICE_X9Y299,SLICE_X9Y300,100", // On Laguna column - "SLICE_X9Y300,SLICE_X9Y299,200", - "SLICE_X0Y299,SLICE_X0Y300,200", // Far from Laguna column - "SLICE_X0Y300,SLICE_X0Y299,200", - "SLICE_X54Y299,SLICE_X56Y300,200", // Slight closer to one Laguna column that is further from sink - "SLICE_X54Y300,SLICE_X56Y299,200", - "SLICE_X50Y299,SLICE_X65Y300,200", - "SLICE_X50Y300,SLICE_X65Y299,300", - "SLICE_X55Y299,SLICE_X55Y300,200", // Equidistant from two Laguna columns - "SLICE_X55Y300,SLICE_X55Y299,200", + Device.AWS_F1 + ",SLICE_X9Y299,SLICE_X9Y300,100", // On Laguna column + Device.AWS_F1 + ",SLICE_X9Y300,SLICE_X9Y299,200", + Device.AWS_F1 + ",SLICE_X0Y299,SLICE_X0Y300,200", // Far from Laguna column + Device.AWS_F1 + ",SLICE_X0Y300,SLICE_X0Y299,200", + Device.AWS_F1 + ",SLICE_X54Y299,SLICE_X56Y300,200", // Slight closer to one Laguna column that is further from sink + Device.AWS_F1 + ",SLICE_X54Y300,SLICE_X56Y299,200", + Device.AWS_F1 + ",SLICE_X50Y299,SLICE_X65Y300,200", + Device.AWS_F1 + ",SLICE_X50Y300,SLICE_X65Y299,300", + Device.AWS_F1 + ",SLICE_X55Y299,SLICE_X55Y300,200", // Equidistant from two Laguna columns + Device.AWS_F1 + ",SLICE_X55Y300,SLICE_X55Y299,200", // Perfect - "SLICE_X9Y241,SLICE_X9Y300,200", - "SLICE_X9Y300,SLICE_X9Y241,200", - "SLICE_X9Y358,SLICE_X9Y299,200", - "SLICE_X9Y299,SLICE_X9Y358,200", - "SLICE_X53Y241,SLICE_X69Y300,500", - "SLICE_X53Y358,SLICE_X69Y299,500", + Device.AWS_F1 + ",SLICE_X9Y241,SLICE_X9Y300,200", + Device.AWS_F1 + ",SLICE_X9Y300,SLICE_X9Y241,200", + Device.AWS_F1 + ",SLICE_X9Y358,SLICE_X9Y299,200", + Device.AWS_F1 + ",SLICE_X9Y299,SLICE_X9Y358,200", + Device.AWS_F1 + ",SLICE_X53Y241,SLICE_X69Y300,500", + Device.AWS_F1 + ",SLICE_X53Y358,SLICE_X69Y299,500", // Far - "SLICE_X9Y240,SLICE_X9Y359,200", // On Laguna - "SLICE_X9Y359,SLICE_X9Y240,200", - "SLICE_X162Y240,SLICE_X162Y430,100", + Device.AWS_F1 + ",SLICE_X9Y240,SLICE_X9Y359,200", // On Laguna + Device.AWS_F1 + ",SLICE_X9Y359,SLICE_X9Y240,200", + Device.AWS_F1 + ",SLICE_X162Y240,SLICE_X162Y430,100", - "SLICE_X162Y430,SLICE_X162Y240,200", - "SLICE_X0Y240,SLICE_X12Y430,300", // Far from Laguna - "SLICE_X0Y430,SLICE_X12Y240,300", + Device.AWS_F1 + ",SLICE_X162Y430,SLICE_X162Y240,200", + Device.AWS_F1 + ",SLICE_X0Y240,SLICE_X12Y430,300", // Far from Laguna + Device.AWS_F1 + ",SLICE_X0Y430,SLICE_X12Y240,300", // Two SLR crossings - "SLICE_X162Y299,SLICE_X162Y599,100", - "SLICE_X162Y599,SLICE_X162Y299,300", + Device.AWS_F1 + ",SLICE_X162Y299,SLICE_X162Y599,100", + Device.AWS_F1 + ",SLICE_X162Y599,SLICE_X162Y299,300", // Three SLR crossings - "SLICE_X79Y0,SLICE_X79Y899,200", // Straight up: on Laguna column (opposite side of Laguna) - "SLICE_X78Y60,SLICE_X78Y839,400", // Straight up: on Laguna column (same side as Laguna) - "SLICE_X0Y0,SLICE_X0Y899,200", // Straight up: far from Laguna column - "SLICE_X168Y0,SLICE_X168Y899,300", // Straight up: far from Laguna column - "SLICE_X9Y0,SLICE_X162Y899,300", // Up and right - "SLICE_X168Y162,SLICE_X9Y899,400", // Up and left + Device.AWS_F1 + ",SLICE_X79Y0,SLICE_X79Y899,200", // Straight up: on Laguna column (opposite side of Laguna) + Device.AWS_F1 + ",SLICE_X78Y60,SLICE_X78Y839,400", // Straight up: on Laguna column (same side as Laguna) + Device.AWS_F1 + ",SLICE_X0Y0,SLICE_X0Y899,200", // Straight up: far from Laguna column + Device.AWS_F1 + ",SLICE_X168Y0,SLICE_X168Y899,300", // Straight up: far from Laguna column + Device.AWS_F1 + ",SLICE_X9Y0,SLICE_X162Y899,300", // Up and right + Device.AWS_F1 + ",SLICE_X168Y162,SLICE_X9Y899,400", // Up and left }) - public void testSLRCrossingNonTimingDriven(String srcSiteName, String dstSiteName, long nodesPoppedLimit) { - testSingleConnectionHelper(Device.AWS_F1, srcSiteName, "AQ", dstSiteName, "A1", nodesPoppedLimit); + public void testSLRCrossingNonTimingDriven(String deviceName, String srcSiteName, String dstSiteName, long nodesPoppedLimit) { + testSingleConnectionHelper(deviceName, srcSiteName, "AQ", dstSiteName, "A1", nodesPoppedLimit); } @ParameterizedTest From be31586abc0a5bce374442911ade81c39423c913 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 20 Oct 2025 16:02:05 -0700 Subject: [PATCH 02/14] [RWRoute] Initial Versal SLR crossing support Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/Connection.java | 12 ++-- .../rapidwright/rwroute/NetWrapper.java | 8 +-- .../xilinx/rapidwright/rwroute/RWRoute.java | 22 +++++-- .../xilinx/rapidwright/rwroute/RouteNode.java | 1 + .../rapidwright/rwroute/RouteNodeGraph.java | 66 +++++++++++++++++-- .../rapidwright/rwroute/RouteNodeInfo.java | 2 + 6 files changed, 86 insertions(+), 25 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/Connection.java b/src/com/xilinx/rapidwright/rwroute/Connection.java index 6e7c4e142..4fd778892 100644 --- a/src/com/xilinx/rapidwright/rwroute/Connection.java +++ b/src/com/xilinx/rapidwright/rwroute/Connection.java @@ -118,7 +118,7 @@ public void computeHpwl() { * @param prevLagunaColumn Array mapping arbitrary tile columns to the previous Laguna column */ public void computeConnectionBoundingBox(short boundingBoxExtensionX, short boundingBoxExtensionY, - int[] nextLagunaColumn, int[] prevLagunaColumn) { + RouteNodeGraph routingGraph) { short xMin, xMax, yMin, yMax; short xNetCenter = (short) Math.ceil(netWrapper.getXCenter()); short yNetCenter = (short) Math.ceil(netWrapper.getYCenter()); @@ -127,11 +127,11 @@ public void computeConnectionBoundingBox(short boundingBoxExtensionX, short boun yMax = maxOfThree(sourceRnode.getEndTileYCoordinate(), sinkRnode.getEndTileYCoordinate(), yNetCenter); yMin = minOfThree(sourceRnode.getEndTileYCoordinate(), sinkRnode.getEndTileYCoordinate(), yNetCenter); - if (isCrossSLR()) { + if (isCrossSLR() && !routingGraph.isVersal) { // For SLR-crossing connections, ensure the bounding box width contains at least one Laguna column // before bounding box extension - int nextLaguna = nextLagunaColumn[xMin]; - int prevLaguna = prevLagunaColumn[xMax]; + int nextLaguna = routingGraph.nextLagunaColumn[xMin]; + int prevLaguna = routingGraph.prevLagunaColumn[xMax]; if (nextLaguna != Integer.MAX_VALUE) { xMax = (short) Math.max(xMax, nextLaguna); } @@ -282,10 +282,6 @@ public void setSinkRnode(RouteNode sinkRnode) { assert(sourceRnode != null); if (!sourceRnode.getTile().getSLR().equals(sinkRnode.getTile().getSLR())) { - if (source.getSiteInst().getDesign().getSeries() == Series.Versal) { - throw new RuntimeException("ERROR: Cross-SLR connections not yet supported on Versal."); - } - if (sourceRnode.getTile().getTileYCoordinate() < sinkRnode.getTile().getTileYCoordinate()) { crossSLRnorth = true; assert(!crossSLRsouth); diff --git a/src/com/xilinx/rapidwright/rwroute/NetWrapper.java b/src/com/xilinx/rapidwright/rwroute/NetWrapper.java index 278a223e1..ff1ea4f0d 100644 --- a/src/com/xilinx/rapidwright/rwroute/NetWrapper.java +++ b/src/com/xilinx/rapidwright/rwroute/NetWrapper.java @@ -58,7 +58,7 @@ public NetWrapper(int id, Net net) { noAltSourceFound = false; } - public void computeHPWLAndCenterCoordinates(int[] nextLagunaColumn, int[] prevLagunaColumn) { + public void computeHPWLAndCenterCoordinates(RouteNodeGraph routingGraph) { int xMin = Integer.MAX_VALUE; int yMin = Integer.MAX_VALUE; int xMax = Integer.MIN_VALUE; @@ -77,10 +77,10 @@ public void computeHPWLAndCenterCoordinates(int[] nextLagunaColumn, int[] prevLa xMax = Integer.max(xMax, x); yMax = Integer.max(yMax, y); - if (connection.isCrossSLR()) { + if (connection.isCrossSLR() && !routingGraph.isVersal) { // For SLR-crossing connections, ensure it contains at least one Laguna column - int nextLaguna = nextLagunaColumn[xMin]; - int prevLaguna = prevLagunaColumn[xMax]; + int nextLaguna = routingGraph.nextLagunaColumn[xMin]; + int prevLaguna = routingGraph.prevLagunaColumn[xMax]; xMin = (short) Math.min(xMin, prevLaguna); xMax = (short) Math.max(xMax, nextLaguna); } diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 9505f9b89..ab0b5760a 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -755,14 +755,13 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { } if (indirect > 0) { - netWrapper.computeHPWLAndCenterCoordinates(routingGraph.nextLagunaColumn, routingGraph.prevLagunaColumn); + netWrapper.computeHPWLAndCenterCoordinates(routingGraph); if (config.isUseBoundingBox()) { for (Connection connection : netWrapper.getConnections()) { if (connection.isDirect()) continue; connection.computeConnectionBoundingBox(config.getBoundingBoxExtensionX(), config.getBoundingBoxExtensionY(), - routingGraph.nextLagunaColumn, - routingGraph.prevLagunaColumn); + routingGraph); } } } @@ -1940,9 +1939,13 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { // Verify invariant that east/west wires stay east/west ... assert(!rnodeType.isEastLocal() || childType.isEastLocal() || // ... unless it's an exclusive sink using a LOCAL_RESERVED node - (childType == RouteNodeType.LOCAL_RESERVED && connection.getSinkRnode().getType() == RouteNodeType.EXCLUSIVE_SINK_BOTH)); + (childType == RouteNodeType.LOCAL_RESERVED && connection.getSinkRnode().getType() == RouteNodeType.EXCLUSIVE_SINK_BOTH) || + // ... or unless it's a Versal SLL input + childRNode.getIntentCode() == IntentCode.NODE_SLL_INPUT); assert(!rnodeType.isWestLocal() || childType.isWestLocal() || - (childType == RouteNodeType.LOCAL_RESERVED && connection.getSinkRnode().getType() == RouteNodeType.EXCLUSIVE_SINK_BOTH)); + (childType == RouteNodeType.LOCAL_RESERVED && connection.getSinkRnode().getType() == RouteNodeType.EXCLUSIVE_SINK_BOTH) || + // ... or unless it's a Versal SLL input + childRNode.getIntentCode() == IntentCode.NODE_SLL_INPUT); break; case NON_LOCAL_LEADING_TO_NORTHBOUND_LAGUNA: case NON_LOCAL_LEADING_TO_SOUTHBOUND_LAGUNA: @@ -1959,7 +1962,11 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { // (a) IMUX (LOCAL_*_LEADING_TO_*_LAGUNA) -> LAG_MUX_ATOM_\\d+_TXOUT // (b) via a LUT routethru: IMUX (LOCAL*) -> CLE_CLE_*_SITE_0_[A-H]_O assert(!rnodeType.isAnyLocal() || rnodeType.isLocalLeadingToLaguna() || - (routingGraph.lutRoutethru && rnode.getIntentCode() == IntentCode.NODE_PINFEED)); + (routingGraph.lutRoutethru && rnode.getIntentCode() == IntentCode.NODE_PINFEED) || + // Allow CLE/*LAG*_PIN -> CLE/*[A-H]Q2?_PIN + (routingGraph.isVersal && connection.isCrossSLR() && + routingGraph.isVersalLagOutRoutethru(rnode, childRNode)) + ); if (!routingGraph.isAccessible(childRNode, rnode, connection)) { continue; @@ -2092,7 +2099,8 @@ protected void evaluateCostAndPush(ConnectionState state, )); int deltaSLR = Math.abs(sinkRnode.getSLRIndex(routingGraph) - childRnode.getSLRIndex(routingGraph)); - if (deltaSLR != 0) { + if (deltaSLR != 0 + && !routingGraph.isVersal) { // FIXME: Update this for Versal // Check for overshooting which occurs when child and sink node are in // adjacent SLRs and less than a SLL wire's length apart in the Y axis. if (deltaSLR == 1) { diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index 0d4815b01..1fa416f4f 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -171,6 +171,7 @@ private void setBaseCost(Series series) { case NODE_LAGUNA_OUTPUT: // LAG_LAG.{LAG_MUX_ATOM_*_TXOUT,RXD*} (US+) case NODE_LAGUNA_DATA: // LAG_LAG.UBUMP* super long lines for u-turns at the boundary of the device (US+) case NODE_SLL_INPUT: // Versal only + case NODE_SLL_OUTPUT: // Versal only case INTENT_DEFAULT: // INT.VCC_WIRE assert(length == 0); break; diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 4ed130591..b916e89a2 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -555,11 +555,17 @@ public void initialize() { */ protected int getBaseWireCount(Tile tile, int startWireIndex) { return baseWireCounts.computeIfAbsent(tile.getTileTypeEnum(), (e) -> { + boolean isSLLType = isVersal && e == TileTypeEnum.SLL; // Check all wires in tile to find the index of the last base wire int lastBaseWire = startWireIndex; for (int i = lastBaseWire + 1; i < tile.getWireCount(); i++) { Node node = Node.getNode(tile, i); - if (node != null && node.getTile() == tile && node.getWireIndex() == i) { + if (node == null) { + continue; + } + if ((node.getTile() == tile && node.getWireIndex() == i) || + // Count Versal SLLs even if they're not based in this tile, since they are bidir + (isSLLType && node.getTile().getTileTypeEnum() == e && node.getIntentCode() == IntentCode.NODE_SLL_DATA)) { lastBaseWire = i; } } @@ -722,6 +728,24 @@ protected boolean isExcluded(RouteNode parent, Node child) { } if (isExcludedTile(child)) { + if (isVersal) { + IntentCode parentIc = parent.getIntentCode(); + if (parentIc == IntentCode.NODE_SLL_OUTPUT) { + // Allow NODE_SLL_OUTPUT -> CLE/*LAG*_PIN + return false; + } + if (parentIc == IntentCode.NODE_CLE_OUTPUT) { + // Allow NODE_CLE_OUTPUT -> NODE_CLE_OUTPUT (e.g. [A-H]Q_PIN -> [A-H]Q) + assert(child.getIntentCode() == IntentCode.NODE_CLE_OUTPUT); + return false; + } + if (child.getIntentCode() == IntentCode.NODE_CLE_OUTPUT && parentIc == IntentCode.NODE_PINFEED && + parent.getWireName().matches("CLE_SLICE[LM]_TOP_[01]_LAG_([NS]|[EW][12])_PIN")) { + assert(child.getWireName().matches("CLE_SLICE[LM]_TOP_[01]_[A-H]Q2?_PIN")); + // Allow CLE/*LAG*_PIN -> CLE/*[A-H]Q2?_PIN + return false; + } + } if (!allowRoutethru(parent, child)) { return true; } @@ -738,6 +762,11 @@ protected boolean isExcluded(RouteNode parent, Node child) { // Disallow these site pin projections if they aren't already in the routing graph (as a potential sink) return childRnode == null; } + + if (ic == IntentCode.NODE_SLL_INPUT && parent.getIntentCode() == IntentCode.NODE_SLL_OUTPUT) { + // Disallow NODE_SLL_OUTPUT -> NODE_SLL_INPUT arcs (why are you able to come off an SLL just to go back onto one?) + return true; + } } else { assert(design.getSeries() == Series.UltraScale || design.getSeries() == Series.UltraScalePlus); @@ -893,6 +922,9 @@ public RouteNode getOrCreate(Node node, RouteNodeType type) { rnodes = new RouteNode[baseWireCount]; nodesMap[tileAddress] = rnodes; } + if (wireIndex >= rnodes.length) { + System.err.print(""); + } RouteNode rnode = rnodes[wireIndex]; if (rnode == null) { rnode = create(node, type); @@ -937,7 +969,8 @@ public boolean isAccessible(RouteNode childRnode, RouteNode parentRnode, Connect return false; } } else { - assert(lutRoutethru); + assert(lutRoutethru || + isVersal && connection.isCrossSLR() && isVersalLagOutRoutethru(parentRnode, childRnode)); assert(Utils.isCLB(childTileType)); // IMUX_[EW]\\d+ -> CLE_CLE_L_SITE_0_[A-H]_O assert(childRnode.getIntentCode() == IntentCode.NODE_CLE_OUTPUT); @@ -958,10 +991,12 @@ public boolean isAccessible(RouteNode childRnode, RouteNode parentRnode, Connect TileTypeEnum childTileType = childRnode.getTile().getTileTypeEnum(); assert(childTileType == TileTypeEnum.INT || - isVersal && EnumSet.of(TileTypeEnum.INTF_LOCF_TR_TILE, TileTypeEnum.INTF_LOCF_BR_TILE, TileTypeEnum.INTF_ROCF_TR_TILE, TileTypeEnum.INTF_ROCF_BR_TILE, - TileTypeEnum.INTF_LOCF_TL_TILE, TileTypeEnum.INTF_LOCF_BL_TILE, TileTypeEnum.INTF_ROCF_TL_TILE, TileTypeEnum.INTF_ROCF_BL_TILE, + (isVersal && EnumSet.of(TileTypeEnum.INTF_LOCF_TR_TILE, TileTypeEnum.INTF_LOCF_BR_TILE, TileTypeEnum.INTF_ROCF_TR_TILE, TileTypeEnum.INTF_ROCF_BR_TILE, + TileTypeEnum.INTF_LOCF_TL_TILE, TileTypeEnum.INTF_LOCF_BL_TILE, TileTypeEnum.INTF_ROCF_TL_TILE, TileTypeEnum.INTF_ROCF_BL_TILE, TileTypeEnum.CLE_BC_CORE, TileTypeEnum.SLL) - .contains(childTileType)); + .contains(childTileType)) || + (isVersal && parentRnode.getIntentCode() == IntentCode.NODE_SLL_OUTPUT && childRnode.getIntentCode() == IntentCode.NODE_PINFEED && Utils.isCLB(childTileType)) + ); if (lutRoutethru && !type.leadsToLaguna()) { // (a) considering LUT routethrus (that do not lead to a Laguna) @@ -1076,9 +1111,12 @@ public boolean isAccessible(RouteNode childRnode, RouteNode parentRnode, Connect return false; case NODE_CLE_BNODE: case NODE_INTF_BNODE: + if (connection.isCrossSLR()) { + return true; + } case NODE_CLE_CNODE: case NODE_INTF_CNODE: - // Only allow [BC]NODEs that reach into the sink tile + // Allow [BC]NODEs that reach into the sink tile return childTile.getTileYCoordinate() == sinkTile.getTileYCoordinate() && childRnode.getEndTileXCoordinate() == sinkTile.getTileXCoordinate(); case NODE_PINBOUNCE: @@ -1089,6 +1127,10 @@ public boolean isAccessible(RouteNode childRnode, RouteNode parentRnode, Connect // LUT routethrus are enabled (which would have already returned true above) break; case NODE_PINFEED: + if (connection.isCrossSLR()) { + // Allow NODE_SLL_OUTPUT -> NODE_PINFEED + return parentRnode.getIntentCode() == IntentCode.NODE_SLL_OUTPUT; + } // Expected to be projected away break; case NODE_CLE_CTRL: @@ -1096,6 +1138,10 @@ public boolean isAccessible(RouteNode childRnode, RouteNode parentRnode, Connect // CTRL pins that are not our target EXCLUSIVE_SINK will have been isExcluded() from the graph break; case NODE_SLL_INPUT: + if (connection.isCrossSLR()) { + assert(parentRnode.getIntentCode() != IntentCode.NODE_SLL_OUTPUT); + return true; + } // Temporarily only allow NODE_SLL_INPUT to be explored if they are the sink // TODO: Revisit when SLR crossings are supported return childRnode == sinkRnode; @@ -1153,4 +1199,12 @@ public void updatePresentCongestionCosts(float presentCongestionFactor) { public float getPresentCongestionCost(int occupancy) { return presentCongestionCosts[occupancy]; } + + public boolean isVersalLagOutRoutethru(Node parent, Node child) { + assert(isVersal); + return parent.getIntentCode() == IntentCode.NODE_PINFEED && + child.getIntentCode() == IntentCode.NODE_CLE_OUTPUT && + parent.getWireName().matches("CLE_SLICE[LM]_TOP_[01]_LAG_([NS]|[EW][12])_PIN") && + child.getWireName().matches("CLE_SLICE[LM]_TOP_[01]_[A-H]Q2?_PIN"); + } } diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java index 3d0287b1c..640e82c78 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java @@ -245,6 +245,8 @@ public static RouteNodeType getType(Node node, RouteNodeGraph routingGraph) { case NODE_CLE_CTRL: // CLE_BC_CORE*.CTRL_[LR]_B* case NODE_INTF_CTRL: // INTF_[LR]OCF_[TB][LR]_TILE.INTF_IRI* return RouteNodeType.LOCAL_BOTH; + case NODE_SLL_DATA: + return RouteNodeType.SUPER_LONG_LINE; case NODE_LAGUNA_DATA: // UltraScale+ only assert(tileTypeEnum == TileTypeEnum.LAG_LAG); From b099c4fb889dc8082e29e1a74e49c74e76a096fa Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 20 Oct 2025 16:24:49 -0700 Subject: [PATCH 03/14] More tests Signed-off-by: Eddie Hung --- test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java index 85736e054..6911d5251 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java @@ -403,8 +403,13 @@ void testSingleConnectionHelper(String partName, @CsvSource({ // Versal // One SLR crossing + // (Too) close + "xcv80,SLICE_X54Y331,SLICE_X54Y332,39700", // Adjacent to crossing SLL (east) + "xcv80,SLICE_X51Y331,SLICE_X51Y332,39000", // Perfect - "xcv80,SLICE_X54Y331,SLICE_X54Y406,500", + "xcv80,SLICE_X54Y331,SLICE_X54Y406,500", // Adjacent to crossing SLL (east) + "xcv80,SLICE_X53Y331,SLICE_X53Y406,200", // Adjacent to crossing SLL (west) + "xcv80,SLICE_X51Y331,SLICE_X51Y406,400", // US+ // One SLR crossing From c7157afa15a0f94c171addb731afd9a7a26436b2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 20 Oct 2025 16:25:19 -0700 Subject: [PATCH 04/14] [RouteNodeGraph] Dynamic SLL length Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/rwroute/Connection.java | 9 +++++---- src/com/xilinx/rapidwright/rwroute/RWRoute.java | 6 +++--- src/com/xilinx/rapidwright/rwroute/RouteNode.java | 9 +++++---- .../rapidwright/rwroute/RouteNodeGraph.java | 15 ++++++++++++--- .../xilinx/rapidwright/rwroute/RouteNodeInfo.java | 10 +++++++--- 5 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/Connection.java b/src/com/xilinx/rapidwright/rwroute/Connection.java index 4fd778892..a0bb19437 100644 --- a/src/com/xilinx/rapidwright/rwroute/Connection.java +++ b/src/com/xilinx/rapidwright/rwroute/Connection.java @@ -127,7 +127,8 @@ public void computeConnectionBoundingBox(short boundingBoxExtensionX, short boun yMax = maxOfThree(sourceRnode.getEndTileYCoordinate(), sinkRnode.getEndTileYCoordinate(), yNetCenter); yMin = minOfThree(sourceRnode.getEndTileYCoordinate(), sinkRnode.getEndTileYCoordinate(), yNetCenter); - if (isCrossSLR() && !routingGraph.isVersal) { + if (isCrossSLR() + && !routingGraph.isVersal) { // FIXME: Update this for Versal // For SLR-crossing connections, ensure the bounding box width contains at least one Laguna column // before bounding box extension int nextLaguna = routingGraph.nextLagunaColumn[xMin]; @@ -148,16 +149,16 @@ public void computeConnectionBoundingBox(short boundingBoxExtensionX, short boun if (isCrossSLR()) { // Equivalently, ensure that cross-SLR connections are at least as high as a SLL; // if necessary, expand the sink side of the bounding box - short heightMinusSLL = (short) ((yMaxBB - yMinBB - 1) - RouteNodeGraph.SUPER_LONG_LINE_LENGTH_IN_TILES); + short heightMinusSLL = (short) ((yMaxBB - yMinBB - 1) - routingGraph.SUPER_LONG_LINE_LENGTH_IN_TILES); if (heightMinusSLL < 0) { if (sourceRnode.getEndTileYCoordinate() <= sinkRnode.getEndTileYCoordinate()) { // Upwards - short newYMaxBB = (short) (yMin + RouteNodeGraph.SUPER_LONG_LINE_LENGTH_IN_TILES + 1); + short newYMaxBB = (short) (yMin + routingGraph.SUPER_LONG_LINE_LENGTH_IN_TILES + 1); assert(newYMaxBB > yMaxBB); yMaxBB = newYMaxBB; } else { // Downwards - short newYMinBB = (short) (yMax - RouteNodeGraph.SUPER_LONG_LINE_LENGTH_IN_TILES - 1); + short newYMinBB = (short) (yMax - routingGraph.SUPER_LONG_LINE_LENGTH_IN_TILES - 1); assert(newYMinBB < yMinBB); yMinBB = newYMinBB; } diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index ab0b5760a..eb497f169 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -2104,10 +2104,10 @@ protected void evaluateCostAndPush(ConnectionState state, // Check for overshooting which occurs when child and sink node are in // adjacent SLRs and less than a SLL wire's length apart in the Y axis. if (deltaSLR == 1) { - int overshootByY = deltaY - RouteNodeGraph.SUPER_LONG_LINE_LENGTH_IN_TILES; + int overshootByY = deltaY - routingGraph.SUPER_LONG_LINE_LENGTH_IN_TILES; if (overshootByY < 0) { - assert(deltaY < RouteNodeGraph.SUPER_LONG_LINE_LENGTH_IN_TILES); - deltaY = RouteNodeGraph.SUPER_LONG_LINE_LENGTH_IN_TILES - overshootByY; + assert(deltaY < routingGraph.SUPER_LONG_LINE_LENGTH_IN_TILES); + deltaY = routingGraph.SUPER_LONG_LINE_LENGTH_IN_TILES - overshootByY; } } diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index 1fa416f4f..4d5077c28 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -95,7 +95,7 @@ protected RouteNode(RouteNodeGraph routingGraph, Node node, RouteNodeType type) endTileYCoordinate = nodeInfo.endTileYCoordinate; length = nodeInfo.length; children = null; - setBaseCost(routingGraph.design.getSeries()); + setBaseCost(routingGraph); historicalCongestionCost = initialHistoricalCongestionCost; usersConnectionCounts = null; visited = 0; @@ -110,7 +110,8 @@ public int compareTo(RouteNode that) { return (int) Math.signum(this.lowerBoundTotalPathCost - that.lowerBoundTotalPathCost); } - private void setBaseCost(Series series) { + private void setBaseCost(RouteNodeGraph routingGraph) { + final Series series = routingGraph.design.getSeries(); baseCost = 0.4f; switch (getType()) { case EXCLUSIVE_SOURCE: @@ -151,8 +152,8 @@ private void setBaseCost(Series series) { break; case SUPER_LONG_LINE: assert(length == 0 || - length == RouteNodeGraph.SUPER_LONG_LINE_LENGTH_IN_TILES); - baseCost = 0.3f * RouteNodeGraph.SUPER_LONG_LINE_LENGTH_IN_TILES; + length == routingGraph.SUPER_LONG_LINE_LENGTH_IN_TILES); + baseCost = 0.3f * routingGraph.SUPER_LONG_LINE_LENGTH_IN_TILES; break; case NON_LOCAL_LEADING_TO_NORTHBOUND_LAGUNA: case NON_LOCAL_LEADING_TO_SOUTHBOUND_LAGUNA: diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index b916e89a2..7efa3a816 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -88,7 +88,7 @@ public class RouteNodeGraph { private long createRnodeTime; - public static final short SUPER_LONG_LINE_LENGTH_IN_TILES = 60; + public final short SUPER_LONG_LINE_LENGTH_IN_TILES; /** Array mapping an INT tile's Y coordinate, to its SLR index */ public final int[] intYToSLRIndex; @@ -190,6 +190,8 @@ public RouteNodeGraph(Design design, RWRouteConfig config) { ultraScalesLocalWires.put(tile.getTileTypeEnum(), localWires); eastWestPattern = Pattern.compile("(((BOUNCE|BYPASS|IMUX|INODE(_[12])?)_(?[EW]))|INT_NODE_IMUX_(?\\d+)_).*"); + + SUPER_LONG_LINE_LENGTH_IN_TILES = 60; } else { assert(isVersal); @@ -218,6 +220,8 @@ public RouteNodeGraph(Design design, RWRouteConfig config) { ultraScalesLocalWires = null; eastWestPattern = Pattern.compile("(((BOUNCE|IMUX_B|[BC]NODE_OUTS)_(?[EW]))|INT_NODE_IMUX_ATOM_(?\\d+)_).*"); + + SUPER_LONG_LINE_LENGTH_IN_TILES = 75; } for (Tile intTile : intTilesToExamine) { @@ -1111,7 +1115,11 @@ public boolean isAccessible(RouteNode childRnode, RouteNode parentRnode, Connect return false; case NODE_CLE_BNODE: case NODE_INTF_BNODE: - if (connection.isCrossSLR()) { + if (connection.isCrossSLR() && + childTile.getTileTypeEnum() == TileTypeEnum.SLL && + childRnode.getSLRIndex(this) != sinkRnode.getSLRIndex(this)) { + // Allow BNODEs since these are used to reach NODE_SLL_INPUT nodes + // TODO: Only allow BNODEs into SLLs that contain SLR crossings return true; } case NODE_CLE_CNODE: @@ -1138,7 +1146,8 @@ public boolean isAccessible(RouteNode childRnode, RouteNode parentRnode, Connect // CTRL pins that are not our target EXCLUSIVE_SINK will have been isExcluded() from the graph break; case NODE_SLL_INPUT: - if (connection.isCrossSLR()) { + if (connection.isCrossSLR() && + childRnode.getSLRIndex(this) != sinkRnode.getSLRIndex(this)) { assert(parentRnode.getIntentCode() != IntentCode.NODE_SLL_OUTPUT); return true; } diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java index 640e82c78..456a91dda 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java @@ -72,12 +72,16 @@ public static RouteNodeInfo get(Node node, RouteNodeGraph routingGraph) { RouteNodeType type = getType(node, routingGraph); short endTileXCoordinate = getEndTileXCoordinate(node, (short) endTile.getTileXCoordinate()); short endTileYCoordinate = (short) endTile.getTileYCoordinate(); - short length = getLength(baseTile, type, endTileXCoordinate, endTileYCoordinate); + short length = getLength(baseTile, type, endTileXCoordinate, endTileYCoordinate, routingGraph); return new RouteNodeInfo(type, endTileXCoordinate, endTileYCoordinate, length); } - private static short getLength(Tile baseTile, RouteNodeType type, short endTileXCoordinate, short endTileYCoordinate) { + private static short getLength(Tile baseTile, + RouteNodeType type, + short endTileXCoordinate, + short endTileYCoordinate, + RouteNodeGraph routingGraph) { TileTypeEnum tileType = baseTile.getTileTypeEnum(); short length = (short) Math.abs(endTileYCoordinate - baseTile.getTileYCoordinate()); if (tileType == TileTypeEnum.LAG_LAG) { @@ -89,7 +93,7 @@ private static short getLength(Tile baseTile, RouteNodeType type, short endTileX switch (tileType) { case LAG_LAG: case LAGUNA_TILE: - assert(length == RouteNodeGraph.SUPER_LONG_LINE_LENGTH_IN_TILES || + assert(length == routingGraph.SUPER_LONG_LINE_LENGTH_IN_TILES || // U-turn length == 0); break; From 5d11d22f282ce8d8953ecb546b7fdebe5c3972e4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 20 Oct 2025 16:29:42 -0700 Subject: [PATCH 05/14] Account for overshooting in Y due to SLLs Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/rwroute/RWRoute.java | 95 ++++++++++--------- .../rapidwright/rwroute/TestRWRoute.java | 6 +- 2 files changed, 51 insertions(+), 50 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index eb497f169..8b2bc2408 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -2099,8 +2099,7 @@ protected void evaluateCostAndPush(ConnectionState state, )); int deltaSLR = Math.abs(sinkRnode.getSLRIndex(routingGraph) - childRnode.getSLRIndex(routingGraph)); - if (deltaSLR != 0 - && !routingGraph.isVersal) { // FIXME: Update this for Versal + if (deltaSLR != 0) { // Check for overshooting which occurs when child and sink node are in // adjacent SLRs and less than a SLL wire's length apart in the Y axis. if (deltaSLR == 1) { @@ -2111,54 +2110,56 @@ protected void evaluateCostAndPush(ConnectionState state, } } - // Account for any detours that must be taken to get to the closest Laguna column - // and from there onto the sink - int nextLagunaColumn = routingGraph.nextLagunaColumn[childX]; - int prevLagunaColumn = routingGraph.prevLagunaColumn[childX]; - if (nextLagunaColumn == prevLagunaColumn) { - // On top of the column - assert(deltaX == Math.abs(sinkX - nextLagunaColumn)); - } else { - assert(rnode.getType() != RouteNodeType.SUPER_LONG_LINE); - - final int deltaXToNextColumn; - final int deltaXToPrevColumn; - final int deltaXToAndFromNextColumn; - final int deltaXToAndFromPrevColumn; - if (nextLagunaColumn == Integer.MAX_VALUE || nextLagunaColumn >= connection.getXMaxBB()) { - deltaXToNextColumn = Integer.MAX_VALUE; - deltaXToAndFromNextColumn = Integer.MAX_VALUE; - } else { - deltaXToNextColumn = Math.abs(nextLagunaColumn - childX); - deltaXToAndFromNextColumn = deltaXToNextColumn + Math.abs(sinkX - nextLagunaColumn); - } - if (prevLagunaColumn == Integer.MIN_VALUE || prevLagunaColumn <= connection.getXMinBB()) { - deltaXToPrevColumn = Integer.MAX_VALUE; - deltaXToAndFromPrevColumn = Integer.MAX_VALUE; - } else { - deltaXToPrevColumn = Math.abs(prevLagunaColumn - childX); - deltaXToAndFromPrevColumn = deltaXToPrevColumn + Math.abs(sinkX - prevLagunaColumn); - } - if (deltaXToNextColumn == deltaXToPrevColumn) { - // Equidistant from both columns, prefer the one closer when considering to/from the sink - deltaX = Math.min(deltaXToAndFromNextColumn, deltaXToAndFromPrevColumn); - } else if (deltaXToNextColumn < deltaXToPrevColumn && - deltaXToAndFromNextColumn <= deltaXToAndFromPrevColumn + maxDetourToSnapBackToPrevLagunaColumn) { - // Closer to the next column and not detouring more than 4 tiles extra to/from using the prev column - assert(deltaX <= deltaXToAndFromNextColumn); - deltaX = deltaXToAndFromNextColumn; - } else if (deltaXToPrevColumn < deltaXToNextColumn && - deltaXToAndFromPrevColumn <= deltaXToAndFromNextColumn + maxDetourToSnapBackToPrevLagunaColumn) { - // Closer to the next column and not detouring more than 4 tiles extra to/from using the prev column - assert(deltaX <= deltaXToAndFromPrevColumn); - deltaX = deltaXToAndFromPrevColumn; + if (!routingGraph.isVersal) { // FIXME: Update this for Versal + // Account for any detours that must be taken to get to the closest Laguna column + // and from there onto the sink + int nextLagunaColumn = routingGraph.nextLagunaColumn[childX]; + int prevLagunaColumn = routingGraph.prevLagunaColumn[childX]; + if (nextLagunaColumn == prevLagunaColumn) { + // On top of the column + assert(deltaX == Math.abs(sinkX - nextLagunaColumn)); } else { - // Pretty much same distance to/from both columns; prefer the closer to column - deltaX = (deltaXToNextColumn < deltaXToPrevColumn) ? deltaXToAndFromNextColumn - : deltaXToAndFromPrevColumn; + assert(rnode.getType() != RouteNodeType.SUPER_LONG_LINE); + + final int deltaXToNextColumn; + final int deltaXToPrevColumn; + final int deltaXToAndFromNextColumn; + final int deltaXToAndFromPrevColumn; + if (nextLagunaColumn == Integer.MAX_VALUE || nextLagunaColumn >= connection.getXMaxBB()) { + deltaXToNextColumn = Integer.MAX_VALUE; + deltaXToAndFromNextColumn = Integer.MAX_VALUE; + } else { + deltaXToNextColumn = Math.abs(nextLagunaColumn - childX); + deltaXToAndFromNextColumn = deltaXToNextColumn + Math.abs(sinkX - nextLagunaColumn); + } + if (prevLagunaColumn == Integer.MIN_VALUE || prevLagunaColumn <= connection.getXMinBB()) { + deltaXToPrevColumn = Integer.MAX_VALUE; + deltaXToAndFromPrevColumn = Integer.MAX_VALUE; + } else { + deltaXToPrevColumn = Math.abs(prevLagunaColumn - childX); + deltaXToAndFromPrevColumn = deltaXToPrevColumn + Math.abs(sinkX - prevLagunaColumn); + } + if (deltaXToNextColumn == deltaXToPrevColumn) { + // Equidistant from both columns, prefer the one closer when considering to/from the sink + deltaX = Math.min(deltaXToAndFromNextColumn, deltaXToAndFromPrevColumn); + } else if (deltaXToNextColumn < deltaXToPrevColumn && + deltaXToAndFromNextColumn <= deltaXToAndFromPrevColumn + maxDetourToSnapBackToPrevLagunaColumn) { + // Closer to the next column and not detouring more than 4 tiles extra to/from using the prev column + assert(deltaX <= deltaXToAndFromNextColumn); + deltaX = deltaXToAndFromNextColumn; + } else if (deltaXToPrevColumn < deltaXToNextColumn && + deltaXToAndFromPrevColumn <= deltaXToAndFromNextColumn + maxDetourToSnapBackToPrevLagunaColumn) { + // Closer to the next column and not detouring more than 4 tiles extra to/from using the prev column + assert(deltaX <= deltaXToAndFromPrevColumn); + deltaX = deltaXToAndFromPrevColumn; + } else { + // Pretty much same distance to/from both columns; prefer the closer to column + deltaX = (deltaXToNextColumn < deltaXToPrevColumn) ? deltaXToAndFromNextColumn + : deltaXToAndFromPrevColumn; + } } + assert(deltaX >= 0 && deltaX < Integer.MAX_VALUE); } - assert(deltaX >= 0 && deltaX < Integer.MAX_VALUE); } } diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java index 6911d5251..89601e7b8 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java @@ -404,12 +404,12 @@ void testSingleConnectionHelper(String partName, // Versal // One SLR crossing // (Too) close - "xcv80,SLICE_X54Y331,SLICE_X54Y332,39700", // Adjacent to crossing SLL (east) - "xcv80,SLICE_X51Y331,SLICE_X51Y332,39000", + "xcv80,SLICE_X54Y331,SLICE_X54Y332,800", // Adjacent to crossing SLL (east) + "xcv80,SLICE_X51Y331,SLICE_X51Y332,400", // Close to crossing SLL // Perfect "xcv80,SLICE_X54Y331,SLICE_X54Y406,500", // Adjacent to crossing SLL (east) "xcv80,SLICE_X53Y331,SLICE_X53Y406,200", // Adjacent to crossing SLL (west) - "xcv80,SLICE_X51Y331,SLICE_X51Y406,400", + "xcv80,SLICE_X51Y331,SLICE_X51Y406,400", // Close to crossing SLL // US+ // One SLR crossing From 186640d7db3f0a9959baba05f151143cc7be1a5a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 20 Oct 2025 16:39:00 -0700 Subject: [PATCH 06/14] Tidy Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/NetWrapper.java | 3 ++- src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java | 3 --- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/NetWrapper.java b/src/com/xilinx/rapidwright/rwroute/NetWrapper.java index ff1ea4f0d..88b3daaf8 100644 --- a/src/com/xilinx/rapidwright/rwroute/NetWrapper.java +++ b/src/com/xilinx/rapidwright/rwroute/NetWrapper.java @@ -77,7 +77,8 @@ public void computeHPWLAndCenterCoordinates(RouteNodeGraph routingGraph) { xMax = Integer.max(xMax, x); yMax = Integer.max(yMax, y); - if (connection.isCrossSLR() && !routingGraph.isVersal) { + if (connection.isCrossSLR() + && !routingGraph.isVersal) { // FIXME: Update this for Versal // For SLR-crossing connections, ensure it contains at least one Laguna column int nextLaguna = routingGraph.nextLagunaColumn[xMin]; int prevLaguna = routingGraph.prevLagunaColumn[xMax]; diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 7efa3a816..5d336da36 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -926,9 +926,6 @@ public RouteNode getOrCreate(Node node, RouteNodeType type) { rnodes = new RouteNode[baseWireCount]; nodesMap[tileAddress] = rnodes; } - if (wireIndex >= rnodes.length) { - System.err.print(""); - } RouteNode rnode = rnodes[wireIndex]; if (rnode == null) { rnode = create(node, type); From 95f1b2bce7aa4a329010dc57a47a7f8e4f7825a6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 20 Oct 2025 16:46:00 -0700 Subject: [PATCH 07/14] One more test Signed-off-by: Eddie Hung --- test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java index 89601e7b8..f27a16e38 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java @@ -410,6 +410,7 @@ void testSingleConnectionHelper(String partName, "xcv80,SLICE_X54Y331,SLICE_X54Y406,500", // Adjacent to crossing SLL (east) "xcv80,SLICE_X53Y331,SLICE_X53Y406,200", // Adjacent to crossing SLL (west) "xcv80,SLICE_X51Y331,SLICE_X51Y406,400", // Close to crossing SLL + "xcv80,SLICE_X0Y331,SLICE_X49Y406,2000", // Far from crossing SLL // US+ // One SLR crossing From c02489775d9624dd81609378075260eddd7de50f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 20 Oct 2025 16:55:24 -0700 Subject: [PATCH 08/14] Tidy Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RWRoute.java | 2 +- src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 8b2bc2408..9aa4064c6 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1944,7 +1944,7 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { childRNode.getIntentCode() == IntentCode.NODE_SLL_INPUT); assert(!rnodeType.isWestLocal() || childType.isWestLocal() || (childType == RouteNodeType.LOCAL_RESERVED && connection.getSinkRnode().getType() == RouteNodeType.EXCLUSIVE_SINK_BOTH) || - // ... or unless it's a Versal SLL input + // ... or unless it's a Versal SLL input childRNode.getIntentCode() == IntentCode.NODE_SLL_INPUT); break; case NON_LOCAL_LEADING_TO_NORTHBOUND_LAGUNA: diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 5d336da36..d9162a090 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -559,7 +559,7 @@ public void initialize() { */ protected int getBaseWireCount(Tile tile, int startWireIndex) { return baseWireCounts.computeIfAbsent(tile.getTileTypeEnum(), (e) -> { - boolean isSLLType = isVersal && e == TileTypeEnum.SLL; + final boolean isSLLType = e == TileTypeEnum.SLL; // Versal only // Check all wires in tile to find the index of the last base wire int lastBaseWire = startWireIndex; for (int i = lastBaseWire + 1; i < tile.getWireCount(); i++) { From fe7836d232483c346fc25794da6013573148589a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Oct 2025 08:58:40 -0700 Subject: [PATCH 09/14] Track NODE_SLL_DATA usage Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RWRoute.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 9aa4064c6..66be486c8 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1468,9 +1468,7 @@ private void computesNodeUsageAndTotalWirelength() { nodeUsageForVersal.add(IntentCode.NODE_IMUX); // NODE_PINFEED exists on Versal but is behind a NODE_IMUX // and gets projectInputPinToINTNode() -ed away - - // TODO: Enable when SLR crossings are supported - // nodeUsageForVersal.add(IntentCode.NODE_SLL_DATA); + nodeUsageForVersal.add(IntentCode.NODE_SLL_DATA); } /** From ef00c2d00d374479b029781aa033065beb91779c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Oct 2025 09:21:39 -0700 Subject: [PATCH 10/14] Fix end tile computation for SLL tiles Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/rwroute/RouteNodeInfo.java | 5 +++-- src/com/xilinx/rapidwright/util/Utils.java | 3 ++- .../xilinx/rapidwright/rwroute/TestRWRoute.java | 15 +++++++++------ 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java index 456a91dda..2dcd090f3 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java @@ -51,9 +51,10 @@ public static RouteNodeInfo get(Node node, RouteNodeGraph routingGraph) { Wire[] wires = node.getAllWiresInNode(); assert(wires[0].getTile() == node.getTile() && wires[0].getWireIndex() == node.getWireIndex()); Tile baseTile = node.getTile(); + TileTypeEnum baseTileType = baseTile.getTileTypeEnum(); TileTypeEnum endTileType; - if (Utils.isLaguna(baseTile.getTileTypeEnum())) { - endTileType = baseTile.getTileTypeEnum(); + if (Utils.isLaguna(baseTileType) || Utils.isInterConnect(baseTileType)) { + endTileType = baseTileType; } else { endTileType = TileTypeEnum.INT; } diff --git a/src/com/xilinx/rapidwright/util/Utils.java b/src/com/xilinx/rapidwright/util/Utils.java index 6f9029f8d..dd14d2981 100644 --- a/src/com/xilinx/rapidwright/util/Utils.java +++ b/src/com/xilinx/rapidwright/util/Utils.java @@ -343,9 +343,10 @@ public static boolean isPS(SiteTypeEnum s) { TileTypeEnum.INT_L, //TileTypeEnum.INT_L_SLV, //TileTypeEnum.INT_L_SLV_FLY, - TileTypeEnum.INT_R + TileTypeEnum.INT_R, //TileTypeEnum.INT_R_SLV, //TileTypeEnum.INT_R_SLV_FLY, + TileTypeEnum.SLL // Versal ); urams = EnumSet.of( diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java index f27a16e38..84858c66c 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java @@ -404,13 +404,16 @@ void testSingleConnectionHelper(String partName, // Versal // One SLR crossing // (Too) close - "xcv80,SLICE_X54Y331,SLICE_X54Y332,800", // Adjacent to crossing SLL (east) - "xcv80,SLICE_X51Y331,SLICE_X51Y332,400", // Close to crossing SLL + "xcv80,SLICE_X54Y331,SLICE_X54Y332,500", // Source adjacent to crossing SLL (east) + "xcv80,SLICE_X53Y332,SLICE_X53Y331,700", // Source adjacent to crossing SLL (west) + "xcv80,SLICE_X51Y331,SLICE_X51Y332,300", // Close to crossing SLL // Perfect - "xcv80,SLICE_X54Y331,SLICE_X54Y406,500", // Adjacent to crossing SLL (east) - "xcv80,SLICE_X53Y331,SLICE_X53Y406,200", // Adjacent to crossing SLL (west) - "xcv80,SLICE_X51Y331,SLICE_X51Y406,400", // Close to crossing SLL - "xcv80,SLICE_X0Y331,SLICE_X49Y406,2000", // Far from crossing SLL + "xcv80,SLICE_X54Y331,SLICE_X54Y406,700", // Source adjacent to crossing SLL (east, north) + "xcv80,SLICE_X53Y331,SLICE_X53Y406,200", // Source adjacent to crossing SLL (west, north) + "xcv80,SLICE_X54Y406,SLICE_X54Y331,1400", // Sink adjacent to crossing SLL (east, south) + "xcv80,SLICE_X53Y406,SLICE_X53Y331,100", // Sink adjacent to crossing SLL (west, south) + "xcv80,SLICE_X51Y331,SLICE_X51Y406,300", // Source close to crossing SLL + "xcv80,SLICE_X0Y331,SLICE_X49Y406,2000", // Source far from crossing SLL // US+ // One SLR crossing From 942fdb2b0e8e8c6384a8442752966daf58add729 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Oct 2025 09:28:52 -0700 Subject: [PATCH 11/14] Refactor routethru check Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/RouteNodeGraph.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index d9162a090..1dc1044f0 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -743,12 +743,6 @@ protected boolean isExcluded(RouteNode parent, Node child) { assert(child.getIntentCode() == IntentCode.NODE_CLE_OUTPUT); return false; } - if (child.getIntentCode() == IntentCode.NODE_CLE_OUTPUT && parentIc == IntentCode.NODE_PINFEED && - parent.getWireName().matches("CLE_SLICE[LM]_TOP_[01]_LAG_([NS]|[EW][12])_PIN")) { - assert(child.getWireName().matches("CLE_SLICE[LM]_TOP_[01]_[A-H]Q2?_PIN")); - // Allow CLE/*LAG*_PIN -> CLE/*[A-H]Q2?_PIN - return false; - } } if (!allowRoutethru(parent, child)) { return true; @@ -1161,17 +1155,28 @@ public boolean isAccessible(RouteNode childRnode, RouteNode parentRnode, Connect } protected boolean allowRoutethru(Node head, Node tail) { + final boolean isCLB = Utils.isCLB(tail.getTile().getTileTypeEnum()); + + if (isVersal) { + if (tail.getIntentCode() == IntentCode.NODE_CLE_OUTPUT && head.getIntentCode() == IntentCode.NODE_PINFEED && + // TODO: Speedup + head.getWireName().matches("CLE_SLICE[LM]_TOP_[01]_LAG_([NS]|[EW][12])_PIN")) { + assert(isVersalLagOutRoutethru(head, tail)); + // Allow CLE/*LAG*_PIN -> CLE/*[A-H]Q2?_PIN routethru + return true; + } + } + if (!lutRoutethru) { return false; } - if (!Utils.isCLB(tail.getTile().getTileTypeEnum())) { + if (!isCLB) { return false; } if (tail.getIntentCode() == IntentCode.NODE_PINFEED) { assert(isVersal); - assert(!lutRoutethru); assert(head.getIntentCode() == IntentCode.NODE_IMUX || head.getIntentCode() == IntentCode.NODE_PINBOUNCE); return false; From 71ef098e60e6867c058d09ee87526a88836efa6d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Oct 2025 09:34:48 -0700 Subject: [PATCH 12/14] Comments Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/RouteNodeGraph.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 1dc1044f0..f86be10e3 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -90,8 +90,9 @@ public class RouteNodeGraph { public final short SUPER_LONG_LINE_LENGTH_IN_TILES; - /** Array mapping an INT tile's Y coordinate, to its SLR index */ + /** Array mapping an INT tile's Y coordinate to its SLR index */ public final int[] intYToSLRIndex; + /** Array mapping an INT tile's X coordinate to the X of the next/previous Laguna column */ public final int[] nextLagunaColumn; public final int[] prevLagunaColumn; @@ -126,7 +127,8 @@ public class RouteNodeGraph { /** Flag for whether design targets the Versal series */ protected final boolean isVersal; - protected final Map baseWireCounts; + /** Map of the TileTypeEnum to the highest base wire index */ + protected final Map highestBaseWireIndex; protected final static int MAX_OCCUPANCY = 256; protected final float[] presentCongestionCosts; @@ -152,7 +154,7 @@ public RouteNodeGraph(Design design, RWRouteConfig config) { preservedMapSize = new AtomicInteger(); asyncPreserveOutstanding = new CountUpDownLatch(); createRnodeTime = 0; - baseWireCounts = new ConcurrentHashMap<>(); + highestBaseWireIndex = new ConcurrentHashMap<>(); Device device = design.getDevice(); intYToSLRIndex = new int[device.getRows()]; @@ -555,10 +557,10 @@ public void initialize() { } /* - * Return the maximum base wire index across all Nodes in this tile + * Return the highest base wire index across all Nodes in this tile */ - protected int getBaseWireCount(Tile tile, int startWireIndex) { - return baseWireCounts.computeIfAbsent(tile.getTileTypeEnum(), (e) -> { + protected int getHighestBaseWireIndex(Tile tile, int startWireIndex) { + return highestBaseWireIndex.computeIfAbsent(tile.getTileTypeEnum(), (e) -> { final boolean isSLLType = e == TileTypeEnum.SLL; // Versal only // Check all wires in tile to find the index of the last base wire int lastBaseWire = startWireIndex; @@ -591,7 +593,7 @@ private Net preserve(Tile tile, int wireIndex, Net net) { int tileAddress = tile.getUniqueAddress(); Net[] nets = preservedMap.get(tileAddress); if (nets == null) { - int baseWireCount = getBaseWireCount(tile, wireIndex); + int baseWireCount = getHighestBaseWireIndex(tile, wireIndex); nets = new Net[baseWireCount]; if (!preservedMap.compareAndSet(tileAddress, null, nets)) { // Another thread must have beat us to a compareAndSet, use that result @@ -916,7 +918,7 @@ public RouteNode getOrCreate(Node node, RouteNodeType type) { int tileAddress = tile.getUniqueAddress(); RouteNode[] rnodes = nodesMap[tileAddress]; if (rnodes == null) { - int baseWireCount = getBaseWireCount(tile, wireIndex); + int baseWireCount = getHighestBaseWireIndex(tile, wireIndex); rnodes = new RouteNode[baseWireCount]; nodesMap[tileAddress] = rnodes; } From fc15bccbbdcfb6de844896812e0952918a44dd6d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Oct 2025 10:10:22 -0700 Subject: [PATCH 13/14] Only check NODE_CLE_BNODE for reaching SLRs Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index f86be10e3..e49c95421 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -1107,14 +1107,14 @@ public boolean isAccessible(RouteNode childRnode, RouteNode parentRnode, Connect assert(childTile != sinkTile); return false; case NODE_CLE_BNODE: - case NODE_INTF_BNODE: if (connection.isCrossSLR() && childTile.getTileTypeEnum() == TileTypeEnum.SLL && childRnode.getSLRIndex(this) != sinkRnode.getSLRIndex(this)) { - // Allow BNODEs since these are used to reach NODE_SLL_INPUT nodes + // Allow CLE BNODEs since these are used to reach NODE_SLL_INPUT nodes // TODO: Only allow BNODEs into SLLs that contain SLR crossings return true; } + case NODE_INTF_BNODE: case NODE_CLE_CNODE: case NODE_INTF_CNODE: // Allow [BC]NODEs that reach into the sink tile From 413cfbda17ad4bd2a44f58d8ddcbd58004739a8c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Oct 2025 12:08:25 -0700 Subject: [PATCH 14/14] Make INODEs for inter-SLR connections accessible Allowing INODE -> BOUNCE -> BNODE -> SLL_INPUT Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/RouteNodeGraph.java | 24 ++++++++++++++----- .../rapidwright/rwroute/TestRWRoute.java | 12 +++++----- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index e49c95421..44f714f6c 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -1103,6 +1103,12 @@ public boolean isAccessible(RouteNode childRnode, RouteNode parentRnode, Connect IntentCode childIntentCode = childRnode.getIntentCode(); switch (childIntentCode) { case NODE_INODE: + if (connection.isCrossSLR() && + childRnode.getSLRIndex(this) != sinkRnode.getSLRIndex(this)) { + // Allow INODEs needed for PINBOUNCE -> BNODE -> NODE_SLL_INPUT + // TODO: Only allow those that lead to a SLR crossing + return true; + } // Block access to all INODEs outside the sink tile, since NODE_INODE -> NODE_IMUX -> NODE_PINFEED (or NODE_INODE -> NODE_PINBOUNCE) assert(childTile != sinkTile); return false; @@ -1111,18 +1117,24 @@ public boolean isAccessible(RouteNode childRnode, RouteNode parentRnode, Connect childTile.getTileTypeEnum() == TileTypeEnum.SLL && childRnode.getSLRIndex(this) != sinkRnode.getSLRIndex(this)) { // Allow CLE BNODEs since these are used to reach NODE_SLL_INPUT nodes - // TODO: Only allow BNODEs into SLLs that contain SLR crossings + // TODO: Only allow those that lead to a SLR crossing return true; } case NODE_INTF_BNODE: case NODE_CLE_CNODE: case NODE_INTF_CNODE: - // Allow [BC]NODEs that reach into the sink tile - return childTile.getTileYCoordinate() == sinkTile.getTileYCoordinate() && - childRnode.getEndTileXCoordinate() == sinkTile.getTileXCoordinate(); + if (childTile.getTileYCoordinate() != sinkTile.getTileYCoordinate() || + childRnode.getEndTileXCoordinate() != sinkTile.getTileXCoordinate()) { + assert(parentRnode.getIntentCode() != IntentCode.NODE_INODE); + return false; + } + // Only allow [BC]NODEs that reach into the sink tile + return true; case NODE_PINBOUNCE: - // BOUNCEs are only accessible through INODEs, so transitively this intent code is unreachable - break; + // PINBOUNCEs are only accessible through an INODE, so arriving here means that this must be an inter-SLR connection + assert(connection.isCrossSLR() && + childRnode.getSLRIndex(this) != sinkRnode.getSLRIndex(this)); + return true; case NODE_IMUX: // IMUXes that are not our target EXCLUSIVE_SINK will have been isExcluded() from the graph unless // LUT routethrus are enabled (which would have already returned true above) diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java index 84858c66c..13ba4832f 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java @@ -404,16 +404,16 @@ void testSingleConnectionHelper(String partName, // Versal // One SLR crossing // (Too) close - "xcv80,SLICE_X54Y331,SLICE_X54Y332,500", // Source adjacent to crossing SLL (east) - "xcv80,SLICE_X53Y332,SLICE_X53Y331,700", // Source adjacent to crossing SLL (west) - "xcv80,SLICE_X51Y331,SLICE_X51Y332,300", // Close to crossing SLL + "xcv80,SLICE_X54Y331,SLICE_X54Y332,1000", // Source adjacent to crossing SLL (east) + "xcv80,SLICE_X53Y332,SLICE_X53Y331,900", // Source adjacent to crossing SLL (west) + "xcv80,SLICE_X51Y331,SLICE_X51Y332,400", // Close to crossing SLL // Perfect "xcv80,SLICE_X54Y331,SLICE_X54Y406,700", // Source adjacent to crossing SLL (east, north) "xcv80,SLICE_X53Y331,SLICE_X53Y406,200", // Source adjacent to crossing SLL (west, north) - "xcv80,SLICE_X54Y406,SLICE_X54Y331,1400", // Sink adjacent to crossing SLL (east, south) + "xcv80,SLICE_X54Y406,SLICE_X54Y331,600", // Sink adjacent to crossing SLL (east, south) "xcv80,SLICE_X53Y406,SLICE_X53Y331,100", // Sink adjacent to crossing SLL (west, south) - "xcv80,SLICE_X51Y331,SLICE_X51Y406,300", // Source close to crossing SLL - "xcv80,SLICE_X0Y331,SLICE_X49Y406,2000", // Source far from crossing SLL + "xcv80,SLICE_X51Y331,SLICE_X51Y406,400", // Source close to crossing SLL + "xcv80,SLICE_X0Y331,SLICE_X49Y406,2700", // Source far from crossing SLL // US+ // One SLR crossing