Skip to content

Commit

Permalink
RouterHelper.invertPossibleGndPinsToVccPins() to invert static LUT in…
Browse files Browse the repository at this point in the history
…puts (#910)

* RouterHelper.invertPossibleGndPinsToVccPins() to invert LUT inputs

Signed-off-by: Eddie Hung <[email protected]>

* Check all connected cells are LUTs before inverting

Signed-off-by: Eddie Hung <[email protected]>

* Add testInvertPossibleGndPinsToVccPinsLutInput()

Signed-off-by: Eddie Hung <[email protected]>

* Address review comments

Signed-off-by: Eddie Hung <[email protected]>

* Do not invert SRL16E pins

Signed-off-by: Eddie Hung <[email protected]>

* EDIFCell to track instantiations via atomic int

Signed-off-by: Eddie Hung <[email protected]>

* Add test

Signed-off-by: Eddie Hung <[email protected]>

* Update src/com/xilinx/rapidwright/edif/EDIFCell.java

Signed-off-by: eddieh-xlnx <[email protected]>

* Skip XDEF where possible

Signed-off-by: Eddie Hung <[email protected]>

* Add and test EDIFCell.isUniquified()

Signed-off-by: Eddie Hung <[email protected]>

* Add and test EDIFHierCellInst.isUniquified()

Signed-off-by: Eddie Hung <[email protected]>

* Do not invert if LUT is not uniquified

TODO for test

Signed-off-by: Eddie Hung <[email protected]>

* Removed unused imports

Signed-off-by: Eddie Hung <[email protected]>

* Remove TODO

Signed-off-by: Eddie Hung <[email protected]>

* Skip XDEF where possible

Signed-off-by: Eddie Hung <[email protected]>

* Add and test EDIFCell.isUniquified()

Signed-off-by: Eddie Hung <[email protected]>

* Add and test EDIFHierCellInst.isUniquified()

Signed-off-by: Eddie Hung <[email protected]>

* {Inc,dec}rement instance count during EDIFCell.{add,remove}CellInst()

Signed-off-by: Eddie Hung <[email protected]>

* EDIFCellInst.setCellTypeRaw() to only incr instance count if parent

Signed-off-by: Eddie Hung <[email protected]>

* Improve TestEDIFCell tests

Signed-off-by: Eddie Hung <[email protected]>

* Improve TestEDIF{Hier,}CellInst too

Signed-off-by: Eddie Hung <[email protected]>

* Add null check

Signed-off-by: Eddie Hung <[email protected]>

* Another null check

Signed-off-by: Eddie Hung <[email protected]>

* EDIFCellInst.isUniquified() only true if has parent cell

Signed-off-by: Eddie Hung <[email protected]>

* EDIFHierCellInst.isUniquified() to not check top level inst

(which has no parent cell)

Signed-off-by: Eddie Hung <[email protected]>

* Expand TestEDIF{Hier,}CellInst

Signed-off-by: Eddie Hung <[email protected]>

* Expand TestEDIFCell including a test that currently fails

Signed-off-by: Eddie Hung <[email protected]>

* Add null check

Signed-off-by: Eddie Hung <[email protected]>

* EDIFCell.decrementInstanceCount() to recursively decrement instances

on detaching the last instance

Signed-off-by: Eddie Hung <[email protected]>

* Refactor into testIsUniquifiedRemoveAndAdd()

removeCellInst() is an easy fix, but addCellInst() is not yet

Signed-off-by: Eddie Hung <[email protected]>

* More questions than answers...

Signed-off-by: Eddie Hung <[email protected]>

* EDIFCell.{add,remove}CellInst() to not increment instance count

Signed-off-by: Eddie Hung <[email protected]>

* EDIFCell.addCellInst() to not increment instance count

Signed-off-by: Eddie Hung <[email protected]>

* EDIFCell.removeCellInst() to call EDIFCellInst.setParentCell()

and move trackChange() and decrementInstanceCount() calls inside

Signed-off-by: Eddie Hung <[email protected]>

* EDIFCellInst.setParentCell() and setCellTypeRaw() to inc/dec inst count

Signed-off-by: Eddie Hung <[email protected]>

* Update tests

Signed-off-by: Eddie Hung <[email protected]>

* Make EDIFCellInst.setParentCell() the only place member is written

Signed-off-by: Eddie Hung <[email protected]>

* Add invertLutInputs param to invertPossibleGndPinsToVccPins()

Signed-off-by: Eddie Hung <[email protected]>

* [RWRoute] Add --noInvertGndToVccForLutInputs option

Signed-off-by: Eddie Hung <[email protected]>

* Fix/improve tests

Signed-off-by: Eddie Hung <[email protected]>

* Add stub for VCC -> GND for testing

Signed-off-by: Eddie Hung <[email protected]>

* Adding implementation of invertVccLutPinsToGndPins()

Signed-off-by: Chris Lavin <[email protected]>

* Temporary workaround to clear logical netlist after Net.rename()

Signed-off-by: Eddie Hung <[email protected]>

* Add null check

Signed-off-by: Eddie Hung <[email protected]>

* Remove @test

Signed-off-by: Eddie Hung <[email protected]>

* Move invertVccLutPinsToGndPins() into RouterHelperSupport

Signed-off-by: Eddie Hung <[email protected]>

* Add comment about LUT6_2

Signed-off-by: Eddie Hung <[email protected]>

* Fix comment

Signed-off-by: Eddie Hung <[email protected]>

* Fill out testInvertPossibleGndPinsToVccPinsLutInputOnlyIfFlattenedAndUniquified()

Signed-off-by: Eddie Hung <[email protected]>

* Bump year

Signed-off-by: Eddie Hung <[email protected]>

* Skip test if !flatten && uniquify

Signed-off-by: Eddie Hung <[email protected]>

---------

Signed-off-by: Eddie Hung <[email protected]>
Signed-off-by: eddieh-xlnx <[email protected]>
Signed-off-by: Chris Lavin <[email protected]>
Co-authored-by: Chris Lavin <[email protected]>
  • Loading branch information
eddieh-xlnx and clavin-xlnx authored Jan 17, 2024
1 parent 6dfd6c2 commit d9e31fc
Show file tree
Hide file tree
Showing 7 changed files with 303 additions and 27 deletions.
3 changes: 2 additions & 1 deletion src/com/xilinx/rapidwright/rwroute/RWRoute.java
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,8 @@ protected void routeStaticNets() {

List<SitePinInst> gndPins = staticNetAndRoutingTargets.get(design.getGndNet());
if (gndPins != null) {
Set<SitePinInst> newVccPins = RouterHelper.invertPossibleGndPinsToVccPins(design, gndPins);
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<>())
Expand Down
28 changes: 27 additions & 1 deletion src/com/xilinx/rapidwright/rwroute/RWRouteConfig.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
*
* Copyright (c) 2021 Ghent University.
* Copyright (c) 2022-2023, Advanced Micro Devices, Inc.
* Copyright (c) 2022-2024, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Author: Yun Zhou, Ghent University.
Expand Down Expand Up @@ -92,6 +92,8 @@ public class RWRouteConfig {
private boolean lutPinSwapping;
/* true to enable LUT routethru */
private boolean lutRoutethru;
/* true to enable GND -> VCC optimization for LUT inputs */
private boolean invertGndToVccForLutInputs;

/** Constructs a Configuration Object */
public RWRouteConfig(String[] arguments) {
Expand Down Expand Up @@ -122,6 +124,7 @@ public RWRouteConfig(String[] arguments) {
printConnectionSpan = false;
lutPinSwapping = false;
lutRoutethru = false;
invertGndToVccForLutInputs = true;
if (arguments != null) {
parseArguments(arguments);
}
Expand Down Expand Up @@ -227,6 +230,9 @@ private void parseArguments(String[] arguments) {
case "--lutRoutethru":
setLutRoutethru(true);
break;
case "--noInvertGndToVccForLutInputs":
setInvertGndToVccForLutInputs(false);
break;
default:
throw new IllegalArgumentException("ERROR: RWRoute argument '" + arg + "' not recognized.");
}
Expand Down Expand Up @@ -737,6 +743,16 @@ public boolean isLutRoutethru() {
return lutRoutethru;
}

/**
* Gets the flag indicating if GND to VCC inversion for LUT inputs is enabled.
* Default: true.
*
* @return True if the flag is set, false otherwise.
*/
public boolean isInvertGndToVccForLutInputs() {
return invertGndToVccForLutInputs;
}

/**
* Sets critical path delay pessimism factor b. It should be greater than 0.
* Default: 100. Can be modified by using "--pessimismB" option, e.g.
Expand Down Expand Up @@ -850,6 +866,16 @@ public void setLutRoutethru(boolean lutRoutethru) {
this.lutRoutethru = lutRoutethru;
}

/**
* Sets the flag for enabling GND to VCC inversion for LUT inputs.
* Default: true.
*
* @param invertGndToVccForLutInputs true to enableGND to VCC inversion for LUT inputs.
*/
public void setInvertGndToVccForLutInputs(boolean invertGndToVccForLutInputs) {
this.invertGndToVccForLutInputs = invertGndToVccForLutInputs;
}

/**
* Sets verbose.
* If true, there will be more info in the routing log file regarding design netlist, routing statistics, and timing report.
Expand Down
125 changes: 104 additions & 21 deletions src/com/xilinx/rapidwright/rwroute/RouterHelper.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
*
* Copyright (c) 2021 Ghent University.
* Copyright (c) 2022-2023, Advanced Micro Devices, Inc.
* Copyright (c) 2022-2024, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Author: Yun Zhou, Ghent University.
Expand Down Expand Up @@ -39,17 +39,22 @@
import java.util.Queue;
import java.util.Set;

import com.xilinx.rapidwright.design.Cell;
import com.xilinx.rapidwright.design.Design;
import com.xilinx.rapidwright.design.DesignTools;
import com.xilinx.rapidwright.design.Net;
import com.xilinx.rapidwright.design.SiteInst;
import com.xilinx.rapidwright.design.SitePinInst;
import com.xilinx.rapidwright.design.tools.LUTTools;
import com.xilinx.rapidwright.device.BEL;
import com.xilinx.rapidwright.device.BELPin;
import com.xilinx.rapidwright.device.IntentCode;
import com.xilinx.rapidwright.device.Node;
import com.xilinx.rapidwright.device.PIP;
import com.xilinx.rapidwright.device.Tile;
import com.xilinx.rapidwright.device.TileTypeEnum;
import com.xilinx.rapidwright.device.Wire;
import com.xilinx.rapidwright.edif.EDIFHierCellInst;
import com.xilinx.rapidwright.timing.TimingEdge;
import com.xilinx.rapidwright.timing.TimingManager;
import com.xilinx.rapidwright.timing.delayestimator.DelayEstimatorBase;
Expand Down Expand Up @@ -366,43 +371,121 @@ private static boolean isInvertibleDSPBELPin(BELPin belPin) {
/**
* Inverts all possible GND sink pins to VCC pins.
* @param design The target design.
* @param pins The static net pins.
* @param pins The GND net pins.
*/
public static Set<SitePinInst> invertPossibleGndPinsToVccPins(Design design, List<SitePinInst> pins) {
Net staticNet = design.getGndNet();
return invertPossibleGndPinsToVccPins(design, pins, true);
}

/**
* Inverts all possible GND sink pins to VCC pins.
* @param design The target design.
* @param pins The GND net pins.
* @param invertLutInputs True to invert LUT inputs.
*/
public static Set<SitePinInst> invertPossibleGndPinsToVccPins(Design design,
List<SitePinInst> pins,
boolean invertLutInputs) {
Net gndNet = design.getGndNet();
Set<SitePinInst> toInvertPins = new HashSet<>();
for (SitePinInst currSitePinInst : pins) {
if (!currSitePinInst.getNet().equals(staticNet))
throw new RuntimeException(currSitePinInst.toString());
BELPin[] belPins = currSitePinInst.getSiteInst().getSiteWirePins(currSitePinInst.getName());
if (belPins.length != 2) {
continue;
}
for (BELPin belPin : belPins) {
if (belPin.isSitePort()) {
continue;
nextSitePin: for (SitePinInst spi : pins) {
if (!spi.getNet().equals(gndNet))
throw new RuntimeException(spi.toString());
SiteInst si = spi.getSiteInst();
String siteWireName = spi.getSiteWireName();
if (invertLutInputs && spi.isLUTInputPin()) {
Collection<Cell> connectedCells = DesignTools.getConnectedCells(spi);
if (connectedCells.isEmpty()) {
for (BELPin belPin : si.getSiteWirePins(siteWireName)) {
if (belPin.isSitePort()) {
continue;
}
BEL bel = belPin.getBEL();
Cell cell = si.getCell(bel);
if (cell == null) {
continue;
}
if (cell.getType().equals("SRL16E") && siteWireName.endsWith("6")) {
// SRL16Es that have been transformed from SRLC32E (assume so here,
// since we don't always have the logical netlist to check)
// require GND on their A6 pin
// See DesignTools.createMissingStaticSitePins(BELPin, SiteInst, Cell)
continue nextSitePin;
}
}
throw new RuntimeException("ERROR: " + gndNet.getName() + " not connected to any Cells");
}
if (!belPin.getBEL().canInvert()) {
for (Cell cell : connectedCells) {
if (!LUTTools.isCellALUT(cell)) {
continue nextSitePin;
}

EDIFHierCellInst ehci = cell.getEDIFHierCellInst();
if (ehci == null) {
// No logical cell (likely encrypted)
continue nextSitePin;
}

if (!ehci.getParent().isUniquified()) {
// Parent cell (instantiating this LUT) is not unique
// This parent may be a LUT6_2 macro cell that has been expanded into LUT6+LUT5,
// and which does not get uniquified by EDIFTools.uniqueifyNetlist().
// Thus, LUT6/LUT5 inside expanded LUT6_2 macros are not eligible for inversion.
continue nextSitePin;
}
}

toInvertPins.add(spi);

for (Cell cell : connectedCells) {
// Find the logical pin name
String physicalPinName = "A" + spi.getName().charAt(1);
String logicalPinName = cell.getLogicalPinMapping(physicalPinName);

// Get the LUT equation
String lutEquation = LUTTools.getLUTEquation(cell);
assert(lutEquation.contains(logicalPinName));

// Compute a new LUT equation with that logical input inverted
String newLutEquation = lutEquation.replace(logicalPinName, "!" + logicalPinName)
// Cancel out double inversions
// (Note: LUTTools.getLUTEquation() only produces equations with '!' instead of '~')
.replace("!!", "");
LUTTools.configureLUT(cell, newLutEquation);
}
} else {
BELPin[] belPins = si.getSiteWirePins(siteWireName);
if (belPins.length != 2) {
continue;
}
if (currSitePinInst.getSite().getName().startsWith("RAM")) {
if (belPin.getBELName().startsWith("CLK")) {
for (BELPin belPin : belPins) {
if (belPin.isSitePort()) {
continue;
}
if (!belPin.getBEL().canInvert()) {
continue;
}
if (spi.getSite().getName().startsWith("RAM")) {
if (belPin.getBELName().startsWith("CLK")) {
continue;
}
}
toInvertPins.add(spi);
}
toInvertPins.add(currSitePinInst);
}
}
}

// Unroute all pins in a batch fashion
DesignTools.unroutePins(staticNet, toInvertPins);
DesignTools.unroutePins(gndNet, toInvertPins);
// Manually remove pins from net, because using DesignTools.batchRemoveSitePins()
// will cause SitePinInst.detachSiteInst() to be called, which we do not want
// as we are simply moving the SPI from one net to another
staticNet.getPins().removeAll(toInvertPins);
gndNet.getPins().removeAll(toInvertPins);

Net vccNet = design.getVccNet();
for (SitePinInst toinvert:toInvertPins) {
assert(toinvert.getSiteInst() != null);
if (!design.getVccNet().addPin(toinvert)) {
if (!vccNet.addPin(toinvert)) {
throw new RuntimeException("ERROR: Couldn't invert site pin " +
toinvert);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2024, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Author: Eddie Hung, Advanced Micro Devices, Inc.
*
* This file is part of RapidWright.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package com.xilinx.rapidwright.support.rwroute;

import com.xilinx.rapidwright.design.Cell;
import com.xilinx.rapidwright.design.Design;
import com.xilinx.rapidwright.design.SiteInst;
import com.xilinx.rapidwright.design.SitePinInst;
import com.xilinx.rapidwright.design.tools.LUTTools;
import com.xilinx.rapidwright.device.BELPin;

import java.util.Set;

public class RouterHelperSupport {
public static void invertVccLutPinsToGndPins(Design design, Set<SitePinInst> pins) {
for (SitePinInst spi : pins) {
assert (spi.getNet() == design.getVccNet());
SiteInst si = spi.getSiteInst();
for (BELPin bp : spi.getSiteWireBELPins()) {
if (bp.isSitePort() || bp.getName().charAt(0) != 'A')
continue;
if (bp.getBEL().isLUT()) {
Cell lut = si.getCell(bp.getBEL());
if (lut != null) {
String eq = LUTTools.getLUTEquation(lut);
String logInput = lut.getLogicalPinMapping(bp.getName());
if (logInput != null) {
LUTTools.configureLUT(lut, eq.replace(logInput, "(~" + logInput + ")"));
} else {
// Doesn't look like this pin is used by this [65]LUT,
// could be used by the other [56]LUT
}
}
}
}
spi.getNet().removePin(spi, true);
design.getGndNet().addPin(spi, true);
}
}
}
4 changes: 2 additions & 2 deletions test/src/com/xilinx/rapidwright/edif/TestEDIFCellInst.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Advanced Micro Devices, Inc.
* Copyright (c) 2023-2024, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Author: Eddie Hung, Advanced Micro Devices, Inc.
Expand Down Expand Up @@ -78,7 +78,7 @@ public void testIsUniquifiedFalse() {
)) {
EDIFCellInst eci = picoblazeTop.getCellInst(name);
// Only checks that this cell instance is unique (e.g. that there is only
// one instantiation) but does not check that any parents on a full
// one instantiation) but does not check that all parents on a full
// hierarchical path (e.g. "picoblaze_{0,1}_{12,13}/processor") is also
// unique --- use EDIFHierCellInst.isUniquified() for that
Assertions.assertTrue(eci.isUniquified());
Expand Down
2 changes: 1 addition & 1 deletion test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ public void testRWRouteDeviceSupport(Series series) {
public void testBug701() {
Design design = RapidWrightDCP.loadDCP("bug701.dcp");

RWRoute.routeDesignFullNonTimingDriven(design);
RWRoute.routeDesignWithUserDefinedArguments(design, new String[] {"--nonTimingDriven", "--noInvertGndToVccForLutInputs"});

Net vcc = design.getVccNet();
Assertions.assertEquals(1, vcc.getPins().size());
Expand Down
Loading

0 comments on commit d9e31fc

Please sign in to comment.