diff --git a/src/com/xilinx/rapidwright/rwroute/Connection.java b/src/com/xilinx/rapidwright/rwroute/Connection.java index 6e7c4e142..a0bb19437 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,12 @@ 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) { // 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 = 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); } @@ -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; } @@ -282,10 +283,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..88b3daaf8 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,11 @@ 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) { // FIXME: Update this for Versal // 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..66be486c8 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); } } } @@ -1469,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); } /** @@ -1940,9 +1937,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 +1960,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; @@ -2096,61 +2101,63 @@ 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; } } - // 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; + 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 { - 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(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/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index 0d4815b01..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: @@ -171,6 +172,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..44f714f6c 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -88,10 +88,11 @@ 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 */ + /** 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()]; @@ -190,6 +192,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 +222,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) { @@ -551,15 +557,21 @@ 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; 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; } } @@ -581,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 @@ -722,6 +734,18 @@ 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 (!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); @@ -889,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; } @@ -937,7 +966,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 +988,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) @@ -1071,24 +1103,47 @@ 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; case NODE_CLE_BNODE: + if (connection.isCrossSLR() && + 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 those that lead to a SLR crossing + return true; + } case NODE_INTF_BNODE: case NODE_CLE_CNODE: case NODE_INTF_CNODE: + 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 childTile.getTileYCoordinate() == sinkTile.getTileYCoordinate() && - childRnode.getEndTileXCoordinate() == sinkTile.getTileXCoordinate(); + 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) 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 +1151,11 @@ 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() && + childRnode.getSLRIndex(this) != sinkRnode.getSLRIndex(this)) { + 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; @@ -1109,17 +1169,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; @@ -1153,4 +1224,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..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; } @@ -72,12 +73,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 +94,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; @@ -245,6 +250,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); 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 197ae2d6d..13ba4832f 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java @@ -401,48 +401,63 @@ void testSingleConnectionHelper(String partName, @ParameterizedTest @CsvSource({ + // Versal + // One SLR crossing + // (Too) close + "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,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,400", // Source close to crossing SLL + "xcv80,SLICE_X0Y331,SLICE_X49Y406,2700", // Source far from crossing SLL + + // 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