Skip to content

Commit 425d89e

Browse files
[RWRoute] Add --lutRoutethru option (#932)
* Move assertion in case no site pin Signed-off-by: Eddie Hung <eddie.hung@amd.com> * RouteNodeInfo.getType() to return WIRE for NODE_PINFEED Since we expect sink RouteNode's to explicit set its type to be PINFEED_I Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Update comment Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Move assertion for twin method Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Add --lutRoutethru option to RWRouteConfig Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Preliminary LUT routethru support Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Changes to RouteNodeGraph constructor Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Add testNonTimingDrivenFullRoutingWithLutRoutethru() Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Do not block INT_NODE_IMUX_ accessibility when LUT routethrus Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Better method names, add comment, print LUT pin swap/routethru flag Signed-off-by: Eddie Hung <eddie.hung@amd.com> * [RWRoute] Analyze a tile below the topmost arbitrary one Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Remove unused import Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Use wireIndex not wireName to block *MUX routethrus Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Fix assertions Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Move global-net fixup before fixRoutes() Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Remove debug Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Enumerate all CLB tiles for *MUX wires Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Add Utils.getLagunaTileTypes() and use Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Fix comment Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Remove unused import Signed-off-by: Eddie Hung <eddie.hung@amd.com> * [RWRoute] Do not pin swap dist. RAMs on the 'H' BELs Since their A and WA inputs are shared Signed-off-by: Eddie Hung <eddie.hung@amd.com> * LUTTools.swapMultipleLutPins() to handle LUT routethrus Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Add TestLUTTools.testUpdateLutPinSwapsFromPIPsWithRWRouteAndLutRoutethrus() Signed-off-by: Eddie Hung <eddie.hung@amd.com> * RouteThruHelper.isRouteThruPIPAvailable() to check out pin conns too Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Fix test Signed-off-by: Eddie Hung <eddie.hung@amd.com> * [PhysNetlistWriter] Recognize static source BELPins (e.g. LUT outputs) Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Revert "RouteThruHelper.isRouteThruPIPAvailable() to check out pin conns too" This reverts commit b049714. Signed-off-by: Eddie Hung <eddie.hung@amd.com> Conflicts: test/src/com/xilinx/rapidwright/design/tools/TestLUTTools.java * Expand TestRouteThruHelper Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Add TestPhysNetlistWriter.testStaticSourceBELPin() Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Tidy up Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Address review comments Signed-off-by: Eddie Hung <eddie.hung@amd.com> * Update src/com/xilinx/rapidwright/rwroute/RWRoute.java Co-authored-by: Chris Lavin <chris.lavin@amd.com> Signed-off-by: eddieh-xlnx <eddie.hung@amd.com> --------- Signed-off-by: Eddie Hung <eddie.hung@amd.com> Signed-off-by: eddieh-xlnx <eddie.hung@amd.com> Co-authored-by: Chris Lavin <chris.lavin@amd.com>
1 parent afd1161 commit 425d89e

File tree

13 files changed

+330
-119
lines changed

13 files changed

+330
-119
lines changed

src/com/xilinx/rapidwright/design/tools/LUTTools.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.ArrayList;
2828
import java.util.Collection;
2929
import java.util.HashMap;
30+
import java.util.HashSet;
3031
import java.util.Iterator;
3132
import java.util.LinkedHashMap;
3233
import java.util.LinkedList;
@@ -687,6 +688,7 @@ public static int swapLutPinsFromPIPs(Design design) {
687688
Map<SitePinInst, String> oldPinToNewPins = new HashMap<>();
688689
Map<Site, List<SitePinInst>> siteToLutSpis = new HashMap<>();
689690
List<SitePin> unmatchedSitePins = new ArrayList<>();
691+
Set<SitePin> routethruSitePins = new HashSet<>();
690692
for (Net net : design.getNets()) {
691693
if (net.isClockNet()) {
692694
continue;
@@ -713,17 +715,30 @@ public static int swapLutPinsFromPIPs(Design design) {
713715
}
714716

715717
for (PIP pip : net.getPIPs()) {
718+
if (pip.isRouteThru()) {
719+
Node startNode = pip.getStartNode();
720+
SitePin newSitePin = startNode.getSitePin();
721+
assert(newSitePin != null);
722+
routethruSitePins.add(newSitePin);
723+
continue;
724+
}
725+
716726
Node endNode = pip.getEndNode();
717727
SitePin newSitePin = (endNode != null) ? endNode.getSitePin() : null;
718728
if (newSitePin == null) {
719729
continue;
720730
}
721731

722732
Site site = newSitePin.getSite();
723-
SiteInst si = design.getSiteInstFromSite(site);
724-
if (si == null) {
733+
List<SitePinInst> lutSpis = siteToLutSpis.get(site);
734+
if (lutSpis == null) {
735+
// No sink pins from this net exist on this site
736+
// (e.g. this pin is used as routethru)
725737
continue;
726738
}
739+
SiteInst si = design.getSiteInstFromSite(site);
740+
assert(si != null);
741+
727742
String newSitePinName = newSitePin.getPinName();
728743
if (!SitePinInst.isLUTInputPin(si, newSitePinName)) {
729744
continue;
@@ -734,12 +749,17 @@ public static int swapLutPinsFromPIPs(Design design) {
734749
System.out.println("WARNING: SitePin " + newSitePin + " visited by PIP " + pip +
735750
" is not a SitePinInst on net " + net + ". Ignoring.");
736751
} else if (!spis.remove(newSpi)) {
737-
// spi is not already on this net
752+
// spi is not already on this net -- could require pin swapping,
753+
// or could be a routethru
738754
unmatchedSitePins.add(newSitePin);
739755
}
740756
}
741757

742758
for (SitePin newSitePin : unmatchedSitePins) {
759+
if (routethruSitePins.contains(newSitePin)) {
760+
// Pin is part of a routethru, ignore it
761+
continue;
762+
}
743763
Site site = newSitePin.getSite();
744764
List<SitePinInst> unmatchedSpis = siteToLutSpis.get(site);
745765
Iterator<SitePinInst> it = unmatchedSpis.iterator();
@@ -764,6 +784,7 @@ public static int swapLutPinsFromPIPs(Design design) {
764784

765785
siteToLutSpis.clear();
766786
unmatchedSitePins.clear();
787+
routethruSitePins.clear();
767788
}
768789

769790
return swapMultipleLutPins(oldPinToNewPins);

src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,7 @@ private static boolean isNodeUsableStaticSource(Node node, NetType type, Design
513513
// before we stop:
514514
// (1) GND_WIRE
515515
// (2) VCC_WIRE
516-
// (3) Unused LUT Outputs (A_0, B_0,...,H_0)
516+
// (3) Unused LUT Outputs ([A-H]_O, [A-H]MUX)
517517
if ((type == NetType.VCC && node.isTiedToVcc()) ||
518518
(type == NetType.GND && node.isTiedToGnd())) {
519519
return true;

src/com/xilinx/rapidwright/rwroute/PartialRouter.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ public class PartialRouter extends RWRoute {
7272

7373
protected class RouteNodeGraphPartial extends RouteNodeGraph {
7474

75-
public RouteNodeGraphPartial(RuntimeTracker setChildrenTimer, Design design) {
76-
super(setChildrenTimer, design);
75+
public RouteNodeGraphPartial(RuntimeTracker setChildrenTimer, Design design, RWRouteConfig config) {
76+
super(setChildrenTimer, design, config);
7777
}
7878

7979
@Override
@@ -87,8 +87,11 @@ protected boolean isExcluded(Node parent, Node child) {
8787
}
8888

8989
protected class RouteNodeGraphPartialTimingDriven extends RouteNodeGraphTimingDriven {
90-
public RouteNodeGraphPartialTimingDriven(RuntimeTracker rnodesTimer, Design design, DelayEstimatorBase delayEstimator, boolean maskNodesCrossRCLK) {
91-
super(rnodesTimer, design, delayEstimator, maskNodesCrossRCLK);
90+
public RouteNodeGraphPartialTimingDriven(RuntimeTracker rnodesTimer,
91+
Design design,
92+
RWRouteConfig config,
93+
DelayEstimatorBase delayEstimator) {
94+
super(rnodesTimer, design, config, delayEstimator);
9295
}
9396

9497
@Override
@@ -172,9 +175,9 @@ protected RouteNodeGraph createRouteNodeGraph() {
172175
if (config.isTimingDriven()) {
173176
/* An instantiated delay estimator that is used to calculate delay of routing resources */
174177
DelayEstimatorBase estimator = new DelayEstimatorBase(design.getDevice(), new InterconnectInfo(), config.isUseUTurnNodes(), 0);
175-
return new RouteNodeGraphPartialTimingDriven(rnodesTimer, design, estimator, config.isMaskNodesCrossRCLK());
178+
return new RouteNodeGraphPartialTimingDriven(rnodesTimer, design, config, estimator);
176179
} else {
177-
return new RouteNodeGraphPartial(rnodesTimer, design);
180+
return new RouteNodeGraphPartial(rnodesTimer, design, config);
178181
}
179182
}
180183

src/com/xilinx/rapidwright/rwroute/RWRoute.java

Lines changed: 134 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ public class RWRoute{
118118
private float oneMinusTimingWeight;
119119
/** Flag for whether LUT pin swaps are to be considered */
120120
protected boolean lutPinSwapping;
121+
/** Flag for whether LUT routethrus are to be considered */
122+
protected boolean lutRoutethru;
121123

122124
/** The current routing iteration */
123125
protected int routeIteration;
@@ -227,7 +229,8 @@ protected void initialize() {
227229
rnodesCreatedThisIteration = 0;
228230
routethruHelper = new RouteThruHelper(design.getDevice());
229231
presentCongestionFactor = config.getInitialPresentCongestionFactor();
230-
lutPinSwapping = config.getLutPinSwapping();
232+
lutPinSwapping = config.isLutPinSwapping();
233+
lutRoutethru = config.isLutRoutethru();
231234

232235
routerTimer.createRuntimeTracker("determine route targets", "Initialization").start();
233236
determineRoutingTargets();
@@ -267,9 +270,9 @@ protected RouteNodeGraph createRouteNodeGraph() {
267270
if (config.isTimingDriven()) {
268271
/* An instantiated delay estimator that is used to calculate delay of routing resources */
269272
DelayEstimatorBase estimator = new DelayEstimatorBase(design.getDevice(), new InterconnectInfo(), config.isUseUTurnNodes(), 0);
270-
return new RouteNodeGraphTimingDriven(rnodesTimer, design, estimator, config.isMaskNodesCrossRCLK());
273+
return new RouteNodeGraphTimingDriven(rnodesTimer, design, config, estimator);
271274
} else {
272-
return new RouteNodeGraph(rnodesTimer, design);
275+
return new RouteNodeGraph(rnodesTimer, design, config);
273276
}
274277
}
275278

@@ -914,96 +917,152 @@ private List<Connection> getCongestedConnections() {
914917
* Assigns a list of nodes to each connection and fix net routes if there are cycles and / or multi-driver nodes.
915918
*/
916919
protected void postRouteProcess() {
917-
if (routeIteration <= config.getMaxIterations()) {
918-
// perform LUT pin mapping updates
919-
if (lutPinSwapping &&
920-
!Boolean.getBoolean("rapidwright.rwroute.lutPinSwapping.deferIntraSiteRoutingUpdates")) {
921-
Map<SitePinInst, String> pinSwaps = new HashMap<>();
922-
for (Connection connection: indirectConnections) {
923-
SitePinInst oldSinkSpi = connection.getSink();
924-
if (!oldSinkSpi.isLUTInputPin() || !oldSinkSpi.isRouted()) {
920+
if (routeIteration > config.getMaxIterations()) {
921+
return;
922+
}
923+
924+
// perform LUT pin mapping updates
925+
if (lutPinSwapping &&
926+
!Boolean.getBoolean("rapidwright.rwroute.lutPinSwapping.deferIntraSiteRoutingUpdates")) {
927+
Map<SitePinInst, String> pinSwaps = new HashMap<>();
928+
for (Connection connection: indirectConnections) {
929+
SitePinInst oldSinkSpi = connection.getSink();
930+
if (!oldSinkSpi.isLUTInputPin() || !oldSinkSpi.isRouted()) {
931+
continue;
932+
}
933+
934+
List<RouteNode> rnodes = connection.getRnodes();
935+
RouteNode newSinkRnode = rnodes.get(0);
936+
if (newSinkRnode == connection.getSinkRnode()) {
937+
continue;
938+
}
939+
connection.setSinkRnode(newSinkRnode);
940+
941+
SitePin newSitePin = newSinkRnode.getNode().getSitePin();
942+
String existing = pinSwaps.put(oldSinkSpi, newSitePin.getPinName());
943+
assert(existing == null);
944+
}
945+
LUTTools.swapMultipleLutPins(pinSwaps);
946+
}
947+
948+
if (lutRoutethru) {
949+
// It is possible for RWRoute to routethru a LUT that is already being used as a
950+
// static source through its *MUX output. By default, the 6LUT is used for this supply.
951+
// When LUT routethru-s are considered, examine both static nets to find
952+
// any cases where the *MUX output pin is used as a static source alongside
953+
// the *_O output being used as a routethru. In such cases, configure the
954+
// OUTMUX* site PIP to source from the 5LUT rather than the default 6LUT
955+
// so that no conflict occurs
956+
for (Net staticNet : Arrays.asList(design.getGndNet(), design.getVccNet())) {
957+
for (SitePinInst spi : staticNet.getPins()) {
958+
if (!spi.isOutPin()) {
959+
continue;
960+
}
961+
SiteInst si = spi.getSiteInst();
962+
if (!Utils.isSLICE(si)) {
925963
continue;
926964
}
927965

928-
List<RouteNode> rnodes = connection.getRnodes();
929-
RouteNode newSinkRnode = rnodes.get(0);
930-
if (newSinkRnode == connection.getSinkRnode()) {
966+
String pinName = spi.getName();
967+
if (!pinName.endsWith("MUX")) {
931968
continue;
932969
}
933-
connection.setSinkRnode(newSinkRnode);
934970

935-
SitePin newSitePin = newSinkRnode.getSitePin();
936-
String existing = pinSwaps.put(oldSinkSpi, newSitePin.getPinName());
937-
assert(existing == null);
971+
Node muxNode = spi.getConnectedNode();
972+
assert(routingGraph.getPreservedNet(muxNode) == staticNet);
973+
974+
Site site = si.getSite();
975+
char lutLetter = pinName.charAt(0);
976+
Node oNode = site.getConnectedNode(lutLetter + "_O");
977+
RouteNode rnode = routingGraph.getNode(oNode);
978+
if (rnode == null || rnode.getOccupancy() == 0) {
979+
// No LUT6 routethru, nothing to be done
980+
continue;
981+
}
982+
983+
if (pinName.charAt(1) == '6') {
984+
throw new RuntimeException("ERROR: Illegal LUT routethru on " + site + "/" + pinName +
985+
" since the 5LUT is being used as a static source");
986+
}
987+
988+
// Perform intra-site routing back to the LUT5 to not conflict with LUT6 routethru
989+
BEL outmux = si.getBEL("OUTMUX" + lutLetter);
990+
si.routeIntraSiteNet(staticNet, outmux.getPin("D5"), outmux.getPin("OUT"));
991+
992+
if (si.getDesign() == null) {
993+
// Rename SiteInst (away from "STATIC_SOURCE_<siteName>") and
994+
// attach it to the design so that intra-site routing updates take effect
995+
si.setName(site.getName());
996+
design.addSiteInst(si);
997+
}
938998
}
939-
LUTTools.swapMultipleLutPins(pinSwaps);
940999
}
1000+
}
9411001

942-
assignNodesToConnections();
1002+
assignNodesToConnections();
9431003

944-
// fix routes with cycles and / or multi-driver nodes
945-
Set<NetWrapper> routes = fixRoutes();
946-
if (config.isTimingDriven()) updateTimingAfterFixingRoutes(routes);
1004+
// fix routes with cycles and / or multi-driver nodes
1005+
Set<NetWrapper> routes = fixRoutes();
1006+
if (config.isTimingDriven()) updateTimingAfterFixingRoutes(routes);
9471007

948-
// Unset the routed state of all source pins
949-
for (Map.Entry<Net, NetWrapper> e : nets.entrySet()) {
950-
Net net = e.getKey();
951-
SitePinInst source = net.getSource();
952-
SitePinInst altSource = net.getAlternateSource();
953-
SiteInst si = source.getSiteInst();
954-
boolean altSourcePreviouslyRouted = altSource != null ? altSource.isRouted() : false;
955-
for (SitePinInst spi : Arrays.asList(source, altSource)) {
956-
if (spi != null) {
957-
spi.setRouted(false);
958-
assert(spi.getSiteInst() == si);
959-
}
1008+
// Unset the routed state of all source pins
1009+
for (Map.Entry<Net, NetWrapper> e : nets.entrySet()) {
1010+
Net net = e.getKey();
1011+
SitePinInst source = net.getSource();
1012+
SitePinInst altSource = net.getAlternateSource();
1013+
SiteInst si = source.getSiteInst();
1014+
boolean altSourcePreviouslyRouted = altSource != null ? altSource.isRouted() : false;
1015+
for (SitePinInst spi : Arrays.asList(source, altSource)) {
1016+
if (spi != null) {
1017+
spi.setRouted(false);
1018+
assert(spi.getSiteInst() == si);
9601019
}
1020+
}
9611021

962-
// Set the routed state on those source pins that were actually used
963-
NetWrapper netWrapper = e.getValue();
964-
for (Connection connection : netWrapper.getConnections()) {
965-
// Examine getNodes() because connection.getRnodes() is empty for direct connections
966-
List<Node> nodes = connection.getNodes();
967-
if (nodes.isEmpty()) {
968-
// Unroutable connection
969-
continue;
970-
}
1022+
// Set the routed state on those source pins that were actually used
1023+
NetWrapper netWrapper = e.getValue();
1024+
for (Connection connection : netWrapper.getConnections()) {
1025+
// Examine getNodes() because connection.getRnodes() is empty for direct connections
1026+
List<Node> nodes = connection.getNodes();
1027+
if (nodes.isEmpty()) {
1028+
// Unroutable connection
1029+
continue;
1030+
}
9711031

972-
// Set the routed state of the used source node
973-
// and if used and not already present, add it to the SiteInst
974-
Node sourceNode = nodes.get(nodes.size() - 1);
975-
SitePinInst usedSpi = null;
976-
for (SitePinInst spi : Arrays.asList(source, altSource)) {
977-
if (spi != null && sourceNode.equals(spi.getConnectedNode())) {
978-
usedSpi = spi;
979-
}
980-
}
981-
if (usedSpi == null) {
982-
throw new RuntimeException("ERROR: Unknown source node " + sourceNode + " on net " + net.getName());
1032+
// Set the routed state of the used source node
1033+
// and if used and not already present, add it to the SiteInst
1034+
Node sourceNode = nodes.get(nodes.size() - 1);
1035+
SitePinInst usedSpi = null;
1036+
for (SitePinInst spi : Arrays.asList(source, altSource)) {
1037+
if (spi != null && sourceNode.equals(spi.getConnectedNode())) {
1038+
usedSpi = spi;
9831039
}
1040+
}
1041+
if (usedSpi == null) {
1042+
throw new RuntimeException("ERROR: Unknown source node " + sourceNode + " on net " + net.getName());
1043+
}
9841044

985-
// Now that we know this SitePinInst is used, make sure it exists in
986-
// the SiteInst
987-
usedSpi.setRouted(true);
988-
if (si.getSitePinInst(usedSpi.getName()) == null) {
989-
si.addPin(usedSpi);
990-
}
1045+
// Now that we know this SitePinInst is used, make sure it exists in
1046+
// the SiteInst
1047+
usedSpi.setRouted(true);
1048+
if (si.getSitePinInst(usedSpi.getName()) == null) {
1049+
si.addPin(usedSpi);
1050+
}
9911051

992-
if (source.isRouted() && (altSource == null || altSource.isRouted())) {
993-
// Break if all sources have been set to be routed
994-
break;
995-
}
1052+
if (source.isRouted() && (altSource == null || altSource.isRouted())) {
1053+
// Break if all sources have been set to be routed
1054+
break;
9961055
}
997-
// If the alt source was previously routed, and is no longer, let's remove it
998-
if (altSource != null && altSourcePreviouslyRouted && !altSource.isRouted()) {
999-
boolean sourceRouted = source.isRouted();
1000-
altSource.getSiteInst().removePin(altSource);
1001-
net.removePin(altSource);
1002-
source.setRouted(sourceRouted);
1003-
if (altSource.getName().endsWith("_O") && source.getName().endsWith("MUX") && source.isRouted()) {
1004-
// Add site routing back if we are keeping the MUX pin
1005-
source.getSiteInst().routeIntraSiteNet(net, altSource.getBELPin(), altSource.getBELPin());
1006-
}
1056+
}
1057+
// If the alt source was previously routed, and is no longer, let's remove it
1058+
if (altSource != null && altSourcePreviouslyRouted && !altSource.isRouted()) {
1059+
boolean sourceRouted = source.isRouted();
1060+
altSource.getSiteInst().removePin(altSource);
1061+
net.removePin(altSource);
1062+
source.setRouted(sourceRouted);
1063+
if (altSource.getName().endsWith("_O") && source.getName().endsWith("MUX") && source.isRouted()) {
1064+
// Add site routing back if we are keeping the MUX pin
1065+
source.getSiteInst().routeIntraSiteNet(net, altSource.getBELPin(), altSource.getBELPin());
10071066
}
10081067
}
10091068
}

0 commit comments

Comments
 (0)