diff --git a/src/com/xilinx/rapidwright/rwroute/Connection.java b/src/com/xilinx/rapidwright/rwroute/Connection.java index 8d69c63ec..acb3fbe7e 100644 --- a/src/com/xilinx/rapidwright/rwroute/Connection.java +++ b/src/com/xilinx/rapidwright/rwroute/Connection.java @@ -269,6 +269,10 @@ public RouteNode getSourceRnode() { return sourceRnode; } + public RouteNode getSourceRnode(boolean backwardRouting) { + return backwardRouting ? sinkRnode : sourceRnode; + } + public void setSourceRnode(RouteNode sourceNode) { sourceRnode = sourceNode; } @@ -277,6 +281,10 @@ public RouteNode getSinkRnode() { return sinkRnode; } + public RouteNode getSinkRnode(boolean backwardRouting) { + return backwardRouting ? sourceRnode : sinkRnode; + } + public void setSinkRnode(RouteNode sinkRnode) { this.sinkRnode = sinkRnode; @@ -483,9 +491,10 @@ public String toString() { return s.toString(); } - public void setAllTargets(RWRoute.ConnectionState state) { - sinkRnode.markTarget(state); + public void setAllTargets(RWRoute.ConnectionState state, boolean backwardRouting) { + getSinkRnode(backwardRouting).markTarget(state); if (altSinkRnodes != null) { + assert(!backwardRouting); // TODO for (RouteNode rnode : altSinkRnodes) { assert(rnode.countConnectionsOfUser(netWrapper) == 0); assert(!rnode.getType().isAnyExclusiveSink()); diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index 4e52d3398..5ca2bcbeb 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -834,6 +834,37 @@ public static Design routeDesignPartialTimingDriven(Design design, Collection pinsToRoute, boolean softPreserve) { + return routeDesignWithUserDefinedArguments(design, new String[] { + "--fixBoundingBox", + "--useUTurnNodes", + "--nonTimingDriven", + "--backwardRouting", + "--verbose"}, + pinsToRoute, softPreserve); + } + + /** + * Routes a design in the partial timing-driven backward routing mode. + * @param design The {@link Design} instance to be routed. + * @param pinsToRoute Collection of {@link SitePinInst}-s to be routed. If null, route all unrouted pins in the design. + * @param softPreserve Allow routed nets to be unrouted and subsequently rerouted in order to improve routability. + */ + public static Design routeDesignPartialTimingDrivenBackward(Design design, Collection pinsToRoute, boolean softPreserve) { + return routeDesignWithUserDefinedArguments(design, new String[] { + "--fixBoundingBox", + "--useUTurnNodes", + "--backwardRouting", + "--verbose"}, + pinsToRoute, softPreserve); + } + /** * The main interface of {@link PartialRouter} that reads in a {@link Design} checkpoint, * and parses the arguments for the {@link RWRouteConfig} object of the router. diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 044dbffdb..a3a2d9ed9 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -660,7 +660,11 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { // its projected-to-INT source node, since it could // be a projection from LAGUNA/RXQ* -> RXD* (node for INT/LOGIC_OUTS_*) assert(sourceINTRnode != null); - routingGraph.preserve(sourceINTNode, net); + if (!config.isBackwardRouting()) { + // Only preserve source node if forward routing, otherwise it will be + // excluded during expansion + routingGraph.preserve(sourceINTNode, net); + } netWrapper.setSourceRnode(sourceINTRnode); } connection.setSourceRnode(sourceINTRnode); @@ -1827,7 +1831,7 @@ protected void finishRouteConnection(Connection connection, RouteNode rnode) { } protected boolean isValidSink(Connection connection, RouteNode rnode) { - return connection.getSinkRnode() == rnode || connection.getAltSinkRnodes().contains(rnode); + return connection.getSinkRnode(config.isBackwardRouting()) == rnode || connection.getAltSinkRnodes().contains(rnode); } /** @@ -1838,6 +1842,7 @@ protected boolean isValidSink(Connection connection, RouteNode rnode) { */ protected boolean saveRouting(Connection connection, RouteNode rnode) { if (!isValidSink(connection, rnode)) { + assert(!config.isBackwardRouting()); // TODO List prevRouting = connection.getRnodes(); // Check that this is the sink path marked by prepareRouteConnection() if (!connection.isRouted() || prevRouting.isEmpty() || !rnode.isTarget()) { @@ -1853,6 +1858,10 @@ protected boolean saveRouting(Connection connection, RouteNode rnode) { } while ((rnode = rnode.getPrev()) != null); List rnodes = connection.getRnodes(); + if (config.isBackwardRouting()) { + Collections.reverse(rnodes); + } + RouteNode sourceRnode = rnodes.get(rnodes.size() - 1); // Only successfully routed if backtracked to this connection's source node return sourceRnode == connection.getSourceRnode(); @@ -1871,7 +1880,7 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { final PriorityQueue queue = state.queue; final NetWrapper netWrapper = connection.getNetWrapper(); final RouteNodeType rnodeType = rnode.getType(); - final boolean rnodeIsLaguna = Utils.isLaguna(rnode.getTile().getTileTypeEnum()); + final boolean rnodeIsLaguna = !config.isBackwardRouting() && Utils.isLaguna(rnode.getTile().getTileTypeEnum()); for (RouteNode childRNode : rnode.getChildren(routingGraph)) { if (childRNode.isVisited(sequence)) { @@ -1919,101 +1928,103 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { continue; } RouteNodeType childType = childRNode.getType(); - switch (childType) { - case LOCAL_EAST_LEADING_TO_NORTHBOUND_LAGUNA: - case LOCAL_EAST_LEADING_TO_SOUTHBOUND_LAGUNA: - case LOCAL_WEST_LEADING_TO_NORTHBOUND_LAGUNA: - case LOCAL_WEST_LEADING_TO_SOUTHBOUND_LAGUNA: - // Lookahead beyond child nodes leading to a Laguna if it won't get overused - lookahead = !childRNode.willOverUse(netWrapper); - // Fall-through - case LOCAL_BOTH: - case LOCAL_EAST: - case LOCAL_WEST: - case LOCAL_RESERVED: - if (!routingGraph.isAccessible(childRNode, rnode, connection)) { - continue; - } - // 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) || - // ... 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) || - // ... 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: - if (connection.isCrossSLR() && connection.getSinkRnode().getSLRIndex(routingGraph) != childRNode.getSLRIndex(routingGraph) && - ((connection.isCrossSLRnorth() && childType == RouteNodeType.NON_LOCAL_LEADING_TO_NORTHBOUND_LAGUNA) || - (connection.isCrossSLRsouth() && childType == RouteNodeType.NON_LOCAL_LEADING_TO_SOUTHBOUND_LAGUNA))) { - // Only lookahead beyond child nodes leading to a Laguna if we require an SLR crossing in that direction, - // and it won't get overused + if (!config.isBackwardRouting()) { + switch (childType) { + case LOCAL_EAST_LEADING_TO_NORTHBOUND_LAGUNA: + case LOCAL_EAST_LEADING_TO_SOUTHBOUND_LAGUNA: + case LOCAL_WEST_LEADING_TO_NORTHBOUND_LAGUNA: + case LOCAL_WEST_LEADING_TO_SOUTHBOUND_LAGUNA: + // Lookahead beyond child nodes leading to a Laguna if it won't get overused lookahead = !childRNode.willOverUse(netWrapper); - } - // Fall-through - case NON_LOCAL: - // LOCALs cannot connect to NON_LOCALs except - // (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) || - // Allow CLE/*LAG*_PIN -> CLE/*[A-H]Q2?_PIN - (routingGraph.isVersal && connection.isCrossSLR() && - routingGraph.isVersalLagOutRoutethru(rnode, childRNode)) - ); - - if (!routingGraph.isAccessible(childRNode, rnode, connection)) { - continue; - } - if (!config.isUseUTurnNodes() && childRNode.getDelay() > 10000) { - // To filter out those nodes that are considered to be excluded with the masking resource approach, - // such as U-turn shape nodes near the boundary - continue; - } - - // Lookahead if parent or child is in a Laguna tile - // (e.g. LAG_MUX_ATOM_\\d+_TXOUT -> UBUMP\\d+ - // LAG_LAGUNA_SITE_[0-3]_RXD[0-5] -> RXD\\d+ - // RXD\\d+ -> INT_NODE_SDQ_\\d+_INT_OUT[01] - // ) - // NOTE: UBUMP\\d+ wires have RouteNodeType.SUPER_LONG_LINE - lookahead |= (rnodeIsLaguna || Utils.isLaguna(childRNode.getTile().getTileTypeEnum())); - break; - case EXCLUSIVE_SINK_BOTH: - case EXCLUSIVE_SINK_EAST: - case EXCLUSIVE_SINK_WEST: - case EXCLUSIVE_SINK_NON_LOCAL: - assert(childType != RouteNodeType.EXCLUSIVE_SINK_EAST || rnodeType == RouteNodeType.LOCAL_EAST || - // Must be an INODE that services Laguna but also feedsthrough above/below to a SLICE sink - rnodeType.isLocalLeadingToLaguna()); - assert(childType != RouteNodeType.EXCLUSIVE_SINK_WEST || rnodeType == RouteNodeType.LOCAL_WEST || - // Must be an INODE that services Laguna but also feedsthrough above/below to a SLICE sink - rnodeType.isLocalLeadingToLaguna()); - assert(childType != RouteNodeType.EXCLUSIVE_SINK_BOTH || rnodeType == RouteNodeType.LOCAL_BOTH || - // [BC]NODEs are LOCAL_{EAST,WEST} since they connect to INODEs, but also service CTRL sinks - (routingGraph.isVersal && EnumSet.of(IntentCode.NODE_CLE_BNODE, IntentCode.NODE_CLE_CNODE, - IntentCode.NODE_INTF_BNODE, IntentCode.NODE_INTF_CNODE) - .contains(rnode.getIntentCode()))); - if (!isAccessibleSink(childRNode, connection)) { - continue; - } - assert(childRNode.getIntentCode() == IntentCode.NODE_PINBOUNCE); - assert(childRNode.countConnectionsOfUser(netWrapper) > 0); - assert(!childRNode.willOverUse(netWrapper)); - break; - case SUPER_LONG_LINE: - assert(connection.isCrossSLR() && - connection.getSinkRnode().getSLRIndex(routingGraph) != rnode.getSLRIndex(routingGraph)); - // Do not lookahead beyond the SLL, since looking-ahead may push many SLLs onto the queue, - // and we want to pick the best (least expensive/congested) one - assert(!lookahead); - break; - default: - throw new RuntimeException("Unexpected rnode type: " + childType); + // Fall-through + case LOCAL_BOTH: + case LOCAL_EAST: + case LOCAL_WEST: + case LOCAL_RESERVED: + if (!routingGraph.isAccessible(childRNode, rnode, connection)) { + continue; + } + // 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) || + // ... 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) || + // ... 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: + if (connection.isCrossSLR() && connection.getSinkRnode().getSLRIndex(routingGraph) != childRNode.getSLRIndex(routingGraph) && + ((connection.isCrossSLRnorth() && childType == RouteNodeType.NON_LOCAL_LEADING_TO_NORTHBOUND_LAGUNA) || + (connection.isCrossSLRsouth() && childType == RouteNodeType.NON_LOCAL_LEADING_TO_SOUTHBOUND_LAGUNA))) { + // Only lookahead beyond child nodes leading to a Laguna if we require an SLR crossing in that direction, + // and it won't get overused + lookahead = !childRNode.willOverUse(netWrapper); + } + // Fall-through + case NON_LOCAL: + // LOCALs cannot connect to NON_LOCALs except + // (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) || + // Allow CLE/*LAG*_PIN -> CLE/*[A-H]Q2?_PIN + (routingGraph.isVersal && connection.isCrossSLR() && + routingGraph.isVersalLagOutRoutethru(rnode, childRNode)) + ); + + if (!routingGraph.isAccessible(childRNode, rnode, connection)) { + continue; + } + if (!config.isUseUTurnNodes() && childRNode.getDelay() > 10000) { + // To filter out those nodes that are considered to be excluded with the masking resource approach, + // such as U-turn shape nodes near the boundary + continue; + } + + // Lookahead if parent or child is in a Laguna tile + // (e.g. LAG_MUX_ATOM_\\d+_TXOUT -> UBUMP\\d+ + // LAG_LAGUNA_SITE_[0-3]_RXD[0-5] -> RXD\\d+ + // RXD\\d+ -> INT_NODE_SDQ_\\d+_INT_OUT[01] + // ) + // NOTE: UBUMP\\d+ wires have RouteNodeType.SUPER_LONG_LINE + lookahead |= (rnodeIsLaguna || Utils.isLaguna(childRNode.getTile().getTileTypeEnum())); + break; + case EXCLUSIVE_SINK_BOTH: + case EXCLUSIVE_SINK_EAST: + case EXCLUSIVE_SINK_WEST: + case EXCLUSIVE_SINK_NON_LOCAL: + assert(childType != RouteNodeType.EXCLUSIVE_SINK_EAST || rnodeType == RouteNodeType.LOCAL_EAST || + // Must be an INODE that services Laguna but also feedsthrough above/below to a SLICE sink + rnodeType.isLocalLeadingToLaguna()); + assert(childType != RouteNodeType.EXCLUSIVE_SINK_WEST || rnodeType == RouteNodeType.LOCAL_WEST || + // Must be an INODE that services Laguna but also feedsthrough above/below to a SLICE sink + rnodeType.isLocalLeadingToLaguna()); + assert(childType != RouteNodeType.EXCLUSIVE_SINK_BOTH || rnodeType == RouteNodeType.LOCAL_BOTH || + // [BC]NODEs are LOCAL_{EAST,WEST} since they connect to INODEs, but also service CTRL sinks + (routingGraph.isVersal && EnumSet.of(IntentCode.NODE_CLE_BNODE, IntentCode.NODE_CLE_CNODE, + IntentCode.NODE_INTF_BNODE, IntentCode.NODE_INTF_CNODE) + .contains(rnode.getIntentCode()))); + if (!isAccessibleSink(childRNode, connection)) { + continue; + } + assert(childRNode.getIntentCode() == IntentCode.NODE_PINBOUNCE); + assert(childRNode.countConnectionsOfUser(netWrapper) > 0); + assert(!childRNode.willOverUse(netWrapper)); + break; + case SUPER_LONG_LINE: + assert(connection.isCrossSLR() && + connection.getSinkRnode().getSLRIndex(routingGraph) != rnode.getSLRIndex(routingGraph)); + // Do not lookahead beyond the SLL, since looking-ahead may push many SLLs onto the queue, + // and we want to pick the best (least expensive/congested) one + assert(!lookahead); + break; + default: + throw new RuntimeException("Unexpected rnode type: " + childType); + } } } @@ -2076,7 +2087,9 @@ protected void evaluateCostAndPush(ConnectionState state, childRnode.setPrev(rnode); float newPartialPathCost = rnode.getUpstreamPathCost(); - newPartialPathCost += state.rnodeCostWeight * getNodeCost(childRnode, connection, countSourceUses, sharingFactor); + if (!config.isBackwardRouting() || childRnode.getType() != RouteNodeType.EXCLUSIVE_SOURCE) { + newPartialPathCost += state.rnodeCostWeight * getNodeCost(childRnode, connection, countSourceUses, sharingFactor); + } newPartialPathCost += state.rnodeWLWeight * childRnode.getLength() / sharingFactor; if (config.isTimingDriven()) { newPartialPathCost += state.dlyWeight * (childRnode.getDelay() + DelayEstimatorBase.getExtraDelay(childRnode, longParent)); @@ -2084,7 +2097,7 @@ protected void evaluateCostAndPush(ConnectionState state, int childX = childRnode.getEndTileXCoordinate(); int childY = childRnode.getEndTileYCoordinate(); - RouteNode sinkRnode = connection.getSinkRnode(); + RouteNode sinkRnode = connection.getSinkRnode(config.isBackwardRouting()); int sinkX = sinkRnode.getBeginTileXCoordinate(); int sinkY = sinkRnode.getBeginTileYCoordinate(); int deltaX = Math.abs(childX - sinkX); @@ -2246,16 +2259,16 @@ protected void prepareRouteConnection(ConnectionState state) { assert(state.queue.isEmpty()); // Sets the sink rnode(s) of the connection as the target(s) - connection.setAllTargets(state); + connection.setAllTargets(state, config.isBackwardRouting()); // Adds the source rnode to the queue - RouteNode sourceRnode = connection.getSourceRnode(); + RouteNode sourceRnode = connection.getSourceRnode(config.isBackwardRouting()); float newPartialPathCost = 0; float newTotalPathCost = 0; boolean lookahead = false; push(state, sourceRnode, newPartialPathCost, newTotalPathCost, lookahead); - assert(routingGraph.isAllowedTile(connection.getSinkRnode())); + assert(routingGraph.isAllowedTile(connection.getSinkRnode(config.isBackwardRouting()))); } /** diff --git a/src/com/xilinx/rapidwright/rwroute/RWRouteConfig.java b/src/com/xilinx/rapidwright/rwroute/RWRouteConfig.java index 29dda5f8e..ad4e40696 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRouteConfig.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRouteConfig.java @@ -106,6 +106,9 @@ public class RWRouteConfig { private float husActivateThreshold; /* PBlock within which RWRoute must stay within */ private String pblock; + + /* true to route backward (Sink ->...->Source) */ + private boolean backwardRouting; /** Constructs a Configuration Object */ public RWRouteConfig(String[] arguments) { @@ -247,6 +250,9 @@ private void parseArguments(String[] arguments) { case "--lutRoutethru": setLutRoutethru(true); break; + case "--backwardRouting": + setBackwardRouting(true); + break; case "--noInvertGndToVccForLutInputs": setInvertGndToVccForLutInputs(false); break; @@ -1081,4 +1087,20 @@ public String toString() { return s.toString(); } + + /** + * Checks if backward routing is enabled. + * @return true if backward routing is enabled, false otherwise. + */ + public boolean isBackwardRouting() { + return backwardRouting; + } + + /** + * Sets the backward routing flag. + * @param backwardRouting true to enable backward routing, false otherwise. + */ + public void setBackwardRouting(boolean backwardRouting) { + this.backwardRouting = backwardRouting; + } } diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index 4d5077c28..b54bdec22 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -173,6 +173,10 @@ private void setBaseCost(RouteNodeGraph routingGraph) { 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 NODE_GLOBAL_LEAF: + case NODE_INT_INTERFACE: + case NODE_DEDICATED: + case NODE_OPTDELAY: case INTENT_DEFAULT: // INT.VCC_WIRE assert(length == 0); break; @@ -495,7 +499,7 @@ public float getBaseCost() { public RouteNode[] getChildren(RouteNodeGraph routingGraph) { if (children == null) { long start = RuntimeTracker.now(); - List allDownHillNodes = getAllDownhillNodes(); + List allDownHillNodes = routingGraph.backwardRouting ? getAllUphillNodes() : getAllDownhillNodes(); List childrenList = new ArrayList<>(allDownHillNodes.size()); for (Node downhill : allDownHillNodes) { if (isExcluded(routingGraph, downhill)) { diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index af03c1e05..e074ab619 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -143,10 +143,13 @@ protected static int getTileCount(Design design) { /** Flag to enable really comprehensive (but performance-impacting) assertions */ protected final static boolean enableComprehensiveAssertions = false; + protected final boolean backwardRouting; + public RouteNodeGraph(Design design, RWRouteConfig config) { this.design = design; lutRoutethru = config.isLutRoutethru(); lutPinSwapping = config.isLutPinSwapping(); + backwardRouting = config.isBackwardRouting(); this.nodesMap = new RouteNode[getTileCount(design)][]; nodesMapSize = new AtomicInteger(); @@ -1171,6 +1174,11 @@ public boolean isAccessible(RouteNode childRnode, RouteNode parentRnode, Connect protected boolean allowRoutethru(RouteNode head, Node tail) { final boolean isCLB = Utils.isCLB(tail.getTile().getTileTypeEnum()); + if (backwardRouting) { + // FIXME: Need a better way to identify LUT routethrus than INT -> CLB edge + return true; + } + if (isVersal) { if (tail.getIntentCode() == IntentCode.NODE_CLE_OUTPUT && head.getIntentCode() == IntentCode.NODE_PINFEED && diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java index d29803b96..2a2b11c64 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java @@ -382,6 +382,15 @@ Design testSingleConnectionHelper(String partName, String srcSiteName, String srcPinName, String dstSiteName, String dstPinName, long nodesPoppedLimit) { + boolean backwardRouting = false; + return testSingleConnectionHelper(partName, srcSiteName, srcPinName, dstSiteName, dstPinName, nodesPoppedLimit, backwardRouting); + } + + Design testSingleConnectionHelper(String partName, + String srcSiteName, String srcPinName, + String dstSiteName, String dstPinName, + long nodesPoppedLimit, + boolean backwardRouting) { Design design = new Design("top", partName); Net net = design.createNet("net"); @@ -394,10 +403,16 @@ Design testSingleConnectionHelper(String partName, List pinsToRoute = new ArrayList<>(); pinsToRoute.add(dstSpi); boolean softPreserve = false; - PartialRouter.routeDesignPartialNonTimingDriven(design, pinsToRoute, softPreserve); + + if (backwardRouting) { + PartialRouter.routeDesignPartialNonTimingDrivenBackward(design, pinsToRoute, softPreserve); + } else { + PartialRouter.routeDesignPartialNonTimingDriven(design, pinsToRoute, softPreserve); + } Assertions.assertTrue(srcSpi.isRouted()); Assertions.assertTrue(dstSpi.isRouted()); + long nodesPopped = Long.parseLong(System.getProperty("rapidwright.rwroute.nodesPopped")); Assertions.assertTrue(nodesPopped >= (nodesPoppedLimit - 100) && nodesPopped <= nodesPoppedLimit); @@ -559,6 +574,21 @@ public void testSingleConnection(String partName, nodesPoppedLimit); } + @ParameterizedTest + @CsvSource({ + "xcau10p,SLICE_X0Y0,A_O,SLICE_X0Y1,A1,400" + }) + public void testSingleConnectionBackward(String partName, + String srcSiteName, String srcPinName, + String dstSiteName, String dstPinName, + int nodesPoppedLimit) { + testSingleConnectionHelper(partName, + srcSiteName, srcPinName, + dstSiteName, dstPinName, + nodesPoppedLimit, + true); + } + @Test public void testDiscussion1245_20250805() { // Adapted from https://github.com/Xilinx/RapidWright/discussions/1245#discussioncomment-14003055