From 8d7aaf7928370b2108e2e4145f49b355bafc7bff Mon Sep 17 00:00:00 2001 From: Wenhao Lin Date: Wed, 13 Nov 2024 09:23:39 -0700 Subject: [PATCH 01/28] Support clock routing on Versal devices Signed-off-by: Wenhao Lin --- .../xilinx/rapidwright/router/RouteNode.java | 14 + .../router/VersalClockRouting.java | 703 ++++++++++++++++++ .../rwroute/GlobalSignalRouting.java | 230 ++++-- 3 files changed, 889 insertions(+), 58 deletions(-) create mode 100644 src/com/xilinx/rapidwright/router/VersalClockRouting.java diff --git a/src/com/xilinx/rapidwright/router/RouteNode.java b/src/com/xilinx/rapidwright/router/RouteNode.java index 061e58068..7fd119b0c 100644 --- a/src/com/xilinx/rapidwright/router/RouteNode.java +++ b/src/com/xilinx/rapidwright/router/RouteNode.java @@ -35,6 +35,7 @@ import com.xilinx.rapidwright.device.PIP; import com.xilinx.rapidwright.device.Tile; import com.xilinx.rapidwright.device.Wire; +import com.xilinx.rapidwright.rwroute.RouterHelper; /** @@ -381,6 +382,19 @@ public ArrayList getPIPsBackToSource() { return pips; } + public ArrayList getPIPsBackToSourceByNodes() { + ArrayList pips = new ArrayList<>(); + RouteNode curr = this; + while (curr.parent != null) { + PIP pip = RouterHelper.findPIPbetweenNodes(Node.getNode(curr.parent), Node.getNode(curr)); + if (pip != null) { + pips.add(pip); + } + curr = curr.parent; + } + return pips; + } + public Wire[] getWiresInNode() { return Node.getWiresInNode(getTile(),getWire()); } diff --git a/src/com/xilinx/rapidwright/router/VersalClockRouting.java b/src/com/xilinx/rapidwright/router/VersalClockRouting.java new file mode 100644 index 000000000..6753041f8 --- /dev/null +++ b/src/com/xilinx/rapidwright/router/VersalClockRouting.java @@ -0,0 +1,703 @@ +package com.xilinx.rapidwright.router; + +import com.xilinx.rapidwright.design.Design; +import com.xilinx.rapidwright.design.DesignTools; +import com.xilinx.rapidwright.design.Net; +import com.xilinx.rapidwright.design.SitePinInst; +import com.xilinx.rapidwright.device.ClockRegion; +import com.xilinx.rapidwright.device.IntentCode; +import com.xilinx.rapidwright.device.Node; +import com.xilinx.rapidwright.device.PIP; + +import com.xilinx.rapidwright.device.Tile; +import com.xilinx.rapidwright.device.Wire; +import com.xilinx.rapidwright.rwroute.NodeStatus; + +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Queue; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Predicate; + +/** + * A collection of utility methods for routing clocks on + * the Versal architecture. + * + * Created on: Nov 1, 2024 + */ +public class VersalClockRouting { + + public static RouteNode routeBUFGToNearestRoutingTrack(Net clk) { + Queue q = new LinkedList<>(); + q.add(new RouteNode(clk.getSource())); + int watchDog = 300; + while (!q.isEmpty()) { + RouteNode curr = q.poll(); + Node currNode = Node.getNode(curr); + IntentCode c = currNode.getIntentCode(); + if (c == IntentCode.NODE_GLOBAL_HROUTE_HSR) { + clk.getPIPs().addAll(curr.getPIPsBackToSourceByNodes()); + return curr; + } + for (Node downhill: currNode.getAllDownhillNodes()) { + q.add(new RouteNode(downhill.getTile(), downhill.getWireIndex(), curr, curr.getLevel()+1)); + } + if (watchDog-- == 0) break; + } + return null; + } + + /** + * Routes a clock from a routing track to a transition point where the clock. + * fans out and transitions from clock routing tracks to clock distribution. + * @param clk The current clock net to contribute routing. + * @param startingRouteNode The intermediate start point of the clock route. + * @param clockRegion The center clock region or the clock region that is one row above or below the center. + * @param adjusted A flag to guard the default functionality when routing to centroid clock region. + * @param findCentroidHroute The flag to indicate the returned RouteNode should be HROUTE in the center or VROUTE going up or down. + */ + public static RouteNode routeToCentroid(Net clk, RouteNode startingRouteNode, ClockRegion clockRegion, boolean adjusted, boolean findCentroidHroute) { + Queue q = RouteNode.createPriorityQueue(); + startingRouteNode.setParent(null); + q.add(startingRouteNode); + Set allowedIntentCodes = EnumSet.of( + IntentCode.NODE_GLOBAL_BUFG, + IntentCode.NODE_GLOBAL_GCLK, + IntentCode.NODE_GLOBAL_HROUTE_HSR, + IntentCode.NODE_GLOBAL_VROUTE, + IntentCode.NODE_GLOBAL_VDISTR_LVL2 + ); + // Tile approxTarget = clockRegion.getApproximateCenter(); + int watchDog = 10000000; + RouteNode centroidHRouteNode = null; + Set visited = new HashSet<>(); + + // In Vivado solutions, we can always find the pattern: + // ... -> NODE_GLOBAL_GCLK -> NODE_GLOBAL_VROUTE -> NODE_GLOBAL_VDISTR_LVL2 -> ... + // and this is how we locate the VROUTE node + + while (!q.isEmpty()) { + RouteNode curr = q.poll(); + Node currNode = Node.getNode(curr); + RouteNode parent = curr.getParent(); + for (Node downhill : currNode.getAllDownhillNodes()) { + if (parent != null) { + Node parentNode = Node.getNode(parent); + if (parentNode.getIntentCode() == IntentCode.NODE_GLOBAL_VROUTE && + currNode.getIntentCode() == IntentCode.NODE_GLOBAL_HROUTE_HSR) { + // Disallow ability to go from VROUTE back to HROUTE + continue; + } + if (downhill.getIntentCode() == IntentCode.NODE_GLOBAL_VDISTR_LVL2 && + currNode.getIntentCode() == IntentCode.NODE_GLOBAL_GCLK && + parentNode.getIntentCode() == IntentCode.NODE_GLOBAL_VROUTE && + clockRegion.equals(currNode.getTile().getClockRegion()) && + clockRegion.equals(parentNode.getTile().getClockRegion()) && + parentNode.getWireName().contains("BOT")) { + if (adjusted) { + if (findCentroidHroute) { + centroidHRouteNode = curr.getParent(); + while (centroidHRouteNode.getIntentCode() != IntentCode.NODE_GLOBAL_HROUTE_HSR) { + centroidHRouteNode = centroidHRouteNode.getParent(); + } + clk.getPIPs().addAll(centroidHRouteNode.getPIPsBackToSourceByNodes()); + return centroidHRouteNode; + } + // assign PIPs based on which RouteNode returned, instead of curr + clk.getPIPs().addAll(parent.getPIPsBackToSourceByNodes()); + return parent; + } else { + clk.getPIPs().addAll(curr.getPIPsBackToSourceByNodes()); + return curr; + } + } + } + + // Only using routing lines to get to centroid + if (!allowedIntentCodes.contains(downhill.getIntentCode())) continue; + if (adjusted && !findCentroidHroute && downhill.getIntentCode() == IntentCode.NODE_GLOBAL_HROUTE_HSR) { + continue; + } + if (visited.contains(downhill)) continue; + RouteNode rn = new RouteNode(downhill.getTile(), downhill.getWireIndex(), curr, curr.getLevel()+1); + + // The clockRegion.getApproximateCenter() may return an INVALID_* tile with huge coordinates. + // Here we use the manhatten distance to the target clock region as the cost. + ClockRegion rnClockRegion = rn.getTile().getClockRegion(); + int cost = Math.abs(rnClockRegion.getColumn() - clockRegion.getColumn()) + Math.abs(rnClockRegion.getRow() - clockRegion.getRow()); + rn.setCost(cost); + q.add(rn); + visited.add(downhill); + } + if (watchDog-- == 0) { + throw new RuntimeException("ERROR: Could not route from " + startingRouteNode + " to clock region " + clockRegion); + } + } + + return null; + } + + /** + * Routes the vertical distribution path and generates a map between each target clock region and the vertical distribution line to + * start from. + * @param clk The clock net. + * @param centroidDistNode Starting point vertical distribution line + * @param clockRegions The target clock regions. + * @return A map of target clock regions and their respective vertical distribution lines + */ + public static Map routeCentroidToVerticalDistributionLines(Net clk, + RouteNode centroidDistNode, + Collection clockRegions, + Function getNodeStatus) { + Map crToVdist = new HashMap<>(); + centroidDistNode.setParent(null); + Queue q = RouteNode.createPriorityQueue(); + HashSet visited = new HashSet<>(); + Set allPIPs = new HashSet<>(); + Set startingPoints = new HashSet<>(); + startingPoints.add(centroidDistNode); + assert(centroidDistNode.getParent() == null); + nextClockRegion: for (ClockRegion cr : clockRegions) { + q.clear(); + visited.clear(); + q.addAll(startingPoints); + Tile crTarget = cr.getApproximateCenter(); + while (!q.isEmpty()) { + RouteNode curr = q.poll(); + visited.add(curr); + IntentCode c = curr.getIntentCode(); + ClockRegion currCR = curr.getTile().getClockRegion(); + if (currCR != null && cr.equals(currCR) && c == IntentCode.NODE_GLOBAL_VDISTR) { + // Only consider base wires + Node currNode = Node.getNode(curr); + if (getNodeStatus.apply(currNode) == NodeStatus.INUSE) { + startingPoints.add(curr); + } else { + List pips = curr.getPIPsBackToSource(); + allPIPs.addAll(pips); + for (PIP p : pips) { + startingPoints.add(p.getStartRouteNode()); + startingPoints.add(p.getEndRouteNode()); + } + } + RouteNode currBase = new RouteNode(currNode); + currBase.setParent(null); + crToVdist.put(cr, currBase); + continue nextClockRegion; + } + for (Wire w : curr.getWireConnections()) { + if (w.getIntentCode() != IntentCode.NODE_GLOBAL_VDISTR) continue; + Node n = Node.getNode(w); + RouteNode rn = new RouteNode(n.getTile(), n.getWireIndex(), curr, curr.getLevel()+1); + if (visited.contains(rn)) continue; + rn.setCost(w.getTile().getManhattanDistance(crTarget)); + q.add(rn); + } + } + throw new RuntimeException("ERROR: Couldn't route to distribution line in clock region " + cr); + } + clk.getPIPs().addAll(allPIPs); + centroidDistNode.setParent(null); + return crToVdist; + } + + public static Map routeVrouteToVerticalDistributionLines(Net clk, + RouteNode vroute, + Collection clockRegions, + Function getNodeStatus) { + Map crToVdist = new HashMap<>(); + vroute.setParent(null); + Queue q = RouteNode.createPriorityQueue(); + HashSet visited = new HashSet<>(); + Set allPIPs = new HashSet<>(); + Set startingPoints = new HashSet<>(); + startingPoints.add(vroute); + assert(vroute.getParent() == null); + // Pattern: NODE_GLOBAL_VROUTE -> ... -> NODE_GLOBAL_VDISTR_LVL2 -> ... -> NODE_GLOBAL_VDISTR_LVL1 -> ... -> NODE_GLOBAL_VDISTR + Set allowedIntentCodes = EnumSet.of( + // IntentCode.NODE_GLOBAL_VROUTE, + IntentCode.NODE_GLOBAL_VDISTR, + IntentCode.NODE_GLOBAL_VDISTR_LVL1, + IntentCode.NODE_GLOBAL_VDISTR_LVL2, + IntentCode.NODE_GLOBAL_GCLK + ); + nextClockRegion: for (ClockRegion cr : clockRegions) { + q.clear(); + visited.clear(); + q.addAll(startingPoints); + Tile crTarget = cr.getApproximateCenter(); + while (!q.isEmpty()) { + RouteNode curr = q.poll(); + // visited.add(curr); + Node currNode = Node.getNode(curr); + IntentCode c = currNode.getIntentCode(); + ClockRegion currCR = currNode.getTile().getClockRegion(); + if (currCR != null && cr.getRow() == currCR.getRow() && c == IntentCode.NODE_GLOBAL_VDISTR) { + // Only consider base wires + if (getNodeStatus.apply(currNode) == NodeStatus.INUSE) { + startingPoints.add(curr); + } else { + // List pips = curr.getPIPsBackToSource(); + List pips = curr.getPIPsBackToSourceByNodes(); + allPIPs.addAll(pips); + for (PIP p : pips) { + startingPoints.add(p.getStartRouteNode()); + startingPoints.add(p.getEndRouteNode()); + } + } + RouteNode currBase = new RouteNode(currNode); + currBase.setParent(null); + crToVdist.put(cr, currBase); + continue nextClockRegion; + } + + for (Node downhill : currNode.getAllDownhillNodes()) { + if (!allowedIntentCodes.contains(downhill.getIntentCode())) { + continue; + } + if (visited.contains(downhill)) continue; + RouteNode rn = new RouteNode(downhill.getTile(), downhill.getWireIndex(), curr, curr.getLevel()+1); + rn.setCost(downhill.getTile().getManhattanDistance(crTarget)); + q.add(rn); + visited.add(downhill); + } + } + throw new RuntimeException("ERROR: Couldn't route to distribution line in clock region " + cr); + } + clk.getPIPs().addAll(allPIPs); + vroute.setParent(null); + return crToVdist; + } + + /** + * Routes from a vertical distribution centroid to destination horizontal distribution lines + * in the clock regions provided. + * @param clk The current clock net + * @param vertDistLines A map of target clock regions and their respective vertical distribution lines + * @param clockRegions target clock regions + * @return The List of nodes from the centroid to the horizontal distribution line. + */ + public static Map routeVerticalToHorizontalDistributionLines(Net clk, + Map vertDistLines, + Collection clockRegions, + Function getNodeStatus) { + // List distLines = new ArrayList<>(); + Map distLines = new HashMap<>(); + Queue q = new LinkedList<>(); + Set allPIPs = new HashSet<>(); + Set visited = new HashSet<>(); + Set allowedIntentCodes = EnumSet.of( + IntentCode.NODE_GLOBAL_HDISTR, + IntentCode.NODE_GLOBAL_VDISTR, + IntentCode.NODE_PINFEED, + IntentCode.NODE_GLOBAL_HDISTR_LOCAL, + IntentCode.NODE_GLOBAL_GCLK + ); + // nextClockRegion: for (Entry e : crMap.entrySet()) { + nextClockRegion: for (ClockRegion targetCR : clockRegions) { + q.clear(); + RouteNode vertDistLine = vertDistLines.get(targetCR); + // assert(vertDistLine.getParent() == null); + vertDistLine.setParent(null); + q.add(vertDistLine); + visited.clear(); + visited.add(Node.getNode(vertDistLine)); + + // ClockRegion targetCR = e.getKey(); + while (!q.isEmpty()) { + RouteNode curr = q.poll(); + IntentCode c = curr.getIntentCode(); + Node currNode = Node.getNode(curr); + RouteNode parent = curr.getParent(); + if (targetCR.equals(curr.getTile().getClockRegion()) && + c == IntentCode.NODE_GLOBAL_GCLK && + parent.getIntentCode() == IntentCode.NODE_GLOBAL_HDISTR_LOCAL) { + // List pips = parent.getPIPsBackToSource(); + List pips = parent.getPIPsBackToSourceByNodes(); + for (PIP pip : pips) { + allPIPs.add(pip); + NodeStatus status = getNodeStatus.apply(pip.getStartNode()); + if (status == NodeStatus.INUSE) { + break; + } + assert(status == NodeStatus.AVAILABLE); + } + + parent.setParent(null); + distLines.put(targetCR, parent); + continue nextClockRegion; + } + + for (Node downhill: currNode.getAllDownhillNodes()) { + if (!allowedIntentCodes.contains(downhill.getIntentCode())) continue; + if (visited.contains(downhill)) continue; + visited.add(downhill); + q.add(new RouteNode(downhill.getTile(), downhill.getWireIndex(), curr, curr.getLevel()+1)); + } + } + throw new RuntimeException("ERROR: Couldn't route to distribution line in clock region " + targetCR); + } + clk.getPIPs().addAll(allPIPs); + return distLines; + } + + /** + * Routes from distribution lines to the leaf clock buffers (LCBs) + * @param clk The current clock net + * @param distLines A map of target clock regions and their respective horizontal distribution lines + * @param lcbTargets The target LCB nodes to route the clock + */ + public static void routeDistributionToLCBs(Net clk, Map distLines, Set lcbTargets) { + Map> startingPoints = getStartingPoints(distLines); + routeToLCBs(clk, startingPoints, lcbTargets); + } + + public static Map> getStartingPoints(Map distLines) { + Map> startingPoints = new HashMap<>(); + for (ClockRegion cr : distLines.keySet()) { + startingPoints.computeIfAbsent(cr, k -> new HashSet<>()).add(distLines.get(cr)); + } + return startingPoints; + } + + public static void routeToLCBs(Net clk, Map> startingPoints, Set lcbTargets) { + Queue q = RouteNode.createPriorityQueue(); + Set allPIPs = new HashSet<>(); + HashSet visited = new HashSet<>(); + Set allowedIntentCodes = EnumSet.of( + IntentCode.NODE_PINFEED, + IntentCode.NODE_GLOBAL_LEAF, + IntentCode.NODE_GLOBAL_GCLK + ); + + nextLCB: for (RouteNode lcb : lcbTargets) { + q.clear(); + visited.clear(); + ClockRegion currCR = lcb.getTile().getClockRegion(); + Set starts = startingPoints.getOrDefault(currCR, Collections.emptySet()); + for (RouteNode rn : starts) { + assert(rn.getParent() == null); + } + q.addAll(starts); + while (!q.isEmpty()) { + RouteNode curr = q.poll(); + visited.add(curr); + if (lcb.equals(curr)) { + List pips = curr.getPIPsBackToSource(); + allPIPs.addAll(pips); + + Set s = startingPoints.get(currCR); + for (PIP p : pips) { + s.add(new RouteNode(p.getTile(),p.getStartWireIndex())); + s.add(new RouteNode(p.getTile(),p.getEndWireIndex())); + } + continue nextLCB; + } + Node currNode = Node.getNode(curr); + for (Node downhill : currNode.getAllDownhillNodes()) { + // Stay in this clock region + if (!currCR.equals(downhill.getTile().getClockRegion())) continue; + if (!allowedIntentCodes.contains(downhill.getIntentCode())) continue; + RouteNode rn = new RouteNode(downhill.getTile(), downhill.getWireIndex(), curr, curr.getLevel()+1); + if (visited.contains(rn)) continue; + if (rn.getWireName().endsWith("_I_CASC_PIN")) continue; + if (rn.getWireName().endsWith("_CLR_B_PIN")) continue; + rn.setCost(rn.getManhattanDistance(lcb)); + q.add(rn); + } + } + throw new RuntimeException("ERROR: Couldn't route to distribution line in clock region " + lcb); + } + clk.getPIPs().addAll(allPIPs); + } + + /** + * @param clk + * @param lcbMappings + * @param getNodeStatus Lambda for indicating the status of a Node: available, in-use (preserved + * for same net as we're routing), or unavailable (preserved for other net). + */ + public static void routeLCBsToSinks(Net clk, Map> lcbMappings, + Function getNodeStatus) { + Set used = new HashSet<>(); + Set visited = new HashSet<>(); + Queue q = new LinkedList<>(); + + Predicate isNodeUnavailable = (node) -> getNodeStatus.apply(node) == NodeStatus.UNAVAILABLE; + Set allowedIntentCodes = EnumSet.of( + IntentCode.NODE_CLE_CNODE, + IntentCode.NODE_INTF_CNODE, + IntentCode.NODE_CLE_CTRL, + IntentCode.NODE_INTF_CTRL, + IntentCode.NODE_IRI, + IntentCode.NODE_INODE, + IntentCode.NODE_PINBOUNCE, + IntentCode.NODE_CLE_BNODE, + IntentCode.NODE_IMUX, + IntentCode.NODE_PINFEED + ); + + RouteThruHelper routeThruHelper = new RouteThruHelper(clk.getDesign().getDevice()); + + for (Entry> e : lcbMappings.entrySet()) { + Set currPIPs = new HashSet<>(); + RouteNode lcb = e.getKey(); + assert(lcb.getParent() == null); + + nextPin: for (SitePinInst sink : e.getValue()) { + RouteNode target = sink.getRouteNode(); + Node targetNode = Node.getNode(target); + q.clear(); + q.add(lcb); + + while (!q.isEmpty()) { + RouteNode curr = q.poll(); + Node currNode = Node.getNode(curr); + if (targetNode.equals(currNode)) { + boolean inuse = false; + for (PIP pip : curr.getPIPsBackToSourceByNodes()) { + if (inuse) { + assert(getNodeStatus.apply(pip.getStartNode()) == NodeStatus.INUSE); + continue; + } + currPIPs.add(pip); + NodeStatus status = getNodeStatus.apply(pip.getStartNode()); + if (status == NodeStatus.INUSE) { + // break; + inuse = true; + continue; + } + assert(status == NodeStatus.AVAILABLE); + } + sink.setRouted(true); + visited.clear(); + continue nextPin; + } + + for (Node downhill : currNode.getAllDownhillNodes()) { + if (!allowedIntentCodes.contains(downhill.getIntentCode())) continue; + if (!visited.add(downhill)) continue; + if (used.contains(downhill)) continue; + // have to allow those routethru-s NODE_IRI -> * + if (routeThruHelper.isRouteThru(currNode, downhill) && downhill.getIntentCode() != IntentCode.NODE_IRI) continue; + if (isNodeUnavailable.test(downhill)) continue; + q.add(new RouteNode(downhill.getTile(), downhill.getWireIndex(), curr, curr.getLevel()+1)); + } + } + throw new RuntimeException("ERROR: Couldn't route LCB " + e.getKey() + " to Pin " + sink); + } + + List clkPIPs = clk.getPIPs(); + for (PIP p : currPIPs) { + used.add(p.getStartNode()); + used.add(p.getEndNode()); + clkPIPs.add(p); + } + } + } + + /** + * Routes from a GLOBAL_VERTICAL_ROUTE to horizontal distribution lines. + * @param clk The clock net to be routed. + * @param vroute The node to start the route. + * @param clockRegions Target clock regions. + * @param down To indicate if it is routing to the group of top clock regions. + * @return A list of RouteNodes indicating the reached horizontal distribution lines. + */ + public static Map routeToHorizontalDistributionLines(Net clk, + RouteNode vroute, + Collection clockRegions, + boolean down, + Function getNodeStatus) { + // First step: map each clock region to a VDISTR node. + // The clock region of this VDISTR node should be in the same column of the centroid (X) and the same row of the target clock region (Y). + Map vertDistLines = routeVrouteToVerticalDistributionLines(clk, vroute, clockRegions, getNodeStatus); + + // Second step: start from the VDISTR node and try to find a HDISTR node in the target clock region. + Map horiDistLines = routeVerticalToHorizontalDistributionLines(clk, vertDistLines, clockRegions, getNodeStatus); + return horiDistLines; + } + + /** + * Routes a partially routed clock. + * It will examine the clock net for SitePinInsts and assumes any present are already routed. It + * then invokes {@link DesignTools#createMissingSitePinInsts(Design, Net)} to discover those not + * yet routed. + * @param design The current design + * @param clkNet The partially routed clock net to make fully routed + * @param getNodeStatus Lambda for indicating the status of a Node: available, in-use (preserved + * for same net as we're routing), or unavailable (preserved for other net). + */ + public static void incrementalClockRouter(Design design, + Net clkNet, + Function getNodeStatus) { + // TODO: hasn't supported incrementalClockRouter on Versal devices yet. + throw new RuntimeException("Hasn't supported incrementalClockRouter on Versal devices yet."); + + // // Assume all existing site pins are already routed + // Set existingPins = new HashSet<>(clkNet.getSinkPins()); + + // // Find any missing site pins, to be used as target, routable sinks + // DesignTools.createMissingSitePinInsts(design, clkNet); + + // List createdPins = new ArrayList<>(clkNet.getSinkPins()); + // createdPins.removeAll(existingPins); + + // if (createdPins.isEmpty()) + // return; + + // incrementalClockRouter(clkNet, createdPins, getNodeStatus); + } + + /** + * Routes a list of unrouted pins from a partially routed clock. + * @param clkNet The partially routed clock net to make fully routed + * @param clkPins A list of unrouted pins on the clock net to route + * @param getNodeStatus Lambda for indicating the status of a Node: available, in-use (preserved + * for same net as we're routing), or unavailable (preserved for other net). + */ + public static void incrementalClockRouter(Net clkNet, + List clkPins, + Function getNodeStatus) { + // TODO: hasn't supported incrementalClockRouter on Versal devices yet. + throw new RuntimeException("Hasn't supported incrementalClockRouter on Versal devices yet."); + + // // Find all horizontal distribution lines to be used as starting points and create a map + // // lookup by clock region + // Map> startingPoints = new HashMap<>(); + // Set vroutesUp = new HashSet<>(); + // Set vroutesDown = new HashSet<>(); + // int centroidY = -1; + // for (PIP p : clkNet.getPIPs()) { + // Node startNode = p.getStartNode(); + // Node endNode = p.getEndNode(); + // for (Node node : new Node[] {startNode, endNode}) { + // if (node == null) continue; + // IntentCode ic = node.getIntentCode(); + // if (ic == IntentCode.NODE_GLOBAL_HDISTR) { + // for (Wire w : node.getAllWiresInNode()) { + // RouteNode rn = new RouteNode(w.getTile(), w.getWireIndex()); + // ClockRegion cr = w.getTile().getClockRegion(); + // if (cr != null) { + // assert(rn.getParent() == null); + // startingPoints.computeIfAbsent(cr, n -> new HashSet<>()) + // .add(rn); + // } + // } + // } else if (node == startNode && endNode.getIntentCode() == IntentCode.NODE_GLOBAL_VDISTR) { + // if (ic == IntentCode.NODE_GLOBAL_VROUTE || ic == IntentCode.NODE_GLOBAL_HROUTE) { + // // Centroid lays where {HROUTE, VROUTE} -> VDISTR + // assert(centroidY == -1); + // centroidY = p.getTile().getTileYCoordinate(); + // } else { + // Tile startTile = startNode.getTile(); + // Tile endTile = endNode.getTile(); + // if (endTile == startTile) { + // for (Wire w : endNode.getAllWiresInNode()) { + // if (w.getTile() != endTile) { + // endTile = w.getTile(); + // break; + // } + // } + // } + + // int startTileY = startTile.getTileYCoordinate(); + // int endTileY = endTile.getTileYCoordinate(); + // if (endTileY > startTileY) { + // vroutesUp.add(endNode); + // } else if (endTileY < startTileY) { + // vroutesDown.add(endNode); + // } + // } + // } + // } + // } + // assert(centroidY != -1); + + // Node currNode = null; + // int currDelta = Integer.MAX_VALUE; + // for (Node node : vroutesUp) { + // int delta = node.getTile().getTileYCoordinate() - centroidY; + // assert(delta >= 0); + // if (delta < currDelta) { + // currDelta = delta; + // currNode = node; + // } + // } + // RouteNode vrouteUp = currNode != null ? new RouteNode(currNode.getTile(), currNode.getWireIndex()) : null; + + // currNode = null; + // currDelta = Integer.MAX_VALUE; + // for (Node node : vroutesDown) { + // int delta = centroidY - node.getTile().getTileYCoordinate(); + // assert(delta >= 0); + // if (delta < currDelta) { + // currDelta = delta; + // currNode = node; + // } + // } + // RouteNode vrouteDown = currNode != null ? new RouteNode(currNode.getTile(), currNode.getWireIndex()) : null; + + // // Find the target leaf clock buffers (LCBs), route from horizontal dist lines to those + // Map> lcbMappings = GlobalSignalRouting.getLCBPinMappings(clkPins, getNodeStatus); + + // final int finalCentroidY = centroidY; + // Set newUpClockRegions = new HashSet<>(); + // Set newDownClockRegions = new HashSet<>(); + // for (Map.Entry> e : lcbMappings.entrySet()) { + // RouteNode lcb = e.getKey(); + // ClockRegion currCR = lcb.getTile().getClockRegion(); + // startingPoints.computeIfAbsent(currCR, n -> { + // if (currCR.getUpperLeft().getTileYCoordinate() > finalCentroidY) { + // newUpClockRegions.add(currCR); + // } else { + // newDownClockRegions.add(currCR); + // } + // return new HashSet<>(); + // }); + // } + // if (!newUpClockRegions.isEmpty()) { + // List upLines = UltraScaleClockRouting.routeToHorizontalDistributionLines(clkNet, + // vrouteUp, + // newUpClockRegions, + // false, + // getNodeStatus); + // if (upLines != null) { + // for (RouteNode rnode : upLines) { + // rnode.setParent(null); + // startingPoints.get(rnode.getTile().getClockRegion()).add(rnode); + // } + // } + // } + // if (!newDownClockRegions.isEmpty()) { + // List downLines = UltraScaleClockRouting.routeToHorizontalDistributionLines(clkNet, + // vrouteDown, + // newDownClockRegions, + // true, + // getNodeStatus); + // if (downLines != null) { + // for (RouteNode rnode : downLines) { + // rnode.setParent(null); + // startingPoints.get(rnode.getTile().getClockRegion()).add(rnode); + // } + // } + // } + + // UltraScaleClockRouting.routeToLCBs(clkNet, startingPoints, lcbMappings.keySet()); + + // // Last mile routing from LCBs to SLICEs + // UltraScaleClockRouting.routeLCBsToSinks(clkNet, lcbMappings, getNodeStatus); + + // // Remove duplicates + // Set uniquePIPs = new HashSet<>(clkNet.getPIPs()); + // clkNet.setPIPs(uniquePIPs); + } +} diff --git a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java index e2bdd88a9..d4b4d3227 100644 --- a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java +++ b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java @@ -24,6 +24,17 @@ package com.xilinx.rapidwright.rwroute; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Queue; +import java.util.Set; +import java.util.function.Function; + import com.xilinx.rapidwright.design.Design; import com.xilinx.rapidwright.design.Net; import com.xilinx.rapidwright.design.NetType; @@ -38,6 +49,7 @@ import com.xilinx.rapidwright.device.Series; import com.xilinx.rapidwright.device.Site; import com.xilinx.rapidwright.device.SitePin; +import com.xilinx.rapidwright.device.SiteTypeEnum; import com.xilinx.rapidwright.device.Tile; import com.xilinx.rapidwright.device.TileTypeEnum; import com.xilinx.rapidwright.device.Wire; @@ -46,20 +58,12 @@ import com.xilinx.rapidwright.router.RouteNode; import com.xilinx.rapidwright.router.RouteThruHelper; import com.xilinx.rapidwright.router.UltraScaleClockRouting; +import com.xilinx.rapidwright.router.VersalClockRouting; import com.xilinx.rapidwright.util.Utils; import java.util.ArrayDeque; -import java.util.ArrayList; import java.util.Comparator; import java.util.EnumSet; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Queue; -import java.util.Set; -import java.util.function.Function; /** * A collection of methods for routing global signals, i.e. GLOBAL_CLOCK, VCC and GND. @@ -190,42 +194,130 @@ private static Map> getListOfNodesFromRoutes(Device device, M * for same net as we're routing), or unavailable (preserved for other net). */ public static void symmetricClkRouting(Net clk, Device device, Function getNodeStatus) { - List clockRegions = getClockRegionsOfNet(clk); - ClockRegion centroid = findCentroid(clk, device); - - List upClockRegions = new ArrayList<>(); - List downClockRegions = new ArrayList<>(); - // divides clock regions into two groups - divideClockRegions(clockRegions, centroid, upClockRegions, downClockRegions); - - RouteNode clkRoutingLine = UltraScaleClockRouting.routeBUFGToNearestRoutingTrack(clk);// first HROUTE - RouteNode centroidHRouteNode = UltraScaleClockRouting.routeToCentroid(clk, clkRoutingLine, centroid, true, true); - - RouteNode vrouteUp = null; - RouteNode vrouteDown; - // Two VROUTEs going up and down - ClockRegion aboveCentroid = upClockRegions.isEmpty() ? null : centroid.getNeighborClockRegion(1, 0); - if (aboveCentroid != null) { - vrouteUp = UltraScaleClockRouting.routeToCentroid(clk, centroidHRouteNode, aboveCentroid, true, false); - } - vrouteDown = UltraScaleClockRouting.routeToCentroid(clk, centroidHRouteNode, centroid.getNeighborClockRegion(0, 0), true, false); + if (device.getSeries() != Series.Versal) { + boolean debug = true; + List clockRegions = getClockRegionsOfNet(clk); + + ClockRegion centroid = findCentroid(clk, device); + if (debug) { + System.out.println("centroid CR: " + centroid); + } + + List upClockRegions = new ArrayList<>(); + List downClockRegions = new ArrayList<>(); + // divides clock regions into two groups + divideClockRegions(clockRegions, centroid, upClockRegions, downClockRegions); + + RouteNode clkRoutingLine = UltraScaleClockRouting.routeBUFGToNearestRoutingTrack(clk);// first HROUTE + + if (debug) { + System.out.println("clkRoutingLine: " + clkRoutingLine); + } + + RouteNode centroidHRouteNode = UltraScaleClockRouting.routeToCentroid(clk, clkRoutingLine, centroid, true, true); + + if (debug) { + System.out.println("centroidHRouteNode: " + centroidHRouteNode); + } + + RouteNode vrouteUp = null; + RouteNode vrouteDown; + // Two VROUTEs going up and down + ClockRegion aboveCentroid = upClockRegions.isEmpty() ? null : centroid.getNeighborClockRegion(1, 0); + if (aboveCentroid != null) { + vrouteUp = UltraScaleClockRouting.routeToCentroid(clk, centroidHRouteNode, aboveCentroid, true, false); + if (debug) { + System.out.println("vrouteUp: " + vrouteUp); + } + } + vrouteDown = UltraScaleClockRouting.routeToCentroid(clk, centroidHRouteNode, centroid.getNeighborClockRegion(0, 0), true, false); + + if (debug) { + System.out.println("vrouteDown: " + vrouteDown); + } + + List upDownDistLines = new ArrayList<>(); + if (aboveCentroid != null) { + List upLines = UltraScaleClockRouting.routeToHorizontalDistributionLines(clk, vrouteUp, upClockRegions, false, getNodeStatus); + if (upLines != null) upDownDistLines.addAll(upLines); + } + + List downLines = UltraScaleClockRouting.routeToHorizontalDistributionLines(clk, vrouteDown, downClockRegions, true, getNodeStatus);//TODO this is where the antenna node shows up + if (downLines != null) upDownDistLines.addAll(downLines); + + Map> lcbMappings = getLCBPinMappings(clk.getPins(), getNodeStatus); + UltraScaleClockRouting.routeDistributionToLCBs(clk, upDownDistLines, lcbMappings.keySet()); + + UltraScaleClockRouting.routeLCBsToSinks(clk, lcbMappings, getNodeStatus); - List upDownDistLines = new ArrayList<>(); - if (aboveCentroid != null) { - List upLines = UltraScaleClockRouting.routeToHorizontalDistributionLines(clk, vrouteUp, upClockRegions, false, getNodeStatus); - if (upLines != null) upDownDistLines.addAll(upLines); + Set clkPIPsWithoutDuplication = new HashSet<>(clk.getPIPs()); + clk.setPIPs(clkPIPsWithoutDuplication); } + else { + // Clock routing on Versal devices + // TODO: Tile.getWireConnections(int wire) is not working correctly on Versal devices, + // so the below clock routing flow goes in the "node way", which means we use Node.getAllDownhillNodes() to + // go downhill instead of Tile.getWireConnections(int wire). This may lead to worse runtime. + + List clockRegions = getClockRegionsOfNet(clk); + Map upDownDistLines = new HashMap<>(); + SitePinInst source = clk.getSource(); + SiteTypeEnum sourceTypeEnum = source.getSiteTypeEnum(); + RouteNode sourceRouteNode = new RouteNode(source); + // In US/US+ clock routing, we use two VROUTE nodes to reach the clock regions above and below the centroid. + // However, we can see that Vivado only use one VROUTE node in the centroid clock region for versal clock routing, + // and reach the above and below clock regions by VDISTR nodes. + RouteNode vroute = null; + System.out.println("SiteTypeEnum of source: " + sourceTypeEnum); + + // In FPGA '24 routing contest benchmarks, we found that there are only two types of source sites for the clock nets: BUFGCE and BUFG_FABRIC. + if (sourceTypeEnum == SiteTypeEnum.BUFG_FABRIC) { + // These source sites are located in the middle of the device. The path from the output pin to VROUTE matches the following pattern: + // NODE_GLOBAL_BUFG (the output node with a suffix "_O") -> + // NODE_GLOBAL_BUFG (has a suffix "_O_PIN") -> + // NODE_GLOBAL_GCLK -> + // NODE_GLOBAL_VROUTE (located in the same clock region of the source site) + + // Notice that Vivado always use the above VROUTE node, there is no need to find a centroid clock region to route to. + + vroute = VersalClockRouting.routeToCentroid(clk, sourceRouteNode, source.getTile().getClockRegion(), true, false); + } else if (sourceTypeEnum == SiteTypeEnum.BUFGCE) { + // Most clock nets in FPGA '24 benchmarks have this type of source site. + // These source sites are located in the bottom of the device (Y=0). The path from the output pin to VROUTE matches the following pattern: + // NODE_GLOBAL_BUFG -> NODE_GLOBAL_BUFG -> NODE_GLOBAL_GCLK -> NODE_GLOBAL_HROUTE_HSR -> NODE_GLOBAL_VROUTE + // which is similar to US/US+ clock routing. + // Notice that we have to quickly reach a NODE_GLOBAL_HROUTE_HSR node, and if we allow the Y coordinate of centroid to be bigger than 1, + // we may fail to do so. Thus, we need to force the Y-coordinate of centroid to be 1. + assert(source.getTile().getTileYCoordinate() == 0); + // And, in X-axis, Vivado doesn't go to the real centroid of target clock regions... it just uses a nearby VROUTE. + int centroidX = sourceRouteNode.getTile().getClockRegion().getColumn(); + // VROUTE nodes are in the clock region where X is odd. + if (centroidX % 2 == 0) centroidX -= 1; + if (centroidX <= 0) centroidX = 1; + + ClockRegion centroid = device.getClockRegion(1, centroidX); + System.out.println("centroid: " + centroid); + RouteNode clkRoutingLine = VersalClockRouting.routeBUFGToNearestRoutingTrack(clk);// first HROUTE + System.out.println("clkRoutingLine: " + clkRoutingLine.getName()); + RouteNode centroidHRouteNode = VersalClockRouting.routeToCentroid(clk, clkRoutingLine, centroid, true, true); + System.out.println("centroidHRouteNode: " + centroidHRouteNode.getName()); + vroute = VersalClockRouting.routeToCentroid(clk, centroidHRouteNode, centroid, true, false); + } else { + throw new RuntimeException("RWRoute hasn't supported routing a clock net with source type " + sourceTypeEnum + " yet."); + } - List downLines = UltraScaleClockRouting.routeToHorizontalDistributionLines(clk, vrouteDown, downClockRegions, true, getNodeStatus);//TODO this is where the antenna node shows up - if (downLines != null) upDownDistLines.addAll(downLines); + System.out.println("vroute: " + vroute.getName()); - Map> lcbMappings = getLCBPinMappings(clk.getPins(), getNodeStatus); - UltraScaleClockRouting.routeDistributionToLCBs(clk, upDownDistLines, lcbMappings.keySet()); + upDownDistLines = VersalClockRouting.routeToHorizontalDistributionLines(clk, vroute, clockRegions, false, getNodeStatus); - UltraScaleClockRouting.routeLCBsToSinks(clk, lcbMappings, getNodeStatus); + Map> lcbMappings = getLCBPinMappings(clk.getPins(), getNodeStatus); + VersalClockRouting.routeDistributionToLCBs(clk, upDownDistLines, lcbMappings.keySet()); - Set clkPIPsWithoutDuplication = new HashSet<>(clk.getPIPs()); - clk.setPIPs(clkPIPsWithoutDuplication); + VersalClockRouting.routeLCBsToSinks(clk, lcbMappings, getNodeStatus); + + Set clkPIPsWithoutDuplication = new HashSet<>(clk.getPIPs()); + clk.setPIPs(clkPIPsWithoutDuplication); + } } /** @@ -272,31 +364,53 @@ public static Map> getLCBPinMappings(List startNodes = new ArrayList<>(); + + if (intNode.getIntentCode() == IntentCode.NODE_IMUX) { + // This node drives a LUT input pin. Vivado reaches this pin in pattern: + // NODE_GLOBAL_LEAF -> NODE_CLE_CNODE -> NODE_INODE -> NODE_IMUX + // Need to go one more step to let prevPrev be a NODE_GLOBAL_LEAF node. + + // And, it seems that each NODE_INODE node is driven by only one NODE_CLE_CNODE node, + // but not each NODE_CLE_CNODE node can find a uphill NODE_GLOBAL_LEAF node, + // thus here I add all NODE_INODE nodes to ensure that we can find candidates. + Tile intTile = intNode.getTile(); + for (Node uphill: intNode.getAllUphillNodes()) { + if (uphill.getIntentCode() == IntentCode.NODE_INODE && uphill.getTile() == intTile) { + startNodes.add(uphill); } + } + } else { + assert(intNode.getIntentCode() == IntentCode.NODE_CLE_CTRL || intNode.getIntentCode() == IntentCode.NODE_INTF_CTRL); + startNodes.add(intNode); + } - NodeStatus prevPrevNodeStatus = getNodeStatus.apply(prevPrev); - if (prevPrevNodeStatus == NodeStatus.UNAVAILABLE) { + outer: for (Node startNode: startNodes) { + for (Node prev : startNode.getAllUphillNodes()) { + NodeStatus prevNodeStatus = getNodeStatus.apply(prev); + if (prevNodeStatus == NodeStatus.UNAVAILABLE) { continue; } - - if (usedLcbs.contains(prevPrev) || prevPrevNodeStatus == NodeStatus.INUSE) { - lcbCandidates.clear(); + + for (Node prevPrev : prev.getAllUphillNodes()) { + if (prevPrev.getIntentCode() != IntentCode.NODE_GLOBAL_LEAF) { + continue; + } + + NodeStatus prevPrevNodeStatus = getNodeStatus.apply(prevPrev); + if (prevPrevNodeStatus == NodeStatus.UNAVAILABLE) { + continue; + } + + if (usedLcbs.contains(prevPrev) || prevPrevNodeStatus == NodeStatus.INUSE) { + lcbCandidates.clear(); + lcbCandidates.add(prevPrev); + break outer; + } + + assert(prevPrevNodeStatus == NodeStatus.AVAILABLE); lcbCandidates.add(prevPrev); - break outer; } - - assert(prevPrevNodeStatus == NodeStatus.AVAILABLE); - lcbCandidates.add(prevPrev); } } From 069ab43b530e2894270d48ebfe5fd002eff3fbc7 Mon Sep 17 00:00:00 2001 From: Wenhao Lin Date: Wed, 13 Nov 2024 09:26:52 -0700 Subject: [PATCH 02/28] Add licence Signed-off-by: Wenhao Lin --- .../router/VersalClockRouting.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/com/xilinx/rapidwright/router/VersalClockRouting.java b/src/com/xilinx/rapidwright/router/VersalClockRouting.java index 6753041f8..f1307fa7a 100644 --- a/src/com/xilinx/rapidwright/router/VersalClockRouting.java +++ b/src/com/xilinx/rapidwright/router/VersalClockRouting.java @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2024, Advanced Micro Devices, Inc. + * All rights reserved. + * + * Author: Wenhao Lin, AMD Research and Advanced Development. + * + * This file is part of RapidWright. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + package com.xilinx.rapidwright.router; import com.xilinx.rapidwright.design.Design; From 801273cf3634760ffbb3787623fb48fab6f02a2b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 13 Nov 2024 17:24:20 -0800 Subject: [PATCH 03/28] testNodeReachabilityVersal to examine some NODE_GLOBAL_LEAF wires Signed-off-by: Eddie Hung --- test/src/com/xilinx/rapidwright/device/TestNode.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/src/com/xilinx/rapidwright/device/TestNode.java b/test/src/com/xilinx/rapidwright/device/TestNode.java index 175172258..ebbab801e 100644 --- a/test/src/com/xilinx/rapidwright/device/TestNode.java +++ b/test/src/com/xilinx/rapidwright/device/TestNode.java @@ -256,6 +256,7 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str "xcvp1002,CLE_W_CORE_X38Y220,NODE_CLE_OUTPUT,,false", "xcvp1002,INTF_ROCF_TR_TILE_X39Y153,NODE_INTF_CNODE,,true", "xcvp1002,INTF_ROCF_TR_TILE_X39Y153,NODE_INTF_BNODE,,true", + "xcvp1002,RCLK_CLE_CORE_X37Y239,NODE_GLOBAL_LEAF,CLK_LEAF_SITES_\\d+_O,false", }) public void testNodeReachabilityVersal(String partName, String tileName, String intentCodeName, String wireNameRegex, boolean local) { Device device = Device.getDevice(partName); @@ -289,7 +290,7 @@ public void testNodeReachabilityVersal(String partName, String tileName, String .map(s -> s.replaceFirst("(INT_NODE_IMUX_ATOM_)(3[2-9]|4[0-9]|5[0-9]|6[0-3]|9[6-9]|10[0-9]|11[0-9]|12[0-7])_INT_OUT[01]", "$1<32-63,96-127>")) .map(s -> s.replaceFirst("([BC]NODE_OUTS_[EW])\\d+", "$1")) .map(s -> s.replaceFirst("((CLE_SLICE[LM]_TOP_[01]|OUT_[NESW]NODE|(NN|EE|SS|WW)(1|2|4|6|7|10|12)(_[EW])?)_)[^ ]+", "$1")) - .map(s -> s.replaceFirst("(CLK_LEAF_SITES_)\\d+_O", "$1")) + .map(s -> s.replaceFirst("(CLK_LEAF_SITES_)\\d+_O(_PIN)?", "$1")) .map(s -> s.replaceFirst("(VCC_WIRE)\\d+", "$1")) .distinct() .sorted() From 467828ea27d8638e4cb268748710dc3ff5f7a0f1 Mon Sep 17 00:00:00 2001 From: Wenhao Lin Date: Thu, 14 Nov 2024 04:40:08 -0700 Subject: [PATCH 04/28] Fix bugs in mapping sinks to LCBs Signed-off-by: Wenhao Lin --- .../rwroute/GlobalSignalRouting.java | 62 ++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java index d4b4d3227..e440c3420 100644 --- a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java +++ b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java @@ -34,6 +34,7 @@ import java.util.Queue; import java.util.Set; import java.util.function.Function; +import java.util.function.Predicate; import com.xilinx.rapidwright.design.Design; import com.xilinx.rapidwright.design.Net; @@ -310,7 +311,7 @@ public static void symmetricClkRouting(Net clk, Device device, Function> lcbMappings = getLCBPinMappings(clk.getPins(), getNodeStatus); + Map> lcbMappings = getLCBPinMappingsOnVersal(clk, getNodeStatus); VersalClockRouting.routeDistributionToLCBs(clk, upDownDistLines, lcbMappings.keySet()); VersalClockRouting.routeLCBsToSinks(clk, lcbMappings, getNodeStatus); @@ -427,6 +428,65 @@ public static Map> getLCBPinMappings(List> getLCBPinMappingsOnVersal(Net clk, + Function getNodeStatus) { + Map> lcbMappings = new HashMap<>(); + Set allowedIntentCodes = EnumSet.of( + IntentCode.NODE_GLOBAL_LEAF, + IntentCode.NODE_CLE_CNODE, + IntentCode.NODE_INTF_CNODE, + IntentCode.NODE_INODE, + IntentCode.NODE_PINBOUNCE, + IntentCode.NODE_CLE_BNODE, + IntentCode.NODE_INTF_BNODE, + IntentCode.NODE_IMUX, + IntentCode.NODE_CLE_CTRL, + IntentCode.NODE_INTF_CTRL, + IntentCode.NODE_IRI, + IntentCode.NODE_PINFEED, + IntentCode.NODE_GLOBAL_LEAF + ); + Set used = new HashSet<>(); + Set visited = new HashSet<>(); + Queue q = new LinkedList<>(); + Predicate isNodeUnavailable = (node) -> getNodeStatus.apply(node) == NodeStatus.UNAVAILABLE; + RouteThruHelper routeThruHelper = new RouteThruHelper(clk.getDesign().getDevice()); + + nextPin: for (SitePinInst p: clk.getPins()) { + if (p.isOutPin()) continue; + Node intNode = RouterHelper.projectInputPinToINTNode(p); + RouteNode intRouteNode = new RouteNode(intNode.getTile(), intNode.getWireIndex(), null, 0); + ClockRegion cr = p.getTile().getClockRegion(); + + q.clear(); + q.add(intRouteNode); + + while (!q.isEmpty()) { + RouteNode curr = q.poll(); + Node currNode = Node.getNode(curr); + + for (Node uphill : currNode.getAllUphillNodes()) { + if (!uphill.getTile().getClockRegion().equals(cr)) continue; + if (!allowedIntentCodes.contains(uphill.getIntentCode())) continue; + if (!visited.add(uphill)) continue; + if (used.contains(uphill)) continue; + if (routeThruHelper.isRouteThru(uphill, currNode) && currNode.getIntentCode() != IntentCode.NODE_IRI) continue; + if (isNodeUnavailable.test(uphill)) continue; + if (uphill.getIntentCode() == IntentCode.NODE_GLOBAL_LEAF) { + RouteNode rn = new RouteNode(uphill.getTile(), uphill.getWireIndex(), null, 0); + lcbMappings.computeIfAbsent(rn, (k) -> new ArrayList<>()).add(p); + visited.clear(); + continue nextPin; + } + q.add(new RouteNode(uphill.getTile(), uphill.getWireIndex(), curr, curr.getLevel()+1)); + } + } + throw new RuntimeException("ERROR: Couldn't map Pin " + p + " to LCB."); + } + + return lcbMappings; + } + /** * Finds the centroid clock region of a clock net. * @param clk The clock net of a design. From 9533bc3a8617270c87040cf3861484090d9e982c Mon Sep 17 00:00:00 2001 From: Wenhao Lin Date: Thu, 14 Nov 2024 04:40:56 -0700 Subject: [PATCH 05/28] Add clock routing test on versal devices Signed-off-by: Wenhao Lin --- .../rapidwright/rwroute/TestRWRoute.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java index 97bb28c56..f5ec0479a 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java @@ -26,6 +26,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -46,6 +47,7 @@ import com.xilinx.rapidwright.design.Design; import com.xilinx.rapidwright.design.DesignTools; import com.xilinx.rapidwright.design.Net; +import com.xilinx.rapidwright.design.NetTools; import com.xilinx.rapidwright.design.SiteInst; import com.xilinx.rapidwright.design.SitePinInst; import com.xilinx.rapidwright.design.Unisim; @@ -529,4 +531,36 @@ public void testSingleConnection(String partName, dstSiteName, dstPinName, nodesPoppedLimit); } + + @Test + public void testClockRoutingOnVersal() { + Design design = RapidWrightDCP.loadDCP("two_clk_check_NetTools.dcp"); + design.setTrackNetChanges(true); + + // Pseudo-randomly unroute some pins from a multi-pin net + for (Net net : design.getNets()) { + if (NetTools.isGlobalClock(net)) { + net.unroute(); + } + } + + String[] args = new String[] { + "--fixBoundingBox", + "--useUTurnNodes", + "--nonTimingDriven", + "--verbose" + }; + RWRouteConfig config = new RWRouteConfig(args); + PartialRouter.preprocess(design); + Collection pinsToRoute = PartialRouter.getUnroutedPins(design); + PartialRouter router = new PartialRouter(design, config, pinsToRoute, false); + + router.initialize(); + router.routeGlobalClkNets(); + + for (Net net : design.getModifiedNets()) { + assertAllPinsRouted(net); + } + VivadoToolsHelper.assertFullyRouted(design); + } } From 579b93a8aed287cc085cff16d18ef3b847b05645 Mon Sep 17 00:00:00 2001 From: Wenhao Lin Date: Thu, 14 Nov 2024 05:38:43 -0700 Subject: [PATCH 06/28] Route backward from sinks to LCBs and update test Signed-off-by: Wenhao Lin --- src/com/xilinx/rapidwright/router/RouteNode.java | 13 +++++++++++++ .../rapidwright/rwroute/GlobalSignalRouting.java | 16 ++++++++-------- .../xilinx/rapidwright/rwroute/TestRWRoute.java | 6 ------ 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/com/xilinx/rapidwright/router/RouteNode.java b/src/com/xilinx/rapidwright/router/RouteNode.java index 7fd119b0c..5d6e77a66 100644 --- a/src/com/xilinx/rapidwright/router/RouteNode.java +++ b/src/com/xilinx/rapidwright/router/RouteNode.java @@ -395,6 +395,19 @@ public ArrayList getPIPsBackToSourceByNodes() { return pips; } + public ArrayList getPIPsForwardToSinkByNodes() { + ArrayList pips = new ArrayList<>(); + RouteNode curr = this; + do { + PIP pip = RouterHelper.findPIPbetweenNodes(Node.getNode(curr), Node.getNode(curr.parent)); + if (pip != null) { + pips.add(pip); + } + curr = curr.parent; + } while (curr.parent != null); + return pips; + } + public Wire[] getWiresInNode() { return Node.getWiresInNode(getTile(),getWire()); } diff --git a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java index e440c3420..a4e48fa08 100644 --- a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java +++ b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java @@ -314,8 +314,6 @@ public static void symmetricClkRouting(Net clk, Device device, Function> lcbMappings = getLCBPinMappingsOnVersal(clk, getNodeStatus); VersalClockRouting.routeDistributionToLCBs(clk, upDownDistLines, lcbMappings.keySet()); - VersalClockRouting.routeLCBsToSinks(clk, lcbMappings, getNodeStatus); - Set clkPIPsWithoutDuplication = new HashSet<>(clk.getPIPs()); clk.setPIPs(clkPIPsWithoutDuplication); } @@ -446,7 +444,6 @@ public static Map> getLCBPinMappingsOnVersal(Net cl IntentCode.NODE_PINFEED, IntentCode.NODE_GLOBAL_LEAF ); - Set used = new HashSet<>(); Set visited = new HashSet<>(); Queue q = new LinkedList<>(); Predicate isNodeUnavailable = (node) -> getNodeStatus.apply(node) == NodeStatus.UNAVAILABLE; @@ -454,12 +451,12 @@ public static Map> getLCBPinMappingsOnVersal(Net cl nextPin: for (SitePinInst p: clk.getPins()) { if (p.isOutPin()) continue; - Node intNode = RouterHelper.projectInputPinToINTNode(p); - RouteNode intRouteNode = new RouteNode(intNode.getTile(), intNode.getWireIndex(), null, 0); + Node sinkNode = p.getConnectedNode(); + RouteNode sinkRouteNode = new RouteNode(sinkNode.getTile(), sinkNode.getWireIndex(), null, 0); ClockRegion cr = p.getTile().getClockRegion(); q.clear(); - q.add(intRouteNode); + q.add(sinkRouteNode); while (!q.isEmpty()) { RouteNode curr = q.poll(); @@ -469,11 +466,14 @@ public static Map> getLCBPinMappingsOnVersal(Net cl if (!uphill.getTile().getClockRegion().equals(cr)) continue; if (!allowedIntentCodes.contains(uphill.getIntentCode())) continue; if (!visited.add(uphill)) continue; - if (used.contains(uphill)) continue; + // if (used.contains(uphill)) continue; if (routeThruHelper.isRouteThru(uphill, currNode) && currNode.getIntentCode() != IntentCode.NODE_IRI) continue; if (isNodeUnavailable.test(uphill)) continue; if (uphill.getIntentCode() == IntentCode.NODE_GLOBAL_LEAF) { - RouteNode rn = new RouteNode(uphill.getTile(), uphill.getWireIndex(), null, 0); + RouteNode rn = new RouteNode(uphill.getTile(), uphill.getWireIndex(), curr, curr.getLevel()+1); + clk.getPIPs().addAll(rn.getPIPsForwardToSinkByNodes()); + rn.setParent(null); + rn.setLevel(0); lcbMappings.computeIfAbsent(rn, (k) -> new ArrayList<>()).add(p); visited.clear(); continue nextPin; diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java index f5ec0479a..b8976b28d 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java @@ -535,9 +535,6 @@ public void testSingleConnection(String partName, @Test public void testClockRoutingOnVersal() { Design design = RapidWrightDCP.loadDCP("two_clk_check_NetTools.dcp"); - design.setTrackNetChanges(true); - - // Pseudo-randomly unroute some pins from a multi-pin net for (Net net : design.getNets()) { if (NetTools.isGlobalClock(net)) { net.unroute(); @@ -558,9 +555,6 @@ public void testClockRoutingOnVersal() { router.initialize(); router.routeGlobalClkNets(); - for (Net net : design.getModifiedNets()) { - assertAllPinsRouted(net); - } VivadoToolsHelper.assertFullyRouted(design); } } From 7da71b37663a2ec1f177837ce47466f7f249811b Mon Sep 17 00:00:00 2001 From: Wenhao Lin Date: Thu, 14 Nov 2024 21:41:34 -0700 Subject: [PATCH 07/28] revert getLCBPinMappings for US/US+ devices Signed-off-by: Wenhao Lin --- .../rwroute/GlobalSignalRouting.java | 81 +++++-------------- 1 file changed, 19 insertions(+), 62 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java index a4e48fa08..730af8850 100644 --- a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java +++ b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java @@ -196,30 +196,16 @@ private static Map> getListOfNodesFromRoutes(Device device, M */ public static void symmetricClkRouting(Net clk, Device device, Function getNodeStatus) { if (device.getSeries() != Series.Versal) { - boolean debug = true; List clockRegions = getClockRegionsOfNet(clk); ClockRegion centroid = findCentroid(clk, device); - if (debug) { - System.out.println("centroid CR: " + centroid); - } - List upClockRegions = new ArrayList<>(); List downClockRegions = new ArrayList<>(); // divides clock regions into two groups divideClockRegions(clockRegions, centroid, upClockRegions, downClockRegions); RouteNode clkRoutingLine = UltraScaleClockRouting.routeBUFGToNearestRoutingTrack(clk);// first HROUTE - - if (debug) { - System.out.println("clkRoutingLine: " + clkRoutingLine); - } - RouteNode centroidHRouteNode = UltraScaleClockRouting.routeToCentroid(clk, clkRoutingLine, centroid, true, true); - - if (debug) { - System.out.println("centroidHRouteNode: " + centroidHRouteNode); - } RouteNode vrouteUp = null; RouteNode vrouteDown; @@ -227,16 +213,9 @@ public static void symmetricClkRouting(Net clk, Device device, Function upDownDistLines = new ArrayList<>(); if (aboveCentroid != null) { List upLines = UltraScaleClockRouting.routeToHorizontalDistributionLines(clk, vrouteUp, upClockRegions, false, getNodeStatus); @@ -363,53 +342,31 @@ public static Map> getLCBPinMappings(List startNodes = new ArrayList<>(); - - if (intNode.getIntentCode() == IntentCode.NODE_IMUX) { - // This node drives a LUT input pin. Vivado reaches this pin in pattern: - // NODE_GLOBAL_LEAF -> NODE_CLE_CNODE -> NODE_INODE -> NODE_IMUX - // Need to go one more step to let prevPrev be a NODE_GLOBAL_LEAF node. - - // And, it seems that each NODE_INODE node is driven by only one NODE_CLE_CNODE node, - // but not each NODE_CLE_CNODE node can find a uphill NODE_GLOBAL_LEAF node, - // thus here I add all NODE_INODE nodes to ensure that we can find candidates. - Tile intTile = intNode.getTile(); - for (Node uphill: intNode.getAllUphillNodes()) { - if (uphill.getIntentCode() == IntentCode.NODE_INODE && uphill.getTile() == intTile) { - startNodes.add(uphill); - } + + outer: for (Node prev : intNode.getAllUphillNodes()) { + NodeStatus prevNodeStatus = getNodeStatus.apply(prev); + if (prevNodeStatus == NodeStatus.UNAVAILABLE) { + continue; } - } else { - assert(intNode.getIntentCode() == IntentCode.NODE_CLE_CTRL || intNode.getIntentCode() == IntentCode.NODE_INTF_CTRL); - startNodes.add(intNode); - } - outer: for (Node startNode: startNodes) { - for (Node prev : startNode.getAllUphillNodes()) { - NodeStatus prevNodeStatus = getNodeStatus.apply(prev); - if (prevNodeStatus == NodeStatus.UNAVAILABLE) { + for (Node prevPrev : prev.getAllUphillNodes()) { + if (prevPrev.getIntentCode() != IntentCode.NODE_GLOBAL_LEAF) { continue; } - - for (Node prevPrev : prev.getAllUphillNodes()) { - if (prevPrev.getIntentCode() != IntentCode.NODE_GLOBAL_LEAF) { - continue; - } - - NodeStatus prevPrevNodeStatus = getNodeStatus.apply(prevPrev); - if (prevPrevNodeStatus == NodeStatus.UNAVAILABLE) { - continue; - } - - if (usedLcbs.contains(prevPrev) || prevPrevNodeStatus == NodeStatus.INUSE) { - lcbCandidates.clear(); - lcbCandidates.add(prevPrev); - break outer; - } - - assert(prevPrevNodeStatus == NodeStatus.AVAILABLE); + + NodeStatus prevPrevNodeStatus = getNodeStatus.apply(prevPrev); + if (prevPrevNodeStatus == NodeStatus.UNAVAILABLE) { + continue; + } + + if (usedLcbs.contains(prevPrev) || prevPrevNodeStatus == NodeStatus.INUSE) { + lcbCandidates.clear(); lcbCandidates.add(prevPrev); + break outer; } + + assert(prevPrevNodeStatus == NodeStatus.AVAILABLE); + lcbCandidates.add(prevPrev); } } From 7470bba46f9108c772b56607fec512b64681a2d3 Mon Sep 17 00:00:00 2001 From: Wenhao Lin Date: Thu, 14 Nov 2024 22:11:03 -0700 Subject: [PATCH 08/28] Modify testNodeReachabilityVersal Signed-off-by: Wenhao Lin --- test/src/com/xilinx/rapidwright/device/TestNode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/com/xilinx/rapidwright/device/TestNode.java b/test/src/com/xilinx/rapidwright/device/TestNode.java index ebbab801e..f1aa47759 100644 --- a/test/src/com/xilinx/rapidwright/device/TestNode.java +++ b/test/src/com/xilinx/rapidwright/device/TestNode.java @@ -256,7 +256,7 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str "xcvp1002,CLE_W_CORE_X38Y220,NODE_CLE_OUTPUT,,false", "xcvp1002,INTF_ROCF_TR_TILE_X39Y153,NODE_INTF_CNODE,,true", "xcvp1002,INTF_ROCF_TR_TILE_X39Y153,NODE_INTF_BNODE,,true", - "xcvp1002,RCLK_CLE_CORE_X37Y239,NODE_GLOBAL_LEAF,CLK_LEAF_SITES_\\d+_O,false", + "xcvp1002,RCLK_CLE_CORE_X37Y239,NODE_GLOBAL_LEAF,CLK_LEAF_SITES_\\d+_O,true", }) public void testNodeReachabilityVersal(String partName, String tileName, String intentCodeName, String wireNameRegex, boolean local) { Device device = Device.getDevice(partName); From 479b9d33594b6951fce1bc14ea7a511dd5564130 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 18 Nov 2024 15:36:16 -0800 Subject: [PATCH 09/28] Add TestGlobalSignalRouting.testSymmetricClkRouting() Signed-off-by: Eddie Hung --- .../rwroute/TestGlobalSignalRouting.java | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestGlobalSignalRouting.java b/test/src/com/xilinx/rapidwright/rwroute/TestGlobalSignalRouting.java index efd1ae6a4..ea8a7bf1e 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestGlobalSignalRouting.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestGlobalSignalRouting.java @@ -26,6 +26,7 @@ import com.xilinx.rapidwright.design.Design; import com.xilinx.rapidwright.design.DesignTools; import com.xilinx.rapidwright.design.Net; +import com.xilinx.rapidwright.design.NetTools; import com.xilinx.rapidwright.design.NetType; import com.xilinx.rapidwright.design.SiteInst; import com.xilinx.rapidwright.design.SitePinInst; @@ -37,6 +38,7 @@ import com.xilinx.rapidwright.util.FileTools; import com.xilinx.rapidwright.util.ReportRouteStatusResult; import com.xilinx.rapidwright.util.VivadoTools; +import com.xilinx.rapidwright.util.VivadoToolsHelper; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; @@ -47,8 +49,8 @@ import java.nio.file.Path; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -import java.util.function.BiFunction; public class TestGlobalSignalRouting { @ParameterizedTest @@ -225,4 +227,24 @@ public void testRouteStaticNetOnVersalDevice(boolean createStaticPins, @TempDir Assertions.assertEquals(0, rrs.netsWithRoutingErrors); } } + + @Test + public void testSymmetricClkRouting() { + Design design = RapidWrightDCP.loadDCP("two_clk_check_NetTools.dcp"); + design.unrouteDesign(); + + for (String netName : Arrays.asList("clk1_IBUF_BUFG", "clk2_IBUF_BUFG", "rst1", "rst2")) { + Net net = design.getNet(netName); + Assertions.assertTrue(NetTools.isGlobalClock(net)); + GlobalSignalRouting.symmetricClkRouting(net, design.getDevice(), (n) -> NodeStatus.AVAILABLE); + } + + if (FileTools.isVivadoOnPath()) { + ReportRouteStatusResult rrs = VivadoTools.reportRouteStatus(design); + Assertions.assertEquals(4, rrs.fullyRoutedNets); + Assertions.assertEquals(0, rrs.netsWithRoutingErrors); + } else { + System.err.println("WARNING: vivado not on PATH"); + } + } } From 0a17c4d544af847d75439e986a334ac53b055c07 Mon Sep 17 00:00:00 2001 From: Wenhao Lin Date: Tue, 19 Nov 2024 00:22:59 -0700 Subject: [PATCH 10/28] Fix testSymmetricClkRouting Signed-off-by: Wenhao Lin --- .../rapidwright/rwroute/TestGlobalSignalRouting.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestGlobalSignalRouting.java b/test/src/com/xilinx/rapidwright/rwroute/TestGlobalSignalRouting.java index ea8a7bf1e..80ce9804d 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestGlobalSignalRouting.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestGlobalSignalRouting.java @@ -32,6 +32,7 @@ import com.xilinx.rapidwright.design.SitePinInst; import com.xilinx.rapidwright.design.Unisim; import com.xilinx.rapidwright.device.Node; +import com.xilinx.rapidwright.device.PIP; import com.xilinx.rapidwright.device.SitePin; import com.xilinx.rapidwright.router.RouteThruHelper; import com.xilinx.rapidwright.support.RapidWrightDCP; @@ -50,7 +51,9 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; public class TestGlobalSignalRouting { @ParameterizedTest @@ -232,11 +235,18 @@ public void testRouteStaticNetOnVersalDevice(boolean createStaticPins, @TempDir public void testSymmetricClkRouting() { Design design = RapidWrightDCP.loadDCP("two_clk_check_NetTools.dcp"); design.unrouteDesign(); + // Simulate the preserve method + Set used = new HashSet<>(); for (String netName : Arrays.asList("clk1_IBUF_BUFG", "clk2_IBUF_BUFG", "rst1", "rst2")) { Net net = design.getNet(netName); Assertions.assertTrue(NetTools.isGlobalClock(net)); - GlobalSignalRouting.symmetricClkRouting(net, design.getDevice(), (n) -> NodeStatus.AVAILABLE); + GlobalSignalRouting.symmetricClkRouting(net, design.getDevice(), (n) -> used.contains(n) ? NodeStatus.UNAVAILABLE : NodeStatus.AVAILABLE); + for (PIP pip: net.getPIPs()) { + for (Node node: Arrays.asList(pip.getStartNode(), pip.getEndNode())) { + if (node != null) used.add(node); + } + } } if (FileTools.isVivadoOnPath()) { From 056349e82cfeb2f811aecfad67ce75ce4fda833d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 19 Nov 2024 11:01:45 -0800 Subject: [PATCH 11/28] Do not use removed method Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/router/RouteNode.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/xilinx/rapidwright/router/RouteNode.java b/src/com/xilinx/rapidwright/router/RouteNode.java index 5d6e77a66..0695a3c09 100644 --- a/src/com/xilinx/rapidwright/router/RouteNode.java +++ b/src/com/xilinx/rapidwright/router/RouteNode.java @@ -386,7 +386,7 @@ public ArrayList getPIPsBackToSourceByNodes() { ArrayList pips = new ArrayList<>(); RouteNode curr = this; while (curr.parent != null) { - PIP pip = RouterHelper.findPIPbetweenNodes(Node.getNode(curr.parent), Node.getNode(curr)); + PIP pip = PIP.getArbitraryPIP(Node.getNode(curr.parent), Node.getNode(curr)); if (pip != null) { pips.add(pip); } @@ -399,7 +399,7 @@ public ArrayList getPIPsForwardToSinkByNodes() { ArrayList pips = new ArrayList<>(); RouteNode curr = this; do { - PIP pip = RouterHelper.findPIPbetweenNodes(Node.getNode(curr), Node.getNode(curr.parent)); + PIP pip = PIP.getArbitraryPIP(Node.getNode(curr), Node.getNode(curr.parent)); if (pip != null) { pips.add(pip); } From a6742690fe924fa5418213e20b721bdd36e91263 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 19 Nov 2024 11:13:29 -0800 Subject: [PATCH 12/28] Small cleanup Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/router/RouteNode.java | 1 - .../rwroute/GlobalSignalRouting.java | 9 ++---- .../rapidwright/rwroute/TestRWRoute.java | 28 ------------------- 3 files changed, 3 insertions(+), 35 deletions(-) diff --git a/src/com/xilinx/rapidwright/router/RouteNode.java b/src/com/xilinx/rapidwright/router/RouteNode.java index 0695a3c09..93453eb13 100644 --- a/src/com/xilinx/rapidwright/router/RouteNode.java +++ b/src/com/xilinx/rapidwright/router/RouteNode.java @@ -35,7 +35,6 @@ import com.xilinx.rapidwright.device.PIP; import com.xilinx.rapidwright.device.Tile; import com.xilinx.rapidwright.device.Wire; -import com.xilinx.rapidwright.rwroute.RouterHelper; /** diff --git a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java index 1ed0b41dd..45d6f3f50 100644 --- a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java +++ b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java @@ -229,9 +229,6 @@ public static void symmetricClkRouting(Net clk, Device device, Function clkPIPsWithoutDuplication = new HashSet<>(clk.getPIPs()); - clk.setPIPs(clkPIPsWithoutDuplication); } else { // Clock routing on Versal devices @@ -292,10 +289,10 @@ public static void symmetricClkRouting(Net clk, Device device, Function> lcbMappings = getLCBPinMappingsOnVersal(clk, getNodeStatus); VersalClockRouting.routeDistributionToLCBs(clk, upDownDistLines, lcbMappings.keySet()); - - Set clkPIPsWithoutDuplication = new HashSet<>(clk.getPIPs()); - clk.setPIPs(clkPIPsWithoutDuplication); } + + Set clkPIPsWithoutDuplication = new HashSet<>(clk.getPIPs()); + clk.setPIPs(clkPIPsWithoutDuplication); } /** diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java index de76dc63d..c4a62f0e2 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java @@ -26,7 +26,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -47,7 +46,6 @@ import com.xilinx.rapidwright.design.Design; import com.xilinx.rapidwright.design.DesignTools; import com.xilinx.rapidwright.design.Net; -import com.xilinx.rapidwright.design.NetTools; import com.xilinx.rapidwright.design.SiteInst; import com.xilinx.rapidwright.design.SitePinInst; import com.xilinx.rapidwright.design.Unisim; @@ -532,30 +530,4 @@ public void testSingleConnection(String partName, dstSiteName, dstPinName, nodesPoppedLimit); } - - @Test - public void testClockRoutingOnVersal() { - Design design = RapidWrightDCP.loadDCP("two_clk_check_NetTools.dcp"); - for (Net net : design.getNets()) { - if (NetTools.isGlobalClock(net)) { - net.unroute(); - } - } - - String[] args = new String[] { - "--fixBoundingBox", - "--useUTurnNodes", - "--nonTimingDriven", - "--verbose" - }; - RWRouteConfig config = new RWRouteConfig(args); - PartialRouter.preprocess(design); - Collection pinsToRoute = PartialRouter.getUnroutedPins(design); - PartialRouter router = new PartialRouter(design, config, pinsToRoute, false); - - router.initialize(); - router.routeGlobalClkNets(); - - VivadoToolsHelper.assertFullyRouted(design); - } } From 741fac3316768a8eea45749bedacc3d441d2a2b0 Mon Sep 17 00:00:00 2001 From: Wenhao Lin Date: Tue, 19 Nov 2024 00:22:59 -0700 Subject: [PATCH 13/28] Fix testSymmetricClkRouting Signed-off-by: Wenhao Lin --- .../rapidwright/rwroute/TestGlobalSignalRouting.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestGlobalSignalRouting.java b/test/src/com/xilinx/rapidwright/rwroute/TestGlobalSignalRouting.java index 545398e3e..ba8d5e192 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestGlobalSignalRouting.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestGlobalSignalRouting.java @@ -33,6 +33,7 @@ import com.xilinx.rapidwright.design.Unisim; import com.xilinx.rapidwright.device.Device; import com.xilinx.rapidwright.device.Node; +import com.xilinx.rapidwright.device.PIP; import com.xilinx.rapidwright.device.SitePin; import com.xilinx.rapidwright.router.RouteThruHelper; import com.xilinx.rapidwright.support.RapidWrightDCP; @@ -52,7 +53,9 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; public class TestGlobalSignalRouting { @ParameterizedTest @@ -324,11 +327,18 @@ public void testMuxOutPinAsStaticSourceEvenWithLutRam(boolean setFmuxCtag, boole public void testSymmetricClkRouting() { Design design = RapidWrightDCP.loadDCP("two_clk_check_NetTools.dcp"); design.unrouteDesign(); + // Simulate the preserve method + Set used = new HashSet<>(); for (String netName : Arrays.asList("clk1_IBUF_BUFG", "clk2_IBUF_BUFG", "rst1", "rst2")) { Net net = design.getNet(netName); Assertions.assertTrue(NetTools.isGlobalClock(net)); - GlobalSignalRouting.symmetricClkRouting(net, design.getDevice(), (n) -> NodeStatus.AVAILABLE); + GlobalSignalRouting.symmetricClkRouting(net, design.getDevice(), (n) -> used.contains(n) ? NodeStatus.UNAVAILABLE : NodeStatus.AVAILABLE); + for (PIP pip: net.getPIPs()) { + for (Node node: Arrays.asList(pip.getStartNode(), pip.getEndNode())) { + if (node != null) used.add(node); + } + } } if (FileTools.isVivadoOnPath()) { From 28106d03a0997141056e9e1c129e150a0ae9d2a4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 19 Nov 2024 11:17:58 -0800 Subject: [PATCH 14/28] Check nets are routed Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/rwroute/TestGlobalSignalRouting.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestGlobalSignalRouting.java b/test/src/com/xilinx/rapidwright/rwroute/TestGlobalSignalRouting.java index ba8d5e192..379dd822d 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestGlobalSignalRouting.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestGlobalSignalRouting.java @@ -339,6 +339,10 @@ public void testSymmetricClkRouting() { if (node != null) used.add(node); } } + DesignTools.updatePinsIsRouted(net); + for (SitePinInst spi : net.getPins()) { + Assertions.assertTrue(spi.isRouted()); + } } if (FileTools.isVivadoOnPath()) { From 27cc5009e3d2096fcbf0ca63eb11b01bc67427b9 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 19 Nov 2024 11:39:18 -0800 Subject: [PATCH 15/28] Refactor Signed-off-by: Eddie Hung --- .../router/VersalClockRouting.java | 61 +++++++++++++++++ .../rwroute/GlobalSignalRouting.java | 65 +------------------ 2 files changed, 62 insertions(+), 64 deletions(-) diff --git a/src/com/xilinx/rapidwright/router/VersalClockRouting.java b/src/com/xilinx/rapidwright/router/VersalClockRouting.java index f1307fa7a..0e8087926 100644 --- a/src/com/xilinx/rapidwright/router/VersalClockRouting.java +++ b/src/com/xilinx/rapidwright/router/VersalClockRouting.java @@ -35,6 +35,7 @@ import com.xilinx.rapidwright.device.Wire; import com.xilinx.rapidwright.rwroute.NodeStatus; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; @@ -722,4 +723,64 @@ public static void incrementalClockRouter(Net clkNet, // Set uniquePIPs = new HashSet<>(clkNet.getPIPs()); // clkNet.setPIPs(uniquePIPs); } + + public static Map> routeLCBsToSinks(Net clk, + Function getNodeStatus) { + Map> lcbMappings = new HashMap<>(); + Set allowedIntentCodes = EnumSet.of( + IntentCode.NODE_CLE_CNODE, + IntentCode.NODE_INTF_CNODE, + IntentCode.NODE_INODE, + IntentCode.NODE_PINBOUNCE, + IntentCode.NODE_CLE_BNODE, + IntentCode.NODE_INTF_BNODE, + IntentCode.NODE_IMUX, + IntentCode.NODE_CLE_CTRL, + IntentCode.NODE_INTF_CTRL, + IntentCode.NODE_IRI, + IntentCode.NODE_PINFEED, + IntentCode.NODE_GLOBAL_LEAF + ); + Set visited = new HashSet<>(); + Queue q = new LinkedList<>(); + Predicate isNodeUnavailable = (node) -> getNodeStatus.apply(node) == NodeStatus.UNAVAILABLE; + RouteThruHelper routeThruHelper = new RouteThruHelper(clk.getDesign().getDevice()); + + nextPin: for (SitePinInst p: clk.getPins()) { + if (p.isOutPin()) continue; + Node sinkNode = p.getConnectedNode(); + RouteNode sinkRouteNode = new RouteNode(sinkNode.getTile(), sinkNode.getWireIndex(), null, 0); + ClockRegion cr = p.getTile().getClockRegion(); + + q.clear(); + q.add(sinkRouteNode); + + while (!q.isEmpty()) { + RouteNode curr = q.poll(); + Node currNode = Node.getNode(curr); + + for (Node uphill : currNode.getAllUphillNodes()) { + if (!uphill.getTile().getClockRegion().equals(cr)) continue; + if (!allowedIntentCodes.contains(uphill.getIntentCode())) continue; + if (!visited.add(uphill)) continue; + // if (used.contains(uphill)) continue; + if (routeThruHelper.isRouteThru(uphill, currNode) && currNode.getIntentCode() != IntentCode.NODE_IRI) continue; + if (isNodeUnavailable.test(uphill)) continue; + if (uphill.getIntentCode() == IntentCode.NODE_GLOBAL_LEAF) { + RouteNode rn = new RouteNode(uphill.getTile(), uphill.getWireIndex(), curr, curr.getLevel()+1); + clk.getPIPs().addAll(rn.getPIPsForwardToSinkByNodes()); + rn.setParent(null); + rn.setLevel(0); + lcbMappings.computeIfAbsent(rn, (k) -> new ArrayList<>()).add(p); + visited.clear(); + continue nextPin; + } + q.add(new RouteNode(uphill.getTile(), uphill.getWireIndex(), curr, curr.getLevel()+1)); + } + } + throw new RuntimeException("ERROR: Couldn't map Pin " + p + " to LCB."); + } + + return lcbMappings; + } } diff --git a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java index 45d6f3f50..a94ecec07 100644 --- a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java +++ b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java @@ -27,14 +27,12 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Queue; import java.util.Set; import java.util.function.Function; -import java.util.function.Predicate; import com.xilinx.rapidwright.design.Design; import com.xilinx.rapidwright.design.Net; @@ -287,7 +285,7 @@ public static void symmetricClkRouting(Net clk, Device device, Function> lcbMappings = getLCBPinMappingsOnVersal(clk, getNodeStatus); + Map> lcbMappings = VersalClockRouting.routeLCBsToSinks(clk, getNodeStatus); VersalClockRouting.routeDistributionToLCBs(clk, upDownDistLines, lcbMappings.keySet()); } @@ -380,67 +378,6 @@ public static Map> getLCBPinMappings(List> getLCBPinMappingsOnVersal(Net clk, - Function getNodeStatus) { - Map> lcbMappings = new HashMap<>(); - Set allowedIntentCodes = EnumSet.of( - IntentCode.NODE_GLOBAL_LEAF, - IntentCode.NODE_CLE_CNODE, - IntentCode.NODE_INTF_CNODE, - IntentCode.NODE_INODE, - IntentCode.NODE_PINBOUNCE, - IntentCode.NODE_CLE_BNODE, - IntentCode.NODE_INTF_BNODE, - IntentCode.NODE_IMUX, - IntentCode.NODE_CLE_CTRL, - IntentCode.NODE_INTF_CTRL, - IntentCode.NODE_IRI, - IntentCode.NODE_PINFEED, - IntentCode.NODE_GLOBAL_LEAF - ); - Set visited = new HashSet<>(); - Queue q = new LinkedList<>(); - Predicate isNodeUnavailable = (node) -> getNodeStatus.apply(node) == NodeStatus.UNAVAILABLE; - RouteThruHelper routeThruHelper = new RouteThruHelper(clk.getDesign().getDevice()); - - nextPin: for (SitePinInst p: clk.getPins()) { - if (p.isOutPin()) continue; - Node sinkNode = p.getConnectedNode(); - RouteNode sinkRouteNode = new RouteNode(sinkNode.getTile(), sinkNode.getWireIndex(), null, 0); - ClockRegion cr = p.getTile().getClockRegion(); - - q.clear(); - q.add(sinkRouteNode); - - while (!q.isEmpty()) { - RouteNode curr = q.poll(); - Node currNode = Node.getNode(curr); - - for (Node uphill : currNode.getAllUphillNodes()) { - if (!uphill.getTile().getClockRegion().equals(cr)) continue; - if (!allowedIntentCodes.contains(uphill.getIntentCode())) continue; - if (!visited.add(uphill)) continue; - // if (used.contains(uphill)) continue; - if (routeThruHelper.isRouteThru(uphill, currNode) && currNode.getIntentCode() != IntentCode.NODE_IRI) continue; - if (isNodeUnavailable.test(uphill)) continue; - if (uphill.getIntentCode() == IntentCode.NODE_GLOBAL_LEAF) { - RouteNode rn = new RouteNode(uphill.getTile(), uphill.getWireIndex(), curr, curr.getLevel()+1); - clk.getPIPs().addAll(rn.getPIPsForwardToSinkByNodes()); - rn.setParent(null); - rn.setLevel(0); - lcbMappings.computeIfAbsent(rn, (k) -> new ArrayList<>()).add(p); - visited.clear(); - continue nextPin; - } - q.add(new RouteNode(uphill.getTile(), uphill.getWireIndex(), curr, curr.getLevel()+1)); - } - } - throw new RuntimeException("ERROR: Couldn't map Pin " + p + " to LCB."); - } - - return lcbMappings; - } - /** * Finds the centroid clock region of a clock net. * @param clk The clock net of a design. From e0bb6514484bf726f0491a2d18393f048d3ebcb2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 19 Nov 2024 11:40:32 -0800 Subject: [PATCH 16/28] VersalClockRouting.routeToCentroid() always has adjusted=true Signed-off-by: Eddie Hung --- .../router/VersalClockRouting.java | 32 ++++++++----------- .../rwroute/GlobalSignalRouting.java | 6 ++-- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/com/xilinx/rapidwright/router/VersalClockRouting.java b/src/com/xilinx/rapidwright/router/VersalClockRouting.java index 0e8087926..4afb69c94 100644 --- a/src/com/xilinx/rapidwright/router/VersalClockRouting.java +++ b/src/com/xilinx/rapidwright/router/VersalClockRouting.java @@ -84,10 +84,9 @@ public static RouteNode routeBUFGToNearestRoutingTrack(Net clk) { * @param clk The current clock net to contribute routing. * @param startingRouteNode The intermediate start point of the clock route. * @param clockRegion The center clock region or the clock region that is one row above or below the center. - * @param adjusted A flag to guard the default functionality when routing to centroid clock region. * @param findCentroidHroute The flag to indicate the returned RouteNode should be HROUTE in the center or VROUTE going up or down. */ - public static RouteNode routeToCentroid(Net clk, RouteNode startingRouteNode, ClockRegion clockRegion, boolean adjusted, boolean findCentroidHroute) { + public static RouteNode routeToCentroid(Net clk, RouteNode startingRouteNode, ClockRegion clockRegion, boolean findCentroidHroute) { Queue q = RouteNode.createPriorityQueue(); startingRouteNode.setParent(null); q.add(startingRouteNode); @@ -125,28 +124,25 @@ public static RouteNode routeToCentroid(Net clk, RouteNode startingRouteNode, Cl clockRegion.equals(currNode.getTile().getClockRegion()) && clockRegion.equals(parentNode.getTile().getClockRegion()) && parentNode.getWireName().contains("BOT")) { - if (adjusted) { - if (findCentroidHroute) { - centroidHRouteNode = curr.getParent(); - while (centroidHRouteNode.getIntentCode() != IntentCode.NODE_GLOBAL_HROUTE_HSR) { - centroidHRouteNode = centroidHRouteNode.getParent(); - } - clk.getPIPs().addAll(centroidHRouteNode.getPIPsBackToSourceByNodes()); - return centroidHRouteNode; + if (findCentroidHroute) { + centroidHRouteNode = curr.getParent(); + while (centroidHRouteNode.getIntentCode() != IntentCode.NODE_GLOBAL_HROUTE_HSR) { + centroidHRouteNode = centroidHRouteNode.getParent(); } - // assign PIPs based on which RouteNode returned, instead of curr - clk.getPIPs().addAll(parent.getPIPsBackToSourceByNodes()); - return parent; - } else { - clk.getPIPs().addAll(curr.getPIPsBackToSourceByNodes()); - return curr; + clk.getPIPs().addAll(centroidHRouteNode.getPIPsBackToSourceByNodes()); + return centroidHRouteNode; } + // assign PIPs based on which RouteNode returned, instead of curr + clk.getPIPs().addAll(parent.getPIPsBackToSourceByNodes()); + return parent; } } // Only using routing lines to get to centroid - if (!allowedIntentCodes.contains(downhill.getIntentCode())) continue; - if (adjusted && !findCentroidHroute && downhill.getIntentCode() == IntentCode.NODE_GLOBAL_HROUTE_HSR) { + if (!allowedIntentCodes.contains(downhill.getIntentCode())) { + continue; + } + if (!findCentroidHroute && downhill.getIntentCode() == IntentCode.NODE_GLOBAL_HROUTE_HSR) { continue; } if (visited.contains(downhill)) continue; diff --git a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java index a94ecec07..19da8ea30 100644 --- a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java +++ b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java @@ -255,7 +255,7 @@ public static void symmetricClkRouting(Net clk, Device device, Function Date: Tue, 19 Nov 2024 11:43:40 -0800 Subject: [PATCH 17/28] More refactoring Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/GlobalSignalRouting.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java index 19da8ea30..16775f426 100644 --- a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java +++ b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java @@ -240,11 +240,13 @@ public static void symmetricClkRouting(Net clk, Device device, Function Date: Tue, 19 Nov 2024 11:46:13 -0800 Subject: [PATCH 18/28] Remove println()-s Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java index 16775f426..f5dc73cf4 100644 --- a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java +++ b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java @@ -242,7 +242,6 @@ public static void symmetricClkRouting(Net clk, Device device, Function Date: Tue, 19 Nov 2024 11:59:41 -0800 Subject: [PATCH 19/28] Cleanup comments Signed-off-by: Eddie Hung --- .../router/VersalClockRouting.java | 165 +----------------- 1 file changed, 5 insertions(+), 160 deletions(-) diff --git a/src/com/xilinx/rapidwright/router/VersalClockRouting.java b/src/com/xilinx/rapidwright/router/VersalClockRouting.java index 4afb69c94..0c81234a9 100644 --- a/src/com/xilinx/rapidwright/router/VersalClockRouting.java +++ b/src/com/xilinx/rapidwright/router/VersalClockRouting.java @@ -97,7 +97,6 @@ public static RouteNode routeToCentroid(Net clk, RouteNode startingRouteNode, Cl IntentCode.NODE_GLOBAL_VROUTE, IntentCode.NODE_GLOBAL_VDISTR_LVL2 ); - // Tile approxTarget = clockRegion.getApproximateCenter(); int watchDog = 10000000; RouteNode centroidHRouteNode = null; Set visited = new HashSet<>(); @@ -149,7 +148,7 @@ public static RouteNode routeToCentroid(Net clk, RouteNode startingRouteNode, Cl RouteNode rn = new RouteNode(downhill.getTile(), downhill.getWireIndex(), curr, curr.getLevel()+1); // The clockRegion.getApproximateCenter() may return an INVALID_* tile with huge coordinates. - // Here we use the manhatten distance to the target clock region as the cost. + // Here we use the Manhattan distance to the target clock region as the cost. ClockRegion rnClockRegion = rn.getTile().getClockRegion(); int cost = Math.abs(rnClockRegion.getColumn() - clockRegion.getColumn()) + Math.abs(rnClockRegion.getRow() - clockRegion.getRow()); rn.setCost(cost); @@ -242,7 +241,6 @@ public static Map routeVrouteToVerticalDistributionLines assert(vroute.getParent() == null); // Pattern: NODE_GLOBAL_VROUTE -> ... -> NODE_GLOBAL_VDISTR_LVL2 -> ... -> NODE_GLOBAL_VDISTR_LVL1 -> ... -> NODE_GLOBAL_VDISTR Set allowedIntentCodes = EnumSet.of( - // IntentCode.NODE_GLOBAL_VROUTE, IntentCode.NODE_GLOBAL_VDISTR, IntentCode.NODE_GLOBAL_VDISTR_LVL1, IntentCode.NODE_GLOBAL_VDISTR_LVL2, @@ -255,7 +253,6 @@ public static Map routeVrouteToVerticalDistributionLines Tile crTarget = cr.getApproximateCenter(); while (!q.isEmpty()) { RouteNode curr = q.poll(); - // visited.add(curr); Node currNode = Node.getNode(curr); IntentCode c = currNode.getIntentCode(); ClockRegion currCR = currNode.getTile().getClockRegion(); @@ -264,7 +261,6 @@ public static Map routeVrouteToVerticalDistributionLines if (getNodeStatus.apply(currNode) == NodeStatus.INUSE) { startingPoints.add(curr); } else { - // List pips = curr.getPIPsBackToSource(); List pips = curr.getPIPsBackToSourceByNodes(); allPIPs.addAll(pips); for (PIP p : pips) { @@ -308,7 +304,6 @@ public static Map routeVerticalToHorizontalDistributionL Map vertDistLines, Collection clockRegions, Function getNodeStatus) { - // List distLines = new ArrayList<>(); Map distLines = new HashMap<>(); Queue q = new LinkedList<>(); Set allPIPs = new HashSet<>(); @@ -320,17 +315,14 @@ public static Map routeVerticalToHorizontalDistributionL IntentCode.NODE_GLOBAL_HDISTR_LOCAL, IntentCode.NODE_GLOBAL_GCLK ); - // nextClockRegion: for (Entry e : crMap.entrySet()) { nextClockRegion: for (ClockRegion targetCR : clockRegions) { q.clear(); RouteNode vertDistLine = vertDistLines.get(targetCR); - // assert(vertDistLine.getParent() == null); vertDistLine.setParent(null); q.add(vertDistLine); visited.clear(); visited.add(Node.getNode(vertDistLine)); - // ClockRegion targetCR = e.getKey(); while (!q.isEmpty()) { RouteNode curr = q.poll(); IntentCode c = curr.getIntentCode(); @@ -339,7 +331,6 @@ public static Map routeVerticalToHorizontalDistributionL if (targetCR.equals(curr.getTile().getClockRegion()) && c == IntentCode.NODE_GLOBAL_GCLK && parent.getIntentCode() == IntentCode.NODE_GLOBAL_HDISTR_LOCAL) { - // List pips = parent.getPIPsBackToSource(); List pips = parent.getPIPsBackToSourceByNodes(); for (PIP pip : pips) { allPIPs.add(pip); @@ -490,7 +481,6 @@ public static void routeLCBsToSinks(Net clk, Map> l currPIPs.add(pip); NodeStatus status = getNodeStatus.apply(pip.getStartNode()); if (status == NodeStatus.INUSE) { - // break; inuse = true; continue; } @@ -558,22 +548,8 @@ public static Map routeToHorizontalDistributionLines(Net public static void incrementalClockRouter(Design design, Net clkNet, Function getNodeStatus) { - // TODO: hasn't supported incrementalClockRouter on Versal devices yet. - throw new RuntimeException("Hasn't supported incrementalClockRouter on Versal devices yet."); - - // // Assume all existing site pins are already routed - // Set existingPins = new HashSet<>(clkNet.getSinkPins()); - - // // Find any missing site pins, to be used as target, routable sinks - // DesignTools.createMissingSitePinInsts(design, clkNet); - - // List createdPins = new ArrayList<>(clkNet.getSinkPins()); - // createdPins.removeAll(existingPins); - - // if (createdPins.isEmpty()) - // return; - - // incrementalClockRouter(clkNet, createdPins, getNodeStatus); + // TODO: + throw new RuntimeException("ERROR: incrementalClockRouter not yet support on Versal devices."); } /** @@ -586,138 +562,8 @@ public static void incrementalClockRouter(Design design, public static void incrementalClockRouter(Net clkNet, List clkPins, Function getNodeStatus) { - // TODO: hasn't supported incrementalClockRouter on Versal devices yet. - throw new RuntimeException("Hasn't supported incrementalClockRouter on Versal devices yet."); - - // // Find all horizontal distribution lines to be used as starting points and create a map - // // lookup by clock region - // Map> startingPoints = new HashMap<>(); - // Set vroutesUp = new HashSet<>(); - // Set vroutesDown = new HashSet<>(); - // int centroidY = -1; - // for (PIP p : clkNet.getPIPs()) { - // Node startNode = p.getStartNode(); - // Node endNode = p.getEndNode(); - // for (Node node : new Node[] {startNode, endNode}) { - // if (node == null) continue; - // IntentCode ic = node.getIntentCode(); - // if (ic == IntentCode.NODE_GLOBAL_HDISTR) { - // for (Wire w : node.getAllWiresInNode()) { - // RouteNode rn = new RouteNode(w.getTile(), w.getWireIndex()); - // ClockRegion cr = w.getTile().getClockRegion(); - // if (cr != null) { - // assert(rn.getParent() == null); - // startingPoints.computeIfAbsent(cr, n -> new HashSet<>()) - // .add(rn); - // } - // } - // } else if (node == startNode && endNode.getIntentCode() == IntentCode.NODE_GLOBAL_VDISTR) { - // if (ic == IntentCode.NODE_GLOBAL_VROUTE || ic == IntentCode.NODE_GLOBAL_HROUTE) { - // // Centroid lays where {HROUTE, VROUTE} -> VDISTR - // assert(centroidY == -1); - // centroidY = p.getTile().getTileYCoordinate(); - // } else { - // Tile startTile = startNode.getTile(); - // Tile endTile = endNode.getTile(); - // if (endTile == startTile) { - // for (Wire w : endNode.getAllWiresInNode()) { - // if (w.getTile() != endTile) { - // endTile = w.getTile(); - // break; - // } - // } - // } - - // int startTileY = startTile.getTileYCoordinate(); - // int endTileY = endTile.getTileYCoordinate(); - // if (endTileY > startTileY) { - // vroutesUp.add(endNode); - // } else if (endTileY < startTileY) { - // vroutesDown.add(endNode); - // } - // } - // } - // } - // } - // assert(centroidY != -1); - - // Node currNode = null; - // int currDelta = Integer.MAX_VALUE; - // for (Node node : vroutesUp) { - // int delta = node.getTile().getTileYCoordinate() - centroidY; - // assert(delta >= 0); - // if (delta < currDelta) { - // currDelta = delta; - // currNode = node; - // } - // } - // RouteNode vrouteUp = currNode != null ? new RouteNode(currNode.getTile(), currNode.getWireIndex()) : null; - - // currNode = null; - // currDelta = Integer.MAX_VALUE; - // for (Node node : vroutesDown) { - // int delta = centroidY - node.getTile().getTileYCoordinate(); - // assert(delta >= 0); - // if (delta < currDelta) { - // currDelta = delta; - // currNode = node; - // } - // } - // RouteNode vrouteDown = currNode != null ? new RouteNode(currNode.getTile(), currNode.getWireIndex()) : null; - - // // Find the target leaf clock buffers (LCBs), route from horizontal dist lines to those - // Map> lcbMappings = GlobalSignalRouting.getLCBPinMappings(clkPins, getNodeStatus); - - // final int finalCentroidY = centroidY; - // Set newUpClockRegions = new HashSet<>(); - // Set newDownClockRegions = new HashSet<>(); - // for (Map.Entry> e : lcbMappings.entrySet()) { - // RouteNode lcb = e.getKey(); - // ClockRegion currCR = lcb.getTile().getClockRegion(); - // startingPoints.computeIfAbsent(currCR, n -> { - // if (currCR.getUpperLeft().getTileYCoordinate() > finalCentroidY) { - // newUpClockRegions.add(currCR); - // } else { - // newDownClockRegions.add(currCR); - // } - // return new HashSet<>(); - // }); - // } - // if (!newUpClockRegions.isEmpty()) { - // List upLines = UltraScaleClockRouting.routeToHorizontalDistributionLines(clkNet, - // vrouteUp, - // newUpClockRegions, - // false, - // getNodeStatus); - // if (upLines != null) { - // for (RouteNode rnode : upLines) { - // rnode.setParent(null); - // startingPoints.get(rnode.getTile().getClockRegion()).add(rnode); - // } - // } - // } - // if (!newDownClockRegions.isEmpty()) { - // List downLines = UltraScaleClockRouting.routeToHorizontalDistributionLines(clkNet, - // vrouteDown, - // newDownClockRegions, - // true, - // getNodeStatus); - // if (downLines != null) { - // for (RouteNode rnode : downLines) { - // rnode.setParent(null); - // startingPoints.get(rnode.getTile().getClockRegion()).add(rnode); - // } - // } - // } - - // UltraScaleClockRouting.routeToLCBs(clkNet, startingPoints, lcbMappings.keySet()); - - // // Last mile routing from LCBs to SLICEs - // UltraScaleClockRouting.routeLCBsToSinks(clkNet, lcbMappings, getNodeStatus); - - // // Remove duplicates - // Set uniquePIPs = new HashSet<>(clkNet.getPIPs()); - // clkNet.setPIPs(uniquePIPs); + // TODO: + throw new RuntimeException("ERROR: incrementalClockRouter not yet support on Versal devices."); } public static Map> routeLCBsToSinks(Net clk, @@ -759,7 +605,6 @@ public static Map> routeLCBsToSinks(Net clk, if (!uphill.getTile().getClockRegion().equals(cr)) continue; if (!allowedIntentCodes.contains(uphill.getIntentCode())) continue; if (!visited.add(uphill)) continue; - // if (used.contains(uphill)) continue; if (routeThruHelper.isRouteThru(uphill, currNode) && currNode.getIntentCode() != IntentCode.NODE_IRI) continue; if (isNodeUnavailable.test(uphill)) continue; if (uphill.getIntentCode() == IntentCode.NODE_GLOBAL_LEAF) { From c43c9fe7e5882d1d7b49a5fb1d477cd50799af2a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 19 Nov 2024 12:23:48 -0800 Subject: [PATCH 20/28] More tidying Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/device/IntentCode.java | 6 +++ .../router/VersalClockRouting.java | 52 +++++++------------ 2 files changed, 25 insertions(+), 33 deletions(-) diff --git a/src/com/xilinx/rapidwright/device/IntentCode.java b/src/com/xilinx/rapidwright/device/IntentCode.java index 2b084c9c5..4e92c8726 100644 --- a/src/com/xilinx/rapidwright/device/IntentCode.java +++ b/src/com/xilinx/rapidwright/device/IntentCode.java @@ -158,6 +158,12 @@ public boolean isUltraScaleClockDistribution() { return NODE_GLOBAL_HDISTR == this || NODE_GLOBAL_VDISTR == this; } + public boolean isVersalClocking() { + return NODE_GLOBAL_HDISTR == this || NODE_GLOBAL_HDISTR_LOCAL == this || NODE_GLOBAL_HROUTE_HSR == this || + NODE_GLOBAL_VDISTR == this || NODE_GLOBAL_VDISTR_LVL2 == this || NODE_GLOBAL_VROUTE == this || + NODE_GLOBAL_GCLK == this || NODE_GLOBAL_LEAF == this || NODE_GLOBAL_BUFG == this; + } + private static final int SERIES7_START_IDX = 23; private static final int SERIES7_END_IDX = SERIES7_START_IDX + 33 - 1; diff --git a/src/com/xilinx/rapidwright/router/VersalClockRouting.java b/src/com/xilinx/rapidwright/router/VersalClockRouting.java index 0c81234a9..69ef74e9c 100644 --- a/src/com/xilinx/rapidwright/router/VersalClockRouting.java +++ b/src/com/xilinx/rapidwright/router/VersalClockRouting.java @@ -110,6 +110,7 @@ public static RouteNode routeToCentroid(Net clk, RouteNode startingRouteNode, Cl Node currNode = Node.getNode(curr); RouteNode parent = curr.getParent(); for (Node downhill : currNode.getAllDownhillNodes()) { + IntentCode intentCode = downhill.getIntentCode(); if (parent != null) { Node parentNode = Node.getNode(parent); if (parentNode.getIntentCode() == IntentCode.NODE_GLOBAL_VROUTE && @@ -117,7 +118,7 @@ public static RouteNode routeToCentroid(Net clk, RouteNode startingRouteNode, Cl // Disallow ability to go from VROUTE back to HROUTE continue; } - if (downhill.getIntentCode() == IntentCode.NODE_GLOBAL_VDISTR_LVL2 && + if (intentCode == IntentCode.NODE_GLOBAL_VDISTR_LVL2 && currNode.getIntentCode() == IntentCode.NODE_GLOBAL_GCLK && parentNode.getIntentCode() == IntentCode.NODE_GLOBAL_VROUTE && clockRegion.equals(currNode.getTile().getClockRegion()) && @@ -138,13 +139,13 @@ public static RouteNode routeToCentroid(Net clk, RouteNode startingRouteNode, Cl } // Only using routing lines to get to centroid - if (!allowedIntentCodes.contains(downhill.getIntentCode())) { + if (!intentCode.isVersalClocking()) { continue; } - if (!findCentroidHroute && downhill.getIntentCode() == IntentCode.NODE_GLOBAL_HROUTE_HSR) { + if (!findCentroidHroute && intentCode == IntentCode.NODE_GLOBAL_HROUTE_HSR) { continue; } - if (visited.contains(downhill)) continue; + if (!visited.add(downhill)) continue; RouteNode rn = new RouteNode(downhill.getTile(), downhill.getWireIndex(), curr, curr.getLevel()+1); // The clockRegion.getApproximateCenter() may return an INVALID_* tile with huge coordinates. @@ -153,7 +154,6 @@ public static RouteNode routeToCentroid(Net clk, RouteNode startingRouteNode, Cl int cost = Math.abs(rnClockRegion.getColumn() - clockRegion.getColumn()) + Math.abs(rnClockRegion.getRow() - clockRegion.getRow()); rn.setCost(cost); q.add(rn); - visited.add(downhill); } if (watchDog-- == 0) { throw new RuntimeException("ERROR: Could not route from " + startingRouteNode + " to clock region " + clockRegion); @@ -296,30 +296,22 @@ public static Map routeVrouteToVerticalDistributionLines * Routes from a vertical distribution centroid to destination horizontal distribution lines * in the clock regions provided. * @param clk The current clock net - * @param vertDistLines A map of target clock regions and their respective vertical distribution lines - * @param clockRegions target clock regions + * @param crMap A map of target clock regions and their respective vertical distribution lines * @return The List of nodes from the centroid to the horizontal distribution line. */ public static Map routeVerticalToHorizontalDistributionLines(Net clk, - Map vertDistLines, - Collection clockRegions, - Function getNodeStatus) { + Map crMap, + Function getNodeStatus) { Map distLines = new HashMap<>(); Queue q = new LinkedList<>(); Set allPIPs = new HashSet<>(); Set visited = new HashSet<>(); - Set allowedIntentCodes = EnumSet.of( - IntentCode.NODE_GLOBAL_HDISTR, - IntentCode.NODE_GLOBAL_VDISTR, - IntentCode.NODE_PINFEED, - IntentCode.NODE_GLOBAL_HDISTR_LOCAL, - IntentCode.NODE_GLOBAL_GCLK - ); - nextClockRegion: for (ClockRegion targetCR : clockRegions) { + nextClockRegion: for (Entry e : crMap.entrySet()) { q.clear(); - RouteNode vertDistLine = vertDistLines.get(targetCR); + RouteNode vertDistLine = e.getValue(); vertDistLine.setParent(null); q.add(vertDistLine); + ClockRegion targetCR = e.getKey(); visited.clear(); visited.add(Node.getNode(vertDistLine)); @@ -328,9 +320,8 @@ public static Map routeVerticalToHorizontalDistributionL IntentCode c = curr.getIntentCode(); Node currNode = Node.getNode(curr); RouteNode parent = curr.getParent(); - if (targetCR.equals(curr.getTile().getClockRegion()) && - c == IntentCode.NODE_GLOBAL_GCLK && - parent.getIntentCode() == IntentCode.NODE_GLOBAL_HDISTR_LOCAL) { + if (targetCR.equals(curr.getTile().getClockRegion()) && c == IntentCode.NODE_GLOBAL_GCLK && + parent.getIntentCode() == IntentCode.NODE_GLOBAL_HDISTR_LOCAL) { List pips = parent.getPIPsBackToSourceByNodes(); for (PIP pip : pips) { allPIPs.add(pip); @@ -347,9 +338,9 @@ public static Map routeVerticalToHorizontalDistributionL } for (Node downhill: currNode.getAllDownhillNodes()) { - if (!allowedIntentCodes.contains(downhill.getIntentCode())) continue; - if (visited.contains(downhill)) continue; - visited.add(downhill); + IntentCode intentCode = downhill.getIntentCode(); + if (intentCode != IntentCode.NODE_PINFEED && !intentCode.isVersalClocking()) continue; + if (!visited.add(downhill)) continue; q.add(new RouteNode(downhill.getTile(), downhill.getWireIndex(), curr, curr.getLevel()+1)); } } @@ -382,11 +373,6 @@ public static void routeToLCBs(Net clk, Map> startin Queue q = RouteNode.createPriorityQueue(); Set allPIPs = new HashSet<>(); HashSet visited = new HashSet<>(); - Set allowedIntentCodes = EnumSet.of( - IntentCode.NODE_PINFEED, - IntentCode.NODE_GLOBAL_LEAF, - IntentCode.NODE_GLOBAL_GCLK - ); nextLCB: for (RouteNode lcb : lcbTargets) { q.clear(); @@ -415,7 +401,8 @@ public static void routeToLCBs(Net clk, Map> startin for (Node downhill : currNode.getAllDownhillNodes()) { // Stay in this clock region if (!currCR.equals(downhill.getTile().getClockRegion())) continue; - if (!allowedIntentCodes.contains(downhill.getIntentCode())) continue; + IntentCode intentCode = downhill.getIntentCode(); + if (intentCode != IntentCode.NODE_PINFEED && !intentCode.isVersalClocking()) continue; RouteNode rn = new RouteNode(downhill.getTile(), downhill.getWireIndex(), curr, curr.getLevel()+1); if (visited.contains(rn)) continue; if (rn.getWireName().endsWith("_I_CASC_PIN")) continue; @@ -531,8 +518,7 @@ public static Map routeToHorizontalDistributionLines(Net Map vertDistLines = routeVrouteToVerticalDistributionLines(clk, vroute, clockRegions, getNodeStatus); // Second step: start from the VDISTR node and try to find a HDISTR node in the target clock region. - Map horiDistLines = routeVerticalToHorizontalDistributionLines(clk, vertDistLines, clockRegions, getNodeStatus); - return horiDistLines; + return routeVerticalToHorizontalDistributionLines(clk, vertDistLines, getNodeStatus); } /** From 690a78fe93e4f0925fbb2b55f0e32dc84f0aa0cf Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 22 Nov 2024 10:46:20 -0800 Subject: [PATCH 21/28] First phase of cleanup; do not pass RouteNode between methods Signed-off-by: Eddie Hung --- .../router/VersalClockRouting.java | 125 ++++++++---------- .../rwroute/GlobalSignalRouting.java | 13 +- .../rapidwright/rwroute/RouterHelper.java | 47 ++++--- 3 files changed, 90 insertions(+), 95 deletions(-) diff --git a/src/com/xilinx/rapidwright/router/VersalClockRouting.java b/src/com/xilinx/rapidwright/router/VersalClockRouting.java index 69ef74e9c..92e3368dc 100644 --- a/src/com/xilinx/rapidwright/router/VersalClockRouting.java +++ b/src/com/xilinx/rapidwright/router/VersalClockRouting.java @@ -34,6 +34,8 @@ import com.xilinx.rapidwright.device.Tile; import com.xilinx.rapidwright.device.Wire; import com.xilinx.rapidwright.rwroute.NodeStatus; +import com.xilinx.rapidwright.rwroute.RouterHelper; +import com.xilinx.rapidwright.rwroute.RouterHelper.NodeWithPrev; import java.util.ArrayList; import java.util.Collection; @@ -58,22 +60,24 @@ */ public class VersalClockRouting { - public static RouteNode routeBUFGToNearestRoutingTrack(Net clk) { - Queue q = new LinkedList<>(); - q.add(new RouteNode(clk.getSource())); + public static Node routeBUFGToNearestRoutingTrack(Net clk) { + Queue q = new LinkedList<>(); + q.add(new NodeWithPrev(clk.getSource().getConnectedNode())); int watchDog = 300; while (!q.isEmpty()) { - RouteNode curr = q.poll(); - Node currNode = Node.getNode(curr); - IntentCode c = currNode.getIntentCode(); + NodeWithPrev curr = q.poll(); + IntentCode c = curr.getIntentCode(); if (c == IntentCode.NODE_GLOBAL_HROUTE_HSR) { - clk.getPIPs().addAll(curr.getPIPsBackToSourceByNodes()); + List path = curr.getPrevPath(); + clk.getPIPs().addAll(RouterHelper.getPIPsFromNodes(path)); return curr; } - for (Node downhill: currNode.getAllDownhillNodes()) { - q.add(new RouteNode(downhill.getTile(), downhill.getWireIndex(), curr, curr.getLevel()+1)); + for (Node downhill: curr.getAllDownhillNodes()) { + q.add(new NodeWithPrev(downhill, curr)); + } + if (watchDog-- == 0) { + break; } - if (watchDog-- == 0) break; } return null; } @@ -82,23 +86,15 @@ public static RouteNode routeBUFGToNearestRoutingTrack(Net clk) { * Routes a clock from a routing track to a transition point where the clock. * fans out and transitions from clock routing tracks to clock distribution. * @param clk The current clock net to contribute routing. - * @param startingRouteNode The intermediate start point of the clock route. + * @param startingNode The intermediate start point of the clock route. * @param clockRegion The center clock region or the clock region that is one row above or below the center. * @param findCentroidHroute The flag to indicate the returned RouteNode should be HROUTE in the center or VROUTE going up or down. */ - public static RouteNode routeToCentroid(Net clk, RouteNode startingRouteNode, ClockRegion clockRegion, boolean findCentroidHroute) { + public static Node routeToCentroid(Net clk, Node startingNode, ClockRegion clockRegion, boolean findCentroidHroute) { Queue q = RouteNode.createPriorityQueue(); - startingRouteNode.setParent(null); - q.add(startingRouteNode); - Set allowedIntentCodes = EnumSet.of( - IntentCode.NODE_GLOBAL_BUFG, - IntentCode.NODE_GLOBAL_GCLK, - IntentCode.NODE_GLOBAL_HROUTE_HSR, - IntentCode.NODE_GLOBAL_VROUTE, - IntentCode.NODE_GLOBAL_VDISTR_LVL2 - ); + q.add(new RouteNode(startingNode)); int watchDog = 10000000; - RouteNode centroidHRouteNode = null; + RouteNode centroidHRouteNode; Set visited = new HashSet<>(); // In Vivado solutions, we can always find the pattern: @@ -130,11 +126,11 @@ public static RouteNode routeToCentroid(Net clk, RouteNode startingRouteNode, Cl centroidHRouteNode = centroidHRouteNode.getParent(); } clk.getPIPs().addAll(centroidHRouteNode.getPIPsBackToSourceByNodes()); - return centroidHRouteNode; + return Node.getNode(centroidHRouteNode); } // assign PIPs based on which RouteNode returned, instead of curr clk.getPIPs().addAll(parent.getPIPsBackToSourceByNodes()); - return parent; + return Node.getNode(parent); } } @@ -156,7 +152,7 @@ public static RouteNode routeToCentroid(Net clk, RouteNode startingRouteNode, Cl q.add(rn); } if (watchDog-- == 0) { - throw new RuntimeException("ERROR: Could not route from " + startingRouteNode + " to clock region " + clockRegion); + throw new RuntimeException("ERROR: Could not route from " + startingNode + " to clock region " + clockRegion); } } @@ -227,18 +223,16 @@ public static Map routeCentroidToVerticalDistributionLin return crToVdist; } - public static Map routeVrouteToVerticalDistributionLines(Net clk, - RouteNode vroute, - Collection clockRegions, - Function getNodeStatus) { - Map crToVdist = new HashMap<>(); - vroute.setParent(null); + public static Map routeVrouteToVerticalDistributionLines(Net clk, + Node vroute, + Collection clockRegions, + Function getNodeStatus) { + Map crToVdist = new HashMap<>(); Queue q = RouteNode.createPriorityQueue(); HashSet visited = new HashSet<>(); Set allPIPs = new HashSet<>(); Set startingPoints = new HashSet<>(); - startingPoints.add(vroute); - assert(vroute.getParent() == null); + startingPoints.add(new RouteNode(vroute)); // Pattern: NODE_GLOBAL_VROUTE -> ... -> NODE_GLOBAL_VDISTR_LVL2 -> ... -> NODE_GLOBAL_VDISTR_LVL1 -> ... -> NODE_GLOBAL_VDISTR Set allowedIntentCodes = EnumSet.of( IntentCode.NODE_GLOBAL_VDISTR, @@ -268,9 +262,7 @@ public static Map routeVrouteToVerticalDistributionLines startingPoints.add(p.getEndRouteNode()); } } - RouteNode currBase = new RouteNode(currNode); - currBase.setParent(null); - crToVdist.put(cr, currBase); + crToVdist.put(cr, currNode); continue nextClockRegion; } @@ -288,7 +280,6 @@ public static Map routeVrouteToVerticalDistributionLines throw new RuntimeException("ERROR: Couldn't route to distribution line in clock region " + cr); } clk.getPIPs().addAll(allPIPs); - vroute.setParent(null); return crToVdist; } @@ -299,21 +290,20 @@ public static Map routeVrouteToVerticalDistributionLines * @param crMap A map of target clock regions and their respective vertical distribution lines * @return The List of nodes from the centroid to the horizontal distribution line. */ - public static Map routeVerticalToHorizontalDistributionLines(Net clk, - Map crMap, - Function getNodeStatus) { - Map distLines = new HashMap<>(); + public static Map routeVerticalToHorizontalDistributionLines(Net clk, + Map crMap, + Function getNodeStatus) { + Map distLines = new HashMap<>(); Queue q = new LinkedList<>(); Set allPIPs = new HashSet<>(); Set visited = new HashSet<>(); - nextClockRegion: for (Entry e : crMap.entrySet()) { + nextClockRegion: for (Entry e : crMap.entrySet()) { q.clear(); - RouteNode vertDistLine = e.getValue(); - vertDistLine.setParent(null); - q.add(vertDistLine); + Node vertDistLine = e.getValue(); + q.add(new RouteNode(vertDistLine)); ClockRegion targetCR = e.getKey(); visited.clear(); - visited.add(Node.getNode(vertDistLine)); + visited.add(vertDistLine); while (!q.isEmpty()) { RouteNode curr = q.poll(); @@ -333,7 +323,7 @@ public static Map routeVerticalToHorizontalDistributionL } parent.setParent(null); - distLines.put(targetCR, parent); + distLines.put(targetCR, Node.getNode(parent)); continue nextClockRegion; } @@ -356,20 +346,22 @@ public static Map routeVerticalToHorizontalDistributionL * @param distLines A map of target clock regions and their respective horizontal distribution lines * @param lcbTargets The target LCB nodes to route the clock */ - public static void routeDistributionToLCBs(Net clk, Map distLines, Set lcbTargets) { - Map> startingPoints = getStartingPoints(distLines); + public static void routeDistributionToLCBs(Net clk, Map distLines, Set lcbTargets) { + Map> startingPoints = getStartingPoints(distLines); routeToLCBs(clk, startingPoints, lcbTargets); } - public static Map> getStartingPoints(Map distLines) { - Map> startingPoints = new HashMap<>(); - for (ClockRegion cr : distLines.keySet()) { - startingPoints.computeIfAbsent(cr, k -> new HashSet<>()).add(distLines.get(cr)); + public static Map> getStartingPoints(Map distLines) { + Map> startingPoints = new HashMap<>(); + for (Entry e : distLines.entrySet()) { + ClockRegion cr = e.getKey(); + Node distLine = e.getValue(); + startingPoints.computeIfAbsent(cr, k -> new HashSet<>()).add(distLine); } return startingPoints; } - public static void routeToLCBs(Net clk, Map> startingPoints, Set lcbTargets) { + public static void routeToLCBs(Net clk, Map> startingPoints, Set lcbTargets) { Queue q = RouteNode.createPriorityQueue(); Set allPIPs = new HashSet<>(); HashSet visited = new HashSet<>(); @@ -378,11 +370,10 @@ public static void routeToLCBs(Net clk, Map> startin q.clear(); visited.clear(); ClockRegion currCR = lcb.getTile().getClockRegion(); - Set starts = startingPoints.getOrDefault(currCR, Collections.emptySet()); - for (RouteNode rn : starts) { - assert(rn.getParent() == null); + Set starts = startingPoints.getOrDefault(currCR, Collections.emptySet()); + for (Node n : starts) { + q.add(new RouteNode(n)); } - q.addAll(starts); while (!q.isEmpty()) { RouteNode curr = q.poll(); visited.add(curr); @@ -390,10 +381,10 @@ public static void routeToLCBs(Net clk, Map> startin List pips = curr.getPIPsBackToSource(); allPIPs.addAll(pips); - Set s = startingPoints.get(currCR); + Set s = startingPoints.get(currCR); for (PIP p : pips) { - s.add(new RouteNode(p.getTile(),p.getStartWireIndex())); - s.add(new RouteNode(p.getTile(),p.getEndWireIndex())); + s.add(p.getStartNode()); + s.add(p.getEndNode()); } continue nextLCB; } @@ -508,14 +499,14 @@ public static void routeLCBsToSinks(Net clk, Map> l * @param down To indicate if it is routing to the group of top clock regions. * @return A list of RouteNodes indicating the reached horizontal distribution lines. */ - public static Map routeToHorizontalDistributionLines(Net clk, - RouteNode vroute, - Collection clockRegions, - boolean down, - Function getNodeStatus) { + public static Map routeToHorizontalDistributionLines(Net clk, + Node vroute, + Collection clockRegions, + boolean down, + Function getNodeStatus) { // First step: map each clock region to a VDISTR node. // The clock region of this VDISTR node should be in the same column of the centroid (X) and the same row of the target clock region (Y). - Map vertDistLines = routeVrouteToVerticalDistributionLines(clk, vroute, clockRegions, getNodeStatus); + Map vertDistLines = routeVrouteToVerticalDistributionLines(clk, vroute, clockRegions, getNodeStatus); // Second step: start from the VDISTR node and try to find a HDISTR node in the target clock region. return routeVerticalToHorizontalDistributionLines(clk, vertDistLines, getNodeStatus); diff --git a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java index f5dc73cf4..d19cb74cc 100644 --- a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java +++ b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java @@ -235,16 +235,15 @@ public static void symmetricClkRouting(Net clk, Device device, Function clockRegions = getClockRegionsOfNet(clk); - Map upDownDistLines = new HashMap<>(); + Map upDownDistLines; SitePinInst source = clk.getSource(); SiteTypeEnum sourceTypeEnum = source.getSiteTypeEnum(); - RouteNode sourceRouteNode = new RouteNode(source); // In US/US+ clock routing, we use two VROUTE nodes to reach the clock regions above and below the centroid. // However, we can see that Vivado only use one VROUTE node in the centroid clock region for Versal clock routing, // and reach the above and below clock regions by VDISTR nodes. ClockRegion centroid; - RouteNode centroidHRouteNode; + Node centroidHRouteNode; // In FPGA '24 routing contest benchmarks, we found that there are only two types of source sites for the clock nets: BUFGCE and BUFG_FABRIC. if (sourceTypeEnum == SiteTypeEnum.BUFG_FABRIC) { @@ -256,7 +255,7 @@ public static void symmetricClkRouting(Net clk, Device device, Function getPrevPath() { + List path = new ArrayList<>(); + NodeWithPrev curr = this; + while (curr != null) { + path.add(curr); + curr = curr.getPrev(); + } + return path; + } } /** @@ -540,14 +557,11 @@ public static boolean routeDirectConnection(Connection directConnection) { * @return A list of nodes making up the path. */ public static List findPathBetweenNodes(Node source, Node sink) { - List path = new ArrayList<>(); if (source.equals(sink)) { - return path; // for pins without additional projected int_node + return Collections.emptyList(); // for pins without additional projected int_node } if (source.getAllDownhillNodes().contains(sink)) { - path.add(sink); - path.add(source); - return path; + return Arrays.asList(sink, source); } NodeWithPrev sourcer = new NodeWithPrev(source); sourcer.setPrev(null); @@ -559,16 +573,10 @@ public static List findPathBetweenNodes(Node source, Node sink) { !Utils.isClocking(sink.getTile().getTileTypeEnum()); int watchdog = 10000; - boolean success = false; while (!queue.isEmpty()) { NodeWithPrev curr = queue.poll(); if (curr.equals(sink)) { - while (curr != null) { - path.add(curr); - curr = curr.getPrev(); - } - success = true; - break; + return curr.getPrevPath(); } for (Node n : curr.getAllDownhillNodes()) { if (blockClocking && Utils.isClocking(n.getTile().getTileTypeEnum())) { @@ -584,11 +592,8 @@ public static List findPathBetweenNodes(Node source, Node sink) { } } - if (!success) { - System.err.println("ERROR: Failed to find a path between two nodes: " + source + ", " + sink); - path.clear(); - } - return path; + System.err.println("ERROR: Failed to find a path between two nodes: " + source + ", " + sink); + return Collections.emptyList(); } /** From b914d597616d8e85fdcc832736127b846e710a66 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 22 Nov 2024 12:31:27 -0800 Subject: [PATCH 22/28] [VersalClockRouting] Rewrite without RouteNode Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/router/RouteNode.java | 26 -- .../router/VersalClockRouting.java | 434 +++++++++--------- .../rwroute/GlobalSignalRouting.java | 5 +- 3 files changed, 210 insertions(+), 255 deletions(-) diff --git a/src/com/xilinx/rapidwright/router/RouteNode.java b/src/com/xilinx/rapidwright/router/RouteNode.java index 93453eb13..061e58068 100644 --- a/src/com/xilinx/rapidwright/router/RouteNode.java +++ b/src/com/xilinx/rapidwright/router/RouteNode.java @@ -381,32 +381,6 @@ public ArrayList getPIPsBackToSource() { return pips; } - public ArrayList getPIPsBackToSourceByNodes() { - ArrayList pips = new ArrayList<>(); - RouteNode curr = this; - while (curr.parent != null) { - PIP pip = PIP.getArbitraryPIP(Node.getNode(curr.parent), Node.getNode(curr)); - if (pip != null) { - pips.add(pip); - } - curr = curr.parent; - } - return pips; - } - - public ArrayList getPIPsForwardToSinkByNodes() { - ArrayList pips = new ArrayList<>(); - RouteNode curr = this; - do { - PIP pip = PIP.getArbitraryPIP(Node.getNode(curr), Node.getNode(curr.parent)); - if (pip != null) { - pips.add(pip); - } - curr = curr.parent; - } while (curr.parent != null); - return pips; - } - public Wire[] getWiresInNode() { return Node.getWiresInNode(getTile(),getWire()); } diff --git a/src/com/xilinx/rapidwright/router/VersalClockRouting.java b/src/com/xilinx/rapidwright/router/VersalClockRouting.java index 92e3368dc..77c7d0d18 100644 --- a/src/com/xilinx/rapidwright/router/VersalClockRouting.java +++ b/src/com/xilinx/rapidwright/router/VersalClockRouting.java @@ -32,21 +32,21 @@ import com.xilinx.rapidwright.device.PIP; import com.xilinx.rapidwright.device.Tile; -import com.xilinx.rapidwright.device.Wire; import com.xilinx.rapidwright.rwroute.NodeStatus; import com.xilinx.rapidwright.rwroute.RouterHelper; import com.xilinx.rapidwright.rwroute.RouterHelper.NodeWithPrev; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.PriorityQueue; import java.util.Queue; import java.util.Set; import java.util.function.Function; @@ -59,9 +59,29 @@ * Created on: Nov 1, 2024 */ public class VersalClockRouting { + public static class NodeWithPrevAndCost extends NodeWithPrev implements Comparable { + protected int cost; + public NodeWithPrevAndCost(Node node) { + super(node); + setCost(0); + } + public NodeWithPrevAndCost(Node node, NodeWithPrev prev, int cost) { + super(node, prev); + setCost(cost); + } + + public void setCost(int cost) { + this.cost = cost; + } + + @Override + public int compareTo(NodeWithPrevAndCost that) { + return Integer.compare(this.cost, that.cost); + } + } public static Node routeBUFGToNearestRoutingTrack(Net clk) { - Queue q = new LinkedList<>(); + Queue q = new ArrayDeque<>(); q.add(new NodeWithPrev(clk.getSource().getConnectedNode())); int watchDog = 300; while (!q.isEmpty()) { @@ -88,68 +108,67 @@ public static Node routeBUFGToNearestRoutingTrack(Net clk) { * @param clk The current clock net to contribute routing. * @param startingNode The intermediate start point of the clock route. * @param clockRegion The center clock region or the clock region that is one row above or below the center. - * @param findCentroidHroute The flag to indicate the returned RouteNode should be HROUTE in the center or VROUTE going up or down. + * @param findCentroidHroute The flag to indicate the returned Node should be HROUTE in the center or VROUTE going up or down. */ public static Node routeToCentroid(Net clk, Node startingNode, ClockRegion clockRegion, boolean findCentroidHroute) { - Queue q = RouteNode.createPriorityQueue(); - q.add(new RouteNode(startingNode)); - int watchDog = 10000000; - RouteNode centroidHRouteNode; + Queue q = new PriorityQueue<>(); + q.add(new NodeWithPrevAndCost(startingNode)); + int watchDog = 10000; Set visited = new HashSet<>(); + Tile crApproxCenterTile = clockRegion.getApproximateCenter(); // In Vivado solutions, we can always find the pattern: // ... -> NODE_GLOBAL_GCLK -> NODE_GLOBAL_VROUTE -> NODE_GLOBAL_VDISTR_LVL2 -> ... // and this is how we locate the VROUTE node while (!q.isEmpty()) { - RouteNode curr = q.poll(); - Node currNode = Node.getNode(curr); - RouteNode parent = curr.getParent(); - for (Node downhill : currNode.getAllDownhillNodes()) { - IntentCode intentCode = downhill.getIntentCode(); - if (parent != null) { - Node parentNode = Node.getNode(parent); - if (parentNode.getIntentCode() == IntentCode.NODE_GLOBAL_VROUTE && - currNode.getIntentCode() == IntentCode.NODE_GLOBAL_HROUTE_HSR) { - // Disallow ability to go from VROUTE back to HROUTE - continue; - } - if (intentCode == IntentCode.NODE_GLOBAL_VDISTR_LVL2 && - currNode.getIntentCode() == IntentCode.NODE_GLOBAL_GCLK && - parentNode.getIntentCode() == IntentCode.NODE_GLOBAL_VROUTE && - clockRegion.equals(currNode.getTile().getClockRegion()) && - clockRegion.equals(parentNode.getTile().getClockRegion()) && - parentNode.getWireName().contains("BOT")) { - if (findCentroidHroute) { - centroidHRouteNode = curr.getParent(); - while (centroidHRouteNode.getIntentCode() != IntentCode.NODE_GLOBAL_HROUTE_HSR) { - centroidHRouteNode = centroidHRouteNode.getParent(); - } - clk.getPIPs().addAll(centroidHRouteNode.getPIPsBackToSourceByNodes()); - return Node.getNode(centroidHRouteNode); + NodeWithPrevAndCost curr = q.poll(); + boolean possibleCentroid = false; + Node parent = curr.getPrev(); + if (parent != null) { + IntentCode parentIntentCode = parent.getIntentCode(); + IntentCode currIntentCode = curr.getIntentCode(); + if (parentIntentCode == IntentCode.NODE_GLOBAL_VROUTE && + currIntentCode == IntentCode.NODE_GLOBAL_HROUTE_HSR) { + // Disallow ability to go from VROUTE back to HROUTE + continue; + } + if (currIntentCode == IntentCode.NODE_GLOBAL_GCLK && + parentIntentCode == IntentCode.NODE_GLOBAL_VROUTE && + clockRegion.equals(curr.getTile().getClockRegion()) && + clockRegion.equals(parent.getTile().getClockRegion()) && + parent.getWireName().contains("BOT")) { + possibleCentroid = true; + } + } + for (Node downhill : curr.getAllDownhillNodes()) { + IntentCode downhillIntentCode = downhill.getIntentCode(); + // Only using routing lines to get to centroid + if (!downhillIntentCode.isVersalClocking()) { + continue; + } + + if (possibleCentroid && downhillIntentCode == IntentCode.NODE_GLOBAL_VDISTR_LVL2) { + NodeWithPrev centroidHRouteNode = curr.getPrev(); + if (findCentroidHroute) { + while (centroidHRouteNode.getIntentCode() != IntentCode.NODE_GLOBAL_HROUTE_HSR) { + centroidHRouteNode = centroidHRouteNode.getPrev(); } - // assign PIPs based on which RouteNode returned, instead of curr - clk.getPIPs().addAll(parent.getPIPsBackToSourceByNodes()); - return Node.getNode(parent); } + List path = centroidHRouteNode.getPrevPath(); + clk.getPIPs().addAll(RouterHelper.getPIPsFromNodes(path)); + return centroidHRouteNode; } - // Only using routing lines to get to centroid - if (!intentCode.isVersalClocking()) { + if (!findCentroidHroute && downhillIntentCode == IntentCode.NODE_GLOBAL_HROUTE_HSR) { continue; } - if (!findCentroidHroute && intentCode == IntentCode.NODE_GLOBAL_HROUTE_HSR) { + if (!visited.add(downhill)) { continue; } - if (!visited.add(downhill)) continue; - RouteNode rn = new RouteNode(downhill.getTile(), downhill.getWireIndex(), curr, curr.getLevel()+1); - - // The clockRegion.getApproximateCenter() may return an INVALID_* tile with huge coordinates. - // Here we use the Manhattan distance to the target clock region as the cost. - ClockRegion rnClockRegion = rn.getTile().getClockRegion(); - int cost = Math.abs(rnClockRegion.getColumn() - clockRegion.getColumn()) + Math.abs(rnClockRegion.getRow() - clockRegion.getRow()); - rn.setCost(cost); - q.add(rn); + + int cost = downhill.getTile().getManhattanDistance(crApproxCenterTile); + q.add(new NodeWithPrevAndCost(downhill, curr, cost)); } if (watchDog-- == 0) { throw new RuntimeException("ERROR: Could not route from " + startingNode + " to clock region " + clockRegion); @@ -159,80 +178,16 @@ public static Node routeToCentroid(Net clk, Node startingNode, ClockRegion clock return null; } - /** - * Routes the vertical distribution path and generates a map between each target clock region and the vertical distribution line to - * start from. - * @param clk The clock net. - * @param centroidDistNode Starting point vertical distribution line - * @param clockRegions The target clock regions. - * @return A map of target clock regions and their respective vertical distribution lines - */ - public static Map routeCentroidToVerticalDistributionLines(Net clk, - RouteNode centroidDistNode, - Collection clockRegions, - Function getNodeStatus) { - Map crToVdist = new HashMap<>(); - centroidDistNode.setParent(null); - Queue q = RouteNode.createPriorityQueue(); - HashSet visited = new HashSet<>(); - Set allPIPs = new HashSet<>(); - Set startingPoints = new HashSet<>(); - startingPoints.add(centroidDistNode); - assert(centroidDistNode.getParent() == null); - nextClockRegion: for (ClockRegion cr : clockRegions) { - q.clear(); - visited.clear(); - q.addAll(startingPoints); - Tile crTarget = cr.getApproximateCenter(); - while (!q.isEmpty()) { - RouteNode curr = q.poll(); - visited.add(curr); - IntentCode c = curr.getIntentCode(); - ClockRegion currCR = curr.getTile().getClockRegion(); - if (currCR != null && cr.equals(currCR) && c == IntentCode.NODE_GLOBAL_VDISTR) { - // Only consider base wires - Node currNode = Node.getNode(curr); - if (getNodeStatus.apply(currNode) == NodeStatus.INUSE) { - startingPoints.add(curr); - } else { - List pips = curr.getPIPsBackToSource(); - allPIPs.addAll(pips); - for (PIP p : pips) { - startingPoints.add(p.getStartRouteNode()); - startingPoints.add(p.getEndRouteNode()); - } - } - RouteNode currBase = new RouteNode(currNode); - currBase.setParent(null); - crToVdist.put(cr, currBase); - continue nextClockRegion; - } - for (Wire w : curr.getWireConnections()) { - if (w.getIntentCode() != IntentCode.NODE_GLOBAL_VDISTR) continue; - Node n = Node.getNode(w); - RouteNode rn = new RouteNode(n.getTile(), n.getWireIndex(), curr, curr.getLevel()+1); - if (visited.contains(rn)) continue; - rn.setCost(w.getTile().getManhattanDistance(crTarget)); - q.add(rn); - } - } - throw new RuntimeException("ERROR: Couldn't route to distribution line in clock region " + cr); - } - clk.getPIPs().addAll(allPIPs); - centroidDistNode.setParent(null); - return crToVdist; - } - public static Map routeVrouteToVerticalDistributionLines(Net clk, Node vroute, Collection clockRegions, Function getNodeStatus) { Map crToVdist = new HashMap<>(); - Queue q = RouteNode.createPriorityQueue(); - HashSet visited = new HashSet<>(); + Queue q = new PriorityQueue<>(); + Set visited = new HashSet<>(); Set allPIPs = new HashSet<>(); - Set startingPoints = new HashSet<>(); - startingPoints.add(new RouteNode(vroute)); + Set startingPoints = new HashSet<>(); + startingPoints.add(new NodeWithPrevAndCost(vroute)); // Pattern: NODE_GLOBAL_VROUTE -> ... -> NODE_GLOBAL_VDISTR_LVL2 -> ... -> NODE_GLOBAL_VDISTR_LVL1 -> ... -> NODE_GLOBAL_VDISTR Set allowedIntentCodes = EnumSet.of( IntentCode.NODE_GLOBAL_VDISTR, @@ -244,37 +199,35 @@ public static Map routeVrouteToVerticalDistributionLines(Net q.clear(); visited.clear(); q.addAll(startingPoints); - Tile crTarget = cr.getApproximateCenter(); + Tile crApproxCenterTile = cr.getApproximateCenter(); while (!q.isEmpty()) { - RouteNode curr = q.poll(); - Node currNode = Node.getNode(curr); - IntentCode c = currNode.getIntentCode(); - ClockRegion currCR = currNode.getTile().getClockRegion(); + NodeWithPrevAndCost curr = q.poll(); + IntentCode c = curr.getIntentCode(); + ClockRegion currCR = curr.getTile().getClockRegion(); if (currCR != null && cr.getRow() == currCR.getRow() && c == IntentCode.NODE_GLOBAL_VDISTR) { // Only consider base wires - if (getNodeStatus.apply(currNode) == NodeStatus.INUSE) { + if (getNodeStatus.apply(curr) == NodeStatus.INUSE) { startingPoints.add(curr); } else { - List pips = curr.getPIPsBackToSourceByNodes(); - allPIPs.addAll(pips); - for (PIP p : pips) { - startingPoints.add(p.getStartRouteNode()); - startingPoints.add(p.getEndRouteNode()); + List path = curr.getPrevPath(); + for (Node node : path) { + startingPoints.add(new NodeWithPrevAndCost(node)); } + allPIPs.addAll(RouterHelper.getPIPsFromNodes(path)); } - crToVdist.put(cr, currNode); + crToVdist.put(cr, curr); continue nextClockRegion; } - for (Node downhill : currNode.getAllDownhillNodes()) { + for (Node downhill : curr.getAllDownhillNodes()) { if (!allowedIntentCodes.contains(downhill.getIntentCode())) { continue; } - if (visited.contains(downhill)) continue; - RouteNode rn = new RouteNode(downhill.getTile(), downhill.getWireIndex(), curr, curr.getLevel()+1); - rn.setCost(downhill.getTile().getManhattanDistance(crTarget)); - q.add(rn); - visited.add(downhill); + if (!visited.add(downhill)) { + continue; + } + int cost = downhill.getTile().getManhattanDistance(crApproxCenterTile); + q.add(new NodeWithPrevAndCost(downhill, curr, cost)); } } throw new RuntimeException("ERROR: Couldn't route to distribution line in clock region " + cr); @@ -294,44 +247,48 @@ public static Map routeVerticalToHorizontalDistributionLines( Map crMap, Function getNodeStatus) { Map distLines = new HashMap<>(); - Queue q = new LinkedList<>(); + Queue q = new ArrayDeque<>(); Set allPIPs = new HashSet<>(); Set visited = new HashSet<>(); nextClockRegion: for (Entry e : crMap.entrySet()) { q.clear(); Node vertDistLine = e.getValue(); - q.add(new RouteNode(vertDistLine)); + q.add(new NodeWithPrev(vertDistLine)); ClockRegion targetCR = e.getKey(); visited.clear(); visited.add(vertDistLine); while (!q.isEmpty()) { - RouteNode curr = q.poll(); - IntentCode c = curr.getIntentCode(); - Node currNode = Node.getNode(curr); - RouteNode parent = curr.getParent(); - if (targetCR.equals(curr.getTile().getClockRegion()) && c == IntentCode.NODE_GLOBAL_GCLK && - parent.getIntentCode() == IntentCode.NODE_GLOBAL_HDISTR_LOCAL) { - List pips = parent.getPIPsBackToSourceByNodes(); - for (PIP pip : pips) { - allPIPs.add(pip); - NodeStatus status = getNodeStatus.apply(pip.getStartNode()); + NodeWithPrev curr = q.poll(); + NodeWithPrev parent = curr.getPrev(); + if (targetCR.equals(curr.getTile().getClockRegion()) && + curr.getIntentCode() == IntentCode.NODE_GLOBAL_GCLK && + parent.getIntentCode() == IntentCode.NODE_GLOBAL_HDISTR_LOCAL) { + List path = curr.getPrevPath(); + int i; + for (i = 1; i < path.size(); i++) { + Node node = path.get(i); + NodeStatus status = getNodeStatus.apply(node); if (status == NodeStatus.INUSE) { break; } assert(status == NodeStatus.AVAILABLE); } - - parent.setParent(null); - distLines.put(targetCR, Node.getNode(parent)); + allPIPs.addAll(RouterHelper.getPIPsFromNodes(path.subList(1, i))); + parent.setPrev(null); + distLines.put(targetCR, parent); continue nextClockRegion; } - for (Node downhill: currNode.getAllDownhillNodes()) { + for (Node downhill: curr.getAllDownhillNodes()) { IntentCode intentCode = downhill.getIntentCode(); - if (intentCode != IntentCode.NODE_PINFEED && !intentCode.isVersalClocking()) continue; - if (!visited.add(downhill)) continue; - q.add(new RouteNode(downhill.getTile(), downhill.getWireIndex(), curr, curr.getLevel()+1)); + if (intentCode != IntentCode.NODE_PINFEED && !intentCode.isVersalClocking()) { + continue; + } + if (!visited.add(downhill)) { + continue; + } + q.add(new NodeWithPrev(downhill, curr)); } } throw new RuntimeException("ERROR: Couldn't route to distribution line in clock region " + targetCR); @@ -346,7 +303,7 @@ public static Map routeVerticalToHorizontalDistributionLines( * @param distLines A map of target clock regions and their respective horizontal distribution lines * @param lcbTargets The target LCB nodes to route the clock */ - public static void routeDistributionToLCBs(Net clk, Map distLines, Set lcbTargets) { + public static void routeDistributionToLCBs(Net clk, Map distLines, Set lcbTargets) { Map> startingPoints = getStartingPoints(distLines); routeToLCBs(clk, startingPoints, lcbTargets); } @@ -361,45 +318,48 @@ public static Map> getStartingPoints(Map> startingPoints, Set lcbTargets) { - Queue q = RouteNode.createPriorityQueue(); + public static void routeToLCBs(Net clk, Map> startingPoints, Set lcbTargets) { + Queue q = new PriorityQueue<>(); Set allPIPs = new HashSet<>(); - HashSet visited = new HashSet<>(); + Set visited = new HashSet<>(); - nextLCB: for (RouteNode lcb : lcbTargets) { + nextLCB: for (Node lcb : lcbTargets) { q.clear(); visited.clear(); - ClockRegion currCR = lcb.getTile().getClockRegion(); - Set starts = startingPoints.getOrDefault(currCR, Collections.emptySet()); - for (Node n : starts) { - q.add(new RouteNode(n)); + Tile lcbTile = lcb.getTile(); + ClockRegion currCR = lcbTile.getClockRegion(); + for (Node node : startingPoints.getOrDefault(currCR, Collections.emptySet())) { + q.add(new NodeWithPrevAndCost(node)); } while (!q.isEmpty()) { - RouteNode curr = q.poll(); + NodeWithPrevAndCost curr = q.poll(); visited.add(curr); if (lcb.equals(curr)) { - List pips = curr.getPIPsBackToSource(); - allPIPs.addAll(pips); - - Set s = startingPoints.get(currCR); - for (PIP p : pips) { - s.add(p.getStartNode()); - s.add(p.getEndNode()); + Set set = startingPoints.get(currCR); + List path = curr.getPrevPath(); + for (Node node : path) { + set.add(node); } + allPIPs.addAll(RouterHelper.getPIPsFromNodes(path)); continue nextLCB; } - Node currNode = Node.getNode(curr); - for (Node downhill : currNode.getAllDownhillNodes()) { + for (Node downhill : curr.getAllDownhillNodes()) { // Stay in this clock region - if (!currCR.equals(downhill.getTile().getClockRegion())) continue; + if (!currCR.equals(downhill.getTile().getClockRegion())) { + continue; + } IntentCode intentCode = downhill.getIntentCode(); - if (intentCode != IntentCode.NODE_PINFEED && !intentCode.isVersalClocking()) continue; - RouteNode rn = new RouteNode(downhill.getTile(), downhill.getWireIndex(), curr, curr.getLevel()+1); - if (visited.contains(rn)) continue; - if (rn.getWireName().endsWith("_I_CASC_PIN")) continue; - if (rn.getWireName().endsWith("_CLR_B_PIN")) continue; - rn.setCost(rn.getManhattanDistance(lcb)); - q.add(rn); + if (intentCode != IntentCode.NODE_PINFEED && !intentCode.isVersalClocking()) { + continue; + } + if (downhill.getWireName().endsWith("_I_CASC_PIN") || downhill.getWireName().endsWith("_CLR_B_PIN")) { + continue; + } + if (visited.contains(downhill)) { + continue; + } + int cost = downhill.getTile().getManhattanDistance(lcbTile); + q.add(new NodeWithPrevAndCost(downhill, curr, cost)); } } throw new RuntimeException("ERROR: Couldn't route to distribution line in clock region " + lcb); @@ -413,11 +373,11 @@ public static void routeToLCBs(Net clk, Map> startingPoin * @param getNodeStatus Lambda for indicating the status of a Node: available, in-use (preserved * for same net as we're routing), or unavailable (preserved for other net). */ - public static void routeLCBsToSinks(Net clk, Map> lcbMappings, + public static void routeLCBsToSinks(Net clk, Map> lcbMappings, Function getNodeStatus) { Set used = new HashSet<>(); Set visited = new HashSet<>(); - Queue q = new LinkedList<>(); + Queue q = new ArrayDeque<>(); Predicate isNodeUnavailable = (node) -> getNodeStatus.apply(node) == NodeStatus.UNAVAILABLE; Set allowedIntentCodes = EnumSet.of( @@ -435,48 +395,60 @@ public static void routeLCBsToSinks(Net clk, Map> l RouteThruHelper routeThruHelper = new RouteThruHelper(clk.getDesign().getDevice()); - for (Entry> e : lcbMappings.entrySet()) { + for (Entry> e : lcbMappings.entrySet()) { Set currPIPs = new HashSet<>(); - RouteNode lcb = e.getKey(); - assert(lcb.getParent() == null); + Node lcb = e.getKey(); nextPin: for (SitePinInst sink : e.getValue()) { - RouteNode target = sink.getRouteNode(); - Node targetNode = Node.getNode(target); + Node target = sink.getConnectedNode(); q.clear(); - q.add(lcb); + q.add(new NodeWithPrev(lcb)); while (!q.isEmpty()) { - RouteNode curr = q.poll(); - Node currNode = Node.getNode(curr); - if (targetNode.equals(currNode)) { + NodeWithPrev curr = q.poll(); + if (target.equals(curr)) { boolean inuse = false; - for (PIP pip : curr.getPIPsBackToSourceByNodes()) { + List path = curr.getPrevPath(); + int i; + for (i = 1; i < path.size(); i++) { + Node node = path.get(i); if (inuse) { - assert(getNodeStatus.apply(pip.getStartNode()) == NodeStatus.INUSE); + assert(getNodeStatus.apply(node) == NodeStatus.INUSE); continue; } - currPIPs.add(pip); - NodeStatus status = getNodeStatus.apply(pip.getStartNode()); + currPIPs.add(PIP.getArbitraryPIP(node, path.get(i-1))); + NodeStatus status = getNodeStatus.apply(node); if (status == NodeStatus.INUSE) { inuse = true; continue; } assert(status == NodeStatus.AVAILABLE); } + currPIPs.addAll(RouterHelper.getPIPsFromNodes(path.subList(1, i))); sink.setRouted(true); visited.clear(); continue nextPin; } - for (Node downhill : currNode.getAllDownhillNodes()) { - if (!allowedIntentCodes.contains(downhill.getIntentCode())) continue; - if (!visited.add(downhill)) continue; - if (used.contains(downhill)) continue; + for (Node downhill : curr.getAllDownhillNodes()) { + IntentCode downhillIntentCode = downhill.getIntentCode(); + if (!allowedIntentCodes.contains(downhillIntentCode)) { + continue; + } + if (!visited.add(downhill)) { + continue; + } + if (used.contains(downhill)) { + continue; + } // have to allow those routethru-s NODE_IRI -> * - if (routeThruHelper.isRouteThru(currNode, downhill) && downhill.getIntentCode() != IntentCode.NODE_IRI) continue; - if (isNodeUnavailable.test(downhill)) continue; - q.add(new RouteNode(downhill.getTile(), downhill.getWireIndex(), curr, curr.getLevel()+1)); + if (routeThruHelper.isRouteThru(curr, downhill) && downhillIntentCode != IntentCode.NODE_IRI) { + continue; + } + if (isNodeUnavailable.test(downhill)) { + continue; + } + q.add(new NodeWithPrev(downhill, curr)); } } throw new RuntimeException("ERROR: Couldn't route LCB " + e.getKey() + " to Pin " + sink); @@ -543,9 +515,9 @@ public static void incrementalClockRouter(Net clkNet, throw new RuntimeException("ERROR: incrementalClockRouter not yet support on Versal devices."); } - public static Map> routeLCBsToSinks(Net clk, - Function getNodeStatus) { - Map> lcbMappings = new HashMap<>(); + public static Map> routeLCBsToSinks(Net clk, + Function getNodeStatus) { + Map> lcbMappings = new HashMap<>(); Set allowedIntentCodes = EnumSet.of( IntentCode.NODE_CLE_CNODE, IntentCode.NODE_INTF_CNODE, @@ -561,39 +533,49 @@ public static Map> routeLCBsToSinks(Net clk, IntentCode.NODE_GLOBAL_LEAF ); Set visited = new HashSet<>(); - Queue q = new LinkedList<>(); + Queue q = new ArrayDeque<>(); Predicate isNodeUnavailable = (node) -> getNodeStatus.apply(node) == NodeStatus.UNAVAILABLE; RouteThruHelper routeThruHelper = new RouteThruHelper(clk.getDesign().getDevice()); nextPin: for (SitePinInst p: clk.getPins()) { - if (p.isOutPin()) continue; - Node sinkNode = p.getConnectedNode(); - RouteNode sinkRouteNode = new RouteNode(sinkNode.getTile(), sinkNode.getWireIndex(), null, 0); + if (p.isOutPin()) { + continue; + } + NodeWithPrev sink = new NodeWithPrev(p.getConnectedNode()); ClockRegion cr = p.getTile().getClockRegion(); q.clear(); - q.add(sinkRouteNode); + q.add(sink); while (!q.isEmpty()) { - RouteNode curr = q.poll(); - Node currNode = Node.getNode(curr); - - for (Node uphill : currNode.getAllUphillNodes()) { - if (!uphill.getTile().getClockRegion().equals(cr)) continue; - if (!allowedIntentCodes.contains(uphill.getIntentCode())) continue; - if (!visited.add(uphill)) continue; - if (routeThruHelper.isRouteThru(uphill, currNode) && currNode.getIntentCode() != IntentCode.NODE_IRI) continue; - if (isNodeUnavailable.test(uphill)) continue; - if (uphill.getIntentCode() == IntentCode.NODE_GLOBAL_LEAF) { - RouteNode rn = new RouteNode(uphill.getTile(), uphill.getWireIndex(), curr, curr.getLevel()+1); - clk.getPIPs().addAll(rn.getPIPsForwardToSinkByNodes()); - rn.setParent(null); - rn.setLevel(0); - lcbMappings.computeIfAbsent(rn, (k) -> new ArrayList<>()).add(p); + NodeWithPrev curr = q.poll(); + for (Node uphill : curr.getAllUphillNodes()) { + if (!uphill.getTile().getClockRegion().equals(cr)) { + continue; + } + IntentCode uphillIntentCode = uphill.getIntentCode(); + if (!allowedIntentCodes.contains(uphillIntentCode)) { + continue; + } + if (!visited.add(uphill)) { + continue; + } + if (routeThruHelper.isRouteThru(uphill, curr) && curr.getIntentCode() != IntentCode.NODE_IRI) { + continue; + } + if (isNodeUnavailable.test(uphill)) { + continue; + } + NodeWithPrev node = new NodeWithPrev(uphill, curr); + if (uphillIntentCode == IntentCode.NODE_GLOBAL_LEAF) { + List path = node.getPrevPath(); + boolean srcToSinkOrder = true; + clk.getPIPs().addAll(RouterHelper.getPIPsFromNodes(path, srcToSinkOrder)); + lcbMappings.computeIfAbsent(uphill, (k) -> new ArrayList<>()).add(p); visited.clear(); continue nextPin; } - q.add(new RouteNode(uphill.getTile(), uphill.getWireIndex(), curr, curr.getLevel()+1)); + q.add(node); } } throw new RuntimeException("ERROR: Couldn't map Pin " + p + " to LCB."); diff --git a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java index d19cb74cc..c6dee9cbb 100644 --- a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java +++ b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java @@ -235,7 +235,6 @@ public static void symmetricClkRouting(Net clk, Device device, Function clockRegions = getClockRegionsOfNet(clk); - Map upDownDistLines; SitePinInst source = clk.getSource(); SiteTypeEnum sourceTypeEnum = source.getSiteTypeEnum(); // In US/US+ clock routing, we use two VROUTE nodes to reach the clock regions above and below the centroid. @@ -279,9 +278,9 @@ public static void symmetricClkRouting(Net clk, Device device, Function upDownDistLines = VersalClockRouting.routeToHorizontalDistributionLines(clk, vroute, clockRegions, false, getNodeStatus); - Map> lcbMappings = VersalClockRouting.routeLCBsToSinks(clk, getNodeStatus); + Map> lcbMappings = VersalClockRouting.routeLCBsToSinks(clk, getNodeStatus); VersalClockRouting.routeDistributionToLCBs(clk, upDownDistLines, lcbMappings.keySet()); } From 58b61262a732f861575ab5e18678e201e597b9d9 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 22 Nov 2024 14:05:26 -0800 Subject: [PATCH 23/28] More tidying up Signed-off-by: Eddie Hung --- .../router/VersalClockRouting.java | 46 +++++++++++-------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/com/xilinx/rapidwright/router/VersalClockRouting.java b/src/com/xilinx/rapidwright/router/VersalClockRouting.java index 77c7d0d18..9d8c8706f 100644 --- a/src/com/xilinx/rapidwright/router/VersalClockRouting.java +++ b/src/com/xilinx/rapidwright/router/VersalClockRouting.java @@ -265,17 +265,17 @@ public static Map routeVerticalToHorizontalDistributionLines( curr.getIntentCode() == IntentCode.NODE_GLOBAL_GCLK && parent.getIntentCode() == IntentCode.NODE_GLOBAL_HDISTR_LOCAL) { List path = curr.getPrevPath(); - int i; - for (i = 1; i < path.size(); i++) { + for (int i = 1; i < path.size(); i++) { Node node = path.get(i); NodeStatus status = getNodeStatus.apply(node); if (status == NodeStatus.INUSE) { break; } assert(status == NodeStatus.AVAILABLE); + if (i > 1) { + allPIPs.add(PIP.getArbitraryPIP(node, path.get(i-1))); + } } - allPIPs.addAll(RouterHelper.getPIPsFromNodes(path.subList(1, i))); - parent.setPrev(null); distLines.put(targetCR, parent); continue nextClockRegion; } @@ -304,21 +304,22 @@ public static Map routeVerticalToHorizontalDistributionLines( * @param lcbTargets The target LCB nodes to route the clock */ public static void routeDistributionToLCBs(Net clk, Map distLines, Set lcbTargets) { - Map> startingPoints = getStartingPoints(distLines); + Map> startingPoints = getStartingPoints(distLines); routeToLCBs(clk, startingPoints, lcbTargets); } - public static Map> getStartingPoints(Map distLines) { - Map> startingPoints = new HashMap<>(); + public static Map> getStartingPoints(Map distLines) { + Map> startingPoints = new HashMap<>(); for (Entry e : distLines.entrySet()) { ClockRegion cr = e.getKey(); Node distLine = e.getValue(); - startingPoints.computeIfAbsent(cr, k -> new HashSet<>()).add(distLine); + startingPoints.computeIfAbsent(cr, k -> new HashSet<>()) + .add(new NodeWithPrevAndCost(distLine)); } return startingPoints; } - public static void routeToLCBs(Net clk, Map> startingPoints, Set lcbTargets) { + public static void routeToLCBs(Net clk, Map> startingPoints, Set lcbTargets) { Queue q = new PriorityQueue<>(); Set allPIPs = new HashSet<>(); Set visited = new HashSet<>(); @@ -328,19 +329,23 @@ public static void routeToLCBs(Net clk, Map> startingPoin visited.clear(); Tile lcbTile = lcb.getTile(); ClockRegion currCR = lcbTile.getClockRegion(); - for (Node node : startingPoints.getOrDefault(currCR, Collections.emptySet())) { - q.add(new NodeWithPrevAndCost(node)); + Set starts = startingPoints.getOrDefault(currCR, Collections.emptySet()); + for (NodeWithPrev n : starts) { + assert(n.getPrev() == null); } + q.addAll(starts); while (!q.isEmpty()) { NodeWithPrevAndCost curr = q.poll(); visited.add(curr); if (lcb.equals(curr)) { - Set set = startingPoints.get(currCR); List path = curr.getPrevPath(); - for (Node node : path) { - set.add(node); - } allPIPs.addAll(RouterHelper.getPIPsFromNodes(path)); + + Set s = startingPoints.get(currCR); + for (Node n : path) { + s.add(new NodeWithPrevAndCost(n)); + } + continue nextLCB; } for (Node downhill : curr.getAllDownhillNodes()) { @@ -355,6 +360,9 @@ public static void routeToLCBs(Net clk, Map> startingPoin if (downhill.getWireName().endsWith("_I_CASC_PIN") || downhill.getWireName().endsWith("_CLR_B_PIN")) { continue; } + // if (!visited.add(downhill)) { + // continue; + // } if (visited.contains(downhill)) { continue; } @@ -409,14 +417,15 @@ public static void routeLCBsToSinks(Net clk, Map> lcbMap if (target.equals(curr)) { boolean inuse = false; List path = curr.getPrevPath(); - int i; - for (i = 1; i < path.size(); i++) { + for (int i = 1; i < path.size(); i++) { Node node = path.get(i); if (inuse) { assert(getNodeStatus.apply(node) == NodeStatus.INUSE); continue; } - currPIPs.add(PIP.getArbitraryPIP(node, path.get(i-1))); + if (i > 1) { + currPIPs.add(PIP.getArbitraryPIP(node, path.get(i - 1))); + } NodeStatus status = getNodeStatus.apply(node); if (status == NodeStatus.INUSE) { inuse = true; @@ -424,7 +433,6 @@ public static void routeLCBsToSinks(Net clk, Map> lcbMap } assert(status == NodeStatus.AVAILABLE); } - currPIPs.addAll(RouterHelper.getPIPsFromNodes(path.subList(1, i))); sink.setRouted(true); visited.clear(); continue nextPin; From 5e17bfac3df963f713ec0f2d5f024f77c1f3c914 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 22 Nov 2024 15:35:01 -0800 Subject: [PATCH 24/28] Even more tidying Signed-off-by: Eddie Hung --- .../router/VersalClockRouting.java | 105 +----------------- 1 file changed, 3 insertions(+), 102 deletions(-) diff --git a/src/com/xilinx/rapidwright/router/VersalClockRouting.java b/src/com/xilinx/rapidwright/router/VersalClockRouting.java index 9d8c8706f..0046e341d 100644 --- a/src/com/xilinx/rapidwright/router/VersalClockRouting.java +++ b/src/com/xilinx/rapidwright/router/VersalClockRouting.java @@ -360,9 +360,6 @@ public static void routeToLCBs(Net clk, Map> lcbMappings, - Function getNodeStatus) { - Set used = new HashSet<>(); - Set visited = new HashSet<>(); - Queue q = new ArrayDeque<>(); - - Predicate isNodeUnavailable = (node) -> getNodeStatus.apply(node) == NodeStatus.UNAVAILABLE; - Set allowedIntentCodes = EnumSet.of( - IntentCode.NODE_CLE_CNODE, - IntentCode.NODE_INTF_CNODE, - IntentCode.NODE_CLE_CTRL, - IntentCode.NODE_INTF_CTRL, - IntentCode.NODE_IRI, - IntentCode.NODE_INODE, - IntentCode.NODE_PINBOUNCE, - IntentCode.NODE_CLE_BNODE, - IntentCode.NODE_IMUX, - IntentCode.NODE_PINFEED - ); - - RouteThruHelper routeThruHelper = new RouteThruHelper(clk.getDesign().getDevice()); - - for (Entry> e : lcbMappings.entrySet()) { - Set currPIPs = new HashSet<>(); - Node lcb = e.getKey(); - - nextPin: for (SitePinInst sink : e.getValue()) { - Node target = sink.getConnectedNode(); - q.clear(); - q.add(new NodeWithPrev(lcb)); - - while (!q.isEmpty()) { - NodeWithPrev curr = q.poll(); - if (target.equals(curr)) { - boolean inuse = false; - List path = curr.getPrevPath(); - for (int i = 1; i < path.size(); i++) { - Node node = path.get(i); - if (inuse) { - assert(getNodeStatus.apply(node) == NodeStatus.INUSE); - continue; - } - if (i > 1) { - currPIPs.add(PIP.getArbitraryPIP(node, path.get(i - 1))); - } - NodeStatus status = getNodeStatus.apply(node); - if (status == NodeStatus.INUSE) { - inuse = true; - continue; - } - assert(status == NodeStatus.AVAILABLE); - } - sink.setRouted(true); - visited.clear(); - continue nextPin; - } - - for (Node downhill : curr.getAllDownhillNodes()) { - IntentCode downhillIntentCode = downhill.getIntentCode(); - if (!allowedIntentCodes.contains(downhillIntentCode)) { - continue; - } - if (!visited.add(downhill)) { - continue; - } - if (used.contains(downhill)) { - continue; - } - // have to allow those routethru-s NODE_IRI -> * - if (routeThruHelper.isRouteThru(curr, downhill) && downhillIntentCode != IntentCode.NODE_IRI) { - continue; - } - if (isNodeUnavailable.test(downhill)) { - continue; - } - q.add(new NodeWithPrev(downhill, curr)); - } - } - throw new RuntimeException("ERROR: Couldn't route LCB " + e.getKey() + " to Pin " + sink); - } - - List clkPIPs = clk.getPIPs(); - for (PIP p : currPIPs) { - used.add(p.getStartNode()); - used.add(p.getEndNode()); - clkPIPs.add(p); - } - } - } - /** * Routes from a GLOBAL_VERTICAL_ROUTE to horizontal distribution lines. * @param clk The clock net to be routed. @@ -506,7 +407,7 @@ public static void incrementalClockRouter(Design design, Net clkNet, Function getNodeStatus) { // TODO: - throw new RuntimeException("ERROR: incrementalClockRouter not yet support on Versal devices."); + throw new RuntimeException("ERROR: Incremental clock routing not yet supported for Versal devices."); } /** @@ -520,7 +421,7 @@ public static void incrementalClockRouter(Net clkNet, List clkPins, Function getNodeStatus) { // TODO: - throw new RuntimeException("ERROR: incrementalClockRouter not yet support on Versal devices."); + throw new RuntimeException("ERROR: Incremental clock routing not yet supported for Versal devices."); } public static Map> routeLCBsToSinks(Net clk, @@ -586,7 +487,7 @@ public static Map> routeLCBsToSinks(Net clk, q.add(node); } } - throw new RuntimeException("ERROR: Couldn't map Pin " + p + " to LCB."); + throw new RuntimeException("ERROR: Couldn't route pin " + sink + " to any LCB"); } return lcbMappings; From 36a6342afa3a4e7d17ba5d67c72b24454efcf020 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 22 Nov 2024 15:42:48 -0800 Subject: [PATCH 25/28] Last bit of tidying Signed-off-by: Eddie Hung --- .../router/VersalClockRouting.java | 3 +-- .../rwroute/GlobalSignalRouting.java | 21 ++++++++----------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/com/xilinx/rapidwright/router/VersalClockRouting.java b/src/com/xilinx/rapidwright/router/VersalClockRouting.java index 0046e341d..4cfc2add7 100644 --- a/src/com/xilinx/rapidwright/router/VersalClockRouting.java +++ b/src/com/xilinx/rapidwright/router/VersalClockRouting.java @@ -336,7 +336,6 @@ public static void routeToLCBs(Net clk, Map path = curr.getPrevPath(); allPIPs.addAll(RouterHelper.getPIPsFromNodes(path)); @@ -360,7 +359,7 @@ public static void routeToLCBs(Net clk, Map> getListOfNodesFromRoutes(Device device, M * for same net as we're routing), or unavailable (preserved for other net). */ public static void symmetricClkRouting(Net clk, Device device, Function getNodeStatus) { - if (device.getSeries() != Series.Versal) { + if (device.getSeries() == Series.UltraScale || device.getSeries() == Series.UltraScalePlus) { List clockRegions = getClockRegionsOfNet(clk); ClockRegion centroid = findCentroid(clk, device); @@ -227,12 +227,8 @@ public static void symmetricClkRouting(Net clk, Device device, Function clockRegions = getClockRegionsOfNet(clk); SitePinInst source = clk.getSource(); @@ -244,7 +240,6 @@ public static void symmetricClkRouting(Net clk, Device device, Function @@ -256,9 +251,9 @@ public static void symmetricClkRouting(Net clk, Device device, Function NODE_GLOBAL_BUFG -> NODE_GLOBAL_GCLK -> NODE_GLOBAL_HROUTE_HSR -> NODE_GLOBAL_VROUTE + // Assume that these source sites are located in the bottom of the device (Y=0). + // The path from the output pin to VROUTE matches the following pattern: + // NODE_GLOBAL_BUFG -> NODE_GLOBAL_BUFG -> NODE_GLOBAL_GCLK -> NODE_GLOBAL_HROUTE_HSR -> NODE_GLOBAL_VROUTE // which is similar to US/US+ clock routing. // Notice that we have to quickly reach a NODE_GLOBAL_HROUTE_HSR node, and if we allow the Y coordinate of centroid to be bigger than 1, // we may fail to do so. Thus, we need to force the Y-coordinate of centroid to be 1. @@ -268,12 +263,12 @@ public static void symmetricClkRouting(Net clk, Device device, Function> lcbMappings = VersalClockRouting.routeLCBsToSinks(clk, getNodeStatus); VersalClockRouting.routeDistributionToLCBs(clk, upDownDistLines, lcbMappings.keySet()); + } else { + throw new RuntimeException("ERROR: GlobalSignalRouting.symmetricClkRouting() does not support the " + device.getSeries() + " series."); } Set clkPIPsWithoutDuplication = new HashSet<>(clk.getPIPs()); From 823f291b38eb59d5c650690939746d436cc1f290 Mon Sep 17 00:00:00 2001 From: Wenhao Lin Date: Mon, 25 Nov 2024 12:41:27 -0700 Subject: [PATCH 26/28] Add Javadoc Signed-off-by: Wenhao Lin --- .../xilinx/rapidwright/router/VersalClockRouting.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/com/xilinx/rapidwright/router/VersalClockRouting.java b/src/com/xilinx/rapidwright/router/VersalClockRouting.java index 4cfc2add7..16fa116b8 100644 --- a/src/com/xilinx/rapidwright/router/VersalClockRouting.java +++ b/src/com/xilinx/rapidwright/router/VersalClockRouting.java @@ -237,11 +237,12 @@ public static Map routeVrouteToVerticalDistributionLines(Net } /** - * Routes from a vertical distribution centroid to destination horizontal distribution lines - * in the clock regions provided. + * For each target clock region, route from the provided vertical distribution line to a + * horizontal distribution line that has a GLOBAL_GLK child node in this clock region. + * This simulates the behavior of Vivado. * @param clk The current clock net * @param crMap A map of target clock regions and their respective vertical distribution lines - * @return The List of nodes from the centroid to the horizontal distribution line. + * @return The map of target clock regions and their respective horizontal distribution lines. */ public static Map routeVerticalToHorizontalDistributionLines(Net clk, Map crMap, @@ -377,7 +378,7 @@ public static void routeToLCBs(Net clk, Map routeToHorizontalDistributionLines(Net clk, Node vroute, From e4e2114533224aa308ebc077f6076a01172a4ce5 Mon Sep 17 00:00:00 2001 From: eddieh-xlnx Date: Tue, 26 Nov 2024 15:25:20 -0800 Subject: [PATCH 27/28] Apply suggestions from code review Co-authored-by: Chris Lavin Signed-off-by: eddieh-xlnx --- src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java index 070348746..6aaf00f26 100644 --- a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java +++ b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java @@ -234,7 +234,7 @@ public static void symmetricClkRouting(Net clk, Device device, Function // NODE_GLOBAL_VROUTE (located in the same clock region of the source site) - // Notice that Vivado always use the above VROUTE node, there is no need to find a centroid clock region to route to. + // Notice that Vivado always uses the above VROUTE node, there is no need to find a centroid clock region to route to. centroid = source.getTile().getClockRegion(); centroidHRouteNode = source.getConnectedNode(); } else if (sourceTypeEnum == SiteTypeEnum.BUFGCE) { From 0617b15b4ef1e524fd0ddc21a7ddb2203ff8f953 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 26 Nov 2024 15:31:34 -0800 Subject: [PATCH 28/28] Address review comments Signed-off-by: Eddie Hung --- .../router/UltraScaleClockRouting.java | 2 +- .../router/VersalClockRouting.java | 2 +- .../rwroute/GlobalSignalRouting.java | 180 ++++++++++-------- 3 files changed, 100 insertions(+), 84 deletions(-) diff --git a/src/com/xilinx/rapidwright/router/UltraScaleClockRouting.java b/src/com/xilinx/rapidwright/router/UltraScaleClockRouting.java index ed25b11d4..a87e33961 100644 --- a/src/com/xilinx/rapidwright/router/UltraScaleClockRouting.java +++ b/src/com/xilinx/rapidwright/router/UltraScaleClockRouting.java @@ -437,7 +437,7 @@ public static void routeToLCBs(Net clk, Map> startin q.add(rn); } } - throw new RuntimeException("ERROR: Couldn't route to distribution line in clock region " + lcb); + throw new RuntimeException("ERROR: Couldn't route to leaf clock buffer " + lcb); } clk.getPIPs().addAll(allPIPs); } diff --git a/src/com/xilinx/rapidwright/router/VersalClockRouting.java b/src/com/xilinx/rapidwright/router/VersalClockRouting.java index 16fa116b8..0d5fbcea6 100644 --- a/src/com/xilinx/rapidwright/router/VersalClockRouting.java +++ b/src/com/xilinx/rapidwright/router/VersalClockRouting.java @@ -367,7 +367,7 @@ public static void routeToLCBs(Net clk, Map> getListOfNodesFromRoutes(Device device, M * for same net as we're routing), or unavailable (preserved for other net). */ public static void symmetricClkRouting(Net clk, Device device, Function getNodeStatus) { - if (device.getSeries() == Series.UltraScale || device.getSeries() == Series.UltraScalePlus) { - List clockRegions = getClockRegionsOfNet(clk); - - ClockRegion centroid = findCentroid(clk, device); - List upClockRegions = new ArrayList<>(); - List downClockRegions = new ArrayList<>(); - // divides clock regions into two groups - divideClockRegions(clockRegions, centroid, upClockRegions, downClockRegions); - - RouteNode clkRoutingLine = UltraScaleClockRouting.routeBUFGToNearestRoutingTrack(clk);// first HROUTE - RouteNode centroidHRouteNode = UltraScaleClockRouting.routeToCentroid(clk, clkRoutingLine, centroid, true, true); - - RouteNode vrouteUp = null; - RouteNode vrouteDown; - // Two VROUTEs going up and down - ClockRegion aboveCentroid = upClockRegions.isEmpty() ? null : centroid.getNeighborClockRegion(1, 0); - if (aboveCentroid != null) { - vrouteUp = UltraScaleClockRouting.routeToCentroid(clk, centroidHRouteNode, aboveCentroid, true, false); - } - vrouteDown = UltraScaleClockRouting.routeToCentroid(clk, centroidHRouteNode, centroid.getNeighborClockRegion(0, 0), true, false); + switch (device.getSeries()) { + case UltraScale: + case UltraScalePlus: + symmetricClockRoutingUltraScales(clk, device, getNodeStatus); + break; + case Versal: + symmetricClockRoutingVersal(clk, device, getNodeStatus); + break; + default: + throw new RuntimeException("ERROR: GlobalSignalRouting.symmetricClkRouting() does not support the " + device.getSeries() + " series."); + } - List upDownDistLines = new ArrayList<>(); - if (aboveCentroid != null) { - List upLines = UltraScaleClockRouting.routeToHorizontalDistributionLines(clk, vrouteUp, upClockRegions, false, getNodeStatus); - if (upLines != null) upDownDistLines.addAll(upLines); - } + Set clkPIPsWithoutDuplication = new HashSet<>(clk.getPIPs()); + clk.setPIPs(clkPIPsWithoutDuplication); + } - List downLines = UltraScaleClockRouting.routeToHorizontalDistributionLines(clk, vrouteDown, downClockRegions, true, getNodeStatus);//TODO this is where the antenna node shows up - if (downLines != null) upDownDistLines.addAll(downLines); - - Map> lcbMappings = getLCBPinMappings(clk.getPins(), getNodeStatus); - UltraScaleClockRouting.routeDistributionToLCBs(clk, upDownDistLines, lcbMappings.keySet()); - - UltraScaleClockRouting.routeLCBsToSinks(clk, lcbMappings, getNodeStatus); - } else if (device.getSeries() == Series.Versal) { - // Clock routing on Versal devices - - List clockRegions = getClockRegionsOfNet(clk); - SitePinInst source = clk.getSource(); - SiteTypeEnum sourceTypeEnum = source.getSiteTypeEnum(); - // In US/US+ clock routing, we use two VROUTE nodes to reach the clock regions above and below the centroid. - // However, we can see that Vivado only uses one VROUTE node in the centroid clock region for Versal clock routing, - // and reach the above and below clock regions by VDISTR nodes. - - ClockRegion centroid; - Node centroidHRouteNode; - - if (sourceTypeEnum == SiteTypeEnum.BUFG_FABRIC) { - // These source sites are located in the middle of the device. The path from the output pin to VROUTE matches the following pattern: - // NODE_GLOBAL_BUFG (the output node with a suffix "_O") -> - // NODE_GLOBAL_BUFG (has a suffix "_O_PIN") -> - // NODE_GLOBAL_GCLK -> - // NODE_GLOBAL_VROUTE (located in the same clock region of the source site) - - // Notice that Vivado always uses the above VROUTE node, there is no need to find a centroid clock region to route to. - centroid = source.getTile().getClockRegion(); - centroidHRouteNode = source.getConnectedNode(); - } else if (sourceTypeEnum == SiteTypeEnum.BUFGCE) { - // Assume that these source sites are located in the bottom of the device (Y=0). - // The path from the output pin to VROUTE matches the following pattern: - // NODE_GLOBAL_BUFG -> NODE_GLOBAL_BUFG -> NODE_GLOBAL_GCLK -> NODE_GLOBAL_HROUTE_HSR -> NODE_GLOBAL_VROUTE - // which is similar to US/US+ clock routing. - // Notice that we have to quickly reach a NODE_GLOBAL_HROUTE_HSR node, and if we allow the Y coordinate of centroid to be bigger than 1, - // we may fail to do so. Thus, we need to force the Y-coordinate of centroid to be 1. - assert(source.getTile().getTileYCoordinate() == 0); - // And, in X-axis, Vivado doesn't go to the real centroid of target clock regions... it just uses a nearby VROUTE. - int centroidX = source.getTile().getClockRegion().getColumn(); - // VROUTE nodes are in the clock region where X is odd. - if (centroidX % 2 == 0) centroidX -= 1; - if (centroidX <= 0) centroidX = 1; - centroid = device.getClockRegion(1, centroidX); - - Node clkRoutingLine = VersalClockRouting.routeBUFGToNearestRoutingTrack(clk);// first HROUTE - centroidHRouteNode = VersalClockRouting.routeToCentroid(clk, clkRoutingLine, centroid, true); - } else { - throw new RuntimeException("ERROR: Routing clock net with source type " + sourceTypeEnum + " not supported."); - } + private static void symmetricClockRoutingUltraScales(Net clk, Device device, Function getNodeStatus) { + // Clock routing on UltraScale/UltraScale+ devices + assert(device.getSeries() == Series.UltraScale || device.getSeries() == Series.UltraScalePlus); + + List clockRegions = getClockRegionsOfNet(clk); - Node vroute = VersalClockRouting.routeToCentroid(clk, centroidHRouteNode, centroid, false); + ClockRegion centroid = findCentroid(clk, device); + List upClockRegions = new ArrayList<>(); + List downClockRegions = new ArrayList<>(); + // divides clock regions into two groups + divideClockRegions(clockRegions, centroid, upClockRegions, downClockRegions); - Map upDownDistLines = VersalClockRouting.routeToHorizontalDistributionLines(clk, vroute, clockRegions, false, getNodeStatus); + RouteNode clkRoutingLine = UltraScaleClockRouting.routeBUFGToNearestRoutingTrack(clk);// first HROUTE + RouteNode centroidHRouteNode = UltraScaleClockRouting.routeToCentroid(clk, clkRoutingLine, centroid, true, true); - Map> lcbMappings = VersalClockRouting.routeLCBsToSinks(clk, getNodeStatus); - VersalClockRouting.routeDistributionToLCBs(clk, upDownDistLines, lcbMappings.keySet()); + RouteNode vrouteUp = null; + RouteNode vrouteDown; + // Two VROUTEs going up and down + ClockRegion aboveCentroid = upClockRegions.isEmpty() ? null : centroid.getNeighborClockRegion(1, 0); + if (aboveCentroid != null) { + vrouteUp = UltraScaleClockRouting.routeToCentroid(clk, centroidHRouteNode, aboveCentroid, true, false); + } + vrouteDown = UltraScaleClockRouting.routeToCentroid(clk, centroidHRouteNode, centroid.getNeighborClockRegion(0, 0), true, false); + + List upDownDistLines = new ArrayList<>(); + if (aboveCentroid != null) { + List upLines = UltraScaleClockRouting.routeToHorizontalDistributionLines(clk, vrouteUp, upClockRegions, false, getNodeStatus); + if (upLines != null) upDownDistLines.addAll(upLines); + } + + List downLines = UltraScaleClockRouting.routeToHorizontalDistributionLines(clk, vrouteDown, downClockRegions, true, getNodeStatus);//TODO this is where the antenna node shows up + if (downLines != null) upDownDistLines.addAll(downLines); + + Map> lcbMappings = getLCBPinMappings(clk.getPins(), getNodeStatus); + UltraScaleClockRouting.routeDistributionToLCBs(clk, upDownDistLines, lcbMappings.keySet()); + + UltraScaleClockRouting.routeLCBsToSinks(clk, lcbMappings, getNodeStatus); + } + + private static void symmetricClockRoutingVersal(Net clk, Device device, Function getNodeStatus) { + // Clock routing on Versal devices + assert(device.getSeries() == Series.Versal); + + List clockRegions = getClockRegionsOfNet(clk); + SitePinInst source = clk.getSource(); + SiteTypeEnum sourceTypeEnum = source.getSiteTypeEnum(); + // In US/US+ clock routing, we use two VROUTE nodes to reach the clock regions above and below the centroid. + // However, we can see that Vivado only uses one VROUTE node in the centroid clock region for Versal clock routing, + // and reach the above and below clock regions by VDISTR nodes. + + ClockRegion centroid; + Node centroidHRouteNode; + + if (sourceTypeEnum == SiteTypeEnum.BUFG_FABRIC) { + // These source sites are located in the middle of the device. The path from the output pin to VROUTE matches the following pattern: + // NODE_GLOBAL_BUFG (the output node with a suffix "_O") -> + // NODE_GLOBAL_BUFG (has a suffix "_O_PIN") -> + // NODE_GLOBAL_GCLK -> + // NODE_GLOBAL_VROUTE (located in the same clock region of the source site) + + // Notice that Vivado always uses the above VROUTE node, there is no need to find a centroid clock region to route to. + centroid = source.getTile().getClockRegion(); + centroidHRouteNode = source.getConnectedNode(); + } else if (sourceTypeEnum == SiteTypeEnum.BUFGCE) { + // Assume that these source sites are located in the bottom of the device (Y=0). + // The path from the output pin to VROUTE matches the following pattern: + // NODE_GLOBAL_BUFG -> NODE_GLOBAL_BUFG -> NODE_GLOBAL_GCLK -> NODE_GLOBAL_HROUTE_HSR -> NODE_GLOBAL_VROUTE + // which is similar to US/US+ clock routing. + // Notice that we have to quickly reach a NODE_GLOBAL_HROUTE_HSR node, and if we allow the Y coordinate of centroid to be bigger than 1, + // we may fail to do so. Thus, we need to force the Y-coordinate of centroid to be 1. + assert(source.getTile().getTileYCoordinate() == 0); + // And, in X-axis, Vivado doesn't go to the real centroid of target clock regions... it just uses a nearby VROUTE. + int centroidX = source.getTile().getClockRegion().getColumn(); + // VROUTE nodes are in the clock region where X is odd. + if (centroidX % 2 == 0) centroidX -= 1; + if (centroidX <= 0) centroidX = 1; + centroid = device.getClockRegion(1, centroidX); + + Node clkRoutingLine = VersalClockRouting.routeBUFGToNearestRoutingTrack(clk);// first HROUTE + centroidHRouteNode = VersalClockRouting.routeToCentroid(clk, clkRoutingLine, centroid, true); } else { - throw new RuntimeException("ERROR: GlobalSignalRouting.symmetricClkRouting() does not support the " + device.getSeries() + " series."); + throw new RuntimeException("ERROR: Routing clock net with source type " + sourceTypeEnum + " not supported."); } - Set clkPIPsWithoutDuplication = new HashSet<>(clk.getPIPs()); - clk.setPIPs(clkPIPsWithoutDuplication); + Node vroute = VersalClockRouting.routeToCentroid(clk, centroidHRouteNode, centroid, false); + + Map upDownDistLines = VersalClockRouting.routeToHorizontalDistributionLines(clk, vroute, clockRegions, false, getNodeStatus); + + Map> lcbMappings = VersalClockRouting.routeLCBsToSinks(clk, getNodeStatus); + VersalClockRouting.routeDistributionToLCBs(clk, upDownDistLines, lcbMappings.keySet()); } /**