From d75c40484328f3a492564483a100aed53fcba04f Mon Sep 17 00:00:00 2001 From: eddieh-xlnx Date: Fri, 22 Nov 2024 18:19:03 -0800 Subject: [PATCH] Various preprocessing fixes for Versal routing (#1115) * [IntentCode] Add isVersalCnode() helper method Signed-off-by: Eddie Hung Conflicts: src/com/xilinx/rapidwright/device/IntentCode.java * [GlobalSignalRouting] Allow INTF CNODEs, all CNODEs even if reserved Signed-off-by: Eddie Hung * Revert "[IntentCode] Add isVersalCnode() helper method" This reverts commit 435152a03c734d10fa41b606b0575c797cc3a922. Signed-off-by: Eddie Hung * Move Versal {B,C}NODE heuristic from determineRoutingTargets() to initializeRouting(), which is after route{GlobalClock,Static}Nets() Signed-off-by: Eddie Hung * [RouterHelper] invertPossibleGndPinsToVccPins() exception for DSP58 Signed-off-by: Eddie Hung * [DesignTools] getAllRoutedSitePinsFromPhysicalPin() handle SLICE_FF_CLK_MOD Signed-off-by: Eddie Hung * [DesignTools] getAllRoutedSitePinsFromPhysicalPin() to handle DSP_CAS_DELAY Signed-off-by: Eddie Hung * [CUFR] CUFR and PartialCUFR to default to --hus Emit warning if not enabled Signed-off-by: Eddie Hung * [RouterHelper] invertPossibleGndPinsToVccPins() to invert Versal BRAM.CLK Signed-off-by: Eddie Hung * [RouterHelper] invertPossibleGndPinsToVccPins() to use correct sitewire Signed-off-by: Eddie Hung * [DesignTools] createA1A6ToStaticNets() to handle SRL16s on LUT5+6 Signed-off-by: Eddie Hung * Fix DesignTools.createA1A6ToStaticNets() Signed-off-by: Eddie Hung * [RouteNode] Correct assertions in setBaseCost() for Versal Signed-off-by: Eddie Hung * [TestNode] Extend testNodeReachabilityVersal Signed-off-by: Eddie Hung * Update comment Signed-off-by: Eddie Hung * Update src/com/xilinx/rapidwright/design/DesignTools.java Signed-off-by: eddieh-xlnx --------- Signed-off-by: Eddie Hung Signed-off-by: eddieh-xlnx --- .../rapidwright/design/DesignTools.java | 135 ++++++++++++------ .../xilinx/rapidwright/device/IntentCode.java | 6 + .../rwroute/GlobalSignalRouting.java | 23 +-- .../xilinx/rapidwright/rwroute/RWRoute.java | 52 +++---- .../xilinx/rapidwright/rwroute/RouteNode.java | 29 +++- .../rapidwright/rwroute/RouterHelper.java | 13 +- .../xilinx/rapidwright/device/TestNode.java | 3 +- 7 files changed, 171 insertions(+), 90 deletions(-) diff --git a/src/com/xilinx/rapidwright/design/DesignTools.java b/src/com/xilinx/rapidwright/design/DesignTools.java index 54d747d44..855c948ec 100644 --- a/src/com/xilinx/rapidwright/design/DesignTools.java +++ b/src/com/xilinx/rapidwright/design/DesignTools.java @@ -2296,11 +2296,19 @@ public static List getAllRoutedSitePinsFromPhysicalPin(Cell cell, Net ne } else if (bel.isLUT() || bel.getBELType().endsWith("MUX") || // F[789]MUX // Versal + bel.isSliceFFClkMod() || bel.getName().endsWith("_IMR")) { Cell possibleRouteThru = inst.getCell(bel); - if (possibleRouteThru != null && possibleRouteThru.isRoutethru()) { - String routeThru = possibleRouteThru.getPinMappingsP2L().keySet().iterator().next(); - queue.add(bel.getPin(routeThru)); + if (possibleRouteThru == null) { + BELPin clkBelPin = bel.isSliceFFClkMod() ? bel.getPin("CLK") : null; + if (clkBelPin != null && inst.getNetFromSiteWire(clkBelPin.getSiteWireName()) == net) { + queue.add(clkBelPin); + } + } else { + if (possibleRouteThru.isRoutethru()) { + String routeThru = possibleRouteThru.getPinMappingsP2L().keySet().iterator().next(); + queue.add(bel.getPin(routeThru)); + } } } } @@ -2309,20 +2317,40 @@ public static List getAllRoutedSitePinsFromPhysicalPin(Cell cell, Net ne if (!siteWires.contains(sink.getSiteWireName())) continue; if (sink.isSitePort()) { sitePins.add(sink.getName()); - } else if (sink.getBEL().getBELClass() == BELClass.RBEL) { + continue; + } + BEL bel = sink.getBEL(); + if (bel.getBELClass() == BELClass.RBEL) { // Check if the SitePIP is being used - SitePIP sitePIP = inst.getUsedSitePIP(sink.getBELName()); - if (sitePIP == null) continue; - // Don't proceed if it's configured for a different pin - if (!sitePIP.getInputPinName().equals(sink.getName())) continue; + SitePIP sitePIP = inst.getUsedSitePIP(sink); + if (sitePIP == null) { + continue; + } + assert(sitePIP.getInputPinName().equals(sink.getName())); // Make this the new source to search from and keep looking... queue.add(sitePIP.getOutputPin()); - } else if (sink.getBEL().isFF()) { + } else if (bel.isFF()) { // FF pass thru option (not a site PIP) - siteWireName = sink.getBEL().getPin("Q").getSiteWireName(); + siteWireName = bel.getPin("Q").getSiteWireName(); if (siteWires.contains(siteWireName)) { sitePins.add(siteWireName); } + } else if (bel.getBELType().equals("DSP_CAS_DELAY")) { + // Versal only + SitePIP sitePIP = inst.getUsedSitePIP(sink); + if (sitePIP == null) { + continue; + } + assert(sitePIP.getInputPinName().equals(sink.getName())); + // For an unknown reason, it appears that the sitewire is not painted correctly ... + // Make this the new source to search from and keep looking... + // queue.add(sitePIP.getOutputPin()); + // ... so assume it is and workaround + BELPin source = sitePIP.getOutputPin(); + assert(source.getSiteConns().size() == 1); + BELPin port = source.getSiteConns().get(0); + assert(port.isSitePort()); + sitePins.add(port.getName()); } } } @@ -3244,53 +3272,67 @@ public static void createA1A6ToStaticNets(Design design) { } String belName = bel.getName(); - if ("SRL16E".equals(cell.getType()) || "SRLC32E".equals(cell.getType())) { - String pinName = belName.charAt(0) + "1"; - SitePinInst spi = si.getSitePinInst(pinName); - if (spi != null) { - assert(spi.getNet().isVCCNet()); + char fiveOrSix = belName.charAt(1); + if (fiveOrSix == '5') { + // Assume that only 5LUT can use O5 + assert(cell.getLogicalPinMapping("O5") != null || cell.isRoutethru()); + if (LUTTools.getCompanionLUTCell(cell) != null) { + // 5LUT is used, but 6LUT also exists; let the 6LUT deal with things continue; } - vccNet.createPin(pinName, si); - } + } else { + assert(fiveOrSix == '6'); - if (cell.getLogicalPinMapping("A6") != null) { - // A6 pin is being used by LUT - continue; + if ("SRLC32E".equals(cell.getType())) { + // For SRLC32Es, only the A1 needs to be tied to VCC + String pinName = belName.charAt(0) + "1"; + SitePinInst spi = si.getSitePinInst(pinName); + if (spi == null) { + vccNet.createPin(pinName, si); + } else { + assert(spi.getNet().isVCCNet()); + } + // A6 is needed as a logical pin + assert(cell.getLogicalPinMapping("A6") != null); + } + + if (cell.getLogicalPinMapping("A6") != null) { + // A6 pin is being used by LUT/SRL; no need to tie it to VCC + continue; + } } - char fiveOrSix = belName.charAt(1); - assert(fiveOrSix == '5' || fiveOrSix == '6'); Net staticNet = vccNet; - BEL lut6Bel = (fiveOrSix == '5') ? si.getBEL(belName.charAt(0) + "6LUT") : bel; Net a6Net = si.getNetFromSiteWire(lut6Bel.getPin("A6").getSiteWireName()); - // SRL16Es that have been transformed from SRLC32E require GND on their A6 pin - if (cell.getType().equals("SRL16E") && "SRLC32E".equals(cell.getPropertyValueString("XILINX_LEGACY_PRIM"))) { - staticNet = gndNet; - // Expect sitewire to be VCC and GND - if (!a6Net.isStaticNet()) { - throw new RuntimeException("ERROR: Site pin " + si.getSiteName() + "/" + belName.charAt(0) + "6 is not a static net"); + boolean expectGndNet = false; + if ("SRL16E".equals(cell.getType())) { + String pinName = belName.charAt(0) + "1"; + SitePinInst spi = si.getSitePinInst(pinName); + if (spi == null) { + vccNet.createPin(pinName, si); } - } else { - // Tie A6 to staticNet only if sitewire says so - if (a6Net != staticNet) { - continue; + + // SRL16Es that have been transformed from SRLC32E require GND on their A6 pin + if ("SRLC32E".equals(cell.getPropertyValueString("XILINX_LEGACY_PRIM"))) { + expectGndNet = true; + staticNet = gndNet; + // Expect sitewire to be VCC or GND + if (!a6Net.isStaticNet()) { + throw new RuntimeException("ERROR: Site pin " + si.getSiteName() + "/" + belName.charAt(0) + "6 is not a static net"); + } } } + // Tie A6 to staticNet only if sitewire says so + if (a6Net != staticNet && !expectGndNet) { + continue; + } + if (cell.getLogicalPinMapping("O5") != null) { // LUT output comes out on O5 - if (fiveOrSix == '5') { - // It's a 5LUT - if (si.getCell(belName.charAt(0) + "6LUT") != null) { - // But 6LUT exists; let the 6LUT deal with it - continue; - } - } else { - throw new RuntimeException("Assumption that only 5LUTs can use O5 failed here."); - } + assert(fiveOrSix == '5'); } else { if (fiveOrSix != '6') { // Assume that O6 is only driven by 6LUT, even though possible for 5LUT, unless @@ -3298,7 +3340,6 @@ public static void createA1A6ToStaticNets(Design design) { assert (cell.isRoutethru()); continue; } - assert(fiveOrSix == '6'); } @@ -3370,14 +3411,16 @@ public static void createCeSrRstPinsToVCC(Design design) { Net net = si.getNetFromSiteWire(sitePinName); if (net != null) { if (belPinName == CE) { + if (!net.isVCCNet()) { + continue; + } // CE: it is possible for sitewire to be assigned to a non VCC net, but a SitePinInst to not yet exist - assert(!net.isVCCNet()); - continue; } else { - // SR: it is possible for sitewire to be assigned the GND net, yet still be routed to VCC + assert(belPinName == SR); if (!net.isStaticNet()) { continue; } + // SR: it is possible for sitewire to be assigned the GND net, yet still be routed to VCC } } diff --git a/src/com/xilinx/rapidwright/device/IntentCode.java b/src/com/xilinx/rapidwright/device/IntentCode.java index 2b084c9c5..4e92c8726 100644 --- a/src/com/xilinx/rapidwright/device/IntentCode.java +++ b/src/com/xilinx/rapidwright/device/IntentCode.java @@ -158,6 +158,12 @@ public boolean isUltraScaleClockDistribution() { return NODE_GLOBAL_HDISTR == this || NODE_GLOBAL_VDISTR == this; } + public boolean isVersalClocking() { + return NODE_GLOBAL_HDISTR == this || NODE_GLOBAL_HDISTR_LOCAL == this || NODE_GLOBAL_HROUTE_HSR == this || + NODE_GLOBAL_VDISTR == this || NODE_GLOBAL_VDISTR_LVL2 == this || NODE_GLOBAL_VROUTE == this || + NODE_GLOBAL_GCLK == this || NODE_GLOBAL_LEAF == this || NODE_GLOBAL_BUFG == this; + } + private static final int SERIES7_START_IDX = 23; private static final int SERIES7_END_IDX = SERIES7_START_IDX + 33 - 1; diff --git a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java index 49e8823c4..b00834840 100644 --- a/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java +++ b/src/com/xilinx/rapidwright/rwroute/GlobalSignalRouting.java @@ -444,15 +444,6 @@ public static void routeStaticNet(List pins, } IntentCode uphillIntentCode = uphillNode.getIntentCode(); - if (uphillIntentCode == IntentCode.NODE_CLE_CNODE && intentCode != IntentCode.NODE_CLE_CTRL) { - assert(isVersal); - // Only allow PIPs from NODE_CLE_CNODE to NODE_CLE_CTRL intent codes - // (NODE_CLE_NODEs can also be used to re-enter the INT tile --- do not allow this - // so that these precious resources are not consumed by the static router thereby - // blocking the signal router from using them) - continue; - } - switch(uphillIntentCode) { case NODE_GLOBAL_VDISTR: case NODE_GLOBAL_HROUTE: @@ -469,6 +460,20 @@ public static void routeStaticNet(List pins, case NODE_VLONG7: case NODE_VLONG12: continue; + case NODE_CLE_CNODE: + // Only allow PIPs from NODE_{CLE,INTF}_CNODE to NODE_{CLE,INTF}_CTRL intent codes + // (NODE_CLE_NODEs can also be used to re-enter the INT tile --- do not allow this + // so that these precious resources are not consumed by the static router thereby + // blocking the signal router from using them) + if (intentCode != IntentCode.NODE_CLE_CTRL) { + continue; + } + break; + case NODE_INTF_CNODE: + if (intentCode != IntentCode.NODE_INTF_CTRL) { + continue; + } + break; // VCC net should never need to use S/D/Q nodes ... case NODE_SINGLE: diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index c533c14af..acba903d4 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -326,32 +326,6 @@ 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.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() { @@ -804,6 +778,32 @@ private void initializeRouting() { oneMinusTimingWeight = 1 - timingWeight; oneMinusWlWeight = 1 - wlWeight; printIterationHeader(config.isTimingDriven()); + + // 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.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); + } + } + } + } } /** diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index a5fb5af8c..d4391f7a9 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -165,6 +165,15 @@ private void setBaseCost(Series series) { break; case NODE_VSINGLE: // Versal-only case NODE_HSINGLE: // Versal-only + if (length == 0 && getAllWiresInNode().length == 1) { + assert(getAllDownhillPIPs().isEmpty() || // e.g. INT_X3Y383/OUT_NN1_E_BEG6 and INT_X19Y384/OUT_EE1_E_BEG8 on vp1002 + (ic == IntentCode.NODE_HSINGLE && getWireName().startsWith("INT_SDQ_"))); + // HSINGLE nodes that have a wirename INT_SDQ_* do not travel to any other + // tiles but still have downhill PIPs (and thus we cannot mark as being + // inaccessible without checking getAllDownhillPIPs() or getWireName()) + break; + } + // Fall through case NODE_SINGLE: // US and US+ if (length <= 1) { assert(!getAllDownhillPIPs().isEmpty()); @@ -175,6 +184,14 @@ private void setBaseCost(Series series) { break; case NODE_VDOUBLE: // Versal only case NODE_HDOUBLE: // Versal only + if (length == 0 && getAllWiresInNode().length == 1) { + // e.g. INT_X2Y382/OUT_NN2_W_BEG2 and INT_X18Y384/OUT_WW2_W_BEG4 on vp1002 + assert(getAllDownhillPIPs().isEmpty()); + // This node has no downhill PIPs, mark these as inaccessible so that it will never be queued + type = (byte) RouteNodeType.INACCESSIBLE.ordinal(); + break; + } + // Fall through case NODE_DOUBLE: // US and US+ if (length == 0) { assert(!getAllDownhillPIPs().isEmpty()); @@ -194,9 +211,9 @@ private void setBaseCost(Series series) { } } break; - case NODE_HQUAD: + case NODE_HQUAD: // US/US+/Versal if (length == 0) { - // Since this node has zero length (and by extension no downhill PIPs) + // Since this node has zero length (and asserted to have no downhill PIPs) // mark it as being inacccessible so that it will never be queued assert(getAllDownhillPIPs().isEmpty()); type = (byte) RouteNodeType.INACCESSIBLE.ordinal(); @@ -204,9 +221,11 @@ private void setBaseCost(Series series) { baseCost = 0.35f * length; } break; - case NODE_VQUAD: + case NODE_VQUAD: // US/US+/Versal if (length == 0) { - assert(!getAllDownhillPIPs().isEmpty()); + // On Versal, INT_X1Y380/OUT_NN4_W_BEG6 on vp1002 has no downhill PIPs + assert((series == Series.Versal && getAllWiresInNode().length == 1) || + !getAllDownhillPIPs().isEmpty()); } else { // VQUADs have length 4 and 5 baseCost = 0.15f * length; @@ -219,7 +238,7 @@ private void setBaseCost(Series series) { break; case NODE_HLONG: // US/US+ if (length == 0) { - // Since this node has zero length (and by extension no downhill PIPs) + // Since this node has zero length (and asserted to have no downhill PIPs) // mark it as being inacccessible so that it will never be queued assert(getAllDownhillPIPs().isEmpty()); type = (byte) RouteNodeType.INACCESSIBLE.ordinal(); diff --git a/src/com/xilinx/rapidwright/rwroute/RouterHelper.java b/src/com/xilinx/rapidwright/rwroute/RouterHelper.java index 1f61cf225..4eea6d50d 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouterHelper.java +++ b/src/com/xilinx/rapidwright/rwroute/RouterHelper.java @@ -53,6 +53,7 @@ import com.xilinx.rapidwright.device.Node; import com.xilinx.rapidwright.device.PIP; import com.xilinx.rapidwright.device.Series; +import com.xilinx.rapidwright.device.SiteTypeEnum; import com.xilinx.rapidwright.device.Tile; import com.xilinx.rapidwright.device.TileTypeEnum; import com.xilinx.rapidwright.edif.EDIFHierCellInst; @@ -350,7 +351,7 @@ public static Set invertPossibleGndPinsToVccPins(Design design, } Collection connectedCells = DesignTools.getConnectedCells(spiBelPin, si); if (connectedCells.isEmpty()) { - for (BELPin belPin : si.getSiteWirePins(siteWireName)) { + for (BELPin belPin : si.getSiteWirePins(spiBelPin.getSiteWireName())) { if (belPin.isSitePort()) { continue; } @@ -410,7 +411,12 @@ public static Set invertPossibleGndPinsToVccPins(Design design, } else { BELPin[] belPins = si.getSiteWirePins(siteWireName); if (belPins.length != 2) { - continue; + if (belPins.length == 3 && si.getSiteTypeEnum() == SiteTypeEnum.DSP58 && siteWireName.equals("RSTD")) { + assert(isVersal); + assert(belPins[1].toString().equals("SRCMXINV.RSTAD_UNUSED")); + } else { + continue; + } } for (BELPin belPin : belPins) { if (belPin.isSitePort()) { @@ -421,7 +427,8 @@ public static Set invertPossibleGndPinsToVccPins(Design design, } // Emulate Vivado's behaviour and do not invert CLK* site pins if (Utils.isBRAM(spi.getSiteInst()) && - belPin.getBELName().startsWith("CLK")) { + belPin.getBELName().startsWith("CLK") && + !isVersal) { continue; } toInvertPins.add(spi); diff --git a/test/src/com/xilinx/rapidwright/device/TestNode.java b/test/src/com/xilinx/rapidwright/device/TestNode.java index eacef5bd4..a180fe26b 100644 --- a/test/src/com/xilinx/rapidwright/device/TestNode.java +++ b/test/src/com/xilinx/rapidwright/device/TestNode.java @@ -237,7 +237,8 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str "xcvp1002,INT_X38Y220,NODE_IMUX,IMUX_B_E.*,true", "xcvp1002,INT_X38Y220,NODE_IMUX,IMUX_B_W.*,true", "xcvp1002,INT_X38Y220,NODE_SDQNODE,,false", - "xcvp1002,INT_X38Y220,NODE_HSINGLE,,false", + "xcvp1002,INT_X38Y220,NODE_HSINGLE,OUT_.*,false", + "xcvp1002,INT_X38Y220,NODE_HSINGLE,INT_SDQ_RED_ATOM_.*,false", "xcvp1002,INT_X38Y220,NODE_VSINGLE,,false", "xcvp1002,INT_X38Y220,NODE_HDOUBLE,,false", "xcvp1002,INT_X38Y220,NODE_VDOUBLE,,false",