From f405faf843aa992068c591d003924dc037f5d799 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 23 Sep 2024 17:23:07 -0700 Subject: [PATCH 01/43] [RWRoute] Remove unnecessary overrides Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/rwroute/RouteNode.java | 16 ---------------- .../xilinx/rapidwright/rwroute/RouterHelper.java | 11 ----------- 2 files changed, 27 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index 95c67f5c2..63827c0ea 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -256,22 +256,6 @@ public String toString() { return s.toString(); } - @Override - public int hashCode() { - return super.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - // This method requires that object is Node or a subclass of one, otherwise exception will be thrown. - // If so, explicitly call the Node.equals(Node) overload, rather than the general-purpose Node.equals(Object). - return super.equals((Node) obj); - } - /** * Checks if coordinates of a RouteNode Object is within the connection's bounding box. * @param connection The connection that is being routed. diff --git a/src/com/xilinx/rapidwright/rwroute/RouterHelper.java b/src/com/xilinx/rapidwright/rwroute/RouterHelper.java index 71192829b..1842d6d37 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouterHelper.java +++ b/src/com/xilinx/rapidwright/rwroute/RouterHelper.java @@ -78,17 +78,6 @@ void setPrev(NodeWithPrev prev) { NodeWithPrev getPrev() { return prev; } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - // This method requires that object is Node or a subclass of one, otherwise exception will be thrown. - // If so, explicitly call the Node.equals(Node) overload, rather than the general-purpose Node.equals(Object). - return super.equals((Node) obj); - } } /** From 930aa993ad300e1fc5b8ae0c170178e7ddaaf4fd Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 24 Sep 2024 11:10:49 -0700 Subject: [PATCH 02/43] [Connection] getNodes() to return empty list not null Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/Connection.java | 2 +- src/com/xilinx/rapidwright/rwroute/RouterHelper.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/Connection.java b/src/com/xilinx/rapidwright/rwroute/Connection.java index e3d306f99..b9bdefa89 100644 --- a/src/com/xilinx/rapidwright/rwroute/Connection.java +++ b/src/com/xilinx/rapidwright/rwroute/Connection.java @@ -413,7 +413,7 @@ public boolean isCrossSLR() { } public List getNodes() { - return nodes; + return nodes == null ? Collections.emptyList() : nodes; } public void setNodes(List nodes) { diff --git a/src/com/xilinx/rapidwright/rwroute/RouterHelper.java b/src/com/xilinx/rapidwright/rwroute/RouterHelper.java index 1842d6d37..3d0f95b8b 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouterHelper.java +++ b/src/com/xilinx/rapidwright/rwroute/RouterHelper.java @@ -579,7 +579,7 @@ public static short computeNodeDelay(DelayEstimatorBase estimator, Node node) { */ public static boolean routeDirectConnection(Connection directConnection) { directConnection.setNodes(findPathBetweenNodes(directConnection.getSource().getConnectedNode(), directConnection.getSink().getConnectedNode())); - return directConnection.getNodes() != null; + return !directConnection.getNodes().isEmpty(); } /** From e6f96058f441a391e5424e2c60b1d793c151fd6e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 24 Sep 2024 11:32:34 -0700 Subject: [PATCH 03/43] Improve TestRWRoute.testNonTimingDrivenPartialRouting() Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/rwroute/TestRWRoute.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java index 4138f04ec..5dfc90184 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java @@ -26,9 +26,11 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Random; import com.xilinx.rapidwright.util.VivadoToolsHelper; import org.junit.jupiter.api.Assertions; @@ -268,6 +270,19 @@ public void testNonTimingDrivenPartialRouting() { Design design = RapidWrightDCP.loadDCP("picoblaze_partial.dcp"); design.setTrackNetChanges(true); + // Pseudo-randomly unroute some pins from a multi-pin net + Random random = new Random(); + for (Net net : design.getNets()) { + if (!net.getName().endsWith("/processor/t_state_0")) { + continue; + } + + List sinkPins = net.getSinkPins(); + Assertions.assertTrue(sinkPins.size() > 1); + SitePinInst spi = sinkPins.get(random.nextInt(sinkPins.size())); + DesignTools.unroutePins(net, Collections.singletonList(spi)); + } + boolean softPreserve = false; Design routed = PartialRouter.routeDesignPartialNonTimingDriven(design, null, softPreserve); From c1fcf1f1edb7e4a8f009967fe28eba6d8b16a316 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 24 Sep 2024 11:33:31 -0700 Subject: [PATCH 04/43] [PartialRouter] isAccessible() to always allow preserved nets Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/PartialRouter.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index edd035a08..bce5a57f5 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -85,6 +85,16 @@ protected boolean isExcluded(RouteNode parent, Node child) { } return super.isExcluded(parent, child); } + + @Override + public boolean isAccessible(RouteNode childRnode, Connection connection) { + Net preservedNet = getPreservedNet(childRnode); + if (preservedNet == connection.getNetWrapper().getNet()) { + // Always allow nodes preserved for this connection's net + return true; + } + return super.isAccessible(childRnode, connection); + } } protected static class RouteNodeGraphPartialTimingDriven extends RouteNodeGraphTimingDriven { @@ -108,6 +118,16 @@ protected boolean isExcluded(RouteNode parent, Node child) { } return super.isExcluded(parent, child); } + + @Override + public boolean isAccessible(RouteNode childRnode, Connection connection) { + Net preservedNet = getPreservedNet(childRnode); + if (preservedNet == connection.getNetWrapper().getNet()) { + // Always allow nodes preserved for this connection's net + return true; + } + return super.isAccessible(childRnode, connection); + } } public PartialRouter(Design design, RWRouteConfig config, Collection pinsToRoute, boolean softPreserve) { From d92ab01f48bfcee183b42318587fc39c9d8537d7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 24 Sep 2024 11:35:53 -0700 Subject: [PATCH 05/43] [PartialRouter] Abandon unrouteable connections Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/PartialRouter.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index bce5a57f5..a10fab57d 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -615,12 +615,20 @@ protected boolean handleUnroutableConnection(Connection connection) { boolean hasAltOutput = super.handleUnroutableConnection(connection); if (hasAltOutput) return true; - if (softPreserve) { - if (routeIteration == 2) { - unpreserveNetsAndReleaseResources(connection); - return true; + if (routeIteration == 2) { + if (softPreserve) { + int netsUnpreserved = unpreserveNetsAndReleaseResources(connection); + if (netsUnpreserved > 0) { + return true; + } } } + if (config.isUseBoundingBox() && !config.isEnlargeBoundingBox()) { + // Since bounding box is never enlarged, there is no hope of routing this connection + // so abandon it + indirectConnections.remove(connection); + return true; + } return false; } From aca84f2239e16e37f2a74d59fb07de6dd605a79c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 24 Sep 2024 11:40:08 -0700 Subject: [PATCH 06/43] [PartialRouter] Check sink routability after preserveAsync() Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/PartialRouter.java | 17 +++++++++++++++++ src/com/xilinx/rapidwright/rwroute/RWRoute.java | 9 --------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index a10fab57d..1adbbef94 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -260,6 +260,23 @@ protected void routeGlobalClkNets() { protected void determineRoutingTargets() { super.determineRoutingTargets(); + // With all routingGraph.preserveAsync() calls having completed, + // now check sink routability + Set netsToUnpreserve = new HashSet<>(); + for (Connection connection : indirectConnections) { + Net net = connection.getNetWrapper().getNet(); + RouteNode sinkRnode = connection.getSinkRnode(); + Net unpreserveNet = routingGraph.getPreservedNet(sinkRnode); + if (unpreserveNet != null && unpreserveNet != net) { + netsToUnpreserve.add(unpreserveNet); + sinkRnode.setType(RouteNodeType.PINFEED_I); + sinkRnode.clearPrev(); + } + } + for (Net unpreserveNet : netsToUnpreserve) { + unpreserveNet(unpreserveNet); + } + // Go through all nets to be routed Map stashedPrev = new HashMap<>(); for (Map.Entry e : nets.entrySet()) { diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index f49f6d1b6..00e035e16 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -578,7 +578,6 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { } else { Node sinkINTNode = nodes.get(0); indirectConnections.add(connection); - checkSinkRoutability(net, sinkINTNode); RouteNode sinkRnode = getOrCreateRouteNode(sinkINTNode, RouteNodeType.PINFEED_I); assert(sinkRnode.getType() == RouteNodeType.PINFEED_I); connection.setSinkRnode(sinkRnode); @@ -687,14 +686,6 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { return netWrapper; } - protected void checkSinkRoutability(Net net, Node sinkNode) { - Net oldNet = routingGraph.getPreservedNet(sinkNode); - if (oldNet != null && oldNet != net) { - throw new RuntimeException("ERROR: Sink node " + sinkNode + " of net '" + net.getName() + "' is " - + " preserved by net '" + oldNet.getName() + "'"); - } - } - /** * Adds span info of a connection. * @param connection A connection of which span info is to be added. From 5fd643b919738f08194fdf8355ae1cd6b291c29b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 24 Sep 2024 11:40:37 -0700 Subject: [PATCH 07/43] Tidy up Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/PartialRouter.java | 2 ++ src/com/xilinx/rapidwright/rwroute/RWRoute.java | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index 1adbbef94..186ba2133 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -505,6 +505,8 @@ protected int unpreserveNetsAndReleaseResources(Connection connection) { } protected void unpreserveNet(Net net) { + assert(!net.getName().equals(Net.Z_NET)); + Set rnodes = new HashSet<>(); NetWrapper netWrapper = nets.get(net); if (netWrapper != null) { diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 00e035e16..3a341c570 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -311,7 +311,7 @@ protected void determineRoutingTargets() { connection.getAltSinkRnodes().removeIf((rnode) -> rnode.getOccupancy() > 0); } - // Wait for all outstanding RouteNodeGraph.asyncPreserve() calls to complete + // Wait for all outstanding RouteNodeGraph.preserveAsync() calls to complete routingGraph.awaitPreserve(); } From 4c1048eb1e96db9a7789efaad6204bf2f765ec84 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 24 Sep 2024 11:41:24 -0700 Subject: [PATCH 08/43] [RWRoute] Lazy source swapping Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/rwroute/RWRoute.java | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 3a341c570..74bab0bca 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1651,20 +1651,35 @@ protected boolean swapOutputPin(Connection connection) { SitePinInst altSource = net.getAlternateSource(); if (altSource == null) { - System.out.println("INFO: No alternative source to swap"); - return false; + altSource = DesignTools.getLegalAlternativeOutputPin(net); + if (altSource != null) { + // Add this SitePinInst to the net, but not to the SiteInst since it's not yet clear we'll be using it + net.addPin(altSource); + DesignTools.routeAlternativeOutputSitePin(net, altSource); + } else { + System.out.println("INFO: No alternative source to swap"); + return false; + } } SitePinInst source = connection.getSource(); if (source.equals(altSource)) { altSource = net.getSource(); } - System.out.println("INFO: Swap source from " + source + " to " + altSource + "\n"); RouteNode altSourceRnode = connection.getAltSourceRnode(); if (altSourceRnode == null) { - throw new RuntimeException("No alternate source pin on net: " + net.getName()); + Node altSourceNode = RouterHelper.projectOutputPinToINTNode(altSource); + if (routingGraph.isPreserved(altSourceNode)) { + System.out.println("INFO: No alternative source to swap"); + return false; + } + assert(routingGraph.getNode(altSourceNode) == null); + altSourceRnode = getOrCreateRouteNode(altSourceNode, RouteNodeType.PINFEED_O); } + + System.out.println("INFO: Swap source from " + source + " to " + altSource + "\n"); + connection.setSource(altSource); connection.setSourceRnode(altSourceRnode); connection.getSink().setRouted(false); From 34badd7552af3fbc86aae94e051d9a51aaa57a41 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 24 Sep 2024 12:41:27 -0700 Subject: [PATCH 09/43] Add messaging Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/rwroute/PartialRouter.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index 186ba2133..e1f2219d3 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -262,19 +262,23 @@ protected void determineRoutingTargets() { // With all routingGraph.preserveAsync() calls having completed, // now check sink routability - Set netsToUnpreserve = new HashSet<>(); + Set unpreserveNets = new HashSet<>(); for (Connection connection : indirectConnections) { Net net = connection.getNetWrapper().getNet(); RouteNode sinkRnode = connection.getSinkRnode(); Net unpreserveNet = routingGraph.getPreservedNet(sinkRnode); if (unpreserveNet != null && unpreserveNet != net) { - netsToUnpreserve.add(unpreserveNet); + unpreserveNets.add(unpreserveNet); sinkRnode.setType(RouteNodeType.PINFEED_I); sinkRnode.clearPrev(); } } - for (Net unpreserveNet : netsToUnpreserve) { - unpreserveNet(unpreserveNet); + + if (unpreserveNets.isEmpty()) { + System.out.println("INFO: Unpreserving " + unpreserveNets.size() + " nets to improve sink routability"); + for (Net unpreserveNet : unpreserveNets) { + unpreserveNet(unpreserveNet); + } } // Go through all nets to be routed From 71811158281e480d3c9aa82389e708a082ab004b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 24 Sep 2024 12:42:47 -0700 Subject: [PATCH 10/43] Try removing stashedPrev Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/PartialRouter.java | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index e1f2219d3..a2fdf51de 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -282,30 +282,10 @@ protected void determineRoutingTargets() { } // Go through all nets to be routed - Map stashedPrev = new HashMap<>(); for (Map.Entry e : nets.entrySet()) { Net net = e.getKey(); NetWrapper netWrapper = e.getValue(); - // Temporarily stash the prev pointer of all sink nodes ahead of recovering routing - // (it's possible for another connection to use a bounce node, but now that node is - // needed as a site pin) - for (Connection connection : netWrapper.getConnections()) { - Consumer action = (rnode) -> { - if (rnode == null) { - return; - } - RouteNode prev = rnode.getPrev(); - if (prev == null) { - return; - } - stashedPrev.put(rnode, prev); - rnode.clearPrev(); - }; - action.accept(connection.getSinkRnode()); - connection.getAltSinkRnodes().forEach(action); - } - // Create all nodes used by this net and set its previous pointer so that: // (a) the routing for each connection can be recovered by // finishRouteConnection() @@ -350,14 +330,6 @@ protected void determineRoutingTargets() { sinkRnode.updatePresentCongestionCost(presentCongestionFactor); } } - - // Restore prev to avoid assertions firing - for (Map.Entry e2 : stashedPrev.entrySet()) { - RouteNode rnode = e2.getKey(); - RouteNode prev = e2.getValue(); - rnode.setPrev(prev); - } - stashedPrev.clear(); } } From 91aa14b814431ce8d94c3a21c8be2867ab3076dd Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 24 Sep 2024 12:49:33 -0700 Subject: [PATCH 11/43] Missing ! Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/PartialRouter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index a2fdf51de..1cf7766ae 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -274,7 +274,7 @@ protected void determineRoutingTargets() { } } - if (unpreserveNets.isEmpty()) { + if (!unpreserveNets.isEmpty()) { System.out.println("INFO: Unpreserving " + unpreserveNets.size() + " nets to improve sink routability"); for (Net unpreserveNet : unpreserveNets) { unpreserveNet(unpreserveNet); From 7091c8ac420bb1652889d950c6a4afa7d3b079cc Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 24 Sep 2024 14:41:40 -0700 Subject: [PATCH 12/43] Fix abandoning connections for unpreservable Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/PartialRouter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index 1cf7766ae..1d2795d40 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -610,7 +610,7 @@ protected boolean handleUnroutableConnection(Connection connection) { boolean hasAltOutput = super.handleUnroutableConnection(connection); if (hasAltOutput) return true; - if (routeIteration == 2) { + if ((routeIteration == 1 && !hasAltOutput) || routeIteration == 2) { if (softPreserve) { int netsUnpreserved = unpreserveNetsAndReleaseResources(connection); if (netsUnpreserved > 0) { @@ -619,8 +619,8 @@ protected boolean handleUnroutableConnection(Connection connection) { } } if (config.isUseBoundingBox() && !config.isEnlargeBoundingBox()) { - // Since bounding box is never enlarged, there is no hope of routing this connection - // so abandon it + // Since bounding box is never enlarged, and there is nothing to be unpreserved, + // then there is no hope of routing this connection so abandon it indirectConnections.remove(connection); return true; } From 0698be2ca8a8fff5e05e1e076781f3f40beee71e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 24 Sep 2024 18:01:50 -0700 Subject: [PATCH 13/43] RWRoute to not pre-emptively set up second source Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/Connection.java | 9 -- .../xilinx/rapidwright/rwroute/RWRoute.java | 124 +++++++----------- 2 files changed, 46 insertions(+), 87 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/Connection.java b/src/com/xilinx/rapidwright/rwroute/Connection.java index b9bdefa89..5f16a93f7 100644 --- a/src/com/xilinx/rapidwright/rwroute/Connection.java +++ b/src/com/xilinx/rapidwright/rwroute/Connection.java @@ -49,7 +49,6 @@ public class Connection implements Comparable{ * They are created based on the INT tile nodes the source and sink SitePinInsts connect to, respectively. */ private RouteNode sourceRnode; - private RouteNode altSourceRnode; private RouteNode sinkRnode; private List altSinkRnodes; /** @@ -284,14 +283,6 @@ public void setSourceRnode(RouteNode sourceNode) { sourceRnode = sourceNode; } - public RouteNode getAltSourceRnode() { - return altSourceRnode; - } - - public void setAltSourceRnode(RouteNode altSourceNode) { - altSourceRnode = altSourceNode; - } - public RouteNode getSinkRnode() { return sinkRnode; } diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 74bab0bca..40aba69e8 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -549,30 +549,13 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { SitePinInst source = net.getSource(); Node sourceINTNode = RouterHelper.projectOutputPinToINTNode(source); - // Pre-emptively set up alternate source since we may expand from both sources - SitePinInst altSource = net.getAlternateSource(); - Node altSourceINTNode = null; - if (altSource == null) { - altSource = DesignTools.getLegalAlternativeOutputPin(net); - if (altSource != null) { - // Add this SitePinInst to the net, but not to the SiteInst since it's not yet clear we'll be using it - net.addPin(altSource); - DesignTools.routeAlternativeOutputSitePin(net, altSource); - } - } - if (altSource != null) { - assert(!altSource.equals(source)); - altSourceINTNode = RouterHelper.projectOutputPinToINTNode(altSource); - } - RouteNode sourceINTRnode = null; - RouteNode altSourceINTRnode = null; int indirect = 0; for (SitePinInst sink : sinkPins) { Connection connection = new Connection(numConnectionsToRoute++, source, sink, netWrapper); List nodes = RouterHelper.projectInputPinToINTNode(sink); - if (nodes.isEmpty() || (sourceINTNode == null && altSourceINTNode == null)) { + if (nodes.isEmpty() || sourceINTNode == null) { directConnections.add(connection); connection.setDirect(true); } else { @@ -640,7 +623,7 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { sinkRnode.updatePresentCongestionCost(presentCongestionFactor); } - if (sourceINTNode == null && altSourceINTNode == null) { + if (sourceINTNode == null) { throw new RuntimeException("ERROR: Null projected INT node for the source of net " + net.toStringFull()); } if (sourceINTRnode == null && sourceINTNode != null) { @@ -650,19 +633,12 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { // be a projection from LAGUNA/RXQ* -> RXD* (node for INT/LOGIC_OUTS_*) routingGraph.preserve(sourceINTNode, net); } - if (altSourceINTRnode == null && altSourceINTNode != null) { - altSourceINTRnode = getOrCreateRouteNode(altSourceINTNode, RouteNodeType.PINFEED_O); - } if (sourceINTRnode != null) { connection.setSourceRnode(sourceINTRnode); - connection.setAltSourceRnode(altSourceINTRnode); } else { // Primary source does not reach the fabric (e.g. COUT) - // just use alternate source - assert(altSourceINTRnode != null); - connection.setSource(net.getAlternateSource()); - connection.setSourceRnode(altSourceINTRnode); + throw new RuntimeException(); } connection.setDirect(false); indirect++; @@ -1640,48 +1616,62 @@ protected boolean handleCongestedConnection(Connection connection) { return false; } - /** - * Swaps the output pin of a connection, if its net has an alternative output pin. - * @param connection The connection in question. - * @return true, if the output pin has been swapped. - */ - protected boolean swapOutputPin(Connection connection) { - NetWrapper netWrapper = connection.getNetWrapper(); - Net net = netWrapper.getNet(); + protected Pair setupAlternateSource(SitePinInst source) { + Net net = source.getNet(); + assert(net != null); - SitePinInst altSource = net.getAlternateSource(); - if (altSource == null) { - altSource = DesignTools.getLegalAlternativeOutputPin(net); - if (altSource != null) { + SitePinInst altSource; + if (source.equals(net.getSource())) { + altSource = net.getAlternateSource(); + if (altSource == null) { + // TODO: Cache this + altSource = DesignTools.getLegalAlternativeOutputPin(net); + if (altSource == null) { + return null; + } // Add this SitePinInst to the net, but not to the SiteInst since it's not yet clear we'll be using it net.addPin(altSource); DesignTools.routeAlternativeOutputSitePin(net, altSource); - } else { - System.out.println("INFO: No alternative source to swap"); - return false; } + } else { + assert(source.equals(net.getAlternateSource())); + altSource = net.getSource(); + assert(altSource != null); } - SitePinInst source = connection.getSource(); - if (source.equals(altSource)) { - altSource = net.getSource(); + Node altSourceNode = RouterHelper.projectOutputPinToINTNode(altSource); + if (altSourceNode == null) { + return null; } - RouteNode altSourceRnode = connection.getAltSourceRnode(); - if (altSourceRnode == null) { - Node altSourceNode = RouterHelper.projectOutputPinToINTNode(altSource); - if (routingGraph.isPreserved(altSourceNode)) { - System.out.println("INFO: No alternative source to swap"); - return false; - } - assert(routingGraph.getNode(altSourceNode) == null); - altSourceRnode = getOrCreateRouteNode(altSourceNode, RouteNodeType.PINFEED_O); + if (routingGraph.isPreserved(altSourceNode)) { + return null; } - System.out.println("INFO: Swap source from " + source + " to " + altSource + "\n"); + RouteNode altSourceRnode = getOrCreateRouteNode(altSourceNode, RouteNodeType.PINFEED_O); + assert(altSourceRnode != null); + return new Pair<>(altSource, altSourceRnode); + } + /** + * Swaps the output pin of a connection, if its net has an alternative output pin. + * @param connection The connection in question. + * @return true, if the output pin has been swapped. + */ + protected boolean swapOutputPin(Connection connection) { + SitePinInst source = connection.getSource(); + Pair altSourceAndRnode = setupAlternateSource(connection.getSource()); + if (altSourceAndRnode == null) { + return false; + } + + SitePinInst altSource = altSourceAndRnode.getFirst(); + System.out.println("INFO: Swap source from " + source + " to " + altSource + "\n"); connection.setSource(altSource); + + RouteNode altSourceRnode = altSourceAndRnode.getSecond(); connection.setSourceRnode(altSourceRnode); + connection.getSink().setRouted(false); return true; } @@ -1732,29 +1722,7 @@ private boolean saveRouting(Connection connection, RouteNode rnode) { RouteNode sourceRnode = rnodes.get(rnodes.size()-1); if (!sourceRnode.equals(connection.getSourceRnode())) { - if (!sourceRnode.equals(connection.getAltSourceRnode())) { - // Didn't backtrack to alternate source either -- invalid routing - return false; - } - - // Used source node is different to the one set on the connection - Net net = connection.getNetWrapper().getNet(); - - // Update connection's source SPI - if (connection.getSource() == net.getSource()) { - // Swap to alternate source - connection.setSource(net.getAlternateSource()); - } else if (connection.getSource() == net.getAlternateSource()) { - // Swap back to main source - connection.setSource(net.getSource()); - } else { - // Backtracked to neither the net's source nor its alternate source - throw new RuntimeException("Backtracking terminated at unexpected rnode: " + rnode); - } - - // Swap source rnode - connection.setAltSourceRnode(connection.getSourceRnode()); - connection.setSourceRnode(sourceRnode); + throw new RuntimeException(); } return true; From 3bce2ee0f5178d1cd835ad44bbb47f4fe91a4605 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 24 Sep 2024 18:15:27 -0700 Subject: [PATCH 14/43] Refactor output pin swapping/connection abandonment Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/PartialRouter.java | 29 +++++++++---------- .../xilinx/rapidwright/rwroute/RWRoute.java | 29 +++++++++++++++---- 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index 1d2795d40..eff59cf48 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -607,23 +607,22 @@ protected void unpreserveNet(Net net) { @Override protected boolean handleUnroutableConnection(Connection connection) { - boolean hasAltOutput = super.handleUnroutableConnection(connection); - if (hasAltOutput) - return true; - if ((routeIteration == 1 && !hasAltOutput) || routeIteration == 2) { - if (softPreserve) { - int netsUnpreserved = unpreserveNetsAndReleaseResources(connection); - if (netsUnpreserved > 0) { - return true; - } - } - } - if (config.isUseBoundingBox() && !config.isEnlargeBoundingBox()) { - // Since bounding box is never enlarged, and there is nothing to be unpreserved, - // then there is no hope of routing this connection so abandon it - indirectConnections.remove(connection); + enlargeBoundingBox(connection); + if (routeIteration == 1 && swapOutputPin(connection)) { return true; } + if (softPreserve && ( + // First iteration, without alternate source + (routeIteration == 1 && connection.getNetWrapper().getNet().getAlternateSource() == null) || + // Second iteration, with alternate source + (routeIteration == 2 && connection.getNetWrapper().getNet().getAlternateSource() != null)) + ) { + int netsUnpreserved = unpreserveNetsAndReleaseResources(connection); + if (netsUnpreserved > 0) { + return true; + } + } + abandonConnectionIfUnroutable(connection); return false; } diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 40aba69e8..fe09d5766 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1598,21 +1598,38 @@ protected void routeIndirectConnection(Connection connection) { targets.clear(); } + protected void enlargeBoundingBox(Connection connection) { + if (!config.isEnlargeBoundingBox()) { + return; + } + + connection.enlargeBoundingBox(config.getExtensionXIncrement(), config.getExtensionYIncrement()); + } + + protected void abandonConnectionIfUnroutable(Connection connection) { + if (!config.isUseBoundingBox() || config.isEnlargeBoundingBox()) { + return; + } + + // Since bounding box is never enlarged there is no hope of routing this connection so abandon it + indirectConnections.remove(connection); + } + /** * Deals with a failed connection by possible output pin swapping and unrouting preserved nets if the router is in the soft preserve mode. * @param connection The failed connection. */ protected boolean handleUnroutableConnection(Connection connection) { - if (config.isEnlargeBoundingBox()) { - connection.enlargeBoundingBox(config.getExtensionXIncrement(), config.getExtensionYIncrement()); + enlargeBoundingBox(connection); + if (routeIteration == 1 && swapOutputPin(connection)) { + return true; } - return routeIteration == 1 && swapOutputPin(connection); + abandonConnectionIfUnroutable(connection); + return false; } protected boolean handleCongestedConnection(Connection connection) { - if (config.isEnlargeBoundingBox()) { - connection.enlargeBoundingBox(config.getExtensionXIncrement(), config.getExtensionYIncrement()); - } + enlargeBoundingBox(connection); return false; } From b0de24bfffd8c8497191ece9746699c7226c8195 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 24 Sep 2024 18:22:34 -0700 Subject: [PATCH 15/43] Abandon connections with message, and remove from sorted Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RWRoute.java | 5 ++++- src/com/xilinx/rapidwright/util/VivadoTools.java | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index fe09d5766..0c720246a 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1609,10 +1609,13 @@ protected void enlargeBoundingBox(Connection connection) { protected void abandonConnectionIfUnroutable(Connection connection) { if (!config.isUseBoundingBox() || config.isEnlargeBoundingBox()) { return; - } + } + + System.out.println(" " + "Abandoning"); // Since bounding box is never enlarged there is no hope of routing this connection so abandon it indirectConnections.remove(connection); + sortedIndirectConnections.remove(connection); } /** diff --git a/src/com/xilinx/rapidwright/util/VivadoTools.java b/src/com/xilinx/rapidwright/util/VivadoTools.java index 6ffe05bec..52e910ffe 100644 --- a/src/com/xilinx/rapidwright/util/VivadoTools.java +++ b/src/com/xilinx/rapidwright/util/VivadoTools.java @@ -131,7 +131,6 @@ public static ReportRouteStatusResult reportRouteStatus(Design design) { final Path dcp = writeCheckpoint(design); boolean encrypted = !design.getNetlist().getEncryptedCells().isEmpty(); ReportRouteStatusResult rrs = reportRouteStatus(dcp, dcp.getParent(), encrypted); - FileTools.deleteFolder(dcp.getParent().toString()); return rrs; From b8ad542a15c4c31d985ed03d7baedf1c63d2c3f4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 24 Sep 2024 18:53:53 -0700 Subject: [PATCH 16/43] Fix for nets with direct and indirect connections Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/rwroute/RWRoute.java | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 0c720246a..c561b62f1 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -554,11 +554,34 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { for (SitePinInst sink : sinkPins) { Connection connection = new Connection(numConnectionsToRoute++, source, sink, netWrapper); List nodes = RouterHelper.projectInputPinToINTNode(sink); + if (sourceINTNode == null && !nodes.isEmpty()) { + // Sink can be projected to an INT tile, but source cannot be; try alternate source + Pair altSourceAndRnode = setupAlternateSource(connection.getSource()); + if (altSourceAndRnode != null) { + SitePinInst altSource = altSourceAndRnode.getFirst(); + RouteNode altSourceINTRnode = altSourceAndRnode.getSecond(); + connection.setSource(altSource); + connection.setSourceRnode(altSourceINTRnode); + } + } - if (nodes.isEmpty() || sourceINTNode == null) { + if (sourceINTNode == null && connection.getSourceRnode() == null) { directConnections.add(connection); connection.setDirect(true); } else { + if (connection.getSourceRnode() == null) { + assert(sourceINTNode != null); + if (sourceINTRnode == null) { + sourceINTRnode = getOrCreateRouteNode(sourceINTNode, RouteNodeType.PINFEED_O); + // Where only a single primary source exists, always preserve + // its projected-to-INT source node, since it could + // be a projection from LAGUNA/RXQ* -> RXD* (node for INT/LOGIC_OUTS_*) + routingGraph.preserve(sourceINTNode, net); + } + assert(sourceINTRnode != null); + connection.setSourceRnode(sourceINTRnode); + } + Node sinkINTNode = nodes.get(0); indirectConnections.add(connection); RouteNode sinkRnode = getOrCreateRouteNode(sinkINTNode, RouteNodeType.PINFEED_I); @@ -623,23 +646,6 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { sinkRnode.updatePresentCongestionCost(presentCongestionFactor); } - if (sourceINTNode == null) { - throw new RuntimeException("ERROR: Null projected INT node for the source of net " + net.toStringFull()); - } - if (sourceINTRnode == null && sourceINTNode != null) { - sourceINTRnode = getOrCreateRouteNode(sourceINTNode, RouteNodeType.PINFEED_O); - // Where only a single primary source exists, always preserve - // its projected-to-INT source node, since it could - // be a projection from LAGUNA/RXQ* -> RXD* (node for INT/LOGIC_OUTS_*) - routingGraph.preserve(sourceINTNode, net); - } - - if (sourceINTRnode != null) { - connection.setSourceRnode(sourceINTRnode); - } else { - // Primary source does not reach the fabric (e.g. COUT) - throw new RuntimeException(); - } connection.setDirect(false); indirect++; connection.computeHpwl(); From 9857956967473f1262e12f85f96d00063222ef45 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 24 Sep 2024 20:32:20 -0700 Subject: [PATCH 17/43] Refactor into RWRoute.saveRoutingSource() Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RWRoute.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index c561b62f1..6f078b78f 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1716,6 +1716,16 @@ protected void finishRouteConnection(Connection connection, RouteNode rnode) { } } + protected void saveRoutingSource(Connection connection) { + List rnodes = connection.getRnodes(); + RouteNode sourceRnode = rnodes.get(rnodes.size() - 1); + if (sourceRnode.equals(connection.getSourceRnode())) { + return; + } + + throw new RuntimeException("ERROR: Backtracking terminated at unexpected rnode: " + sourceRnode); + } + /** * Traces back for a connection from its sink rnode to its source, in order to build and store the routing path. * @param connection: The connection that is being routed. @@ -1746,11 +1756,7 @@ private boolean saveRouting(Connection connection, RouteNode rnode) { return false; } - RouteNode sourceRnode = rnodes.get(rnodes.size()-1); - if (!sourceRnode.equals(connection.getSourceRnode())) { - throw new RuntimeException(); - } - + saveRoutingSource(connection); return true; } From ce6edd88b5b03632f744b843e7ec049df435e4ba Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 24 Sep 2024 22:05:12 -0700 Subject: [PATCH 18/43] Refactor Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/Connection.java | 1 + .../rapidwright/rwroute/PartialRouter.java | 99 +++++++++---------- 2 files changed, 47 insertions(+), 53 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/Connection.java b/src/com/xilinx/rapidwright/rwroute/Connection.java index 5f16a93f7..e965f64e4 100644 --- a/src/com/xilinx/rapidwright/rwroute/Connection.java +++ b/src/com/xilinx/rapidwright/rwroute/Connection.java @@ -352,6 +352,7 @@ public SitePinInst getSource() { } public void setSource(SitePinInst source) { + assert(source != null); this.source = source; } diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index eff59cf48..044c6efea 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -33,7 +33,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; @@ -269,7 +268,7 @@ protected void determineRoutingTargets() { Net unpreserveNet = routingGraph.getPreservedNet(sinkRnode); if (unpreserveNet != null && unpreserveNet != net) { unpreserveNets.add(unpreserveNet); - sinkRnode.setType(RouteNodeType.PINFEED_I); + assert(sinkRnode.getType() == RouteNodeType.PINFEED_I); sinkRnode.clearPrev(); } } @@ -280,57 +279,6 @@ protected void determineRoutingTargets() { unpreserveNet(unpreserveNet); } } - - // Go through all nets to be routed - for (Map.Entry e : nets.entrySet()) { - Net net = e.getKey(); - NetWrapper netWrapper = e.getValue(); - - // Create all nodes used by this net and set its previous pointer so that: - // (a) the routing for each connection can be recovered by - // finishRouteConnection() - // (b) RouteNode.setChildren() will know to only allow this incoming - // arc on these nodes - for (PIP pip : net.getPIPs()) { - Node start = (pip.isReversed()) ? pip.getEndNode() : pip.getStartNode(); - Node end = (pip.isReversed()) ? pip.getStartNode() : pip.getEndNode(); - - // Do not include arcs that the router wouldn't explore - // e.g. those that leave the INT tile, since we project pins to their INT tile - if (routingGraph.isExcludedTile(end)) - continue; - - RouteNode rstart = getOrCreateRouteNode(start, null); - RouteNode rend = getOrCreateRouteNode(end, null); - assert (rend.getPrev() == null); - rend.setPrev(rstart); - } - - // Use the prev pointers to attempt to recover routing for all indirect connections - for (Connection connection : netWrapper.getConnections()) { - if (connection.isDirect()) { - continue; - } - RouteNode sourceRnode = connection.getSourceRnode(); - RouteNode sinkRnode = connection.getSinkRnode(); - assert(sourceRnode.getType() == RouteNodeType.PINFEED_O); - assert(sinkRnode.getType() == RouteNodeType.PINFEED_I); - - // Even though this connection is not expected to have any routing yet, - // perform a rip up anyway in order to release any exclusive sinks - // ahead of finishRouteConnection() - assert(connection.getRnodes().isEmpty()); - connection.getSink().setRouted(false); - ripUp(connection); - - finishRouteConnection(connection, sinkRnode); - if (!connection.getSink().isRouted() && connection.getAltSinkRnodes().isEmpty()) { - // Undo what ripUp() did for this connection which has a single exclusive sink - sinkRnode.incrementUser(connection.getNetWrapper()); - sinkRnode.updatePresentCongestionCost(presentCongestionFactor); - } - } - } } @Override @@ -407,6 +355,51 @@ protected void addNetConnectionToRoutingTargets(Net net) { if (partiallyPreserved) { partiallyPreservedNets.add(netWrapper); } + + // Create all nodes used by this net and set its previous pointer so that: + // (a) the routing for each connection can be recovered by + // finishRouteConnection() + // (b) RouteNode.setChildren() will know to only allow this incoming + // arc on these nodes + for (PIP pip : net.getPIPs()) { + Node start = (pip.isReversed()) ? pip.getEndNode() : pip.getStartNode(); + Node end = (pip.isReversed()) ? pip.getStartNode() : pip.getEndNode(); + + // Do not include arcs that the router wouldn't explore + // e.g. those that leave the INT tile, since we project pins to their INT tile + if (routingGraph.isExcludedTile(end)) + continue; + + RouteNode rstart = getOrCreateRouteNode(start, null); + RouteNode rend = getOrCreateRouteNode(end, null); + assert(rend.getPrev() == null); + rend.setPrev(rstart); + } + + // Use the prev pointers to attempt to recover routing for all indirect connections + for (Connection connection : netWrapper.getConnections()) { + if (connection.isDirect()) { + continue; + } + RouteNode sourceRnode = connection.getSourceRnode(); + RouteNode sinkRnode = connection.getSinkRnode(); + assert(sourceRnode.getType() == RouteNodeType.PINFEED_O); + assert(sinkRnode.getType() == RouteNodeType.PINFEED_I); + + // Even though this connection is not expected to have any routing yet, + // perform a rip up anyway in order to release any exclusive sinks + // ahead of finishRouteConnection() + assert(connection.getRnodes().isEmpty()); + connection.getSink().setRouted(false); + ripUp(connection); + + finishRouteConnection(connection, sinkRnode); + if (!connection.getSink().isRouted() && connection.getAltSinkRnodes().isEmpty()) { + // Undo what ripUp() did for this connection which has a single exclusive sink + sinkRnode.incrementUser(connection.getNetWrapper()); + sinkRnode.updatePresentCongestionCost(presentCongestionFactor); + } + } } if (net.hasPIPs()) { From 9e64488d5a1982b8ea68bc7f073e15d5267b55f1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 24 Sep 2024 22:34:00 -0700 Subject: [PATCH 19/43] Remove stale comment Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RWRoute.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 6f078b78f..267e7ec3a 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1655,7 +1655,6 @@ protected Pair setupAlternateSource(SitePinInst source) { if (altSource == null) { return null; } - // Add this SitePinInst to the net, but not to the SiteInst since it's not yet clear we'll be using it net.addPin(altSource); DesignTools.routeAlternativeOutputSitePin(net, altSource); } From f6e4a7704498b9fc929681d8cf3c5dded25fd2ab Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 24 Sep 2024 23:02:48 -0700 Subject: [PATCH 20/43] Cache result of finding alt source pins Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/NetWrapper.java | 50 +++++++++++++++++++ .../xilinx/rapidwright/rwroute/RWRoute.java | 33 +++++------- 2 files changed, 62 insertions(+), 21 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/NetWrapper.java b/src/com/xilinx/rapidwright/rwroute/NetWrapper.java index d2b75a8a9..d68e9e0e5 100644 --- a/src/com/xilinx/rapidwright/rwroute/NetWrapper.java +++ b/src/com/xilinx/rapidwright/rwroute/NetWrapper.java @@ -27,7 +27,10 @@ import java.util.ArrayList; import java.util.List; +import com.xilinx.rapidwright.design.DesignTools; import com.xilinx.rapidwright.design.Net; +import com.xilinx.rapidwright.design.SitePinInst; +import com.xilinx.rapidwright.device.Node; /** * A wrapper class of {@link Net} with additional information for the router. @@ -44,11 +47,15 @@ public class NetWrapper{ private float yCenter; /** The half-perimeter wirelength */ private short doubleHpwl; + boolean noAltSourceFound; + private RouteNode sourceRnode; + private RouteNode altSourceRnode; public NetWrapper(int id, Net net) { this.id = id; this.net = net; connections = new ArrayList<>(); + noAltSourceFound = false; } public void computeHPWLAndCenterCoordinates(int[] nextLagunaColumn, int[] prevLagunaColumn) { @@ -128,4 +135,47 @@ public int hashCode() { return id; } + public RouteNode getSourceRnode() { + return sourceRnode; + } + + public void setSourceRnode(RouteNode sourceRnode) { + this.sourceRnode = sourceRnode; + } + + public SitePinInst getAltSource(RouteNodeGraph routingGraph) { + if (noAltSourceFound) { + return null; + } + + SitePinInst altSource = net.getAlternateSource(); + if (altSource == null) { + altSource = DesignTools.getLegalAlternativeOutputPin(net); + if (altSource == null) { + noAltSourceFound = true; + return null; + } + + net.addPin(altSource); + DesignTools.routeAlternativeOutputSitePin(net, altSource); + + Node altSourceNode = RouterHelper.projectOutputPinToINTNode(altSource); + if (altSourceNode == null) { + noAltSourceFound = true; + return null; + } + + if (routingGraph.isPreserved(altSourceNode)) { + noAltSourceFound = true; + return null; + } + + altSourceRnode = routingGraph.getOrCreate(altSourceNode, RouteNodeType.PINFEED_O); + } + return altSource; + } + + public RouteNode getAltSourceRnode() { + return altSourceRnode; + } } diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 267e7ec3a..17873646a 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -577,6 +577,7 @@ 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_*) routingGraph.preserve(sourceINTNode, net); + netWrapper.setSourceRnode(sourceINTRnode); } assert(sourceINTRnode != null); connection.setSourceRnode(sourceINTRnode); @@ -1646,34 +1647,24 @@ protected Pair setupAlternateSource(SitePinInst source) { Net net = source.getNet(); assert(net != null); - SitePinInst altSource; + NetWrapper netWrapper = nets.get(net); + assert(netWrapper != null); + + SitePinInst altSource = netWrapper.getAltSource(routingGraph); + if (altSource == null) { + return null; + } + + RouteNode altSourceRnode; if (source.equals(net.getSource())) { - altSource = net.getAlternateSource(); - if (altSource == null) { - // TODO: Cache this - altSource = DesignTools.getLegalAlternativeOutputPin(net); - if (altSource == null) { - return null; - } - net.addPin(altSource); - DesignTools.routeAlternativeOutputSitePin(net, altSource); - } + altSourceRnode = netWrapper.getAltSourceRnode(); } else { assert(source.equals(net.getAlternateSource())); altSource = net.getSource(); assert(altSource != null); + altSourceRnode = netWrapper.getSourceRnode(); } - Node altSourceNode = RouterHelper.projectOutputPinToINTNode(altSource); - if (altSourceNode == null) { - return null; - } - - if (routingGraph.isPreserved(altSourceNode)) { - return null; - } - - RouteNode altSourceRnode = getOrCreateRouteNode(altSourceNode, RouteNodeType.PINFEED_O); assert(altSourceRnode != null); return new Pair<>(altSource, altSourceRnode); } From c233041c79ab349825339763b5e2cf346c8106fc Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 24 Sep 2024 23:05:48 -0700 Subject: [PATCH 21/43] Inline trivial method Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/PartialRouter.java | 8 ++++---- .../xilinx/rapidwright/rwroute/RWRoute.java | 18 +++--------------- .../xilinx/rapidwright/rwroute/RouteNode.java | 2 +- .../rapidwright/rwroute/RouteNodeGraph.java | 4 ++++ 4 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index 044c6efea..137dcdef9 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -370,8 +370,8 @@ protected void addNetConnectionToRoutingTargets(Net net) { if (routingGraph.isExcludedTile(end)) continue; - RouteNode rstart = getOrCreateRouteNode(start, null); - RouteNode rend = getOrCreateRouteNode(end, null); + RouteNode rstart = routingGraph.getOrCreate(start); + RouteNode rend = routingGraph.getOrCreate(end); assert(rend.getPrev() == null); rend.setPrev(rstart); } @@ -530,8 +530,8 @@ protected void unpreserveNet(Net net) { boolean startPreserved = routingGraph.unpreserve(start); boolean endPreserved = routingGraph.unpreserve(end); - RouteNode rstart = getOrCreateRouteNode(start, null); - RouteNode rend = getOrCreateRouteNode(end, null); + RouteNode rstart = routingGraph.getOrCreate(start); + RouteNode rend = routingGraph.getOrCreate(end); boolean rstartAdded = rnodes.add(rstart); boolean rendAdded = rnodes.add(rend); assert(rstartAdded == startPreserved); diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 17873646a..313ec7e9d 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -572,7 +572,7 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { if (connection.getSourceRnode() == null) { assert(sourceINTNode != null); if (sourceINTRnode == null) { - sourceINTRnode = getOrCreateRouteNode(sourceINTNode, RouteNodeType.PINFEED_O); + sourceINTRnode = routingGraph.getOrCreate(sourceINTNode, RouteNodeType.PINFEED_O); // Where only a single primary source exists, always preserve // its projected-to-INT source node, since it could // be a projection from LAGUNA/RXQ* -> RXD* (node for INT/LOGIC_OUTS_*) @@ -585,7 +585,7 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { Node sinkINTNode = nodes.get(0); indirectConnections.add(connection); - RouteNode sinkRnode = getOrCreateRouteNode(sinkINTNode, RouteNodeType.PINFEED_I); + RouteNode sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.PINFEED_I); assert(sinkRnode.getType() == RouteNodeType.PINFEED_I); connection.setSinkRnode(sinkRnode); @@ -635,7 +635,7 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { if (routingGraph.isPreserved(node)) { continue; } - RouteNode altSinkRnode = getOrCreateRouteNode(node, RouteNodeType.PINFEED_I); + RouteNode altSinkRnode = routingGraph.getOrCreate(node, RouteNodeType.PINFEED_I); assert(altSinkRnode.getType() == RouteNodeType.PINFEED_I); connection.addAltSinkRnode(altSinkRnode); } @@ -677,18 +677,6 @@ private void addConnectionSpanInfo(Connection connection) { connectionSpan.merge(connection.getHpwl(), 1, Integer::sum); } - /** - * Creates a {@link RouteNode} Object based on a {@link Node} instance and avoids duplicates, - * used for creating the source and sink rnodes of {@link Connection} instances. - * NOTE: This method does not consider whether returned node is preserved. - * @param node The node associated to the {@link SitePinInst} instance. - * @param type The {@link RouteNodeType} of the {@link RouteNode} Object. - * @return The created {@link RouteNode} instance. - */ - protected RouteNode getOrCreateRouteNode(Node node, RouteNodeType type) { - return routingGraph.getOrCreate(node, type); - } - /** * @return ConnectionState object to be used for routing. */ diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index 63827c0ea..27f4ef547 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -382,7 +382,7 @@ public RouteNode[] getChildren(RouteNodeGraph routingGraph) { continue; } - RouteNode child = routingGraph.getOrCreate(downhill, null); + RouteNode child = routingGraph.getOrCreate(downhill); childrenList.add(child);//the sink rnode of a target connection has been created up-front } if (!childrenList.isEmpty()) { diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 89e01ad87..1e4b98f90 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -520,6 +520,10 @@ protected RouteNode create(Node node, RouteNodeType type) { return new RouteNode(this, node, type); } + public RouteNode getOrCreate(Node node) { + return getOrCreate(node, null); + } + public RouteNode getOrCreate(Node node, RouteNodeType type) { Tile tile = node.getTile(); int wireIndex = node.getWireIndex(); From a3d6dbc3c9ba93cff204ae5505c1354e0025de7e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 25 Sep 2024 09:26:44 -0700 Subject: [PATCH 22/43] NetWrapper.getAltSource() to compute altSourceRnode when pin already exists Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/NetWrapper.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/com/xilinx/rapidwright/rwroute/NetWrapper.java b/src/com/xilinx/rapidwright/rwroute/NetWrapper.java index d68e9e0e5..7f9042f70 100644 --- a/src/com/xilinx/rapidwright/rwroute/NetWrapper.java +++ b/src/com/xilinx/rapidwright/rwroute/NetWrapper.java @@ -158,7 +158,8 @@ public SitePinInst getAltSource(RouteNodeGraph routingGraph) { net.addPin(altSource); DesignTools.routeAlternativeOutputSitePin(net, altSource); - + } + if (altSourceRnode == null) { Node altSourceNode = RouterHelper.projectOutputPinToINTNode(altSource); if (altSourceNode == null) { noAltSourceFound = true; @@ -172,6 +173,7 @@ public SitePinInst getAltSource(RouteNodeGraph routingGraph) { altSourceRnode = routingGraph.getOrCreate(altSourceNode, RouteNodeType.PINFEED_O); } + assert(altSourceRnode != null); return altSource; } From ac6f7962c8c4799a377f9ad9d4f62d7c02bc6f59 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 25 Sep 2024 09:32:32 -0700 Subject: [PATCH 23/43] Allow promotion for PINBOUNCE to PINFEED_I Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RWRoute.java | 2 +- src/com/xilinx/rapidwright/rwroute/RouteNode.java | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 313ec7e9d..806d88fcf 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -586,7 +586,7 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { Node sinkINTNode = nodes.get(0); indirectConnections.add(connection); RouteNode sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.PINFEED_I); - assert(sinkRnode.getType() == RouteNodeType.PINFEED_I); + sinkRnode.setType(RouteNodeType.PINFEED_I); connection.setSinkRnode(sinkRnode); // Where appropriate, allow all 6 LUT pins to be swapped to begin with diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index 27f4ef547..64be238cb 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -312,9 +312,12 @@ public RouteNodeType getType() { * @param type New RouteNodeType value. */ public void setType(RouteNodeType type) { - // Only support demotion from PINFEED_I to WIRE or PINBOUNCE since they have the same base cost - assert(this.type == RouteNodeType.PINFEED_I - && (type == RouteNodeType.WIRE || type == RouteNodeType.PINBOUNCE)); + assert(this.type == type || + // Support demotion from PINFEED_I to PINBOUNCE since they have the same base cost + (this.type == RouteNodeType.PINFEED_I && type == RouteNodeType.PINBOUNCE) || + // Or promotion from PINBOUNCE to PINFEED_I (by PartialRouter when PINBOUNCE on + // preserved net needs to become a PINFEED_I) + (this.type == RouteNodeType.PINBOUNCE && type == RouteNodeType.PINFEED_I)); this.type = type; } From 60fbb6ed29f4522c6c359d6582b2f6a863427623 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 25 Sep 2024 09:32:56 -0700 Subject: [PATCH 24/43] Fix assertion in RWRoute.push() Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RWRoute.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 806d88fcf..69c3d38d5 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1996,7 +1996,8 @@ private float getNodeCost(RouteNode rnode, Connection connection, int countSameS * @param newTotalPathCost Total path cost of childRnode. */ protected void push(ConnectionState state, RouteNode childRnode, float newPartialPathCost, float newTotalPathCost) { - assert(childRnode.getPrev() != null || childRnode.getType() == RouteNodeType.PINFEED_O); + // Pushed node must have a prev pointer, unless it is a source (with no upstream path cost) + assert(childRnode.getPrev() != null || newPartialPathCost == 0); childRnode.setLowerBoundTotalPathCost(newTotalPathCost); childRnode.setUpstreamPathCost(newPartialPathCost); // Use the number-of-connections-routed-so-far as the identifier for whether a rnode From c5342e070a94b6a9f732223c01f8bfe321483ffd Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 25 Sep 2024 09:53:31 -0700 Subject: [PATCH 25/43] Fix broken assumptions Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/Connection.java | 1 - .../rapidwright/rwroute/PartialRouter.java | 34 +++++++++---------- .../xilinx/rapidwright/rwroute/RWRoute.java | 24 ++++--------- 3 files changed, 23 insertions(+), 36 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/Connection.java b/src/com/xilinx/rapidwright/rwroute/Connection.java index e965f64e4..ce09bee42 100644 --- a/src/com/xilinx/rapidwright/rwroute/Connection.java +++ b/src/com/xilinx/rapidwright/rwroute/Connection.java @@ -272,7 +272,6 @@ public float getCriticality() { public void resetRoute() { getRnodes().clear(); - sink.setRouted(false); } public RouteNode getSourceRnode() { diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index 137dcdef9..6c911d24e 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -269,7 +269,6 @@ protected void determineRoutingTargets() { if (unpreserveNet != null && unpreserveNet != net) { unpreserveNets.add(unpreserveNet); assert(sinkRnode.getType() == RouteNodeType.PINFEED_I); - sinkRnode.clearPrev(); } } @@ -381,10 +380,6 @@ protected void addNetConnectionToRoutingTargets(Net net) { if (connection.isDirect()) { continue; } - RouteNode sourceRnode = connection.getSourceRnode(); - RouteNode sinkRnode = connection.getSinkRnode(); - assert(sourceRnode.getType() == RouteNodeType.PINFEED_O); - assert(sinkRnode.getType() == RouteNodeType.PINFEED_I); // Even though this connection is not expected to have any routing yet, // perform a rip up anyway in order to release any exclusive sinks @@ -393,12 +388,8 @@ protected void addNetConnectionToRoutingTargets(Net net) { connection.getSink().setRouted(false); ripUp(connection); + RouteNode sinkRnode = connection.getSinkRnode(); finishRouteConnection(connection, sinkRnode); - if (!connection.getSink().isRouted() && connection.getAltSinkRnodes().isEmpty()) { - // Undo what ripUp() did for this connection which has a single exclusive sink - sinkRnode.incrementUser(connection.getNetWrapper()); - sinkRnode.updatePresentCongestionCost(presentCongestionFactor); - } } } @@ -409,6 +400,20 @@ protected void addNetConnectionToRoutingTargets(Net net) { } } + @Override + protected void finishRouteConnection(Connection connection, RouteNode rnode) { + super.finishRouteConnection(connection, rnode); + + if (!connection.getSink().isRouted()) { + connection.resetRoute(); + if (connection.getAltSinkRnodes().isEmpty()) { + // Undo what ripUp() would have done for this connection which has a single exclusive sink + rnode.incrementUser(connection.getNetWrapper()); + rnode.updatePresentCongestionCost(presentCongestionFactor); + } + } + } + /** * Return preserved nets that are using resources immediately downhill of the source and * immediately uphill of the sink of the connection. @@ -499,13 +504,13 @@ protected void unpreserveNet(Net net) { // Since net already exists, all the nodes it uses must already // have been created RouteNode rstart = routingGraph.getNode(start); - assert (rstart != null); + assert(rstart != null); boolean rstartAdded = rnodes.add(rstart); boolean startPreserved = routingGraph.unpreserve(start); assert(rstartAdded == startPreserved); RouteNode rend = routingGraph.getNode(end); - assert (rend != null); + assert(rend != null); boolean rendAdded = rnodes.add(rend); boolean endPreserved = routingGraph.unpreserve(end); assert(rendAdded == endPreserved); @@ -558,11 +563,6 @@ protected void unpreserveNet(Net net) { ripUp(connection); finishRouteConnection(connection, sinkRnode); - if (!connection.getSink().isRouted() && connection.getAltSinkRnodes().isEmpty()) { - // Undo what ripUp() did for this connection which has a single exclusive sink - sinkRnode.incrementUser(connection.getNetWrapper()); - sinkRnode.updatePresentCongestionCost(presentCongestionFactor); - } } netToPins.put(net, net.getSinkPins()); diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 69c3d38d5..ad7bf1346 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1566,7 +1566,9 @@ protected void routeIndirectConnection(Connection connection) { queue.clear(); finishRouteConnection(connection, rnode); if (!connection.getSink().isRouted()) { - throw new RuntimeException("Unable to save routing for connection " + connection); + List rnodes = connection.getRnodes(); + throw new RuntimeException("ERROR: Unable to save routing for connection " + connection + "\n" + + " Backtracking terminated at " + rnodes.get(rnodes.size() -1)); } if (config.isTimingDriven()) connection.updateRouteDelay(); assert(connection.getSink().isRouted()); @@ -1574,8 +1576,8 @@ protected void routeIndirectConnection(Connection connection) { assert(queue.isEmpty()); // Clears previous route of the connection connection.resetRoute(); + connection.getSink().setRouted(false); assert(connection.getRnodes().isEmpty()); - assert(!connection.getSink().isRouted()); if (connection.getAltSinkRnodes().isEmpty()) { // Undo what ripUp() did for this connection which has a single exclusive sink @@ -1686,31 +1688,19 @@ protected boolean swapOutputPin(Connection connection) { */ protected void finishRouteConnection(Connection connection, RouteNode rnode) { boolean routed = saveRouting(connection, rnode); + connection.getSink().setRouted(routed); if (routed) { - connection.getSink().setRouted(routed); updateUsersAndPresentCongestionCost(connection); - } else { - connection.resetRoute(); } } - protected void saveRoutingSource(Connection connection) { - List rnodes = connection.getRnodes(); - RouteNode sourceRnode = rnodes.get(rnodes.size() - 1); - if (sourceRnode.equals(connection.getSourceRnode())) { - return; - } - - throw new RuntimeException("ERROR: Backtracking terminated at unexpected rnode: " + sourceRnode); - } - /** * Traces back for a connection from its sink rnode to its source, in order to build and store the routing path. * @param connection: The connection that is being routed. * @param rnode RouteNode to start backtracking from. * @return True if backtracking successful. */ - private boolean saveRouting(Connection connection, RouteNode rnode) { + protected boolean saveRouting(Connection connection, RouteNode rnode) { RouteNode sinkRnode = connection.getSinkRnode(); List altSinkRnodes = connection.getAltSinkRnodes(); if (rnode != sinkRnode && !altSinkRnodes.contains(rnode)) { @@ -1733,8 +1723,6 @@ private boolean saveRouting(Connection connection, RouteNode rnode) { // No prev pointer from sink rnode -> not routed return false; } - - saveRoutingSource(connection); return true; } From 65db0262266a72bf5c6f6c1d3d03b668c429d331 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 25 Sep 2024 09:57:57 -0700 Subject: [PATCH 26/43] Move RWRoute.setupAlternateSource() to Connection.getOrCreateAlternateSource() Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/Connection.java | 22 ++++++++++++++ .../rapidwright/rwroute/NetWrapper.java | 2 +- .../xilinx/rapidwright/rwroute/RWRoute.java | 30 ++----------------- 3 files changed, 25 insertions(+), 29 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/Connection.java b/src/com/xilinx/rapidwright/rwroute/Connection.java index ce09bee42..b5ffc9c2b 100644 --- a/src/com/xilinx/rapidwright/rwroute/Connection.java +++ b/src/com/xilinx/rapidwright/rwroute/Connection.java @@ -34,6 +34,7 @@ import com.xilinx.rapidwright.device.Node; import com.xilinx.rapidwright.timing.TimingEdge; import com.xilinx.rapidwright.timing.delayestimator.DelayEstimatorBase; +import com.xilinx.rapidwright.util.Pair; /** * A Connection instance represents a pair of source-sink {@link SitePinInst} instances of a {@link Net} instance. @@ -489,4 +490,25 @@ public void setAllTargets(RWRoute.ConnectionState state) { } } } + + protected Pair getOrCreateAlternateSource(RouteNodeGraph routingGraph) { + SitePinInst altSource = netWrapper.getOrCreateAlternateSource(routingGraph); + if (altSource == null) { + return null; + } + + Net net = netWrapper.getNet(); + RouteNode altSourceRnode; + if (source.equals(net.getSource())) { + altSourceRnode = netWrapper.getAltSourceRnode(); + } else { + assert(source.equals(net.getAlternateSource())); + altSource = net.getSource(); + assert(altSource != null); + altSourceRnode = netWrapper.getSourceRnode(); + } + + assert(altSourceRnode != null); + return new Pair<>(altSource, altSourceRnode); + } } diff --git a/src/com/xilinx/rapidwright/rwroute/NetWrapper.java b/src/com/xilinx/rapidwright/rwroute/NetWrapper.java index 7f9042f70..4b5c9f120 100644 --- a/src/com/xilinx/rapidwright/rwroute/NetWrapper.java +++ b/src/com/xilinx/rapidwright/rwroute/NetWrapper.java @@ -143,7 +143,7 @@ public void setSourceRnode(RouteNode sourceRnode) { this.sourceRnode = sourceRnode; } - public SitePinInst getAltSource(RouteNodeGraph routingGraph) { + public SitePinInst getOrCreateAlternateSource(RouteNodeGraph routingGraph) { if (noAltSourceFound) { return null; } diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index ad7bf1346..d70778639 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -556,7 +556,7 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { List nodes = RouterHelper.projectInputPinToINTNode(sink); if (sourceINTNode == null && !nodes.isEmpty()) { // Sink can be projected to an INT tile, but source cannot be; try alternate source - Pair altSourceAndRnode = setupAlternateSource(connection.getSource()); + Pair altSourceAndRnode = connection.getOrCreateAlternateSource(routingGraph); if (altSourceAndRnode != null) { SitePinInst altSource = altSourceAndRnode.getFirst(); RouteNode altSourceINTRnode = altSourceAndRnode.getSecond(); @@ -1633,32 +1633,6 @@ protected boolean handleCongestedConnection(Connection connection) { return false; } - protected Pair setupAlternateSource(SitePinInst source) { - Net net = source.getNet(); - assert(net != null); - - NetWrapper netWrapper = nets.get(net); - assert(netWrapper != null); - - SitePinInst altSource = netWrapper.getAltSource(routingGraph); - if (altSource == null) { - return null; - } - - RouteNode altSourceRnode; - if (source.equals(net.getSource())) { - altSourceRnode = netWrapper.getAltSourceRnode(); - } else { - assert(source.equals(net.getAlternateSource())); - altSource = net.getSource(); - assert(altSource != null); - altSourceRnode = netWrapper.getSourceRnode(); - } - - assert(altSourceRnode != null); - return new Pair<>(altSource, altSourceRnode); - } - /** * Swaps the output pin of a connection, if its net has an alternative output pin. * @param connection The connection in question. @@ -1666,7 +1640,7 @@ protected Pair setupAlternateSource(SitePinInst source) { */ protected boolean swapOutputPin(Connection connection) { SitePinInst source = connection.getSource(); - Pair altSourceAndRnode = setupAlternateSource(connection.getSource()); + Pair altSourceAndRnode = connection.getOrCreateAlternateSource(routingGraph); if (altSourceAndRnode == null) { return false; } From 6b8eb104fc3ac1dce3dd05e28d88fcce55856067 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 25 Sep 2024 16:46:22 -0700 Subject: [PATCH 27/43] Fix RWRoute.saveRouting() return value Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RWRoute.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index d70778639..6d6c8205f 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1693,11 +1693,9 @@ protected boolean saveRouting(Connection connection, RouteNode rnode) { } while ((rnode = rnode.getPrev()) != null); List rnodes = connection.getRnodes(); - if (rnodes.size() == 1) { - // No prev pointer from sink rnode -> not routed - return false; - } - return true; + RouteNode sourceRnode = rnodes.get(rnodes.size() - 1); + // Only succesfully routed if backtracked to this connection's source node + return sourceRnode == connection.getSourceRnode(); } /** From 47af493810a95ccd1efd3af3813a83bf61db7e5f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 25 Sep 2024 17:13:30 -0700 Subject: [PATCH 28/43] Consistency Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/PartialRouter.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index 6c911d24e..488d2b1cf 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -274,8 +274,10 @@ protected void determineRoutingTargets() { if (!unpreserveNets.isEmpty()) { System.out.println("INFO: Unpreserving " + unpreserveNets.size() + " nets to improve sink routability"); - for (Net unpreserveNet : unpreserveNets) { - unpreserveNet(unpreserveNet); + for (Net net : unpreserveNets) { + System.out.println("\t" + net); + assert(!net.isStaticNet()); + unpreserveNet(net); } } } From 33600691231a1d303361bc1572fbd548eb7aeed7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 25 Sep 2024 20:51:50 -0700 Subject: [PATCH 29/43] Reverse whitespace change Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/util/VivadoTools.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/xilinx/rapidwright/util/VivadoTools.java b/src/com/xilinx/rapidwright/util/VivadoTools.java index 52e910ffe..6ffe05bec 100644 --- a/src/com/xilinx/rapidwright/util/VivadoTools.java +++ b/src/com/xilinx/rapidwright/util/VivadoTools.java @@ -131,6 +131,7 @@ public static ReportRouteStatusResult reportRouteStatus(Design design) { final Path dcp = writeCheckpoint(design); boolean encrypted = !design.getNetlist().getEncryptedCells().isEmpty(); ReportRouteStatusResult rrs = reportRouteStatus(dcp, dcp.getParent(), encrypted); + FileTools.deleteFolder(dcp.getParent().toString()); return rrs; From 4b110443f9720041a567a0a0d830424916d0ac54 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 25 Sep 2024 20:54:26 -0700 Subject: [PATCH 30/43] Bump copyright Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/Connection.java | 2 +- src/com/xilinx/rapidwright/rwroute/NetWrapper.java | 2 +- src/com/xilinx/rapidwright/rwroute/PartialRouter.java | 2 +- src/com/xilinx/rapidwright/rwroute/RouteNode.java | 2 +- src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/Connection.java b/src/com/xilinx/rapidwright/rwroute/Connection.java index b5ffc9c2b..3521fe9f8 100644 --- a/src/com/xilinx/rapidwright/rwroute/Connection.java +++ b/src/com/xilinx/rapidwright/rwroute/Connection.java @@ -1,7 +1,7 @@ /* * * Copyright (c) 2021 Ghent University. - * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. + * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. * All rights reserved. * * Author: Yun Zhou, Ghent University. diff --git a/src/com/xilinx/rapidwright/rwroute/NetWrapper.java b/src/com/xilinx/rapidwright/rwroute/NetWrapper.java index 4b5c9f120..200bbf7c6 100644 --- a/src/com/xilinx/rapidwright/rwroute/NetWrapper.java +++ b/src/com/xilinx/rapidwright/rwroute/NetWrapper.java @@ -1,7 +1,7 @@ /* * * Copyright (c) 2021 Ghent University. - * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. + * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. * All rights reserved. * * Author: Yun Zhou, Ghent University. diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index 488d2b1cf..01379912d 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -1,7 +1,7 @@ /* * * Copyright (c) 2021 Ghent University. - * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. + * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. * All rights reserved. * * Author: Yun Zhou, Ghent University. diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index 64be238cb..0353978a2 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -1,7 +1,7 @@ /* * * Copyright (c) 2021 Ghent University. - * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. + * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. * All rights reserved. * * Author: Yun Zhou, Ghent University. diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 1e4b98f90..e84026377 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2022, Xilinx, Inc. - * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. + * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. * All rights reserved. * * Author: Eddie Hung, Xilinx Research Labs. From de4504f604acb10367bba0e94cf5f11d3be8f8bf Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 25 Sep 2024 22:11:33 -0700 Subject: [PATCH 31/43] Direct connection if sink cannot be projected Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RWRoute.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 6d6c8205f..073b0399d 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -565,7 +565,8 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { } } - if (sourceINTNode == null && connection.getSourceRnode() == null) { + if ((sourceINTNode == null && connection.getSourceRnode() == null) || nodes.isEmpty()) { + // Direct connection if either source or sink pin cannot be projected to INT tile directConnections.add(connection); connection.setDirect(true); } else { From 39866ca06788917f222e086257abd2fd37d156de Mon Sep 17 00:00:00 2001 From: eddieh-xlnx Date: Wed, 25 Sep 2024 22:26:29 -0700 Subject: [PATCH 32/43] Apply suggestions from code review Signed-off-by: eddieh-xlnx --- src/com/xilinx/rapidwright/rwroute/RWRoute.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 073b0399d..38c480456 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -555,7 +555,8 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { Connection connection = new Connection(numConnectionsToRoute++, source, sink, netWrapper); List nodes = RouterHelper.projectInputPinToINTNode(sink); if (sourceINTNode == null && !nodes.isEmpty()) { - // Sink can be projected to an INT tile, but source cannot be; try alternate source + // Sink can be projected to an INT tile, but primary source (e.g. COUT) + // cannot be; try alternate source Pair altSourceAndRnode = connection.getOrCreateAlternateSource(routingGraph); if (altSourceAndRnode != null) { SitePinInst altSource = altSourceAndRnode.getFirst(); @@ -577,10 +578,10 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { // Where only a single primary source exists, always preserve // 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); netWrapper.setSourceRnode(sourceINTRnode); } - assert(sourceINTRnode != null); connection.setSourceRnode(sourceINTRnode); } From 6ef43cb6f807a8fe5ac642ba8c5b81cd7007acd2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 26 Sep 2024 10:31:41 -0700 Subject: [PATCH 33/43] Set random seed for Test.testNonTimingDrivenPartialRouting() Signed-off-by: Eddie Hung --- test/RapidWrightDCP | 2 +- test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/RapidWrightDCP b/test/RapidWrightDCP index 9c4416ef7..ce3bdaadd 160000 --- a/test/RapidWrightDCP +++ b/test/RapidWrightDCP @@ -1 +1 @@ -Subproject commit 9c4416ef76e590988dda9036e8101768f5574730 +Subproject commit ce3bdaadd45c616d58202d00485b6d3f073e32af diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java index 5dfc90184..64833797e 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java @@ -271,7 +271,7 @@ public void testNonTimingDrivenPartialRouting() { design.setTrackNetChanges(true); // Pseudo-randomly unroute some pins from a multi-pin net - Random random = new Random(); + Random random = new Random(0); for (Net net : design.getNets()) { if (!net.getName().endsWith("/processor/t_state_0")) { continue; From 36112096bb5a4eed6d33cfbd90d47a9dad621a6a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 26 Sep 2024 10:32:59 -0700 Subject: [PATCH 34/43] Condition to avoid extra work Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/PartialRouter.java | 68 ++++++++++--------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index 01379912d..6b6e5c45d 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -357,41 +357,43 @@ protected void addNetConnectionToRoutingTargets(Net net) { partiallyPreservedNets.add(netWrapper); } - // Create all nodes used by this net and set its previous pointer so that: - // (a) the routing for each connection can be recovered by - // finishRouteConnection() - // (b) RouteNode.setChildren() will know to only allow this incoming - // arc on these nodes - for (PIP pip : net.getPIPs()) { - Node start = (pip.isReversed()) ? pip.getEndNode() : pip.getStartNode(); - Node end = (pip.isReversed()) ? pip.getStartNode() : pip.getEndNode(); - - // Do not include arcs that the router wouldn't explore - // e.g. those that leave the INT tile, since we project pins to their INT tile - if (routingGraph.isExcludedTile(end)) - continue; - - RouteNode rstart = routingGraph.getOrCreate(start); - RouteNode rend = routingGraph.getOrCreate(end); - assert(rend.getPrev() == null); - rend.setPrev(rstart); - } - - // Use the prev pointers to attempt to recover routing for all indirect connections - for (Connection connection : netWrapper.getConnections()) { - if (connection.isDirect()) { - continue; + if (net.hasPIPs()) { + // Create all nodes used by this net and set its previous pointer so that: + // (a) the routing for each connection can be recovered by + // finishRouteConnection() + // (b) RouteNode.setChildren() will know to only allow this incoming + // arc on these nodes + for (PIP pip : net.getPIPs()) { + Node start = (pip.isReversed()) ? pip.getEndNode() : pip.getStartNode(); + Node end = (pip.isReversed()) ? pip.getStartNode() : pip.getEndNode(); + + // Do not include arcs that the router wouldn't explore + // e.g. those that leave the INT tile, since we project pins to their INT tile + if (routingGraph.isExcludedTile(end)) + continue; + + RouteNode rstart = routingGraph.getOrCreate(start); + RouteNode rend = routingGraph.getOrCreate(end); + assert(rend.getPrev() == null); + rend.setPrev(rstart); } - // Even though this connection is not expected to have any routing yet, - // perform a rip up anyway in order to release any exclusive sinks - // ahead of finishRouteConnection() - assert(connection.getRnodes().isEmpty()); - connection.getSink().setRouted(false); - ripUp(connection); - - RouteNode sinkRnode = connection.getSinkRnode(); - finishRouteConnection(connection, sinkRnode); + // Use the prev pointers to attempt to recover routing for all indirect connections + for (Connection connection : netWrapper.getConnections()) { + if (connection.isDirect()) { + continue; + } + + // Even though this connection is not expected to have any routing yet, + // perform a rip up anyway in order to release any exclusive sinks + // ahead of finishRouteConnection() + assert(connection.getRnodes().isEmpty()); + connection.getSink().setRouted(false); + ripUp(connection); + + RouteNode sinkRnode = connection.getSinkRnode(); + finishRouteConnection(connection, sinkRnode); + } } } From 6caa610d9ea0d85ce1acd35694485801de29611a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 26 Sep 2024 10:34:48 -0700 Subject: [PATCH 35/43] Move getPreservedNet() call to after Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/PartialRouter.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index 6b6e5c45d..799df1c67 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -87,12 +87,16 @@ protected boolean isExcluded(RouteNode parent, Node child) { @Override public boolean isAccessible(RouteNode childRnode, Connection connection) { + if (super.isAccessible(childRnode, connection)) { + return true; + } Net preservedNet = getPreservedNet(childRnode); if (preservedNet == connection.getNetWrapper().getNet()) { // Always allow nodes preserved for this connection's net + super.isAccessible(childRnode, connection); return true; } - return super.isAccessible(childRnode, connection); + return false; } } From a83acd4947932f43f2d27f374453a9a7b4dccff1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 26 Sep 2024 10:35:50 -0700 Subject: [PATCH 36/43] Remove unused method Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RouteNode.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index 0353978a2..f272f0a15 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -562,13 +562,6 @@ public void setPrev(RouteNode prev) { this.prev = prev; } - /** - * Clears the parent RouteNode instance. - */ - public void clearPrev() { - this.prev = null; - } - /** * Gets the present congestion cost of a RouteNode Object. * @return The present congestion of a RouteNode Object. From 12348cebf029650af90ab589861c03ee8eed5356 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 26 Sep 2024 10:38:29 -0700 Subject: [PATCH 37/43] Try AtomicReferenceArray instead of ConcurrentHashMap Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/RouteNodeGraph.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index e84026377..f7022d2e5 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -35,9 +35,8 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReferenceArray; import com.xilinx.rapidwright.design.Design; import com.xilinx.rapidwright.design.Net; @@ -71,7 +70,7 @@ public class RouteNodeGraph { /** * A map of preserved nodes to their nets */ - private final Map preservedMap; + private final AtomicReferenceArray preservedMap; private final AtomicInteger preservedMapSize; /** @@ -121,15 +120,15 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map(); + preservedMap = new AtomicReferenceArray<>(device.getColumns() * device.getRows()); preservedMapSize = new AtomicInteger(); asyncPreserveOutstanding = new CountUpDownLatch(); targets = new ArrayList<>(); createRnodeTime = 0; - Device device = design.getDevice(); intYToSLRIndex = new int[device.getRows()]; Tile[][] intTiles = device.getTilesByRootName("INT"); for (int y = 0; y < intTiles.length; y++) { @@ -299,7 +298,14 @@ protected Net preserve(Node node, Net net) { private Net preserve(Tile tile, int wireIndex, Net net) { // Assumes that tile/wireIndex describes the base wire on the node // No need to synchronize access to 'nets' since collisions are not expected - Net[] nets = preservedMap.computeIfAbsent(tile, (t) -> new Net[t.getWireCount()]); + int tileId = tile.getUniqueAddress(); + Net[] nets = preservedMap.get(tileId); + if (nets == null) { + nets = new Net[tile.getWireCount()]; + if (!preservedMap.compareAndSet(tileId, null, nets)) { + nets = preservedMap.get(tileId); + } + } Net oldNet = nets[wireIndex]; // Do not clobber the old value if (oldNet == null) { @@ -379,7 +385,7 @@ public boolean unpreserve(Node node) { private boolean unpreserve(Tile tile, int wireIndex) { // Assumes that tile/wireIndex describes the base wire on its node - Net[] nets = preservedMap.get(tile); + Net[] nets = preservedMap.get(tile.getUniqueAddress()); if (nets == null || nets[wireIndex] == null) return false; nets[wireIndex] = null; @@ -389,7 +395,7 @@ private boolean unpreserve(Tile tile, int wireIndex) { public boolean isPreserved(Node node) { Tile tile = node.getTile(); int wireIndex = node.getWireIndex(); - Net[] nets = preservedMap.get(tile); + Net[] nets = preservedMap.get(tile.getUniqueAddress()); return nets != null && nets[wireIndex] != null; } @@ -455,7 +461,7 @@ public Net getPreservedNet(Node node) { private Net getPreservedNet(Tile tile, int wireIndex) { // Assumes that tile/wireIndex describes the base wire on its node - Net[] nets = preservedMap.get(tile); + Net[] nets = preservedMap.get(tile.getUniqueAddress()); return nets != null ? nets[wireIndex] : null; } @@ -561,6 +567,7 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { Tile sinkTile = connection.getSinkRnode().getTile(); if (childX != sinkTile.getTileXCoordinate()) { + // Not in same column return false; } From dcfe994b0afc6647a03aed99e9495b259da8e77b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 26 Sep 2024 10:40:12 -0700 Subject: [PATCH 38/43] Revert RapidWrightDCP submodule Signed-off-by: Eddie Hung --- test/RapidWrightDCP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/RapidWrightDCP b/test/RapidWrightDCP index ce3bdaadd..9c4416ef7 160000 --- a/test/RapidWrightDCP +++ b/test/RapidWrightDCP @@ -1 +1 @@ -Subproject commit ce3bdaadd45c616d58202d00485b6d3f073e32af +Subproject commit 9c4416ef76e590988dda9036e8101768f5574730 From cb57eb21c5a30ca33617aff3142c49dfebf1a3d9 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 26 Sep 2024 10:47:36 -0700 Subject: [PATCH 39/43] Revert "Try AtomicReferenceArray instead of ConcurrentHashMap" This reverts commit 12348cebf029650af90ab589861c03ee8eed5356. Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/RouteNodeGraph.java | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index f7022d2e5..e84026377 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -35,8 +35,9 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReferenceArray; +import java.util.concurrent.atomic.AtomicLong; import com.xilinx.rapidwright.design.Design; import com.xilinx.rapidwright.design.Net; @@ -70,7 +71,7 @@ public class RouteNodeGraph { /** * A map of preserved nodes to their nets */ - private final AtomicReferenceArray preservedMap; + private final Map preservedMap; private final AtomicInteger preservedMapSize; /** @@ -120,15 +121,15 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map(device.getColumns() * device.getRows()); + preservedMap = new ConcurrentHashMap<>(); preservedMapSize = new AtomicInteger(); asyncPreserveOutstanding = new CountUpDownLatch(); targets = new ArrayList<>(); createRnodeTime = 0; + Device device = design.getDevice(); intYToSLRIndex = new int[device.getRows()]; Tile[][] intTiles = device.getTilesByRootName("INT"); for (int y = 0; y < intTiles.length; y++) { @@ -298,14 +299,7 @@ protected Net preserve(Node node, Net net) { private Net preserve(Tile tile, int wireIndex, Net net) { // Assumes that tile/wireIndex describes the base wire on the node // No need to synchronize access to 'nets' since collisions are not expected - int tileId = tile.getUniqueAddress(); - Net[] nets = preservedMap.get(tileId); - if (nets == null) { - nets = new Net[tile.getWireCount()]; - if (!preservedMap.compareAndSet(tileId, null, nets)) { - nets = preservedMap.get(tileId); - } - } + Net[] nets = preservedMap.computeIfAbsent(tile, (t) -> new Net[t.getWireCount()]); Net oldNet = nets[wireIndex]; // Do not clobber the old value if (oldNet == null) { @@ -385,7 +379,7 @@ public boolean unpreserve(Node node) { private boolean unpreserve(Tile tile, int wireIndex) { // Assumes that tile/wireIndex describes the base wire on its node - Net[] nets = preservedMap.get(tile.getUniqueAddress()); + Net[] nets = preservedMap.get(tile); if (nets == null || nets[wireIndex] == null) return false; nets[wireIndex] = null; @@ -395,7 +389,7 @@ private boolean unpreserve(Tile tile, int wireIndex) { public boolean isPreserved(Node node) { Tile tile = node.getTile(); int wireIndex = node.getWireIndex(); - Net[] nets = preservedMap.get(tile.getUniqueAddress()); + Net[] nets = preservedMap.get(tile); return nets != null && nets[wireIndex] != null; } @@ -461,7 +455,7 @@ public Net getPreservedNet(Node node) { private Net getPreservedNet(Tile tile, int wireIndex) { // Assumes that tile/wireIndex describes the base wire on its node - Net[] nets = preservedMap.get(tile.getUniqueAddress()); + Net[] nets = preservedMap.get(tile); return nets != null ? nets[wireIndex] : null; } @@ -567,7 +561,6 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { Tile sinkTile = connection.getSinkRnode().getTile(); if (childX != sinkTile.getTileXCoordinate()) { - // Not in same column return false; } From f4ab6dc034c570d69609d606146762685277dba4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 26 Sep 2024 10:48:04 -0700 Subject: [PATCH 40/43] Revert [PartialRouter] isAccessible() to always allow preserved nets Signed-off-by: Eddie Hung As it seems to be an expensive look up in the hot path for little gain --- .../rapidwright/rwroute/PartialRouter.java | 26 ++----------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index 799df1c67..15687694d 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -84,20 +84,6 @@ protected boolean isExcluded(RouteNode parent, Node child) { } return super.isExcluded(parent, child); } - - @Override - public boolean isAccessible(RouteNode childRnode, Connection connection) { - if (super.isAccessible(childRnode, connection)) { - return true; - } - Net preservedNet = getPreservedNet(childRnode); - if (preservedNet == connection.getNetWrapper().getNet()) { - // Always allow nodes preserved for this connection's net - super.isAccessible(childRnode, connection); - return true; - } - return false; - } } protected static class RouteNodeGraphPartialTimingDriven extends RouteNodeGraphTimingDriven { @@ -121,16 +107,6 @@ protected boolean isExcluded(RouteNode parent, Node child) { } return super.isExcluded(parent, child); } - - @Override - public boolean isAccessible(RouteNode childRnode, Connection connection) { - Net preservedNet = getPreservedNet(childRnode); - if (preservedNet == connection.getNetWrapper().getNet()) { - // Always allow nodes preserved for this connection's net - return true; - } - return super.isAccessible(childRnode, connection); - } } public PartialRouter(Design design, RWRouteConfig config, Collection pinsToRoute, boolean softPreserve) { @@ -413,6 +389,8 @@ protected void finishRouteConnection(Connection connection, RouteNode rnode) { super.finishRouteConnection(connection, rnode); if (!connection.getSink().isRouted()) { + // TODO: Consider backtrack-ed result into alternate source + connection.resetRoute(); if (connection.getAltSinkRnodes().isEmpty()) { // Undo what ripUp() would have done for this connection which has a single exclusive sink From aed25d36fce3c250b53f943884c4c05336a2db83 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 26 Sep 2024 12:20:02 -0700 Subject: [PATCH 41/43] Add TODO Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/rwroute/PartialRouter.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index 15687694d..ea9601800 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -49,6 +49,7 @@ import com.xilinx.rapidwright.timing.TimingManager; import com.xilinx.rapidwright.timing.delayestimator.DelayEstimatorBase; import com.xilinx.rapidwright.timing.delayestimator.InterconnectInfo; +import com.xilinx.rapidwright.util.Pair; /** * A class extending {@link RWRoute} for partial routing. @@ -389,7 +390,19 @@ protected void finishRouteConnection(Connection connection, RouteNode rnode) { super.finishRouteConnection(connection, rnode); if (!connection.getSink().isRouted()) { - // TODO: Consider backtrack-ed result into alternate source + List rnodes = connection.getRnodes(); + SitePinInst altSource = connection.getNetWrapper().getNet().getAlternateSource(); + if (rnodes.size() > 1 && altSource != null) { + RouteNode sourceRnode = rnodes.get(rnodes.size() - 1); + assert(connection.getSourceRnode() != sourceRnode); + Pair altSourceAndRnode = connection.getOrCreateAlternateSource(routingGraph); + assert(altSourceAndRnode != null); + RouteNode altSourceRnode = altSourceAndRnode.getSecond(); + if (sourceRnode == altSourceRnode) { + // We must have backtracked to the alternate source + throw new RuntimeException("TODO"); + } + } connection.resetRoute(); if (connection.getAltSinkRnodes().isEmpty()) { From 807470307341e66f90625a2f13ceb7aa549d7d61 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 26 Sep 2024 12:37:19 -0700 Subject: [PATCH 42/43] Add PartialRouter.saveRouting() override Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/PartialRouter.java | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index ea9601800..43f6ff41e 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -385,25 +385,43 @@ protected void addNetConnectionToRoutingTargets(Net net) { } } + @Override + protected boolean saveRouting(Connection connection, RouteNode rnode) { + if (super.saveRouting(connection, rnode)) { + return true; + } + + List rnodes = connection.getRnodes(); + RouteNode sourceRnode = rnodes.get(rnodes.size() - 1); + assert(sourceRnode != connection.getSourceRnode()); // Would have returned already + if (sourceRnode == rnode) { + // No back-tracking beyond the first node + assert(rnodes.size() == 1); + return false; + } + assert(rnodes.size() > 1); + + // Check if alternate source exists (without creating one if it doesn't) + if (connection.getNetWrapper().getNet().getAlternateSource() != null) { + Pair altSourceAndRnode = connection.getOrCreateAlternateSource(routingGraph); + assert(altSourceAndRnode != null); + RouteNode altSourceRnode = altSourceAndRnode.getSecond(); + if (sourceRnode == altSourceRnode) { + // We backtracked to the alternate source + SitePinInst altSource = altSourceAndRnode.getFirst(); + connection.setSource(altSource); + connection.setSourceRnode(altSourceRnode); + return true; + } + } + return false; + } + @Override protected void finishRouteConnection(Connection connection, RouteNode rnode) { super.finishRouteConnection(connection, rnode); if (!connection.getSink().isRouted()) { - List rnodes = connection.getRnodes(); - SitePinInst altSource = connection.getNetWrapper().getNet().getAlternateSource(); - if (rnodes.size() > 1 && altSource != null) { - RouteNode sourceRnode = rnodes.get(rnodes.size() - 1); - assert(connection.getSourceRnode() != sourceRnode); - Pair altSourceAndRnode = connection.getOrCreateAlternateSource(routingGraph); - assert(altSourceAndRnode != null); - RouteNode altSourceRnode = altSourceAndRnode.getSecond(); - if (sourceRnode == altSourceRnode) { - // We must have backtracked to the alternate source - throw new RuntimeException("TODO"); - } - } - connection.resetRoute(); if (connection.getAltSinkRnodes().isEmpty()) { // Undo what ripUp() would have done for this connection which has a single exclusive sink From d006b61d2715ce94435acdc2d69cee444988d029 Mon Sep 17 00:00:00 2001 From: eddieh-xlnx Date: Thu, 26 Sep 2024 18:36:49 -0700 Subject: [PATCH 43/43] Apply suggestions from code review Signed-off-by: eddieh-xlnx --- src/com/xilinx/rapidwright/rwroute/PartialRouter.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index 43f6ff41e..2b2c2f025 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -241,7 +241,10 @@ protected void determineRoutingTargets() { super.determineRoutingTargets(); // With all routingGraph.preserveAsync() calls having completed, - // now check sink routability + // now check that no sinks are preserved by another net + // (e.g. a pin was moved from one net to the other, but + // its old routing was not ripped up and got preserved) + // if so, unpreserve that blocking net Set unpreserveNets = new HashSet<>(); for (Connection connection : indirectConnections) { Net net = connection.getNetWrapper().getNet();