diff --git a/src/com/xilinx/rapidwright/rwroute/Connection.java b/src/com/xilinx/rapidwright/rwroute/Connection.java index 95a7f87e0..703682a8e 100644 --- a/src/com/xilinx/rapidwright/rwroute/Connection.java +++ b/src/com/xilinx/rapidwright/rwroute/Connection.java @@ -305,7 +305,7 @@ public void addAltSinkRnode(RouteNode sinkRnode) { } else { assert(!altSinkRnodes.contains(sinkRnode)); } - assert(sinkRnode.getType().isExclusiveSink() || + assert(sinkRnode.getType().isAnyExclusiveSink() || // Can be a WIRE if node is not exclusive a sink sinkRnode.getType() == RouteNodeType.NON_LOCAL); altSinkRnodes.add(sinkRnode); @@ -487,7 +487,7 @@ public void setAllTargets(RWRoute.ConnectionState state) { // where the same physical pin services more than one logical pin if (rnode.countConnectionsOfUser(netWrapper) == 0 || // Except if it is not an EXCLUSIVE_SINK - rnode.getType().isExclusiveSink()) { + !rnode.getType().isAnyExclusiveSink()) { assert(rnode.getIntentCode() != IntentCode.NODE_PINBOUNCE); rnode.markTarget(state); } diff --git a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java index 730af8850..1ed0b41dd 100644 --- a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java +++ b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java @@ -462,22 +462,20 @@ private static ClockRegion findCentroid(Net clk, Device device) { } /** - * Routes a static net (GND or VCC). - * @param currNet The current static net to be routed. + * Routes pins from a static net (GND or VCC). + * @param pins A list of static pins to be routed (must all be on the same net). * @param getNodeState Lambda to get a node's status (available, unavailable, already in-use). * @param design The {@link Design} instance to use. * @param routeThruHelper The {@link RouteThruHelper} instance to use. */ - public static void routeStaticNet(Net currNet, + public static void routeStaticNet(List pins, Function getNodeState, Design design, RouteThruHelper routeThruHelper) { - NetType netType = currNet.getType(); - Set netPIPs = new HashSet<>(currNet.getPIPs()); Queue q = new ArrayDeque<>(); Set usedRoutingNodes = new HashSet<>(); Map prevNode = new HashMap<>(); List pathNodes = new ArrayList<>(); - Set sitePinsToCreate = new HashSet<>(); + List sitePinsToCreate = new ArrayList<>(); final Node INVALID_NODE = new Node(null, Integer.MAX_VALUE); assert(INVALID_NODE.isInvalidNode()); @@ -512,12 +510,25 @@ public static void routeStaticNet(Net currNet, } // Collect all node-sink pairs to be routed + Net currNet = null; Map nodeToRouteToSink = new HashMap<>(); - for (SitePinInst sink : currNet.getPins()) { - if (sink.isRouted() || sink.isOutPin()) { + for (SitePinInst sink : pins) { + if (currNet == null) { + currNet = sink.getNet(); + assert(currNet != null); + } else { + assert(currNet == sink.getNet()); + } + assert(!sink.isOutPin()); + if (sink.isRouted()) { continue; } - nodeToRouteToSink.put(sink.getConnectedNode(), sink); + + Node node = sink.getConnectedNode(); + if (getNodeState.apply(node) != NodeStatus.INUSE) { + throw new RuntimeException("ERROR: Site pin " + sink + " is not available for net " + currNet); + } + nodeToRouteToSink.put(node, sink); } // Sort them by their tile, ensuring that sinks in the same tile are routed in sequence @@ -525,6 +536,7 @@ public static void routeStaticNet(Net currNet, List nodesToRoute = new ArrayList<>(nodeToRouteToSink.keySet()); nodesToRoute.sort(Comparator.comparing((n) -> n.getTile().getUniqueAddress())); + NetType netType = currNet.getType(); for (Node node : nodesToRoute) { int watchdog = 10000; SitePinInst sink = nodeToRouteToSink.get(node); @@ -651,18 +663,6 @@ public static void routeStaticNet(Net currNet, node = uphillNode; break search; } - - // uphillNode must be a sink to be routed; preserve only the current routing, clear the queue, - // and restart routing from this new sink to encourage reuse - assert(!uphillSink.isRouted()); - do { - usedRoutingNodes.add(node); - node = prevNode.get(node); - } while (node != INVALID_NODE); - prevNode.keySet().removeIf((n) -> !usedRoutingNodes.contains(n) && !n.equals(uphillNode)); - q.clear(); - q.add(uphillNode); - continue search; } q.add(uphillNode); @@ -684,7 +684,9 @@ public static void routeStaticNet(Net currNet, // Note that the static net router goes backward from sinks to sources, // requiring the srcToSinkOrder parameter to be set to true below - netPIPs.addAll(RouterHelper.getPIPsFromNodes(pathNodes, true)); + for (PIP pip : RouterHelper.getPIPsFromNodes(pathNodes, true)) { + currNet.addPIP(pip); + } pathNodes.clear(); sink.setRouted(true); @@ -695,6 +697,7 @@ public static void routeStaticNet(Net currNet, } } + assert(sitePinsToCreate.stream().distinct().count() == sitePinsToCreate.size()); for (SitePin sitePin : sitePinsToCreate) { Site site = sitePin.getSite(); SiteInst si = design.getSiteInstFromSite(site); @@ -722,8 +725,6 @@ public static void routeStaticNet(Net currNet, currNet.addPin(spi, updateSiteRouting); spi.setRouted(true); } - - currNet.setPIPs(netPIPs); } /** diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index 90435b794..2e4699ba8 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -256,7 +256,7 @@ protected void determineRoutingTargets() { preservedNet = routingGraph.getPreservedNet(sinkRnode); if (preservedNet != null && preservedNet != net) { unpreserveNets.add(preservedNet); - assert(sinkRnode.getType().isExclusiveSink()); + assert(sinkRnode.getType().isAnyExclusiveSink()); } } @@ -290,8 +290,17 @@ protected void addGlobalClkRoutingTargets(Net clk) { @Override protected void addStaticNetRoutingTargets(Net staticNet) { - preserveNet(staticNet, true); if (staticNet.hasPIPs()) { + // Preserve only the static net's PIPs and its output pins; its input pins will be + // preserved by routeStaticNets() + List outputPins = new ArrayList<>(); + for (SitePinInst spi : staticNet.getPins()) { + if (!spi.isOutPin()) { + continue; + } + outputPins.add(spi); + } + routingGraph.preserveAsync(staticNet, outputPins); numPreservedStaticNets++; } @@ -310,8 +319,12 @@ protected void addStaticNetRoutingTargets(Net staticNet) { @Override protected void preserveNet(Net net, boolean async) { - List pinsToRoute = netToPins.get(net); - // Only preserve those pins that are not to be routed + List pinsToRoute = null; + if (!net.isStaticNet()) { + // For signal nets, only preserve those pins that are not to be routed + // All sink pins must be preserved for static nets since the static router does not resolve conflicts + pinsToRoute = netToPins.get(net); + } List pinsToPreserve; if (pinsToRoute == null) { pinsToPreserve = net.getPins(); @@ -599,7 +612,7 @@ protected void unpreserveNet(Net net) { RouteNode sourceRnode = connection.getSourceRnode(); RouteNode sinkRnode = connection.getSinkRnode(); assert(sourceRnode.getType() == RouteNodeType.EXCLUSIVE_SOURCE); - assert(sinkRnode.getType().isExclusiveSink()); + assert(sinkRnode.getType().isAnyExclusiveSink()); // Even though this connection is not expected to have any routing yet, // perform a rip up anyway in order to release any exclusive sinks diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index e7c3723d5..aa2325a04 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -56,10 +56,10 @@ import com.xilinx.rapidwright.util.Pair; import com.xilinx.rapidwright.util.RuntimeTracker; import com.xilinx.rapidwright.util.RuntimeTrackerTree; +import com.xilinx.rapidwright.util.Utils; import java.util.ArrayList; import java.util.Arrays; -import java.util.BitSet; import java.util.Collection; import java.util.Collections; import java.util.EnumMap; @@ -67,6 +67,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -325,6 +326,32 @@ protected void determineRoutingTargets() { // Wait for all outstanding RouteNodeGraph.preserveAsync() calls to complete routingGraph.awaitPreserve(); + + // On Versal only, reserve all uphills of NODE_(CLE|INTF)_CTRL sinks since + // their [BC]NODEs can also be used to reach NODE_INODEs --- not applying this + // heuristic can lead to avoidable congestion + if (routingGraph.isVersal) { + for (Connection connection : indirectConnections) { + RouteNode sinkRnode = connection.getSinkRnode(); + if (sinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK_BOTH) { + for (Node uphill : sinkRnode.getAllUphillNodes()) { + if (uphill.isTiedToVcc()) { + continue; + } + Net preservedNet = routingGraph.getPreservedNet(uphill); + if (preservedNet != null && preservedNet != connection.getNetWrapper().getNet()) { + continue; + } + assert((sinkRnode.getIntentCode() == IntentCode.NODE_CLE_CTRL && + (uphill.getIntentCode() == IntentCode.NODE_CLE_CNODE || uphill.getIntentCode() == IntentCode.NODE_CLE_BNODE)) || + (sinkRnode.getIntentCode() == IntentCode.NODE_INTF_CTRL && + (uphill.getIntentCode() == IntentCode.NODE_INTF_CNODE || uphill.getIntentCode() == IntentCode.NODE_INTF_BNODE))); + RouteNode rnode = routingGraph.getOrCreate(uphill, RouteNodeType.LOCAL_RESERVED); + rnode.setType(RouteNodeType.LOCAL_RESERVED); + } + } + } + } } private void categorizeNets() { @@ -493,11 +520,9 @@ protected void addStaticNetRoutingTargets(Net staticNet) { if (sinks.size() > 0) { staticNet.unroute(); // Remove all output pins from unrouted net as those used will be repopulated - staticNet.getPins().removeIf(SitePinInst::isOutPin); + staticNet.setPins(sinks); - // Preserve all pins (e.g. in case of BOUNCE nodes that may serve as a site pin) - preserveNet(staticNet, true); - staticNetAndRoutingTargets.put(staticNet, sinks); + staticNetAndRoutingTargets.put(staticNet, new ArrayList<>(sinks)); } else { numNotNeedingRoutingNets++; } @@ -507,20 +532,64 @@ protected void addStaticNetRoutingTargets(Net staticNet) { * Routes static nets. */ protected void routeStaticNets() { - if (staticNetAndRoutingTargets.isEmpty()) - return; + Net vccNet = design.getVccNet(); + Net gndNet = design.getGndNet(); + + boolean noStaticRouting = staticNetAndRoutingTargets.isEmpty(); + if (!noStaticRouting) { + List gndPins = staticNetAndRoutingTargets.get(gndNet); + if (gndPins != null) { + boolean invertGndToVccForLutInputs = config.isInvertGndToVccForLutInputs(); + Set newVccPins = RouterHelper.invertPossibleGndPinsToVccPins(design, gndPins, invertGndToVccForLutInputs); + if (!newVccPins.isEmpty()) { + gndPins.removeAll(newVccPins); + staticNetAndRoutingTargets.computeIfAbsent(vccNet, (net) -> new ArrayList<>()) + .addAll(newVccPins); + } + } + + Iterator>> it = staticNetAndRoutingTargets.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry> e = it.next(); + Net staticNet = e.getKey(); + List pins = e.getValue(); + // For some encrypted designs, it's possible that RapidWright cannot infer all SitePinInst-s leading to + // some site pins (e.g. CKEN) defaulting those to static nets. Detect such cases -- when signal nets are + // already routed to and preserved at those uninferrable SitePinInst-s -- and remove them from being a + // static net sink + pins.removeIf(spi -> { + Net preservedNet = routingGraph.getPreservedNet(spi.getConnectedNode()); + if (preservedNet == null) { + // This sink is not preserved by any net, allow + return false; + } + // Sink preserved by another net, abandon; check that it cannot have been preserved by this static net + assert(preservedNet != staticNet); + return true; + }); + + // Remove from map if empty + if (pins.isEmpty()) { + it.remove(); + } + } + } - List gndPins = staticNetAndRoutingTargets.get(design.getGndNet()); - if (gndPins != null) { - boolean invertGndToVccForLutInputs = config.isInvertGndToVccForLutInputs(); - Set newVccPins = RouterHelper.invertPossibleGndPinsToVccPins(design, gndPins, invertGndToVccForLutInputs); - if (!newVccPins.isEmpty()) { - gndPins.removeAll(newVccPins); - staticNetAndRoutingTargets.computeIfAbsent(design.getVccNet(), (net) -> new ArrayList<>()) - .addAll(newVccPins); + // Preserve all static nets' sink pins regardless of whether any routing is necessary + for (Net staticNet : Arrays.asList(vccNet, gndNet)) { + for (SitePinInst spi : staticNet.getPins()) { + if (spi.isOutPin()) { + continue; + } + routingGraph.preserve(spi.getConnectedNode(), staticNet); } } + if (noStaticRouting) { + // Now that all static nets have been fully preserved, return if no work to be done + return; + } + for (Map.Entry> e : staticNetAndRoutingTargets.entrySet()) { Net staticNet = e.getKey(); List pins = e.getValue(); @@ -528,7 +597,7 @@ protected void routeStaticNets() { System.out.println("INFO: Routing " + pins.size() + " pins of " + staticNet); Function gns = (node) -> getGlobalRoutingNodeStatus(staticNet, node); - GlobalSignalRouting.routeStaticNet(staticNet, gns, design, routethruHelper); + GlobalSignalRouting.routeStaticNet(pins, gns, design, routethruHelper); preserveNet(staticNet, false); } @@ -601,21 +670,31 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { } indirectConnections.add(connection); - BitSet[] eastWestWires = (routingGraph.eastWestWires == null) ? null : - routingGraph.eastWestWires.get(sinkINTNode.getTile().getTileTypeEnum()); - RouteNode sinkRnode; - if (eastWestWires != null && eastWestWires[0].get(sinkINTNode.getWireIndex())) { - sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_EAST); - sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK_EAST); - } else if (eastWestWires != null && eastWestWires[1].get(sinkINTNode.getWireIndex())) { - sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_WEST); - sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK_WEST); - } else { - sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK); - sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK); - } + + // Inform RouteNodeInfo.getType() that this a sink to prevent it from returning + // RouteNodeType.LAGUNA_PINFEED and instead return LOCAL_{EAST,WEST} + boolean forceSink = true; + RouteNodeType sinkType = RouteNodeInfo.getType(sinkINTNode, null, routingGraph, forceSink); + assert(sinkType.isAnyLocal()); + sinkType = sinkType == RouteNodeType.LOCAL_EAST ? RouteNodeType.EXCLUSIVE_SINK_EAST : + sinkType == RouteNodeType.LOCAL_WEST ? RouteNodeType.EXCLUSIVE_SINK_WEST : + sinkType == RouteNodeType.LOCAL_BOTH ? RouteNodeType.EXCLUSIVE_SINK_BOTH : + null; + assert(sinkType != null); + RouteNode sinkRnode = routingGraph.getOrCreate(sinkINTNode, sinkType); + sinkRnode.setType(sinkType); connection.setSinkRnode(sinkRnode); + if (sinkINTNode.getTile() != sink.getTile()) { + TileTypeEnum sinkTileType = sink.getTile().getTileTypeEnum(); + if (Utils.isLaguna(sinkTileType)) { + // Sinks in Laguna tiles must be Laguna registers (but will be projected into the INT tile) + // however, it's possible for another net to use the sink node as a bounce -- prevent that here + assert(sinkINTNode.getTile().getTileTypeEnum() == TileTypeEnum.INT); + routingGraph.preserve(sink.getConnectedNode(), net); + } + } + // Where appropriate, allow all 6 LUT pins to be swapped to begin with char lutLetter = sink.getName().charAt(0); int numberOfSwappablePins = (lutPinSwapping && sink.isLUTInputPin()) @@ -665,7 +744,7 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { continue; } RouteNode altSinkRnode = routingGraph.getOrCreate(node, sinkRnode.getType()); - assert(altSinkRnode.getType().isExclusiveSink()); + assert(altSinkRnode.getType().isAnyExclusiveSink()); connection.addAltSinkRnode(altSinkRnode); } @@ -1811,22 +1890,24 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { continue; } switch (childRNode.getType()) { - case LOCAL: + case LOCAL_BOTH: case LOCAL_EAST: case LOCAL_WEST: + case LOCAL_RESERVED: if (!routingGraph.isAccessible(childRNode, connection)) { continue; } - // Verify invariant that east/west wires stay east/west - assert(rnode.getType() != RouteNodeType.LOCAL_EAST || childRNode.getType() == RouteNodeType.LOCAL_EAST); - assert(rnode.getType() != RouteNodeType.LOCAL_WEST || childRNode.getType() == RouteNodeType.LOCAL_WEST); + // Verify invariant that east/west wires stay east/west ... + assert(rnode.getType() != RouteNodeType.LOCAL_EAST || childRNode.getType() == RouteNodeType.LOCAL_EAST || + // ... unless it's an exclusive sink using a LOCAL_RESERVED node + (childRNode.getType() == RouteNodeType.LOCAL_RESERVED && connection.getSinkRnode().getType() == RouteNodeType.EXCLUSIVE_SINK_BOTH)); + assert(rnode.getType() != RouteNodeType.LOCAL_WEST || childRNode.getType() == RouteNodeType.LOCAL_WEST || + (childRNode.getType() == RouteNodeType.LOCAL_RESERVED && connection.getSinkRnode().getType() == RouteNodeType.EXCLUSIVE_SINK_BOTH)); break; case NON_LOCAL: // LOCALs cannot connect to NON_LOCALs except via a LUT routethru - assert(!rnode.getType().isLocal() || - routingGraph.lutRoutethru && rnode.getIntentCode() == IntentCode.NODE_PINFEED || - // FIXME: - design.getSeries() == Series.Versal); + assert(!rnode.getType().isAnyLocal() || + routingGraph.lutRoutethru && rnode.getIntentCode() == IntentCode.NODE_PINFEED); if (!routingGraph.isAccessible(childRNode, connection)) { continue; @@ -1837,14 +1918,16 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { continue; } break; - case EXCLUSIVE_SINK: + case EXCLUSIVE_SINK_BOTH: case EXCLUSIVE_SINK_EAST: case EXCLUSIVE_SINK_WEST: assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK_EAST || rnode.getType() == RouteNodeType.LOCAL_EAST); assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK_WEST || rnode.getType() == RouteNodeType.LOCAL_WEST); - assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK || rnode.getType() == RouteNodeType.LOCAL || - // FIXME: - design.getSeries() == Series.Versal); + assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK_BOTH || rnode.getType() == RouteNodeType.LOCAL_BOTH || + // [BC]NODEs are LOCAL_{EAST,WEST} since they connect to INODEs, but also service CTRL sinks + (routingGraph.isVersal && EnumSet.of(IntentCode.NODE_CLE_BNODE, IntentCode.NODE_CLE_CNODE, + IntentCode.NODE_INTF_BNODE, IntentCode.NODE_INTF_CNODE) + .contains(rnode.getIntentCode()))); if (!isAccessibleSink(childRNode, connection)) { continue; } @@ -1889,7 +1972,7 @@ protected boolean isAccessibleSink(RouteNode child, Connection connection) { } protected boolean isAccessibleSink(RouteNode child, Connection connection, boolean assertOnOveruse) { - assert(child.getType().isExclusiveSink()); + assert(child.getType().isAnyExclusiveSink()); assert(!assertOnOveruse || !child.isOverUsed()); if (child.isTarget()) { diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index 8f8f78d12..df1f36bee 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -33,6 +33,7 @@ import com.xilinx.rapidwright.util.RuntimeTracker; import java.util.ArrayList; +import java.util.EnumSet; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; @@ -123,22 +124,24 @@ private void setBaseCost(Series series) { assert(length == 0 || (length <= 3 && series == Series.Versal)); break; - case EXCLUSIVE_SINK: + case EXCLUSIVE_SINK_BOTH: case EXCLUSIVE_SINK_EAST: case EXCLUSIVE_SINK_WEST: assert(length == 0 || (length == 1 && (series == Series.UltraScalePlus || series == Series.UltraScale) && getIntentCode() == IntentCode.NODE_PINBOUNCE)); break; - case LOCAL: + case LOCAL_BOTH: assert(length == 0); break; case LOCAL_EAST: case LOCAL_WEST: + case LOCAL_RESERVED: assert(length == 0 || (length == 1 && ( ((series == Series.UltraScalePlus || series == Series.UltraScale) && getIntentCode() == IntentCode.NODE_PINBOUNCE) || (series == Series.UltraScalePlus && getWireName().matches("INODE_[EW]_\\d+_FT[01]")) || - (series == Series.UltraScale && getWireName().matches("INODE_[12]_[EW]_\\d+_FT[NS]")) + (series == Series.UltraScale && getWireName().matches("INODE_[12]_[EW]_\\d+_FT[NS]")) || + (series == Series.Versal && EnumSet.of(IntentCode.NODE_CLE_BNODE, IntentCode.NODE_CLE_CNODE).contains(getIntentCode())) )) ); break; @@ -221,20 +224,6 @@ private void setBaseCost(Series series) { // Feedthrough nodes to reach tiles immediately above/below (length == 1 && getWireName().matches("OUT_[NESW]NODE_[EW]_\\d+"))); break; - case NODE_INODE: // INT.INT_NODE_IMUX_ATOM_*_INT_OUT[01] - case NODE_IMUX: // INT.IMUX_B_[EW]* - case NODE_CLE_CTRL: // CLE_BC_CORE*.CTRL_[LR]_B* - case NODE_INTF_CTRL: // INTF_[LR]OCF_[TB][LR]_TILE.INTF_IRI* - assert(length == 0); - break; - case NODE_CLE_BNODE: // CLE_BC_CORE*.BNODE_OUTS_[EW]* - case NODE_CLE_CNODE: // CLE_BC_CORE*.CNODE_OUTS_[EW]* - case NODE_INTF_BNODE: // INTF_[LR]OCF_[TB][LR]_TILE.IF_INT_BNODE_OUTS* - case NODE_INTF_CNODE: // INTF_[LR]OCF_[TB][LR]_TILE.IF_INT_CNODE_OUTS* - // length == 1 because one side of BCNODE-s are shared between CLE_W_CORE_XaYb and CLE_E_CORE_X(a+1)Yb - // or CLE_W_CORE_X(a-1)Yb and CLE_E_CORE_XaYb - assert(length <= 1); - break; default: throw new RuntimeException(ic.toString()); } @@ -367,10 +356,13 @@ public RouteNodeType getType() { public void setType(RouteNodeType type) { assert(this.type == type || // Support demotion from EXCLUSIVE_SINK to LOCAL since they have the same base cost - (this.type.isExclusiveSink() && type == RouteNodeType.LOCAL) || + (this.type.isAnyExclusiveSink() && type.isAnyLocal()) || // Or promotion from LOCAL to EXCLUSIVE_SINK (by PartialRouter when NODE_PINBOUNCE on // a newly unpreserved net becomes a sink) - (this.type == RouteNodeType.LOCAL && type.isExclusiveSink())); + (this.type.isAnyLocal() && type.isAnyExclusiveSink())) || + // Or promotion for any LOCAL to a LOCAL_RESERVED (by determineRoutingTargets() + // for uphills of CTRL sinks) + (this.type.isAnyLocal() && type == RouteNodeType.LOCAL_RESERVED); this.type = type; } diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index ece65969e..b9cc7aa5d 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -35,6 +35,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -102,14 +103,17 @@ public class RouteNodeGraph { /** Flag for whether LUT routethrus are to be considered */ protected final boolean lutRoutethru; - /** Map indicating (for UltraScale/UltraScale+ only) the wire indices that have a local intent code, - * but is what RWRoute will consider to be non-local, e.g. INT_NODE_SDQ_* + /** Map indicating (for UltraScale/UltraScale+ only) the subset wire indices of a NODE_LOCAL that are + * what RWRoute should assign a LOCAL_* type, e.g. excluding INT_NODE_SDQ_* */ - protected final Map ultraScalesNonLocalWires; + protected final Map ultraScalesLocalWires; /** Map indicating the wire indices corresponding to the east/west side of interconnect tiles */ protected final Map eastWestWires; + /** Flag for whether design targets the Versal series */ + protected final boolean isVersal; + public RouteNodeGraph(Design design, RWRouteConfig config) { this(design, config, new HashMap<>()); } @@ -141,30 +145,45 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map intTileIntentCodeCareSet; Pattern eastWestPattern; - - Tile intTile = device.getArbitraryTileOfType(TileTypeEnum.INT); - // Device.getArbitraryTileOfType() typically gives you the North-Western-most - // tile (with minimum X, maximum Y). Analyze the tile just below that. - intTile = intTile.getTileXYNeighbor(0, -1); - - BitSet wires = new BitSet(); - BitSet eastWires = new BitSet(); - BitSet westWires = new BitSet(); + eastWestWires = new EnumMap<>(TileTypeEnum.class); + BitSet localWires = new BitSet(); if (isUltraScale || isUltraScalePlus) { - ultraScalesNonLocalWires = new EnumMap<>(TileTypeEnum.class); - ultraScalesNonLocalWires.put(intTile.getTileTypeEnum(), wires); - eastWestPattern = Pattern.compile("(((BOUNCE|BYPASS|IMUX|INODE(_[12])?)_([EW]))|INT_NODE_IMUX_(\\d+)_).*"); - - eastWestWires = new EnumMap<>(TileTypeEnum.class); - eastWestWires.put(intTile.getTileTypeEnum(), new BitSet[]{eastWires, westWires}); + intTile = device.getArbitraryTileOfType(TileTypeEnum.INT); + // Device.getArbitraryTileOfType() typically gives you the North-Western-most + // tile (with minimum X, maximum Y). Analyze the tile just below that. + intTile = intTile.getTileXYNeighbor(0, -1); + intTileIntentCodeCareSet = EnumSet.of( + IntentCode.NODE_PINFEED, + IntentCode.NODE_PINBOUNCE, + IntentCode.NODE_LOCAL); + + ultraScalesLocalWires = new EnumMap<>(TileTypeEnum.class); + ultraScalesLocalWires.put(intTile.getTileTypeEnum(), localWires); + + eastWestPattern = Pattern.compile("(((BOUNCE|BYPASS|IMUX|INODE(_[12])?)_(?[EW]))|INT_NODE_IMUX_(?\\d+)_).*"); } else { - assert(series == Series.Versal); - ultraScalesNonLocalWires = null; - - // FIXME: - eastWestPattern = null; - eastWestWires = null; + assert(isVersal); + + // Find an INT tile adjacent to a CLE_BC_CORE tile since Versal devices may contain AIEs on their northern edge + Tile bcCoreTile = device.getArbitraryTileOfType(TileTypeEnum.CLE_BC_CORE); + // Device.getArbitraryTileOfType() typically gives you the North-Western-most + // tile (with minimum X, maximum Y). Analyze the tile just below that. + intTile = bcCoreTile.getTileNeighbor(2, 0); + assert(intTile.getTileTypeEnum() == TileTypeEnum.INT); + intTileIntentCodeCareSet = EnumSet.of( + IntentCode.NODE_IMUX, + IntentCode.NODE_PINBOUNCE, + IntentCode.NODE_INODE, + IntentCode.NODE_CLE_BNODE, + IntentCode.NODE_CLE_CNODE); + + ultraScalesLocalWires = null; + + eastWestPattern = Pattern.compile("(((BOUNCE|IMUX_B|[BC]NODE_OUTS)_(?[EW]))|INT_NODE_IMUX_ATOM_(?\\d+)_).*"); } for (int wireIndex = 0; wireIndex < intTile.getWireCount(); wireIndex++) { @@ -173,74 +192,118 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map new BitSet[]{new BitSet(), new BitSet()}); + BitSet eastWires = eastWestWires[0]; + BitSet westWires = eastWestWires[1]; + String ew = m.group("eastwest"); + String inode; + if (ew != null) { + // [BC]NODEs connect to INODEs opposite to their wire name + if (baseIntentCode == IntentCode.NODE_CLE_BNODE || baseIntentCode == IntentCode.NODE_CLE_CNODE) { + ew = ew.equals("E") ? "W" : "E"; } - } else if (m.group(6) != null) { - int i = Integer.valueOf(m.group(6)); - if (i < 32 || (isUltraScale && (i >= 64 && i < 96))) { + if (ew.equals("E")) { eastWires.set(baseNode.getWireIndex()); } else { - assert(i < 64 || (isUltraScale && (i >= 96 && i < 128))); + assert(ew.equals("W")); westWires.set(baseNode.getWireIndex()); } + } else { + if ((inode = m.group("inode")) != null) { + int i = Integer.valueOf(inode); + if (i < 32 || ((isUltraScale || isVersal) && i >= 64 && i < 96)) { + eastWires.set(baseNode.getWireIndex()); + } else { + assert(i < 64 || (isUltraScale || isVersal && i >= 96 && i < 128)); + westWires.set(baseNode.getWireIndex()); + } + } } } else { - assert(baseWireName.matches("CTRL_[EW](_B)?\\d+|INT_NODE_GLOBAL_\\d+(_INT)?_OUT[01]?") - // FIXME: - || series == Series.Versal); + assert((isUltraScale || isUltraScalePlus) && baseWireName.matches("CTRL_[EW](_B)?\\d+|INT_NODE_GLOBAL_\\d+(_INT)?_OUT[01]?")); } } + if (isVersal) { + // With NODE_CLE_[BC]NODEs being handled as part of the INT tile above, compute east/west wires + // in INTF_* tiles here + BiConsumer, Boolean> lambda = (types, east) -> { + for (TileTypeEnum tte : types) { + Tile intfTile = device.getArbitraryTileOfType(tte); + BitSet eastWestWires = this.eastWestWires.computeIfAbsent(tte, + k -> new BitSet[]{new BitSet(), new BitSet()})[east ? 0 : 1]; + for (int wireIndex = 0; wireIndex < intfTile.getWireCount(); wireIndex++) { + IntentCode baseIntentCode = intfTile.getWireIntentCode(wireIndex); + if (baseIntentCode != IntentCode.NODE_INTF_BNODE && baseIntentCode != IntentCode.NODE_INTF_CNODE) { + continue; + } + assert(Node.getNode(intfTile, wireIndex).getTile() == intfTile); + + eastWestWires.set(wireIndex); + } + } + }; + + lambda.accept(Arrays.asList( + TileTypeEnum.INTF_LOCF_TR_TILE, + TileTypeEnum.INTF_LOCF_BR_TILE, + TileTypeEnum.INTF_ROCF_TR_TILE, + TileTypeEnum.INTF_ROCF_BR_TILE), true); + lambda.accept(Arrays.asList( + TileTypeEnum.INTF_LOCF_TL_TILE, + TileTypeEnum.INTF_LOCF_BL_TILE, + TileTypeEnum.INTF_ROCF_TL_TILE, + TileTypeEnum.INTF_ROCF_BL_TILE), false); + } + if (lutRoutethru) { assert(isUltraScalePlus || isUltraScale); @@ -250,19 +313,19 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map pins) { String pinName = pin.getName(); char lutLetter = pinName.charAt(0); String otherPinName = null; - String otherPinNameSuffix = design.getSeries() == Series.Versal ? "Q" : "MUX"; + String otherPinNameSuffix = isVersal ? "Q" : "MUX"; if (pinName.endsWith(otherPinNameSuffix)) { otherPinName = lutLetter + "_O"; } else if (pinName.endsWith("_O")) { @@ -481,24 +544,37 @@ protected boolean isExcluded(RouteNode parent, Node child) { } } - if (child.getIntentCode() == IntentCode.NODE_PINFEED) { - // PINFEEDs can lead to a site pin, or into a Laguna tile - RouteNode childRnode = getNode(child); - if (childRnode != null) { - assert(childRnode.getType().isExclusiveSink() || - childRnode.getType() == RouteNodeType.LAGUNA_PINFEED || - (lutRoutethru && childRnode.getType().isLocal())); - } else if (!lutRoutethru) { - // child does not already exist in our routing graph, meaning it's not a used site pin - // in our design, but it could be a LAGUNA_I - if (lagunaI == null) { - // No LAGUNA_Is - return true; - } - BitSet bs = lagunaI.get(child.getTile()); - if (bs == null || !bs.get(child.getWireIndex())) { - // Not a LAGUNA_I -- skip it - return true; + IntentCode ic = child.getIntentCode(); + if (isVersal) { + assert(ic != IntentCode.NODE_PINFEED); // This intent code should have been projected away + + if ((!lutRoutethru && ic == IntentCode.NODE_IMUX) || ic == IntentCode.NODE_CLE_CTRL || ic == IntentCode.NODE_INTF_CTRL) { + // Disallow these site pin projections if they aren't already in the routing graph (as a potential sink) + RouteNode childRnode = getNode(child); + return childRnode == null; + } + } else { + assert(design.getSeries() == Series.UltraScale || design.getSeries() == Series.UltraScalePlus); + + if (child.getIntentCode() == IntentCode.NODE_PINFEED) { + // PINFEEDs can lead to a site pin, or into a Laguna tile + RouteNode childRnode = getNode(child); + if (childRnode != null) { + assert(childRnode.getType().isAnyExclusiveSink() || + childRnode.getType() == RouteNodeType.LAGUNA_PINFEED || + (lutRoutethru && childRnode.getType().isAnyLocal())); + } else if (!lutRoutethru) { + // child does not already exist in our routing graph, meaning it's not a used site pin + // in our design, but it could be a LAGUNA_I + if (lagunaI == null) { + // No LAGUNA_Is + return true; + } + BitSet bs = lagunaI.get(child.getTile()); + if (bs == null || !bs.get(child.getWireIndex())) { + // Not a LAGUNA_I -- skip it + return true; + } } } } @@ -613,7 +689,8 @@ public int averageChildren() { public boolean isAccessible(RouteNode childRnode, Connection connection) { // Only consider LOCAL nodes when: // (a) considering LUT routethrus - if (!childRnode.getType().isLocal() || lutRoutethru) { + RouteNodeType type = childRnode.getType(); + if (!type.isAnyLocal() || lutRoutethru) { return true; } @@ -628,30 +705,60 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { } // (c) on the same side as the sink - RouteNodeType type = childRnode.getType(); Tile sinkTile = sinkRnode.getTile(); switch (sinkRnode.getType()) { case EXCLUSIVE_SINK_EAST: - if (type == RouteNodeType.LOCAL_WEST) { + if (type == RouteNodeType.LOCAL_WEST || type == RouteNodeType.LOCAL_RESERVED) { // West wires can never reach an east sink return false; } break; case EXCLUSIVE_SINK_WEST: - if (type == RouteNodeType.LOCAL_EAST) { + if (type == RouteNodeType.LOCAL_EAST || type == RouteNodeType.LOCAL_RESERVED) { // East wires can never reach a west sink return false; } break; - case EXCLUSIVE_SINK: - // Only both-sided wires (e.g. INT_NODE_GLOBAL_*) can reach a both-sided sink (CTRL_*) - if (type != RouteNodeType.LOCAL) { - return false; - } - if (design.getSeries() == Series.UltraScale || design.getSeries() == Series.UltraScalePlus) { - // This must be a CTRL sink; these can only be accessed from the sink tile rather than Y +/- 1 below - return childTile == sinkTile; + case EXCLUSIVE_SINK_BOTH: + // This must be a CTRL sink that can be accessed from both east/west sides + + if (isVersal) { + assert(sinkRnode.getIntentCode() == IntentCode.NODE_CLE_CTRL || sinkRnode.getIntentCode() == IntentCode.NODE_INTF_CTRL); + + if (childTile == sinkTile) { + // CTRL sinks can be only accessed directly from LOCAL_RESERVED nodes in the sink CLE_BC_CORE/INTF_* tile ... + if (type != RouteNodeType.LOCAL_RESERVED) { + return false; + } + } else { + // ... or via LOCAL nodes in the two INT tiles either side + if (childTile.getTileYCoordinate() != sinkTile.getTileYCoordinate() || + Math.abs(childTile.getTileXCoordinate() - sinkTile.getTileXCoordinate()) > 1) { + return false; + } + if (childTile.getTileTypeEnum() != TileTypeEnum.INT) { + // e.g. CLE_BC_CORE_X50Y4 and CLE_BC_CORE_1_X50Y4 on xcvc1502 + return false; + } + // Allow use of INODE + PINBOUNCEs in the two INT tiles on either side of sink + assert(childRnode.getIntentCode() == IntentCode.NODE_INODE || childRnode.getIntentCode() == IntentCode.NODE_PINBOUNCE); + return true; + } + } else { + assert(design.getSeries() == Series.UltraScale || design.getSeries() == Series.UltraScalePlus); + assert(sinkRnode.getWireName().startsWith("CTRL_")); + + // CTRL sinks can only be accessed from LOCAL nodes in the sink tile (rather than Y +/- 1 below) + if (childTile != sinkTile) { + return false; + } + + // Only both-sided wires (e.g. INT_NODE_GLOBAL_*) can reach a both-sided sink (CTRL_*) + if (type != RouteNodeType.LOCAL_BOTH) { + return false; + } } + assert(childTile == sinkTile); break; default: throw new RuntimeException("ERROR: Unexpected sink type " + sinkRnode.getType()); @@ -662,6 +769,41 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { return true; } + if (isVersal) { + assert(sinkRnode.getType() != RouteNodeType.EXCLUSIVE_SINK_BOTH); + assert(sinkRnode.getIntentCode() == IntentCode.NODE_IMUX || sinkRnode.getIntentCode() == IntentCode.NODE_PINBOUNCE); + + IntentCode childIntentCode = childRnode.getIntentCode(); + switch (childIntentCode) { + case NODE_INODE: + // Block access to all INODEs outside the sink tile, since NODE_INODE -> NODE_IMUX -> NODE_PINFEED (or NODE_INODE -> NODE_PINBOUNCE) + assert(childTile != sinkTile); + return false; + case NODE_CLE_BNODE: + case NODE_INTF_BNODE: + case NODE_CLE_CNODE: + case NODE_INTF_CNODE: + // Only allow [BC]NODEs that reach into the sink tile + return childTile.getTileYCoordinate() == sinkTile.getTileYCoordinate() && + childRnode.getEndTileXCoordinate() == sinkTile.getTileXCoordinate(); + case NODE_PINBOUNCE: + // BOUNCEs are only accessible through INODEs, so transitively this intent code is unreachable + break; + case NODE_IMUX: + // IMUXes that are not our target EXCLUSIVE_SINK will have been isExcluded() from the graph unless LUT routethrus are enabled + assert(lutRoutethru); + break; + case NODE_PINFEED: + // Expected to be projected away + break; + case NODE_CLE_CTRL: + case NODE_INTF_CTRL: + // CTRL pins that are not our target EXCLUSIVE_SINK will have been isExcluded() from the graph + break; + } + throw new RuntimeException("ERROR: Unhandled IntentCode: " + childIntentCode); + } + // (e) when in same X as the sink tile, but Y +/- 1 return childX == sinkTile.getTileXCoordinate() && Math.abs(childTile.getTileYCoordinate() - sinkTile.getTileYCoordinate()) <= 1; diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java index 2387dd745..2b06ce855 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java @@ -24,7 +24,6 @@ import com.xilinx.rapidwright.device.IntentCode; import com.xilinx.rapidwright.device.Node; -import com.xilinx.rapidwright.device.Series; import com.xilinx.rapidwright.device.Tile; import com.xilinx.rapidwright.device.TileTypeEnum; import com.xilinx.rapidwright.device.Wire; @@ -66,7 +65,8 @@ public static RouteNodeInfo get(Node node, RouteNodeGraph routingGraph) { endTile = node.getTile(); } - RouteNodeType type = getType(node, endTile, routingGraph); + boolean forceSink = false; + RouteNodeType type = getType(node, endTile, routingGraph, forceSink); short endTileXCoordinate = getEndTileXCoordinate(node, type, (short) endTile.getTileXCoordinate()); short endTileYCoordinate = (short) endTile.getTileYCoordinate(); short length = getLength(baseTile, type, endTileXCoordinate, endTileYCoordinate); @@ -126,7 +126,7 @@ private static short getEndTileXCoordinate(Node node, RouteNodeType type, short return endTileXCoordinate; } - private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph routingGraph) { + public static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph routingGraph, boolean forceSink) { // NOTE: IntentCode is device-dependent IntentCode ic = node.getIntentCode(); TileTypeEnum tileTypeEnum = node.getTile().getTileTypeEnum(); @@ -134,22 +134,25 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou case NODE_LOCAL: { // US/US+ assert(tileTypeEnum == TileTypeEnum.INT); if (routingGraph != null) { - BitSet bs = routingGraph.ultraScalesNonLocalWires.get(tileTypeEnum); + BitSet bs = routingGraph.ultraScalesLocalWires.get(tileTypeEnum); if (!bs.get(node.getWireIndex())) { - BitSet[] eastWestWires = routingGraph.eastWestWires.get(tileTypeEnum); - if (eastWestWires[0].get(node.getWireIndex())) { - return RouteNodeType.LOCAL_EAST; - } else if (eastWestWires[1].get(node.getWireIndex())) { - return RouteNodeType.LOCAL_WEST; - } - return RouteNodeType.LOCAL; + break; } - break; + BitSet[] eastWestWires = routingGraph.eastWestWires.get(tileTypeEnum); + if (eastWestWires[0].get(node.getWireIndex())) { + return RouteNodeType.LOCAL_EAST; + } else if (eastWestWires[1].get(node.getWireIndex())) { + return RouteNodeType.LOCAL_WEST; + } + return RouteNodeType.LOCAL_BOTH; } } case NODE_PINFEED: - if (routingGraph != null && routingGraph.lagunaI != null) { + if (routingGraph == null || routingGraph.isVersal) { + return RouteNodeType.LOCAL_BOTH; + } + if (routingGraph.lagunaI != null && !forceSink) { BitSet bs = routingGraph.lagunaI.get(node.getTile()); if (bs != null && bs.get(node.getWireIndex())) { return RouteNodeType.LAGUNA_PINFEED; @@ -157,18 +160,27 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou } // Fall through case NODE_PINBOUNCE: - if (routingGraph != null && routingGraph.eastWestWires != null) { + case NODE_INODE: // INT.INT_NODE_IMUX_ATOM_*_INT_OUT[01] (Versal only) + case NODE_IMUX: // INT.IMUX_B_[EW]* (Versal only) + case NODE_CLE_CNODE: // CLE_BC_CORE*.CNODE_OUTS_[EW]* (Versal only) + case NODE_CLE_BNODE: // CLE_BC_CORE*.BNODE_OUTS_[EW]* (Versal only) + case NODE_INTF_BNODE: // INTF_[LR]OCF_[TB][LR]_TILE.IF_INT_BNODE_OUTS* (Versal only) + case NODE_INTF_CNODE: // INTF_[LR]OCF_[TB][LR]_TILE.IF_INT_CNODE_OUTS* (Versal only) + if (routingGraph != null) { BitSet[] eastWestWires = routingGraph.eastWestWires.get(tileTypeEnum); if (eastWestWires[0].get(node.getWireIndex())) { return RouteNodeType.LOCAL_EAST; } else if (eastWestWires[1].get(node.getWireIndex())) { return RouteNodeType.LOCAL_WEST; } - assert(node.getWireName().startsWith("CTRL_") || - // FIXME: - routingGraph.design.getSeries() == Series.Versal); + assert(!routingGraph.isVersal && node.getWireName().startsWith("CTRL_")); } - return RouteNodeType.LOCAL; + return RouteNodeType.LOCAL_BOTH; + + // Versal only + case NODE_CLE_CTRL: // CLE_BC_CORE*.CTRL_[LR]_B* + case NODE_INTF_CTRL: // INTF_[LR]OCF_[TB][LR]_TILE.INTF_IRI* + return RouteNodeType.LOCAL_BOTH; case NODE_LAGUNA_OUTPUT: // UltraScale+ only assert(tileTypeEnum == TileTypeEnum.LAG_LAG); @@ -179,6 +191,7 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou case NODE_LAGUNA_DATA: // UltraScale+ only assert(tileTypeEnum == TileTypeEnum.LAG_LAG); + assert(endTile != null); if (node.getTile() != endTile) { return RouteNodeType.SUPER_LONG_LINE; } @@ -190,6 +203,7 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou if (tileTypeEnum == TileTypeEnum.LAGUNA_TILE) { // UltraScale only String wireName = node.getWireName(); if (wireName.startsWith("UBUMP")) { + assert(endTile != null); assert(node.getTile() != endTile); return RouteNodeType.SUPER_LONG_LINE; } else if (wireName.endsWith("_TXOUT")) { diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java index 0c024bb0b..7df6c3bfe 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java @@ -28,7 +28,7 @@ public enum RouteNodeType { EXCLUSIVE_SOURCE, - EXCLUSIVE_SINK, + EXCLUSIVE_SINK_BOTH, EXCLUSIVE_SINK_EAST, EXCLUSIVE_SINK_WEST, @@ -46,15 +46,17 @@ public enum RouteNodeType { NON_LOCAL, - LOCAL, + LOCAL_BOTH, LOCAL_EAST, - LOCAL_WEST; + LOCAL_WEST, - public boolean isExclusiveSink() { - return this == EXCLUSIVE_SINK || this == EXCLUSIVE_SINK_EAST || this == EXCLUSIVE_SINK_WEST; + LOCAL_RESERVED; + + public boolean isAnyExclusiveSink() { + return this == EXCLUSIVE_SINK_BOTH || this == EXCLUSIVE_SINK_EAST || this == EXCLUSIVE_SINK_WEST; } - public boolean isLocal() { - return this == LOCAL || this == LOCAL_EAST || this == LOCAL_WEST; + public boolean isAnyLocal() { + return this == LOCAL_BOTH || this == LOCAL_EAST || this == LOCAL_WEST || this == LOCAL_RESERVED; } } diff --git a/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java b/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java index c51cc6789..d57747c92 100644 --- a/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java +++ b/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java @@ -128,7 +128,7 @@ private NetWrapper createNetWrapper(Net net) { if (sinkINTNode == null) { connection.setDirect(true); } else { - connection.setSinkRnode(routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK)); + connection.setSinkRnode(routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_BOTH)); if (sourceINTNode == null) { sourceINTNode = RouterHelper.projectOutputPinToINTNode(source); } diff --git a/test/src/com/xilinx/rapidwright/device/TestNode.java b/test/src/com/xilinx/rapidwright/device/TestNode.java index f1aa47759..b45964650 100644 --- a/test/src/com/xilinx/rapidwright/device/TestNode.java +++ b/test/src/com/xilinx/rapidwright/device/TestNode.java @@ -228,8 +228,10 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str @ParameterizedTest @CsvSource({ - "xcvp1002,INT_X38Y220,NODE_PINBOUNCE,BOUNCE_E.*,true", - "xcvp1002,INT_X38Y220,NODE_PINBOUNCE,BOUNCE_W.*,true", + "xcvp1002,INT_X38Y220,NODE_PINBOUNCE,BOUNCE_E([0-9]|1[0-5]),true", + "xcvp1002,INT_X38Y220,NODE_PINBOUNCE,BOUNCE_E(1[6-9]|2[0-9]|3[01]),true", + "xcvp1002,INT_X38Y220,NODE_PINBOUNCE,BOUNCE_W([0-9]|1[0-5]),true", + "xcvp1002,INT_X38Y220,NODE_PINBOUNCE,BOUNCE_W(1[6-9]|2[0-9]|3[01]),true", "xcvp1002,INT_X38Y220,NODE_INODE,INT_NODE_IMUX_ATOM_([0-9]|1[0-9]|2[0-9]|3[01]|6[4-9]|7[0-9]|8[0-9]|9[0-5])_.*,true", "xcvp1002,INT_X38Y220,NODE_INODE,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])_.*,true", "xcvp1002,INT_X38Y220,NODE_IMUX,IMUX_B_E.*,true", diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestGlobalSignalRouting.java b/test/src/com/xilinx/rapidwright/rwroute/TestGlobalSignalRouting.java index cf196000b..efd1ae6a4 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestGlobalSignalRouting.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestGlobalSignalRouting.java @@ -124,13 +124,13 @@ public void testRouteStaticNet() { RouteThruHelper routeThruHelper = new RouteThruHelper(design.getDevice()); - GlobalSignalRouting.routeStaticNet(gndNet, (n) -> getNodeState(design, NetType.GND, n), design, routeThruHelper); + GlobalSignalRouting.routeStaticNet(gndPins, (n) -> getNodeState(design, NetType.GND, n), design, routeThruHelper); gndPins = gndNet.getPins(); - Assertions.assertEquals(857, gndPins.stream().filter((spi) -> spi.isOutPin()).count()); + Assertions.assertEquals(737, gndPins.stream().filter((spi) -> spi.isOutPin()).count()); Assertions.assertEquals(19010, gndPins.stream().filter((spi) -> !spi.isOutPin()).count()); - Assertions.assertEquals(33201, gndNet.getPIPs().size()); + Assertions.assertEquals(33429, gndNet.getPIPs().size()); - GlobalSignalRouting.routeStaticNet(vccNet, (n) -> getNodeState(design, NetType.VCC, n), design, routeThruHelper); + GlobalSignalRouting.routeStaticNet(vccPins, (n) -> getNodeState(design, NetType.VCC, n), design, routeThruHelper); vccPins = vccNet.getPins(); Assertions.assertEquals(0, vccPins.stream().filter((spi) -> spi.isOutPin()).count()); Assertions.assertEquals(23099, vccPins.stream().filter((spi) -> !spi.isOutPin()).count()); @@ -209,12 +209,12 @@ public void testRouteStaticNetOnVersalDevice(boolean createStaticPins, @TempDir RouteThruHelper routeThruHelper = new RouteThruHelper(design.getDevice()); Design finalDesign = design; - GlobalSignalRouting.routeStaticNet(gndNet, (n) -> getNodeState(finalDesign, NetType.GND, n), design, routeThruHelper); + GlobalSignalRouting.routeStaticNet(gndPins, (n) -> getNodeState(finalDesign, NetType.GND, n), design, routeThruHelper); Assertions.assertEquals(8, gndPins.stream().filter((spi) -> spi.isOutPin()).count()); Assertions.assertEquals(123, gndPins.stream().filter((spi) -> !spi.isOutPin()).count()); Assertions.assertEquals(436, gndNet.getPIPs().size()); - GlobalSignalRouting.routeStaticNet(vccNet, (n) -> getNodeState(finalDesign, NetType.VCC, n), design, routeThruHelper); + GlobalSignalRouting.routeStaticNet(vccPins, (n) -> getNodeState(finalDesign, NetType.VCC, n), design, routeThruHelper); Assertions.assertEquals(0, vccPins.stream().filter((spi) -> spi.isOutPin()).count()); Assertions.assertEquals(232, vccPins.stream().filter((spi) -> !spi.isOutPin()).count()); Assertions.assertEquals(464, vccNet.getPIPs().size());