Skip to content

Commit

Permalink
Merge branch 'master' into rwroute_cleanup2
Browse files Browse the repository at this point in the history
Conflicts:
	src/com/xilinx/rapidwright/rwroute/Connection.java
	src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java
	src/com/xilinx/rapidwright/rwroute/PartialRouter.java
	src/com/xilinx/rapidwright/rwroute/RWRoute.java
	src/com/xilinx/rapidwright/rwroute/RouteNode.java
	src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java
	src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java
	src/com/xilinx/rapidwright/rwroute/RouteNodeType.java
  • Loading branch information
eddieh-xlnx committed Nov 18, 2024
2 parents 062e4d9 + 9cd25a6 commit 88145ed
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 111 deletions.
2 changes: 1 addition & 1 deletion src/com/xilinx/rapidwright/rwroute/Connection.java
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,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().isAnyExclusiveSink()) {
!rnode.getType().isAnyExclusiveSink()) {
assert(rnode.getIntentCode() != IntentCode.NODE_PINBOUNCE);
rnode.markTarget(state);
}
Expand Down
39 changes: 20 additions & 19 deletions src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java
Original file line number Diff line number Diff line change
Expand Up @@ -331,16 +331,15 @@ 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();
Queue<Node> q = new ArrayDeque<>();
Set<Node> usedRoutingNodes = new HashSet<>();
Map<Node, Node> prevNode = new HashMap<>();
Expand Down Expand Up @@ -380,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 @@ -519,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 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 @@ -299,8 +299,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 @@ -319,8 +328,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
102 changes: 79 additions & 23 deletions src/com/xilinx/rapidwright/rwroute/RWRoute.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,18 @@
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;
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 +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++;
}
Expand All @@ -533,28 +532,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);
}
}

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);
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();
}
}
}

// 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 Expand Up @@ -628,17 +671,30 @@ protected NetWrapper createNetWrapperAndConnections(Net net) {

indirectConnections.add(connection);

RouteNodeInfo rni = RouteNodeInfo.get(sinkINTNode, routingGraph);
assert(rni.type.isAnyLocal());
RouteNodeType sinkType = rni.type == RouteNodeType.LOCAL_EAST ? RouteNodeType.EXCLUSIVE_SINK_EAST :
rni.type == RouteNodeType.LOCAL_WEST ? RouteNodeType.EXCLUSIVE_SINK_WEST :
rni.type == RouteNodeType.LOCAL_BOTH ? RouteNodeType.EXCLUSIVE_SINK_BOTH :
null;
// 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())
Expand Down Expand Up @@ -1820,10 +1876,10 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) {
continue;
}
switch (childRNode.getType()) {
case LOCAL_RESERVED:
case LOCAL_BOTH:
case LOCAL_EAST:
case LOCAL_WEST:
case LOCAL_RESERVED:
if (!routingGraph.isAccessible(childRNode, connection)) {
continue;
}
Expand Down
Loading

0 comments on commit 88145ed

Please sign in to comment.