Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GlobalSignalRouting] routeStaticNets() to take a list of static pins #1105

Merged
merged 20 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 25 additions & 24 deletions src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java
Original file line number Diff line number Diff line change
Expand Up @@ -331,22 +331,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<SitePinInst> pins,
Function<Node,NodeStatus> getNodeState,
Design design, RouteThruHelper routeThruHelper) {
NetType netType = currNet.getType();
Set<PIP> netPIPs = new HashSet<>(currNet.getPIPs());
Queue<Node> q = new ArrayDeque<>();
Set<Node> usedRoutingNodes = new HashSet<>();
Map<Node, Node> prevNode = new HashMap<>();
List<Node> pathNodes = new ArrayList<>();
Set<SitePin> sitePinsToCreate = new HashSet<>();
List<SitePin> sitePinsToCreate = new ArrayList<>();
final Node INVALID_NODE = new Node(null, Integer.MAX_VALUE);
assert(INVALID_NODE.isInvalidNode());

Expand Down Expand Up @@ -381,19 +379,33 @@ public static void routeStaticNet(Net currNet,
}

// Collect all node-sink pairs to be routed
Net currNet = null;
Map<Node,SitePinInst> 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
// to maximize sharing
List<Node> 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);
Expand Down Expand Up @@ -520,18 +532,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);
Expand All @@ -553,7 +553,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);
Expand All @@ -564,6 +566,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);
Expand Down Expand Up @@ -591,8 +594,6 @@ public static void routeStaticNet(Net currNet,
currNet.addPin(spi, updateSiteRouting);
spi.setRouted(true);
}

currNet.setPIPs(netPIPs);
}

/**
Expand Down
19 changes: 16 additions & 3 deletions src/com/xilinx/rapidwright/rwroute/PartialRouter.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<SitePinInst> outputPins = new ArrayList<>();
for (SitePinInst spi : staticNet.getPins()) {
if (!spi.isOutPin()) {
continue;
}
outputPins.add(spi);
}
routingGraph.preserveAsync(staticNet, outputPins);
numPreservedStaticNets++;
}

Expand All @@ -310,8 +319,12 @@ protected void addStaticNetRoutingTargets(Net staticNet) {

@Override
protected void preserveNet(Net net, boolean async) {
List<SitePinInst> pinsToRoute = netToPins.get(net);
// Only preserve those pins that are not to be routed
List<SitePinInst> 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<SitePinInst> pinsToPreserve;
if (pinsToRoute == null) {
pinsToPreserve = net.getPins();
Expand Down
74 changes: 58 additions & 16 deletions src/com/xilinx/rapidwright/rwroute/RWRoute.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@

import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.EnumSet;
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;
Expand Down Expand Up @@ -519,11 +519,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++;
}
Expand All @@ -533,28 +531,72 @@ 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<SitePinInst> gndPins = staticNetAndRoutingTargets.get(gndNet);
if (gndPins != null) {
boolean invertGndToVccForLutInputs = config.isInvertGndToVccForLutInputs();
Set<SitePinInst> newVccPins = RouterHelper.invertPossibleGndPinsToVccPins(design, gndPins, invertGndToVccForLutInputs);
if (!newVccPins.isEmpty()) {
gndPins.removeAll(newVccPins);
staticNetAndRoutingTargets.computeIfAbsent(vccNet, (net) -> new ArrayList<>())
.addAll(newVccPins);
}
}

Iterator<Map.Entry<Net,List<SitePinInst>>> it = staticNetAndRoutingTargets.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Net,List<SitePinInst>> e = it.next();
Net staticNet = e.getKey();
List<SitePinInst> 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<SitePinInst> gndPins = staticNetAndRoutingTargets.get(design.getGndNet());
if (gndPins != null) {
boolean invertGndToVccForLutInputs = config.isInvertGndToVccForLutInputs();
Set<SitePinInst> 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<Net,List<SitePinInst>> e : staticNetAndRoutingTargets.entrySet()) {
Net staticNet = e.getKey();
List<SitePinInst> pins = e.getValue();

System.out.println("INFO: Routing " + pins.size() + " pins of " + staticNet);

Function<Node, NodeStatus> gns = (node) -> getGlobalRoutingNodeStatus(staticNet, node);
GlobalSignalRouting.routeStaticNet(staticNet, gns, design, routethruHelper);
GlobalSignalRouting.routeStaticNet(pins, gns, design, routethruHelper);

preserveNet(staticNet, false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -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());
Expand Down
Loading