diff --git a/src/com/xilinx/rapidwright/edif/EDIFNet.java b/src/com/xilinx/rapidwright/edif/EDIFNet.java index e4bd503db..4993765a4 100644 --- a/src/com/xilinx/rapidwright/edif/EDIFNet.java +++ b/src/com/xilinx/rapidwright/edif/EDIFNet.java @@ -1,7 +1,7 @@ /* * * Copyright (c) 2017-2022, Xilinx, Inc. - * Copyright (c) 2022, Advanced Micro Devices, Inc. + * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. * All rights reserved. * * Author: Chris Lavin, Xilinx Research Labs. @@ -224,6 +224,10 @@ public EDIFPortInst createPortInst(EDIFPort port, EDIFCellInst cellInst) { return new EDIFPortInst(port, this, cellInst); } + public EDIFPortInst createPortInst(EDIFPort port, EDIFCellInst cellInst, boolean deferSort) { + return new EDIFPortInst(port, this, cellInst, deferSort); + } + public EDIFPortInst createPortInst(EDIFPort port, int index, EDIFCellInst cellInst) { return new EDIFPortInst(port, this, index, cellInst); } diff --git a/src/com/xilinx/rapidwright/edif/EDIFPortInst.java b/src/com/xilinx/rapidwright/edif/EDIFPortInst.java index 16cabc49e..228ca73c2 100644 --- a/src/com/xilinx/rapidwright/edif/EDIFPortInst.java +++ b/src/com/xilinx/rapidwright/edif/EDIFPortInst.java @@ -65,6 +65,7 @@ public EDIFPortInst(EDIFPortInst portInst) { public EDIFPortInst(EDIFPort port, EDIFNet parentNet, int index) { this(port,parentNet,index,null); } + /** * Constructor to create a single bit port ref and associate it with its * net and instance. @@ -73,7 +74,23 @@ public EDIFPortInst(EDIFPort port, EDIFNet parentNet, int index) { * @param cellInst The instance this port ref belongs to */ public EDIFPortInst(EDIFPort port, EDIFNet parentNet, EDIFCellInst cellInst) { - this(port, parentNet, -1, cellInst); + this(port, parentNet, -1, cellInst, false); + } + + /** + * Constructor to create a single bit port ref and associate it with its + * net and instance. + * @param port The port on the cell this port ref uses + * @param parentNet The net this port ref should belong to + * @param cellInst The instance this port ref belongs to + * @param deferSort The EDIFPortInstList maintains a sorted list of EDIFPortInst + * objects and sorts them upon insertion. Setting this flag to true will skip a sort addition + * but the caller is responsible to conclude a batch of additions with a call to + * {@link EDIFPortInstList#reSortList()}. This is useful when a large number of EDIFPortInsts + * will be added consecutively (such as parsing a netlist). + */ + public EDIFPortInst(EDIFPort port, EDIFNet parentNet, EDIFCellInst cellInst, boolean deferSort) { + this(port, parentNet, -1, cellInst, deferSort); } /** diff --git a/src/com/xilinx/rapidwright/interchange/BELPinCache.java b/src/com/xilinx/rapidwright/interchange/BELPinCache.java new file mode 100644 index 000000000..b1c937009 --- /dev/null +++ b/src/com/xilinx/rapidwright/interchange/BELPinCache.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2023, 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.interchange; + +import com.xilinx.rapidwright.design.SiteInst; +import com.xilinx.rapidwright.device.BEL; +import com.xilinx.rapidwright.device.BELPin; +import com.xilinx.rapidwright.device.SiteTypeEnum; + +import java.util.List; +import java.util.Map; + +/** + * Class for caching BELPin lookups, given a SiteInst object, and string + * indices for the BEL and BELPin names. + */ +public class BELPinCache { + private static class Key { + private final SiteTypeEnum siteTypeEnum; + private final int belStringIdx; + private final int pinStringIdx; + + public Key(SiteInst siteInst, int belStringIdx, int pinStringIdx) { + siteTypeEnum = siteInst.getSiteTypeEnum(); + this.belStringIdx = belStringIdx; + this.pinStringIdx = pinStringIdx; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + siteTypeEnum.ordinal(); + result = prime * result + belStringIdx; + result = prime * result + pinStringIdx; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Key other = (Key) obj; + return belStringIdx == other.belStringIdx && + pinStringIdx == other.pinStringIdx && + siteTypeEnum == other.siteTypeEnum; + } + } + + private final Map map; + + private final List strings; + + public BELPinCache(Map map, List strings) { + this.map = map; + this.strings = strings; + } + + public BELPin getBELPin(SiteInst siteInst, int belStringIdx, int pinStringIdx) { + Key key = new Key(siteInst, belStringIdx, pinStringIdx); + return map.computeIfAbsent(key, (k) -> { + String belName = strings.get(k.belStringIdx); + BEL bel = siteInst.getBEL(belName); + if (bel == null) { + throw new RuntimeException(String.format("ERROR: Failed to get BEL %s", belName)); + } + + String belPinName = strings.get(k.pinStringIdx); + BELPin belPin = bel.getPin(belPinName); + if (belPin == null) { + throw new RuntimeException(String.format("ERROR: Failed to get BEL pin %s/%s", belName, belPinName)); + } + + return belPin; + }); + } +} diff --git a/src/com/xilinx/rapidwright/interchange/DeviceResourcesWriter.java b/src/com/xilinx/rapidwright/interchange/DeviceResourcesWriter.java index da6256532..ecd58b1f2 100644 --- a/src/com/xilinx/rapidwright/interchange/DeviceResourcesWriter.java +++ b/src/com/xilinx/rapidwright/interchange/DeviceResourcesWriter.java @@ -404,7 +404,7 @@ public static void writeDeviceResourcesFile(String part, Device device, CodePerf put(series+"_"+EDIFTools.MACRO_PRIMITIVES_LIB, LogNetlistWriter.DEVICE_MACROS_LIB); }} ); - writer.populateNetlistBuilder(netlist, netlistBuilder); + writer.populateNetlistBuilder(netlist, netlistBuilder, CodePerfTracker.SILENT); writeCellParameterDefinitions(series, netlist, devBuilder.getParameterDefs()); diff --git a/src/com/xilinx/rapidwright/interchange/LogNetlistReader.java b/src/com/xilinx/rapidwright/interchange/LogNetlistReader.java index 985e6f9d6..d89a27e87 100644 --- a/src/com/xilinx/rapidwright/interchange/LogNetlistReader.java +++ b/src/com/xilinx/rapidwright/interchange/LogNetlistReader.java @@ -23,18 +23,6 @@ package com.xilinx.rapidwright.interchange; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import org.capnproto.MessageReader; -import org.capnproto.PrimitiveList; -import org.capnproto.ReaderOptions; -import org.capnproto.StructList; -import org.capnproto.TextList; - import com.xilinx.rapidwright.design.Design; import com.xilinx.rapidwright.design.Unisim; import com.xilinx.rapidwright.device.PartNameTools; @@ -56,46 +44,111 @@ import com.xilinx.rapidwright.interchange.LogicalNetlist.Netlist.Net; import com.xilinx.rapidwright.interchange.LogicalNetlist.Netlist.Port; import com.xilinx.rapidwright.interchange.LogicalNetlist.Netlist.PortInstance; -import com.xilinx.rapidwright.interchange.LogicalNetlist.Netlist.PropertyMap; import com.xilinx.rapidwright.interchange.LogicalNetlist.Netlist.PortInstance.BusIdx; +import com.xilinx.rapidwright.interchange.LogicalNetlist.Netlist.PropertyMap; +import com.xilinx.rapidwright.tests.CodePerfTracker; +import org.capnproto.MessageReader; +import org.capnproto.PrimitiveList; +import org.capnproto.ReaderOptions; +import org.capnproto.StructList; +import org.capnproto.TextList; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.function.Supplier; public class LogNetlistReader { - private StringEnumerator allStrings; - private List allPorts; - private List allCells; - private List allInsts; - private Map libraryRename; + public static boolean CHECK_UNISIM_DEFINITIONS = true; + + private String[] allStrings; + private EDIFPort[] allPorts; + protected EDIFCellInst[] allInsts; + protected EDIFCell[] allCells; + protected Map libraryRename; + + protected Map libraries; + + protected EDIFNetlist n; public LogNetlistReader() { - allStrings = new StringEnumerator(); libraryRename = Collections.emptyMap(); } public LogNetlistReader(StringEnumerator otherAllStrings) { - allStrings = otherAllStrings; - libraryRename = Collections.emptyMap(); + this(); + allStrings = new String[otherAllStrings.size()]; + for (int i = 0; i < otherAllStrings.size(); i++) { + allStrings[i] = otherAllStrings.get(i); + } } - public LogNetlistReader(StringEnumerator otherAllStrings, Map libraryRename) { - allStrings = otherAllStrings; - this.libraryRename = libraryRename; + public LogNetlistReader(StringEnumerator outsideAllStrings, Map libraryRename) { + this(outsideAllStrings); + this.libraryRename = new HashMap<>(libraryRename.size()); + for (Map.Entry e : libraryRename.entrySet()) { + Integer keyIndex = outsideAllStrings.getIndex(e.getKey()); + Integer valueIndex = outsideAllStrings.getIndex(e.getValue()); + this.libraryRename.put(keyIndex, valueIndex); + } + } + + protected void readAllStrings(TextList.Reader strListReader) { + if (strListReader.size() == 0) { + if (allStrings == null) { + System.err.println("WARNING: LogNetlistReader has no string data."); + } + return; + } + allStrings = new String[strListReader.size()]; + for (int i = 0; i < strListReader.size(); i++) { + allStrings[i] = strListReader.get(i).toString(); + } + } + + protected String getString(int i) { + return allStrings[i]; + } + + protected void readAllPorts(StructList.Reader portListReader) { + allPorts = new EDIFPort[portListReader.size()]; + for (int i = 0; i < portListReader.size(); i++) { + allPorts[i] = readEDIFPort(portListReader.get(i)); + } + } + + protected EDIFPort getPort(int i) { + return allPorts[i]; + } + + protected void readAllInsts(StructList.Reader instListReader) { + allInsts = new EDIFCellInst[instListReader.size()]; + for (int i = 0; i < instListReader.size(); i++) { + allInsts[i] = readEDIFCellInst(instListReader.get(i)); + } + } + + protected EDIFCellInst getInst(int i) { + return allInsts[i]; } /** * Extracts the property map information from a Cap'n Proto reader object and deserializes it * into an EDIF property map object. The reverse function is - * {@link LogNetlistWriter#populatePropertyMap(PropertyMap.Builder, EDIFPropertyObject)} + * {@link LogNetlistWriter#populatePropertyMap(Supplier, EDIFPropertyObject)} * @param reader The Cap'n Proto reader object * @param obj The EDIF map object */ - private void extractPropertyMap(PropertyMap.Reader reader, EDIFPropertyObject obj) { + protected void extractPropertyMap(PropertyMap.Reader reader, EDIFPropertyObject obj) { StructList.Reader entries = reader.getEntries(); - int count = entries.size(); - for (int i=0; i < count; i++) { + for (int i=0; i < entries.size(); i++) { PropertyMap.Entry.Reader entryReader = entries.get(i); - String key = allStrings.get(entryReader.getKey()); + String key = getString(entryReader.getKey()); if (entryReader.isTextValue()) { - String textValue = allStrings.get(entryReader.getTextValue()); + String textValue = getString(entryReader.getTextValue()); if (textValue.contains("\"")) { throw new RuntimeException("ERROR: String '"+textValue+ "'\n\t value contains unescaped '\"' " @@ -137,7 +190,7 @@ protected static Direction getDirection(EDIFPort port) { * @param port The Cap'n Proto Port Reader object with the direction reference of interest. * @return The corresponding EDIFDirection */ - private static EDIFDirection getEDIFDirection(Port.Reader port) { + protected static EDIFDirection getEDIFDirection(Port.Reader port) { switch (port.getDir()) { case INPUT: return EDIFDirection.INPUT; @@ -150,118 +203,140 @@ private static EDIFDirection getEDIFDirection(Port.Reader port) { } } - private void readEDIFCell(int cellIdx, - StructList.Reader cellListReader, - StructList.Reader instListReader) { - Cell.Reader cellReader = cellListReader.get(cellIdx); + protected void readEDIFCell(Cell.Reader cellReader) { + EDIFCell edifCell = allCells[cellReader.getIndex()]; + assert(edifCell != null); - EDIFCell edifCell = allCells.get(cellReader.getIndex()); + boolean deferSort = true; // Instances PrimitiveList.Int.Reader cellInstsReader = cellReader.getInsts(); int instCount = cellInstsReader.size(); for (int j=0; j < instCount; j++) { - readEDIFCellInst(cellInstsReader.get(j), edifCell, instListReader); + EDIFCellInst eci = getInst(cellInstsReader.get(j)); + edifCell.addCellInst(eci); + eci.setParentCell(edifCell); } // Nets for (Net.Reader netReader : cellReader.getNets()) { - EDIFNet net = new EDIFNet(allStrings.get(netReader.getName()), edifCell); - extractPropertyMap(netReader.getPropMap(), net); + EDIFNet net = new EDIFNet(getString(netReader.getName()), edifCell); + if (netReader.hasPropMap()) { + extractPropertyMap(netReader.getPropMap(), net); + } for (PortInstance.Reader portInstReader : netReader.getPortInsts()) { EDIFCellInst inst = null; if (!portInstReader.isExtPort()) { - inst = allInsts.get(portInstReader.getInst()); + inst = getInst(portInstReader.getInst()); if (inst == null) { throw new RuntimeException("ERROR: EDIFCellInst should already have been read!"); } } - EDIFPort port = allPorts.get(portInstReader.getPort()); + EDIFPort port = getPort(portInstReader.getPort()); BusIdx.Reader portIdxReader = portInstReader.getBusIdx(); if (portIdxReader.isSingleBit()) { - net.createPortInst(port, inst); + net.createPortInst(port, inst, deferSort); } else { - net.createPortInst(port, portIdxReader.getIdx(), inst); + net.createPortInst(port, portIdxReader.getIdx(), inst, deferSort); } } } - // Check if Unisim definitions match - if (edifCell.getLibrary().isHDIPrimitivesLibrary()) { - Unisim cellType = Unisim.valueOf(edifCell.getName()); - EDIFCell cell = Design.getUnisimCell(cellType); - if (cell.getPorts().size() != edifCell.getPorts().size()) { - System.err.println("[WARNING]: Unisim mismatch found in EDIF Library: " - + EDIFTools.EDIF_LIBRARY_HDI_PRIMITIVES_NAME + ", Cell: " - + edifCell.getName() + ", port names/widths mismatch, should be: \n\t" - + cell.getPorts() + ",\n\tbut found: \n\t\t" + edifCell.getPorts()); - } - for (EDIFPort port : cell.getPorts()) { - String portKey = port.getBusName(); - EDIFPort portMatch = edifCell.getPort(portKey); - if (portMatch == null || portMatch.getWidth() != port.getWidth()) { + if (deferSort) { + edifCell.sortEDIFPortInstLists(); + } + + if (CHECK_UNISIM_DEFINITIONS) { + // Check if Unisim definitions match + if (edifCell.getLibrary().isHDIPrimitivesLibrary()) { + Unisim cellType = Unisim.valueOf(edifCell.getName()); + EDIFCell cell = Design.getUnisimCell(cellType); + if (cell.getPorts().size() != edifCell.getPorts().size()) { System.err.println("[WARNING]: Unisim mismatch found in EDIF Library: " - + EDIFTools.EDIF_LIBRARY_HDI_PRIMITIVES_NAME + ", Cell: " + + EDIFTools.EDIF_LIBRARY_HDI_PRIMITIVES_NAME + ", Cell: " + edifCell.getName() + ", port names/widths mismatch, should be: \n\t" - + cell.getPorts() + ",\nbut found: \n\t" + edifCell.getPorts()); + + cell.getPorts() + ",\n\tbut found: \n\t\t" + edifCell.getPorts()); + } + for (EDIFPort port : cell.getPorts()) { + String portKey = port.getBusName(); + EDIFPort portMatch = edifCell.getPort(portKey); + if (portMatch == null || portMatch.getWidth() != port.getWidth()) { + System.err.println("[WARNING]: Unisim mismatch found in EDIF Library: " + + EDIFTools.EDIF_LIBRARY_HDI_PRIMITIVES_NAME + ", Cell: " + + edifCell.getName() + ", port names/widths mismatch, should be: \n\t" + + cell.getPorts() + ",\nbut found: \n\t" + edifCell.getPorts()); + } } } } } - private EDIFCellInst getInst(int instIdx) { - if (instIdx >= allInsts.size()) { - return null; - } + protected EDIFCellInst readEDIFCellInst(CellInstance.Reader instReader) { + String instName = getString(instReader.getName()); - return allInsts.get(instIdx); - } + EDIFCell cell = allCells[instReader.getCell()]; + assert(cell != null); - private void readEDIFCellInst(int instIdx, EDIFCell parent, - StructList.Reader instListReader) { - EDIFCellInst edifCellInst = getInst(instIdx); - if (edifCellInst != null) { - throw new RuntimeException("ERROR: Each EDIFCellInst should only be read once."); + EDIFCell parent = null; + EDIFCellInst edifCellInst = new EDIFCellInst(instName, cell, parent); + + String view = getString(instReader.getView()); + if (!cell.getEDIFView().getName().equals(view)) { + edifCellInst.setViewref(new EDIFName(view)); + } + + if (instReader.hasPropMap()) { + extractPropertyMap(instReader.getPropMap(), edifCellInst); } - CellInstance.Reader instReader = instListReader.get(instIdx); - EDIFCell cell = allCells.get(instReader.getCell()); + return edifCellInst; + } - String instName = allStrings.get(instReader.getName()); - edifCellInst = new EDIFCellInst(instName, cell, parent); - edifCellInst.setViewref(new EDIFName(allStrings.get(instReader.getView()))); + private void readAllCellDecls(StructList.Reader cellDeclsReader) { + libraries = new HashMap<>(); - extractPropertyMap(instReader.getPropMap(), edifCellInst); + allCells = createCells(cellDeclsReader); - EDIFCellInst oldCellInst = allInsts.set(instIdx, edifCellInst); - assert(oldCellInst == null); + libraries = null; + } + + private void readAllCells(StructList.Reader cellsReader) { + for (int i = 0; i < cellsReader.size(); ++i) { + readEDIFCell(cellsReader.get(i)); + } } /** - * Reads Cap'n Proto serialized netlist into a RapidWright netlist in memory + * Reads Cap'n Proto serialized netlist into a RapidWright netlist in memory, with macros expanded. * @param fileName Name of the serialized netlist file - * @return Netlist object in RapidWright framework + * @return EDIFNetlist object in RapidWright framework * @throws IOException */ public static EDIFNetlist readLogNetlist(String fileName) throws IOException { - ReaderOptions readerOptions = new ReaderOptions(32L*1024L*1024L*1024L, 64); - MessageReader readMsg = Interchange.readInterchangeFile(fileName, readerOptions); + return readLogNetlist(fileName, true); + } + /** + * Reads Cap'n Proto serialized netlist into a RapidWright netlist in memory, with macros expanded. + * @param fileName Name of the serialized netlist file + * @param expandMacros If true, expands the macros in the netlist before returning it to the caller. + * @return EDIFNetlist object in RapidWright framework + * @throws IOException + */ + public static EDIFNetlist readLogNetlist(String fileName, boolean expandMacros) throws IOException { + CodePerfTracker t = new CodePerfTracker("Read LogNetlist"); + + t.start("Read File"); + ReaderOptions readerOptions = new ReaderOptions(32L * 1024L * 1024L * 1024L, 64); + MessageReader readMsg = Interchange.readInterchangeFile(fileName, readerOptions); Netlist.Reader netlist = readMsg.getRoot(Netlist.factory); - return getLogNetlist(netlist); - } + t.stop(); - private void readStrings(Netlist.Reader netlist) { - TextList.Reader strListReader = netlist.getStrList(); - int strCount = strListReader.size(); - allStrings.ensureCapacity(strCount); - for (int i=0; i < strCount; i++) { - String str = strListReader.get(i).toString(); - allStrings.add(str); - } + LogNetlistReader reader = new LogNetlistReader(); + return reader.readLogNetlist(netlist, false, expandMacros, t); } private EDIFPort readEDIFPort(Port.Reader portReader) { @@ -271,55 +346,62 @@ private EDIFPort readEDIFPort(Port.Reader portReader) { int end = portReader.getBus().getBusEnd(); width = Math.abs(start-end) + 1; } - String portBusName = allStrings.get(portReader.getName()); + String portBusName = getString(portReader.getName()); if (portReader.isBus()) { portBusName += "["+ portReader.getBus().getBusStart() + ":" + portReader.getBus().getBusEnd() + "]"; } EDIFPort edifPort = new EDIFPort(portBusName, getEDIFDirection(portReader), width); - extractPropertyMap(portReader.getPropMap(), edifPort); - return edifPort; - } - - private void readPorts(Netlist.Reader netlist) { - StructList.Reader portReaderList = netlist.getPortList(); - allPorts = new ArrayList<>(portReaderList.size()); - for (int i = 0; i < portReaderList.size(); ++i) { - Port.Reader portReader = portReaderList.get(i); - allPorts.add(readEDIFPort(portReader)); + if (portReader.hasPropMap()) { + extractPropertyMap(portReader.getPropMap(), edifPort); } + return edifPort; } - private void createCells(EDIFNetlist n, Netlist.Reader netlist) { - StructList.Reader cellDeclsReader = netlist.getCellDecls(); + protected EDIFCell[] createCells(StructList.Reader cellDeclsReader) { + EDIFCell[] cells = new EDIFCell[cellDeclsReader.size()]; - allCells = new ArrayList<>(cellDeclsReader.size()); for (int i = 0; i < cellDeclsReader.size(); ++i) { Netlist.CellDeclaration.Reader cellReader = cellDeclsReader.get(i); - String libraryName = allStrings.get(cellReader.getLib()); - libraryName = libraryRename.getOrDefault(libraryName, libraryName); + cells[i] = createCell(cellReader, EDIFCell::new); + } - EDIFLibrary library = n.getLibrary(libraryName); - if (library == null) { - library = new EDIFLibrary(libraryName); - n.addLibrary(library); - } + return cells; + } - String cellName = allStrings.get(cellReader.getName()); - EDIFCell cell = new EDIFCell(library, cellName); - extractPropertyMap(cellReader.getPropMap(), cell); - cell.setView(allStrings.get(cellReader.getView())); + protected EDIFCell createCell(Netlist.CellDeclaration.Reader cellReader, + BiFunction createCell) { + EDIFLibrary library = getLibrary(cellReader.getLib()); + String cellName = getString(cellReader.getName()); - allCells.add(cell); + EDIFCell cell = createCell.apply(library, cellName); + if (cellReader.hasPropMap()) { + extractPropertyMap(cellReader.getPropMap(), cell); + } + cell.setView(getString(cellReader.getView())); - PrimitiveList.Int.Reader ports = cellReader.getPorts(); - int portCount = ports.size(); - for (int j=0; j < portCount; j++) { - cell.addPort(allPorts.get(ports.get(j))); - } + PrimitiveList.Int.Reader ports = cellReader.getPorts(); + int portCount = ports.size(); + for (int j=0; j < portCount; j++) { + cell.addPort(getPort(ports.get(j))); } - assert(allCells.size() == cellDeclsReader.size()); + + return cell; + } + + protected void addLibraryToNetlist(EDIFLibrary library) { + n.addLibrary(library); + } + + private EDIFLibrary getLibrary(Integer libraryIdx) { + libraryIdx = libraryRename.getOrDefault(libraryIdx, libraryIdx); + return libraries.computeIfAbsent(libraryIdx, (k) -> { + String libraryName = getString(k); + EDIFLibrary library = new EDIFLibrary(libraryName); + addLibraryToNetlist(library); + return library; + }); } /** @@ -340,27 +422,48 @@ public EDIFNetlist readLogNetlist(Netlist.Reader netlist, boolean skipTopStuff) * @return The logical netlist. */ public EDIFNetlist readLogNetlist(Netlist.Reader netlist, boolean skipTopStuff, boolean expandMacros) { - EDIFNetlist n = new EDIFNetlist(netlist.getName().toString()); + CodePerfTracker t = new CodePerfTracker("readLogNetlist"); + return readLogNetlist(netlist, skipTopStuff, expandMacros, t); + } - readPorts(netlist); - createCells(n, netlist); + /** + * Reads an Interchange netlist from Cap'n Proto reader. + * @param netlist The Cap'n Proto netlist reader + * @param skipTopStuff If true, skips netlist design object + * @param expandMacros If true, expands the macros in the netlist before returning it to the caller. + * @param t CodePerfTracker object. + * @return The logical netlist. + */ + public EDIFNetlist readLogNetlist(Netlist.Reader netlist, boolean skipTopStuff, boolean expandMacros, CodePerfTracker t) { + n = new EDIFNetlist(netlist.getName().toString()); - int cellCount = netlist.getCellList().size(); - StructList.Reader cellListReader = netlist.getCellList(); - StructList.Reader instListReader = netlist.getInstList(); - allInsts = new ArrayList<>(Collections.nCopies(instListReader.size(), null)); - for (int i=0; i < cellCount; i++) { - readEDIFCell(i, cellListReader, instListReader); - } - assert(allInsts.size() == instListReader.size()); + t.start("Read Strings"); + readAllStrings(netlist.getStrList()); + + t.stop().start("Read Ports"); + readAllPorts(netlist.getPortList()); + + t.stop().start("Read CellDecls"); + readAllCellDecls(netlist.getCellDecls()); + + t.stop().start("Read Insts"); + readAllInsts(netlist.getInstList()); + + t.stop().start("Read Cells"); + readAllCells(netlist.getCellList()); if (!skipTopStuff) { - EDIFDesign design = new EDIFDesign(allCells.get(netlist.getTopInst().getCell()).getName()); - design.setTopCell(allCells.get(netlist.getTopInst().getCell())); + t.stop().start("Populate Top"); + EDIFDesign design = new EDIFDesign(allCells[netlist.getTopInst().getCell()].getName()); + design.setTopCell(allCells[netlist.getTopInst().getCell()]); n.setDesign(design); - extractPropertyMap(netlist.getPropMap(), design); + if (netlist.hasPropMap()) { + extractPropertyMap(netlist.getPropMap(), design); + } } + t.stop().start("Order Libraries"); + // Put libraries in proper export order List libs = n.getLibrariesInExportOrder(); n.getLibrariesMap().clear(); @@ -369,24 +472,19 @@ public EDIFNetlist readLogNetlist(Netlist.Reader netlist, boolean skipTopStuff, } if (expandMacros) { + t.stop().start("Expand Macros"); String partName = EDIFTools.getPartName(n); if (partName != null) { n.expandMacroUnisims(PartNameTools.getPart(partName).getSeries()); } else { System.err.println("WARNING: Could not determine target device from netlist. Macro " - + "unisims are not expanded. Please add a top netlist property to indicate the " - + "target part such as [part=xcvu095-ffva2104-2-e]. Macro expansion can also be" - + " run manually with EDIFNetlist.expandMacroUnisims(Series)"); + + "unisims are not expanded. Please add a top netlist property to indicate the " + + "target part such as [part=xcvu095-ffva2104-2-e]. Macro expansion can also be" + + " run manually with EDIFNetlist.expandMacroUnisims(Series)"); } } + t.stop().printSummary(); return n; } - - public static EDIFNetlist getLogNetlist(Netlist.Reader netlist) { - LogNetlistReader reader = new LogNetlistReader(); - reader.readStrings(netlist); - return reader.readLogNetlist(netlist, /*skipTopStuff=*/false); - } - } diff --git a/src/com/xilinx/rapidwright/interchange/LogNetlistWriter.java b/src/com/xilinx/rapidwright/interchange/LogNetlistWriter.java index 1d480bf79..b3638aba4 100644 --- a/src/com/xilinx/rapidwright/interchange/LogNetlistWriter.java +++ b/src/com/xilinx/rapidwright/interchange/LogNetlistWriter.java @@ -23,18 +23,6 @@ package com.xilinx.rapidwright.interchange; -import java.io.IOException; -import java.util.Collections; -import java.util.Map; -import java.util.Map.Entry; - -import org.capnproto.MessageBuilder; -import org.capnproto.PrimitiveList; -import org.capnproto.StructList; -import org.capnproto.Text; -import org.capnproto.TextList; -import org.capnproto.Void; - import com.xilinx.rapidwright.device.Device; import com.xilinx.rapidwright.edif.EDIFCell; import com.xilinx.rapidwright.edif.EDIFCellInst; @@ -54,6 +42,20 @@ import com.xilinx.rapidwright.interchange.LogicalNetlist.Netlist.Port; import com.xilinx.rapidwright.interchange.LogicalNetlist.Netlist.PortInstance; import com.xilinx.rapidwright.interchange.LogicalNetlist.Netlist.PropertyMap; +import com.xilinx.rapidwright.tests.CodePerfTracker; +import org.capnproto.MessageBuilder; +import org.capnproto.PrimitiveList; +import org.capnproto.StructList; +import org.capnproto.Text; +import org.capnproto.TextList; +import org.capnproto.Void; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.function.Supplier; public class LogNetlistWriter { @@ -62,46 +64,64 @@ public class LogNetlistWriter { public static final String DEVICE_MACROS_LIB = "macros"; LogNetlistWriter() { - allCells = new IdentityEnumerator<>(); - allInsts = new IdentityEnumerator<>(); - allPorts = new IdentityEnumerator<>(); - allStrings = new StringEnumerator(); - libraryRename = Collections.emptyMap(); + this(null, null); } LogNetlistWriter(StringEnumerator outsideAllStrings) { - allCells = new IdentityEnumerator<>(); - allInsts = new IdentityEnumerator<>(); - allPorts = new IdentityEnumerator<>(); - allStrings = outsideAllStrings; - libraryRename = Collections.emptyMap(); + this(outsideAllStrings, null); } LogNetlistWriter(StringEnumerator outsideAllStrings, Map libraryRename) { allCells = new IdentityEnumerator<>(); allInsts = new IdentityEnumerator<>(); allPorts = new IdentityEnumerator<>(); - allStrings = outsideAllStrings; - this.libraryRename = libraryRename; + if (outsideAllStrings == null) { + allStrings = newEnumerator(); + } else { + allStrings = outsideAllStrings; + } + Map libraryIdxRename = new HashMap<>(); + if (libraryRename != null) { + for (Map.Entry e : libraryRename.entrySet()) { + Integer keyIndex = allStrings.getIndex(e.getKey()); + Integer valueIndex = allStrings.getIndex(e.getValue()); + libraryIdxRename.put(keyIndex, valueIndex); + } + this.libraryRename = Collections.unmodifiableMap(libraryIdxRename); + } else { + this.libraryRename = Collections.emptyMap(); + } } - private IdentityEnumerator allCells; - private IdentityEnumerator allInsts; - private IdentityEnumerator allPorts; - private StringEnumerator allStrings; - private Map libraryRename; + protected StringEnumerator newEnumerator() { + return new StringEnumerator(); + } + + protected final IdentityEnumerator allCells; + protected final IdentityEnumerator allInsts; + private final IdentityEnumerator allPorts; + private final StringEnumerator allStrings; + private final Map libraryRename; /** * Takes an EDIF property map and serializes (writes) it using the Cap'n Proto schema. The * opposite is {@link LogNetlistReader#extractPropertyMap(PropertyMap.Reader, EDIFPropertyObject)} - * @param builder The Cap'n Proto property map builder + * @param getBuilder Supplier lambda returning the Cap'n Proto property map builder. + * A lambda is used to avoid serializing an empty property map object when no + * EDIF properties exist as this still occupies space. In this case, it is + * better to not create the object to begin with. * @param obj The EDIF object that has a property map. */ - private void populatePropertyMap(PropertyMap.Builder builder, EDIFPropertyObject obj) { + private void populatePropertyMap(Supplier getBuilder, EDIFPropertyObject obj) { + Map propMap = obj.getPropertiesMap(); + if (propMap.isEmpty()) + return; + + PropertyMap.Builder builder = getBuilder.get(); StructList.Builder entries = - builder.initEntries(obj.getPropertiesMap().size()); + builder.initEntries(propMap.size()); int i = 0; - for (Entry e : obj.getPropertiesMap().entrySet()) { + for (Entry e : propMap.entrySet()) { PropertyMap.Entry.Builder entry = entries.get(i); entry.setKey(allStrings.getIndex(e.getKey())); switch (e.getValue().getType()) { @@ -123,20 +143,20 @@ private void populatePropertyMap(PropertyMap.Builder builder, EDIFPropertyObject * Gets the possibly-renamed name for a library * @param name The library name to map */ - private String lookupLibName(String name) { + private int lookupLibName(int name) { return libraryRename.getOrDefault(name, name); } /** - * Enumerates all cells, ports and cell instances in the netlist so a integer lookup reference + * Enumerates all cells, ports and cell instances in the netlist so an integer lookup reference * can be used for serialization. * @param n The current netlist to be serialized */ - private void populateEnumerations(EDIFNetlist n) { + protected void populateEnumerations(EDIFNetlist n) { // Enumerate all cells, ports and instances to break cyclic reference dependency // in netlist description - for (EDIFLibrary lib : n.getLibrariesInExportOrder()) { - for (EDIFCell cell : lib.getValidCellExportOrder(false)) { + for (EDIFLibrary lib : n.getLibraries()) { + for (EDIFCell cell : lib.getCells()) { allCells.addObject(cell); for (EDIFPort port : cell.getPorts()) { allPorts.addObject(port); @@ -154,48 +174,72 @@ private void populateEnumerations(EDIFNetlist n) { * @param n The RapidWright netlist (source) * @param netlist The Cap'n Proto netlist message (dest) */ - private void writeTopNetlistStuffToNetlistBuilder(EDIFNetlist n, Netlist.Builder netlist) { + protected void writeTopNetlistStuffToNetlistBuilder(EDIFNetlist n, Netlist.Builder netlist) { netlist.setName(n.getName()); - populatePropertyMap(netlist.getPropMap(), n.getDesign()); + populatePropertyMap(netlist::getPropMap, n.getDesign()); // Store top cell instance CellInstance.Builder topBuilder = netlist.initTopInst(); topBuilder.setName(allStrings.getIndex(n.getTopCellInst().getName())); - topBuilder.setCell(allCells.getIndex(n.getTopCell())); - populatePropertyMap(topBuilder.getPropMap(), n.getTopCellInst()); + topBuilder.setCell(allCells.maybeGetIndex(n.getTopCell())); + populatePropertyMap(topBuilder::getPropMap, n.getTopCellInst()); topBuilder.setView(allStrings.getIndex(n.getTopCellInst().getViewref().getName())); } + private void writeAllCellDeclsToNetlistBuilder(Netlist.Builder netlist) { + writeRangeCellDeclsToNetlistBuilder(netlist, 0, allCells.size() - 1); + } + /** * Writes master list of all cell objects to the Cap'n Proto message netlist * @param netlist The netlist builder. */ private void writeAllCellsToNetlistBuilder(Netlist.Builder netlist) { - StructList.Builder cellDeclsList = netlist.initCellDecls(allCells.size()); - StructList.Builder cellsList = netlist.initCellList(allCells.size()); + writeRangeCellsToNetlistBuilder(netlist, 0, allCells.size() - 1); + } - int i = 0; - for (EDIFCell cell : allCells) { - CellDeclaration.Builder cellDeclBuilder = cellDeclsList.get(i); - cellDeclBuilder.setName(allStrings.getIndex(cell.getName())); - Cell.Builder cellBuilder = cellsList.get(i); - cellBuilder.setIndex(i); - populatePropertyMap(cellDeclBuilder.getPropMap(), cell); + protected void writeRangeCellDeclsToNetlistBuilder(Netlist.Builder netlist, int start, int end) { + StructList.Builder cellDeclsList = netlist.initCellDecls(end - start + 1); + + for (int i = start; i <= end; i++) { + EDIFCell cell = allCells.get(i); + CellDeclaration.Builder cellDeclBuilder = cellDeclsList.get(i - start); + + int idx = allStrings.getIndex(cell.getName()); + + cellDeclBuilder.setName(idx); + populatePropertyMap(cellDeclBuilder::getPropMap, cell); cellDeclBuilder.setView(allStrings.getIndex(cell.getView())); - cellDeclBuilder.setLib(allStrings.getIndex(lookupLibName(cell.getLibrary().getName()))); + int libIdx = allStrings.getIndex(cell.getLibrary().getName()); + cellDeclBuilder.setLib(lookupLibName(libIdx)); - PrimitiveList.Int.Builder insts = cellBuilder.initInsts(cell.getCellInsts().size()); + PrimitiveList.Int.Builder ports = cellDeclBuilder.initPorts(cell.getPorts().size()); int j = 0; - for (EDIFCellInst inst : cell.getCellInsts()) { - insts.set(j, allInsts.getIndex(inst)); + for (EDIFPort port : cell.getPorts()) { + ports.set(j, allPorts.maybeGetIndex(port)); j++; } + } + } - PrimitiveList.Int.Builder ports = cellDeclBuilder.initPorts(cell.getPorts().size()); - j = 0; - for (EDIFPort port : cell.getPorts()) { - ports.set(j, allPorts.getIndex(port)); + /** + * Writes master list of all cell objects to the Cap'n Proto message netlist + * @param netlist The netlist builder. + */ + protected void writeRangeCellsToNetlistBuilder(Netlist.Builder netlist, int start, int end) { + StructList.Builder cellsList = netlist.initCellList(end - start + 1); + + for (int i = start; i <= end; i++) { + EDIFCell cell = allCells.get(i); + + Cell.Builder cellBuilder = cellsList.get(i - start); + cellBuilder.setIndex(i); + + PrimitiveList.Int.Builder insts = cellBuilder.initInsts(cell.getCellInsts().size()); + int j = 0; + for (EDIFCellInst inst : cell.getCellInsts()) { + insts.set(j, allInsts.maybeGetIndex(inst)); j++; } @@ -204,15 +248,15 @@ private void writeAllCellsToNetlistBuilder(Netlist.Builder netlist) { for (EDIFNet net : cell.getNets()) { Net.Builder netBuilder = nets.get(j); netBuilder.setName(allStrings.getIndex(net.getName())); - populatePropertyMap(netBuilder.getPropMap(), net); + populatePropertyMap(netBuilder::getPropMap, net); StructList.Builder portInsts = netBuilder .initPortInsts(net.getPortInsts().size()); int k = 0; for (EDIFPortInst portInst : net.getPortInsts()) { PortInstance.Builder piBuilder = portInsts.get(k); - piBuilder.setPort(allPorts.getIndex(portInst.getPort())); + piBuilder.setPort(allPorts.maybeGetIndex(portInst.getPort())); if (portInst.getCellInst() != null) { - piBuilder.setInst(allInsts.getIndex(portInst.getCellInst())); + piBuilder.setInst(allInsts.maybeGetIndex(portInst.getCellInst())); } else { piBuilder.setExtPort(Void.VOID); } @@ -223,19 +267,17 @@ private void writeAllCellsToNetlistBuilder(Netlist.Builder netlist) { } j++; } - i++; } - } - private void writeAllPortsToNetlistBuilder(Netlist.Builder netlist) { + protected void writeAllPortsToNetlistBuilder(Netlist.Builder netlist) { int i = 0; StructList.Builder portsList = netlist.initPortList(allPorts.size()); for (EDIFPort port : allPorts) { Port.Builder portBuilder = portsList.get(i); portBuilder.setName(allStrings.getIndex(port.getBusName())); portBuilder.setDir(LogNetlistReader.getDirection(port)); - populatePropertyMap(portBuilder.getPropMap(), port); + populatePropertyMap(portBuilder::getPropMap, port); if (port.isBus()) { Bus.Builder bus = portBuilder.initBus(); bus.setBusStart(port.getLeft()); @@ -247,20 +289,19 @@ private void writeAllPortsToNetlistBuilder(Netlist.Builder netlist) { } } - private void writeAllInstsToNetlistBuilder(Netlist.Builder netlist) { - int i = 0; + protected void writeAllInstsToNetlistBuilder(Netlist.Builder netlist) { StructList.Builder cellInstsList = netlist.initInstList(allInsts.size()); - for (EDIFCellInst inst : allInsts) { + for (int i = 0; i < allInsts.size(); i++) { + EDIFCellInst inst = allInsts.get(i); CellInstance.Builder ciBuilder = cellInstsList.get(i); ciBuilder.setName(allStrings.getIndex(inst.getName())); - populatePropertyMap(ciBuilder.getPropMap(), inst); - ciBuilder.setCell(allCells.getIndex(inst.getCellType())); + populatePropertyMap(ciBuilder::getPropMap, inst); + ciBuilder.setCell(allCells.maybeGetIndex(inst.getCellType())); ciBuilder.setView(allStrings.getIndex(inst.getViewref().getName())); - i++; } } - private void writeAllStringsToNetlistBuilder(Netlist.Builder netlist) { + protected void writeAllStringsToNetlistBuilder(Netlist.Builder netlist) { int stringCount = allStrings.size(); TextList.Builder strList = netlist.initStrList(stringCount); for (int i=0; i < stringCount; i++) { @@ -287,6 +328,8 @@ public static void writeLogNetlist(EDIFNetlist n, String fileName) throws IOExce * @throws IOException */ public static void writeLogNetlist(EDIFNetlist n, String fileName, boolean collapseMacros) throws IOException { + CodePerfTracker t = new CodePerfTracker("Write LogNetlist"); + t.start("Collapse Macros"); if (collapseMacros) { Device device = n.getDevice(); if (device != null) { @@ -296,30 +339,38 @@ public static void writeLogNetlist(EDIFNetlist n, String fileName, boolean colla + " could not be identified."); } } - + t.stop().start("Initialize"); MessageBuilder message = new MessageBuilder(); Netlist.Builder netlist = message.initRoot(Netlist.factory); - LogNetlistWriter writer = new LogNetlistWriter(); + t.stop(); + writer.populateNetlistBuilder(n, netlist, t); + t.start("Write Top"); writer.writeTopNetlistStuffToNetlistBuilder(n, netlist); - writer.populateNetlistBuilder(n, netlist); + t.stop().start("Write Strings"); writer.writeAllStringsToNetlistBuilder(netlist); - + t.stop().start("Write File"); Interchange.writeInterchangeFile(fileName, message); + t.stop().printSummary(); } /** - * Helper method to populate the logical netlist object with an existing builder. - * @param n The EDIF Netlist to serialize + * Helper method to populate the logical netlist object with an existing + * builder. + * + * @param n The EDIF Netlist to serialize * @param netlist The current builder object to receive the EDIF Netlist */ - public void populateNetlistBuilder(EDIFNetlist n, Netlist.Builder netlist) { + public void populateNetlistBuilder(EDIFNetlist n, Netlist.Builder netlist, CodePerfTracker t) { + t.start("Populate Enums"); populateEnumerations(n); - + t.stop().start("Write Cells"); + writeAllCellDeclsToNetlistBuilder(netlist); writeAllCellsToNetlistBuilder(netlist); - + t.stop().start("Write Ports"); writeAllPortsToNetlistBuilder(netlist); - + t.stop().start("Write Insts"); writeAllInstsToNetlistBuilder(netlist); + t.stop(); } } diff --git a/src/com/xilinx/rapidwright/interchange/PIPCache.java b/src/com/xilinx/rapidwright/interchange/PIPCache.java new file mode 100644 index 000000000..68b7d74ea --- /dev/null +++ b/src/com/xilinx/rapidwright/interchange/PIPCache.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2023, 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.interchange; + +import com.xilinx.rapidwright.device.PIP; +import com.xilinx.rapidwright.device.Tile; +import com.xilinx.rapidwright.device.TileTypeEnum; + +import java.util.List; +import java.util.Map; + +/** + * Class for caching PIP lookups, given a Tile object, and string + * indices for the start and end wire names. + */ +public class PIPCache { + private static class Key { + private final TileTypeEnum tileTypeEnum; + private final int wire0StringIdx; + private final int wire1StringIdx; + + public Key(Tile tile, int wire0StringIdx, int wire1StringIdx) { + tileTypeEnum = tile.getTileTypeEnum(); + this.wire0StringIdx = wire0StringIdx; + this.wire1StringIdx = wire1StringIdx; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + tileTypeEnum.ordinal(); + result = prime * result + wire0StringIdx; + result = prime * result + wire1StringIdx; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Key other = (Key) obj; + return wire0StringIdx == other.wire0StringIdx && + wire1StringIdx == other.wire1StringIdx && + tileTypeEnum == other.tileTypeEnum; + } + } + + private final Map map; + + private final List strings; + + public PIPCache(Map map, List strings) { + this.map = map; + this.strings = strings; + } + + private Integer getWireIndex(Tile tile, int wireStringIdx) { + String wireName = strings.get(wireStringIdx); + return tile.getWireIndex(wireName); + } + + public PIP getPIP(Tile tile, int wire0StringIdx, int wire1StringIdx) { + Key key = new Key(tile, wire0StringIdx, wire1StringIdx); + PIP pip = map.computeIfAbsent(key, (k) -> { + Integer wire0Idx = getWireIndex(tile, k.wire0StringIdx); + if (wire0Idx == null) { + String wire0 = strings.get(k.wire0StringIdx); + throw new RuntimeException("ERROR: Wire0 " + wire0 + " in tile " + tile + " not found."); + } + + Integer wire1Idx = getWireIndex(tile, k.wire1StringIdx); + if (wire1Idx == null) { + String wire1 = strings.get(k.wire1StringIdx); + throw new RuntimeException("ERROR: Wire1 " + wire1 + " in tile " + tile + " not found."); + } + + return tile.getPIP(wire0Idx, wire1Idx); + }); + PIP newPIP = new PIP(pip); + newPIP.setTile(tile); + return newPIP; + } +} diff --git a/src/com/xilinx/rapidwright/interchange/PhysNetlistReader.java b/src/com/xilinx/rapidwright/interchange/PhysNetlistReader.java index 1eff2c86f..09d7c6808 100644 --- a/src/com/xilinx/rapidwright/interchange/PhysNetlistReader.java +++ b/src/com/xilinx/rapidwright/interchange/PhysNetlistReader.java @@ -23,24 +23,6 @@ package com.xilinx.rapidwright.interchange; -import java.io.IOException; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Queue; -import java.util.Set; - -import org.capnproto.MessageReader; -import org.capnproto.PrimitiveList; -import org.capnproto.ReaderOptions; -import org.capnproto.StructList; -import org.capnproto.TextList; -import org.python.google.common.base.Enums; -import org.python.google.common.base.Optional; - import com.xilinx.rapidwright.design.AltPinMapping; import com.xilinx.rapidwright.design.Cell; import com.xilinx.rapidwright.design.Design; @@ -50,13 +32,14 @@ import com.xilinx.rapidwright.design.SitePinInst; import com.xilinx.rapidwright.design.Unisim; import com.xilinx.rapidwright.device.BEL; -import com.xilinx.rapidwright.device.BELClass; import com.xilinx.rapidwright.device.BELPin; import com.xilinx.rapidwright.device.Device; import com.xilinx.rapidwright.device.PIP; import com.xilinx.rapidwright.device.Site; +import com.xilinx.rapidwright.device.SitePIP; import com.xilinx.rapidwright.device.SiteTypeEnum; import com.xilinx.rapidwright.device.Tile; +import com.xilinx.rapidwright.device.Wire; import com.xilinx.rapidwright.edif.EDIFCell; import com.xilinx.rapidwright.edif.EDIFCellInst; import com.xilinx.rapidwright.edif.EDIFHierCellInst; @@ -81,107 +64,181 @@ import com.xilinx.rapidwright.interchange.PhysicalNetlist.PhysNetlist.RouteBranch; import com.xilinx.rapidwright.interchange.PhysicalNetlist.PhysNetlist.RouteBranch.RouteSegment; import com.xilinx.rapidwright.interchange.PhysicalNetlist.PhysNetlist.SiteInstance; -import com.xilinx.rapidwright.util.Utils; +import com.xilinx.rapidwright.tests.CodePerfTracker; +import org.capnproto.MessageReader; +import org.capnproto.PrimitiveList; +import org.capnproto.ReaderOptions; +import org.capnproto.StructList; +import org.capnproto.TextList; +import org.python.google.common.base.Enums; +import org.python.google.common.base.Optional; + +import java.io.IOException; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.Set; +import java.util.function.Consumer; public class PhysNetlistReader { protected static final String DISABLE_AUTO_IO_BUFFERS = "DISABLE_AUTO_IO_BUFFERS"; protected static final String OUT_OF_CONTEXT = "OUT_OF_CONTEXT"; - private static final String STATIC_SOURCE = "STATIC_SOURCE"; - private static int tieoffInstanceCount = 0; + public static boolean VALIDATE_MACROS_PLACED_FULLY = true; - public static Design readPhysNetlist(String physNetlistFileName, EDIFNetlist netlist) throws IOException { - Design design = new Design(); + /** + * Checks that constant routing and net names are valid. + * This incurs a runtime overhead. + */ + public static boolean CHECK_CONSTANT_ROUTING_AND_NET_NAMING = true; + + /** + * Examines a design to ensure that the provided macro placement is consistent with the + * macro definition in the library. + * This incurs a runtime overhead. + */ + public static boolean CHECK_MACROS_CONSISTENT = true; + + + /** + * When reading placement for physical netlist cells, check for the presence of and + * consistency with logical netlist cells. + * This incurs a runtime overhead. + */ + public static boolean CHECK_AND_CREATE_LOGICAL_CELL_IF_NOT_PRESENT = true; + + protected final Design design; + protected Device device; + + protected List strings; + + protected Map siteInsts; + + protected Map tiles; + + protected PIPCache pipCache; + + protected BELPinCache belPinCache; + + public PhysNetlistReader(EDIFNetlist netlist) { + design = new Design(); design.setNetlist(netlist); + } + + protected Design read(String physNetlistFileName) throws IOException { + CodePerfTracker t = new CodePerfTracker("Read PhysNetlist"); + + t.start("Read File"); ReaderOptions rdOptions = new ReaderOptions(ReaderOptions.DEFAULT_READER_OPTIONS.traversalLimitInWords * 64, ReaderOptions.DEFAULT_READER_OPTIONS.nestingLimit * 128); MessageReader readMsg = Interchange.readInterchangeFile(physNetlistFileName, rdOptions); PhysNetlist.Reader physNetlist = readMsg.getRoot(PhysNetlist.factory); + design.setPartName(physNetlist.getPart().toString()); + device = design.getDevice(); - StringEnumerator allStrings = readAllStrings(physNetlist); + t.stop().start("Read Strings"); + strings = readAllStrings(physNetlist); - checkConstantRoutingAndNetNaming(physNetlist, netlist, allStrings); + if (CHECK_CONSTANT_ROUTING_AND_NET_NAMING) { + t.stop().start("Check Constant Routing & Net Naming"); + checkConstantRoutingAndNetNaming(physNetlist); + } - readSiteInsts(physNetlist, design, allStrings); + t.stop().start("Read SiteInsts"); + readSiteInsts(physNetlist); - readPlacement(physNetlist, design, allStrings); + t.stop().start("Read Placement"); + readPlacement(physNetlist); - checkMacros(design); + if (CHECK_MACROS_CONSISTENT) { + t.stop().start("Check Macros"); + checkMacros(); + } - readRouting(physNetlist, design, allStrings); + t.stop().start("Read Routing"); + readNullNet(physNetlist); + readRouting(physNetlist); - readDesignProperties(physNetlist, design, allStrings); + t.stop().start("Read Design Props"); + readDesignProperties(physNetlist); + + t.stop().printSummary(); return design; } - public static StringEnumerator readAllStrings(PhysNetlist.Reader physNetlist) { - StringEnumerator allStrings = new StringEnumerator(); + public static Design readPhysNetlist(String physNetlistFileName) throws IOException { + return readPhysNetlist(physNetlistFileName, null); + } + + public static Design readPhysNetlist(String physNetlistFileName, EDIFNetlist netlist) throws IOException { + PhysNetlistReader reader = new PhysNetlistReader(netlist); + return reader.read(physNetlistFileName); + } + + public static List readAllStrings(PhysNetlist.Reader physNetlist) { TextList.Reader strListReader = physNetlist.getStrList(); int strCount = strListReader.size(); + List allStrings = new ArrayList<>(strCount); for (int i=0; i < strCount; i++) { String str = strListReader.get(i).toString(); - allStrings.addObject(str); + allStrings.add(str); } return allStrings; } - private static void readSiteInsts(PhysNetlist.Reader physNetlist, Design design, - StringEnumerator strings) { - Device device = design.getDevice(); - StructList.Reader siteInsts = physNetlist.getSiteInsts(); - int siteInstCount = siteInsts.size(); + protected void readSiteInsts(PhysNetlist.Reader physNetlist) { + StructList.Reader siteInstsReader = physNetlist.getSiteInsts(); + int siteInstCount = siteInstsReader.size(); if (siteInstCount == 0 && physNetlist.getPlacements().size() > 0) { System.out.println("WARNING: Missing SiteInst information in *.phys file. RapidWright " - + "will attempt to infer the proper SiteInst, however, it is recommended that " + "SiteInst information be specified to avoid SiteTypeEnum mismatch problems."); } + + siteInsts = new HashMap<>(siteInstCount); + for (int i=0; i < siteInstCount; i++) { - SiteInstance.Reader si = siteInsts.get(i); - String siteName = strings.get(si.getSite()); - SiteTypeEnum type = SiteTypeEnum.valueOf(strings.get(si.getType())); - design.createSiteInst(siteName, type, device.getSite(siteName)); + SiteInstance.Reader r = siteInstsReader.get(i); + String siteName = strings.get(r.getSite()); + SiteTypeEnum type = SiteTypeEnum.valueOf(strings.get(r.getType())); + SiteInst si = design.createSiteInst(siteName, type, device.getSite(siteName)); + siteInsts.put(r.getSite(), si); } } - private static void readPlacement(PhysNetlist.Reader physNetlist, Design design, - StringEnumerator strings) { - HashMap physCells = new HashMap<>(); + protected void readPlacement(PhysNetlist.Reader physNetlist) { StructList.Reader physCellReaders = physNetlist.getPhysCells(); int physCellCount = physCellReaders.size(); + Map physCells = new HashMap<>(physCellCount); for (int i=0; i < physCellCount; i++) { PhysCell.Reader reader = physCellReaders.get(i); - physCells.put(strings.get(reader.getCellName()), reader.getPhysType()); + PhysCellType physType = reader.getPhysType(); + assert(physType == PhysCellType.LOCKED || physType == PhysCellType.PORT); + physCells.put(reader.getCellName(), physType); } - StructList.Reader placements = physNetlist.getPlacements(); int placementCount = placements.size(); - Device device = design.getDevice(); EDIFNetlist netlist = design.getNetlist(); EDIFLibrary macroPrims = Design.getMacroPrimitives(device.getSeries()); - Map> macroLeafChildren = new HashMap<>(); + Set otherBELLocs = new HashSet<>(); for (int i=0; i < placementCount; i++) { CellPlacement.Reader placement = placements.get(i); String cellName = strings.get(placement.getCellName()); - EDIFCellInst cellInst = null; - Site site = device.getSite(strings.get(placement.getSite())); - SiteInst siteInst = design.getSiteInstFromSite(site); - if (siteInst == null) { - siteInst = design.createSiteInst(site); - } + SiteInst siteInst = getSiteInst(placement.getSite()); + assert(siteInst != null); String belName = strings.get(placement.getBel()); - HashSet otherBELLocs = null; - if (physCells.get(cellName) == PhysCellType.LOCKED) { - cellInst = new EDIFCellInst(PhysNetlistWriter.LOCKED,null,null); - if (siteInst == null) { - siteInst = new SiteInst(site.getName(), design, site.getSiteTypeEnum(), site); - } + PhysCellType physType = physCells.get(placement.getCellName()); + if (physType == PhysCellType.LOCKED) { siteInst.setSiteLocked(true); Cell c = siteInst.getCell(belName); if (c == null) { @@ -194,82 +251,79 @@ private static void readPlacement(PhysNetlist.Reader physNetlist, Design design, c.setLocked(true); // c Alternative Blocked Site Type // TODO - } else if (physCells.get(cellName) == PhysCellType.PORT) { + } else if (physType == PhysCellType.PORT) { Cell portCell = new Cell(cellName,siteInst.getBEL(belName)); portCell.setType(PhysNetlistWriter.PORT); siteInst.addCell(portCell); portCell.setBELFixed(placement.getIsBelFixed()); portCell.setSiteFixed(placement.getIsSiteFixed()); } else { - cellInst = netlist.getCellInstFromHierName(cellName); + assert(physType == null); String cellType = strings.get(placement.getType()); - if (cellInst == null) { - Optional maybeUnisim = Enums.getIfPresent(Unisim.class, cellType); - Unisim unisim = maybeUnisim.isPresent() ? maybeUnisim.get() : null; - if (unisim == null) { - EDIFCell cell = new EDIFCell(null,cellType); - cellInst = new EDIFCellInst(cellName,cell, null); + + if (CHECK_AND_CREATE_LOGICAL_CELL_IF_NOT_PRESENT) { + if (netlist == null) { + throw new RuntimeException("No EDIFNetlist supplied"); + } + + EDIFCellInst cellInst = netlist.getCellInstFromHierName(cellName); + if (cellInst == null) { + Optional maybeUnisim = Enums.getIfPresent(Unisim.class, cellType); + Unisim unisim = maybeUnisim.isPresent() ? maybeUnisim.get() : null; + if (unisim == null) { + EDIFCell cell = new EDIFCell(null, cellType); + new EDIFCellInst(cellName, cell, null); + } else { + Design.createUnisimInst(null, cellName, unisim); + } } else { - cellInst = Design.createUnisimInst(null, cellName, unisim); + assert (cellInst.getCellType().getName().equals(cellType)); } - } else { - assert(cellInst.getCellType().getName().equals(cellType)); } if (macroPrims.containsCell(cellType)) { throw new RuntimeException("ERROR: Placement for macro primitive " - + cellInst.getCellType().getName() + " (instance "+cellName+") is " + + cellType + " (instance "+cellName+") is " + "invalid. Please only provide placements for the macro's children " - + "leaf cells: " + cellInst.getCellType().getCellInsts() +"."); + + "leaf cells: " + cellType +"."); } BEL bel = siteInst.getBEL(belName); if (bel == null) { + String siteName = strings.get(placement.getSite()); throw new RuntimeException( - "ERROR: The placement specified on BEL " + site.getName() + "/" + "ERROR: The placement specified on BEL " + siteName + "/" + belName + " could not be found in the target " + "device."); } if (bel.getBELType().equals("HARD0") || bel.getBELType().equals("HARD1")) { + String siteName = strings.get(placement.getSite()); throw new RuntimeException( - "ERROR: The placement specified on BEL " + site.getName() + "/" + "ERROR: The placement specified on BEL " + siteName + "/" + bel.getName() + " is not valid. HARD0 and HARD1 BEL types do not " + "require placed cells."); } Cell existingCell = siteInst.getCell(bel); if (existingCell != null) { + String siteName = strings.get(placement.getSite()); throw new RuntimeException( - "ERROR: Cell \"" + cellName + "\" placement on BEL " + site.getName() + "/" + "ERROR: Cell \"" + cellName + "\" placement on BEL " + siteName + "/" + belName + " conflicts with previously placed cell \"" + existingCell.getName() + "\"."); } Cell cell = new Cell(cellName, siteInst, bel); cell.setBELFixed(placement.getIsBelFixed()); cell.setSiteFixed(placement.getIsSiteFixed()); - if (cellInst != null) { - cell.setType(cellInst.getCellType().getName()); - } + cell.setType(cellType); - PrimitiveList.Int.Reader otherBELs = placement.getOtherBels(); - int otherBELCount = otherBELs.size(); - if (otherBELCount > 0) otherBELLocs = new HashSet(); - for (int j=0; j < otherBELCount; j++) { - String belLoc = strings.get(otherBELs.get(j)); - otherBELLocs.add(belLoc); + if (placement.hasOtherBels()) { + PrimitiveList.Int.Reader otherBELs = placement.getOtherBels(); + int otherBELCount = otherBELs.size(); + for (int j=0; j < otherBELCount; j++) { + otherBELLocs.add(otherBELs.get(j)); + } } } - PhysNet.Reader nullNet = physNetlist.getNullNet(); - StructList.Reader stubs = nullNet.getStubs(); - int stubCount = stubs.size(); - for (int k=0; k < stubCount; k++) { - RouteSegment.Reader segment = stubs.get(k).getRouteSegment(); - PhysSitePIP.Reader spReader = segment.getSitePIP(); - SiteInst sitePIPSiteInst = getSiteInst(spReader.getSite(), design, strings); - sitePIPSiteInst.addSitePIP(strings.get(spReader.getBel()), - strings.get(spReader.getPin())); - } - - StructList.Reader pinMap = placement.getPinMap(); int pinMapCount = pinMap.size(); for (int j=0; j < pinMapCount; j++) { @@ -279,7 +333,7 @@ private static void readPlacement(PhysNetlist.Reader physNetlist, Design design, String cellPinName = strings.get(pinMapping.getCellPin()); Cell c = siteInst.getCell(belName); if (c == null) { - if (otherBELLocs.contains(belName)) { + if (otherBELLocs.remove(pinMapping.getBel())) { BEL bel = siteInst.getBEL(belName); if (bel == null) { throw new RuntimeException("ERROR: Couldn't find BEL " + belName @@ -317,42 +371,44 @@ private static void readPlacement(PhysNetlist.Reader physNetlist, Design design, } } } + + assert(otherBELLocs.isEmpty()); } // Validate macro primitives are placed fully - HashSet checked = new HashSet<>(); - for (Cell c : design.getCells()) { - EDIFCell cellType = c.getParentCell(); - if (cellType != null && macroPrims.containsCell(cellType)) { - String parentHierName = c.getParentHierarchicalInstName(); - if (checked.contains(parentHierName)) continue; - List missingPlacements = null; - List childrenNames = macroLeafChildren.get(cellType.getName()); - if (childrenNames == null) { - childrenNames = EDIFTools.getMacroLeafCellNames(cellType); - macroLeafChildren.put(cellType.getName(), childrenNames); - } - //for (EDIFCellInst inst : cellType.getCellInsts()) { // TODO - Fix up loop list - for (String childName : childrenNames) { - if (childName.equals("VCC") || childName.equals("GND")) { - // Ignore VCC (e.g. from FDRS_1) and GND cells - continue; + if (VALIDATE_MACROS_PLACED_FULLY) { + Map> macroLeafChildren = new HashMap<>(); + Set checked = new HashSet<>(); + for (Cell c : design.getCells()) { + EDIFCell cellType = c.getParentCell(); + if (cellType != null && macroPrims.containsCell(cellType)) { + String parentHierName = c.getParentHierarchicalInstName(); + if (checked.contains(parentHierName)) continue; + List missingPlacements = null; + List childrenNames = macroLeafChildren.computeIfAbsent(cellType.getName(), + (k) -> EDIFTools.getMacroLeafCellNames(cellType)); + //for (EDIFCellInst inst : cellType.getCellInsts()) { // TODO - Fix up loop list + for (String childName : childrenNames) { + if (childName.equals("VCC") || childName.equals("GND")) { + // Ignore VCC (e.g. from FDRS_1) and GND cells + continue; + } + String childCellName = parentHierName + EDIFTools.EDIF_HIER_SEP + childName; + Cell child = design.getCell(childCellName); + if (child == null) { + if (missingPlacements == null) missingPlacements = new ArrayList<>(); + missingPlacements.add(childName + " (" + childCellName + ")"); + } } - String childCellName = parentHierName + EDIFTools.EDIF_HIER_SEP + childName; - Cell child = design.getCell(childCellName); - if (child == null) { - if (missingPlacements == null) missingPlacements = new ArrayList(); - missingPlacements.add(childName + " (" + childCellName + ")"); + if (missingPlacements != null && !cellType.getName().equals("IOBUFDS")) { + throw new RuntimeException("ERROR: Macro primitive '" + parentHierName + + "' is not fully placed. Expected placements for all child cells: " + + cellType.getCellInsts() + ", but missing placements " + + "for cells: " + missingPlacements); } - } - if (missingPlacements != null && !cellType.getName().equals("IOBUFDS")) { - throw new RuntimeException("ERROR: Macro primitive '"+ parentHierName - + "' is not fully placed. Expected placements for all child cells: " - + cellType.getCellInsts() + ", but missing placements " - + "for cells: " + missingPlacements); - } - checked.add(parentHierName); + checked.add(parentHierName); + } } } } @@ -376,160 +432,227 @@ private static NetType getNetType(PhysNet.Reader netReader, String netName) { } } - private static void readRouting(PhysNetlist.Reader physNetlist, Design design, - StringEnumerator strings) { - StructList.Reader nets = physNetlist.getPhysNets(); - EDIFNetlist netlist = design.getNetlist(); + protected void readNullNet(PhysNetlist.Reader physNetlist) { + PhysNet.Reader nullNet = physNetlist.getNullNet(); + StructList.Reader stubs = nullNet.getStubs(); + int stubCount = stubs.size(); + for (int k=0; k < stubCount; k++) { + RouteSegment.Reader segment = stubs.get(k).getRouteSegment(); + PhysSitePIP.Reader spReader = segment.getSitePIP(); + SiteInst sitePIPSiteInst = getSiteInst(spReader.getSite()); + sitePIPSiteInst.addSitePIP(strings.get(spReader.getBel()), + strings.get(spReader.getPin())); + } + } + + private void readRouting(PhysNetlist.Reader physNetlist) { + tiles = new HashMap<>(); + pipCache = new PIPCache(new HashMap<>(), strings); + belPinCache = new BELPinCache(new HashMap<>(), strings); + + StructList.Reader nets = physNetlist.getPhysNets(); + + // For single-threaded read, add net to design object immediately + readRouting(nets, design::addNet); + + tiles = null; + pipCache = null; + belPinCache = null; + } + + protected void readRouting(StructList.Reader nets, Consumer addNetToDesign) { int netCount = nets.size(); + Set stubWires = new HashSet<>(); for (int i=0; i < netCount; i++) { PhysNet.Reader netReader = nets.get(i); String netName = strings.get(netReader.getName()); Net net = new Net(netName); - design.addNet(net); + net.setDesign(design); net.setType(getNetType(netReader, netName)); + addNetToDesign.accept(net); + + // Stub Nodes + if (netReader.hasStubNodes()) { + StructList.Reader stubNodes = netReader.getStubNodes(); + int stubNodeCount = stubNodes.size(); + for (int j = 0; j < stubNodeCount; j++) { + PhysNode.Reader stubNodeReader = stubNodes.get(j); + Tile tile = getTile(stubNodeReader.getTile()); + Integer wireIdx = getWireIndex(tile, stubNodeReader.getWire()); + Wire wire = new Wire(tile, wireIdx); + boolean added = stubWires.add(wire); + assert (added); + } + } // Sources - StructList.Reader routeSrcs = netReader.getSources(); - int routeSrcsCount = routeSrcs.size(); - for (int j=0; j < routeSrcsCount; j++) { - RouteBranch.Reader branchReader = routeSrcs.get(j); - readRouteBranch(branchReader, net, design, strings, null); + if (netReader.hasSources()) { + StructList.Reader routeSrcs = netReader.getSources(); + int routeSrcsCount = routeSrcs.size(); + for (int j = 0; j < routeSrcsCount; j++) { + RouteBranch.Reader branchReader = routeSrcs.get(j); + readRouteBranch(stubWires, branchReader, net, null); + } } // Stubs - StructList.Reader routeStubs = netReader.getStubs(); - int routeStubsCount = routeStubs.size(); - for (int j=0; j < routeStubsCount; j++) { - RouteBranch.Reader branchReader = routeStubs.get(j); - readRouteBranch(branchReader, net, design, strings, null); + if (netReader.hasStubs()) { + StructList.Reader routeStubs = netReader.getStubs(); + int routeStubsCount = routeStubs.size(); + for (int j=0; j < routeStubsCount; j++) { + RouteBranch.Reader branchReader = routeStubs.get(j); + readRouteBranch(stubWires, branchReader, net, null); + } } - // Stub Nodes - StructList.Reader stubNodes = netReader.getStubNodes(); - int stubNodeCount = stubNodes.size(); - Device device = design.getDevice(); - for (int j=0; j < stubNodeCount; j++) { - PhysNode.Reader stubNodeReader = stubNodes.get(j); - Tile tile = device.getTile(strings.get(stubNodeReader.getTile())); - PIP pip = new PIP(tile, stubNodeReader.getWire(), PIP.NULL_END_WIRE_IDX); + // Stub nodes that don't belong on a PIP + for (Wire wire : stubWires) { + PIP pip = new PIP(wire.getTile(), wire.getWireIndex(), PIP.NULL_END_WIRE_IDX); net.addPIP(pip); } + stubWires.clear(); } } - private static void readRouteBranch(RouteBranch.Reader branchReader, Net net, Design design, - StringEnumerator strings, BELPin routeThruLutInput) { + protected void addBELPinToSiteInst(BELPin belPin, SiteInst siteInst, Net net) { + siteInst.routeIntraSiteNet(net, belPin, belPin); + } + + protected void addCellToSiteInst(Cell cell) { + SiteInst siteInst = cell.getSiteInst(); + siteInst.getCellMap().put(cell.getBELName(), cell); + } + + protected void addSitePIPToSiteInst(SitePIP sitePIP, SiteInst siteInst) { + siteInst.addSitePIP(sitePIP); + } + + protected SitePinInst createSitePin(int pinNameIdx, SiteInst siteInst, Net net) { + BELPin belPin = getBELPin(siteInst, pinNameIdx, pinNameIdx); + // An output BELPin is an input site pin + boolean outputPin = !belPin.isOutput(); + String pinName = strings.get(pinNameIdx); + SitePinInst pin = new SitePinInst(outputPin, pinName, siteInst); + net.addPin(pin); + return pin; + } + + private void readRouteBranch(Set stubWires, + RouteBranch.Reader branchReader, + Net net, + BELPin routeThruLutInput) { RouteBranch.RouteSegment.Reader segment = branchReader.getRouteSegment(); - StructList.Reader branches = branchReader.getBranches(); - int branchesCount = branches.size(); - Device device = design.getDevice(); + StructList.Reader branches = null; + int branchesCount; + if (branchReader.hasBranches()) { + branches = branchReader.getBranches(); + branchesCount = branches.size(); + } else { + branchesCount = 0; + } switch(segment.which()) { case PIP:{ PhysPIP.Reader pReader = segment.getPip(); - Tile tile = device.getTile(strings.get(pReader.getTile())); - String wire0 = strings.get(pReader.getWire0()); - String wire1 = strings.get(pReader.getWire1()); + Tile tile = getTile(pReader.getTile()); if (tile == null) { - throw new RuntimeException("ERROR: Tile " + tile + " for pip from wire " + wire0 + " to wire " + wire1 + " not found."); - } - - Integer wire0Idx = tile.getWireIndex(wire0); - if (wire0Idx == null) { - throw new RuntimeException("ERROR: Wire0 " + wire0 + " in tile " + tile + " not found."); + String wire0 = strings.get(pReader.getWire0()); + String wire1 = strings.get(pReader.getWire1()); + throw new RuntimeException("ERROR: Tile " + strings.get(pReader.getTile()) + " for pip from wire " + wire0 + " to wire " + wire1 + " not found."); } - Integer wire1Idx = tile.getWireIndex(wire1); - if (wire1Idx == null) { - throw new RuntimeException("ERROR: Wire1 " + wire1 + " in tile " + tile + " not found."); - } + PIP pip = getPIP(tile, pReader.getWire0(), pReader.getWire1()); + pip.setIsPIPFixed(pReader.getIsFixed()); + pip.setIsReversed(!pReader.getForward()); - PIP pip = tile.getPIP(wire0Idx, wire1Idx); - if (pip == null) { - throw new RuntimeException("ERROR: PIP for tile " + tile + " from wire " + wire0 + " to wire " + wire1 + " not found."); + if (stubWires.remove(pip.getEndWire())) { + pip.setIsStub(true); } - pip.setIsPIPFixed(pReader.getIsFixed()); - pip.setIsReversed(!pReader.getForward()); net.addPIP(pip); break; } case BEL_PIN:{ PhysBelPin.Reader bpReader = segment.getBelPin(); - SiteInst siteInst = getSiteInst(bpReader.getSite(), design, strings); - String belName = strings.get(bpReader.getBel()); - BEL bel = siteInst.getBEL(belName); - if (bel == null) { - throw new RuntimeException(String.format("ERROR: Failed to get BEL %s", belName)); - } - String belPinName = strings.get(bpReader.getPin()); - BELPin belPin = bel.getPin(belPinName); - if (belPin == null) { - throw new RuntimeException(String.format("ERROR: Failed to get BEL pin %s/%s", belName, belPinName)); - } - - // Examine BEL input pins from SLICEL/M only - if (Utils.isSLICE(siteInst) && bel.getBELClass() == BELClass.BEL && belPin.isInput()) { - - // If this route branch terminates here ... - if (branchesCount == 0) { - // ... and it routed through a LUT along the way - if (routeThruLutInput != null) { - // Check that a routethru cell exists - - Cell belCell = siteInst.getCell(bel); - Cell routeThruCell = siteInst.getCell(routeThruLutInput.getBEL()); - if (routeThruCell == null) { - // Routethru cell does not exist, create one - - // Make sure nothing placed there already - if (siteInst.getCell(routeThruLutInput.getBEL()) != null) { - throw new RuntimeException("Routethru inferred for " + siteInst.getSiteName() + "/" + routeThruLutInput.getBELName() - + " but it is already occupied"); + SiteInst siteInst = getPlacedSiteInst(bpReader.getSite()); + BELPin belPin = getBELPin(siteInst, bpReader.getBel(), bpReader.getPin()); + + // Examine LUT input pins only + if (belPin.isInput()) { + BEL bel = belPin.getBEL(); + if (bel.isLUT()) { + // If this route branch terminates here ... + if (branchesCount == 0) { + // ... and it routed through a LUT along the way + if (routeThruLutInput != null) { + // Check that a routethru cell exists + + String belPinName = belPin.getName(); + + Cell belCell = siteInst.getCell(bel); + Cell routeThruCell = siteInst.getCell(routeThruLutInput.getBEL()); + if (routeThruCell == null) { + // Routethru cell does not exist, create one + + // Make sure nothing placed there already + if (siteInst.getCell(routeThruLutInput.getBEL()) != null) { + throw new RuntimeException("Routethru inferred for " + siteInst.getSiteName() + "/" + routeThruLutInput.getBELName() + + " but it is already occupied"); + } + + routeThruCell = new Cell(belCell.getName(), routeThruLutInput.getBEL()); + routeThruCell.setRoutethru(true); + routeThruCell.setType(belCell.getType()); + routeThruCell.setSiteInst(siteInst); + addCellToSiteInst(routeThruCell); + routeThruCell.addPinMapping(routeThruLutInput.getName(), belCell.getLogicalPinMapping(belPinName)); } - routeThruCell = new Cell(belCell.getName(), routeThruLutInput.getBEL()); - routeThruCell.setRoutethru(true); - routeThruCell.setType(belCell.getType()); - routeThruCell.setSiteInst(siteInst); - siteInst.getCellMap().put(routeThruLutInput.getBELName(), routeThruCell); - routeThruCell.addPinMapping(routeThruLutInput.getName(), belCell.getLogicalPinMapping(belPinName)); - } - String physicalPin = routeThruLutInput.getName(); - String logicalPin = belCell.getLogicalPinMapping(belPinName); - if (routeThruCell.getSiteInst() != siteInst || - !routeThruCell.isRoutethru() || - !routeThruCell.getLogicalPinMapping(physicalPin).equals(logicalPin)) { - throw new RuntimeException("Invalid routethru cell: " + routeThruCell); + String physicalPin = routeThruLutInput.getName(); + String logicalPin = belCell.getLogicalPinMapping(belPinName); + if (routeThruCell.getSiteInst() != siteInst || + !routeThruCell.isRoutethru() || + !routeThruCell.getLogicalPinMapping(physicalPin).equals(logicalPin)) { + throw new RuntimeException("Invalid routethru cell: " + routeThruCell); + } } - } - } else if (belName.endsWith("LUT")) { - assert (routeThruLutInput == null); + } else { + assert (routeThruLutInput == null); - routeThruLutInput = belPin; + routeThruLutInput = belPin; + } } - } + } else { + assert(!belPin.isInput()); - siteInst.routeIntraSiteNet(net, belPin, belPin); + // Only output BEL pins affect intra-site routing + addBELPinToSiteInst(belPin, siteInst, net); + } break; } case SITE_P_I_P:{ PhysSitePIP.Reader spReader = segment.getSitePIP(); - SiteInst siteInst = getSiteInst(spReader.getSite(), design, strings); - siteInst.addSitePIP(strings.get(spReader.getBel()), - strings.get(spReader.getPin())); + SiteInst siteInst = getPlacedSiteInst(spReader.getSite()); + BELPin belPin = getBELPin(siteInst, spReader.getBel(), spReader.getPin()); + SitePIP sitePIP = siteInst.getSitePIP(belPin); + addSitePIPToSiteInst(sitePIP, siteInst); break; } case SITE_PIN: { PhysSitePin.Reader spReader = segment.getSitePin(); - SiteInst siteInst = getSiteInst(spReader.getSite(), design, strings); - String pinName = strings.get(spReader.getPin()); - if (siteInst == null && net.isStaticNet()) { - Site site = design.getDevice().getSite(strings.get(spReader.getSite())); - siteInst = new SiteInst(STATIC_SOURCE + tieoffInstanceCount++, site.getSiteTypeEnum()); - siteInst.place(site); - } - - net.addPin(new SitePinInst(pinName, siteInst), false); - + SiteInst siteInst = siteInsts.computeIfAbsent(spReader.getSite(), (k) -> { + Site site = device.getSite(strings.get(k)); + if (!net.isStaticNet()) { + throw new RuntimeException("ERROR: SiteInst for Site " + site.getName() + " not found."); + } + // Create a dummy TIEOFF SiteInst + String name = SiteInst.STATIC_SOURCE + "_" + site.getName(); + SiteInst si = new SiteInst(name, site.getSiteTypeEnum()); + si.place(site); + // Ensure it is not attached to the design + assert(si.getDesign() == null); + return si; + }); + + createSitePin(spReader.getPin(), siteInst, net); assert(routeThruLutInput == null); break; } @@ -540,13 +663,12 @@ private static void readRouteBranch(RouteBranch.Reader branchReader, Net net, De for (int j=0; j < branchesCount; j++) { RouteBranch.Reader bReader = branches.get(j); - readRouteBranch(bReader, net, design, strings, routeThruLutInput); + readRouteBranch(stubWires, bReader, net, routeThruLutInput); } } - private static void readDesignProperties(PhysNetlist.Reader physNetlist, Design design, - StringEnumerator strings) { + protected void readDesignProperties(PhysNetlist.Reader physNetlist) { StructList.Reader props = physNetlist.getProperties(); int propCount = props.size(); for (int i=0; i < propCount; i++) { @@ -562,23 +684,37 @@ private static void readDesignProperties(PhysNetlist.Reader physNetlist, Design } } - private static SiteInst getSiteInst(int stringIdx, Design design, StringEnumerator strings) { - String siteName = strings.get(stringIdx); - Site site = design.getDevice().getSite(siteName); - if (site == null) { - throw new RuntimeException("ERROR: Unknown site " + siteName + - " found while parsing routing"); - } - SiteInst siteInst = design.getSiteInstFromSite(site); - if (siteInst == null && site.getSiteTypeEnum() == SiteTypeEnum.TIEOFF) { - // Create a dummy TIEOFF SiteInst - siteInst = new SiteInst(STATIC_SOURCE + tieoffInstanceCount++, site.getSiteTypeEnum()); - siteInst.place(site); - } + protected SiteInst getSiteInst(int stringIdx) { + return siteInsts.get(stringIdx); + } + + private SiteInst getPlacedSiteInst(int stringIdx) { + SiteInst siteInst = getSiteInst(stringIdx); + assert(siteInst != null && siteInst.isPlaced()); return siteInst; } - private static void checkNetTypeFromCellNet(Map cellPinToPhysicalNet, EDIFNet net, StringEnumerator strings) { + private Tile getTile(int stringIdx) { + return tiles.computeIfAbsent(stringIdx, (i) -> { + String tileName = strings.get(i); + return device.getTile(tileName); + }); + } + + private Integer getWireIndex(Tile tile, int wireStringIdx) { + String wireName = strings.get(wireStringIdx); + return tile.getWireIndex(wireName); + } + + protected BELPin getBELPin(SiteInst siteInst, int belStringIdx, int pinStringIdx) { + return belPinCache.getBELPin(siteInst, belStringIdx, pinStringIdx); + } + + private PIP getPIP(Tile tile, int wire0StringIdx, int wire1StringIdx) { + return pipCache.getPIP(tile, wire0StringIdx, wire1StringIdx); + } + + private static void checkNetTypeFromCellNet(Map cellPinToPhysicalNet, EDIFNet net, List strings) { // Expand EDIFNet and make sure sink cell pins that are part of a // physical net are annotated as a VCC or GND net. // @@ -589,7 +725,7 @@ private static void checkNetTypeFromCellNet(Map cellPinT // If the full physical net is present and the inverting site pips are // labelled, then it would be possible to confirm if the NetType was // always correct. - Queue netsToExpand = new ArrayDeque(); + Queue netsToExpand = new ArrayDeque<>(); netsToExpand.add(net); while (!netsToExpand.isEmpty()) { @@ -633,7 +769,9 @@ private static void checkNetTypeFromCellNet(Map cellPinT } } - private static void mapBelPinsToPhysicalNets(Map belPinToPhysicalNet, PhysNet.Reader netReader, RouteBranch.Reader routeBranch, StringEnumerator strings) { + private void mapBelPinsToPhysicalNets(Map belPinToPhysicalNet, + PhysNet.Reader netReader, + RouteBranch.Reader routeBranch) { // Populate a map from strings formatted like "//" // to PhysNet by recursively expanding routing branches. @@ -644,11 +782,16 @@ private static void mapBelPinsToPhysicalNets(Map belPinT } for (PhysNetlist.RouteBranch.Reader childBranch : routeBranch.getBranches()) { - mapBelPinsToPhysicalNets(belPinToPhysicalNet, netReader, childBranch, strings); + mapBelPinsToPhysicalNets(belPinToPhysicalNet, netReader, childBranch); } } - private static void checkConstantRoutingAndNetNaming(PhysNetlist.Reader PhysicalNetlist, EDIFNetlist netlist, StringEnumerator strings) { + protected void checkConstantRoutingAndNetNaming(PhysNetlist.Reader physNetlist) { + EDIFNetlist netlist = design.getNetlist(); + if (netlist == null) { + throw new RuntimeException("No EDIFNetlist supplied"); + } + // Checks that constant routing and net names are valid. // // Specifically: @@ -666,15 +809,15 @@ private static void checkConstantRoutingAndNetNaming(PhysNetlist.Reader Physical // and Nets.VCC_NET. boolean foundGndNet = false; boolean foundVccNet = false; - Map belPinToPhysicalNet = new HashMap(); - Set netNames = new HashSet(); - for (PhysNet.Reader physNet : PhysicalNetlist.getPhysNets()) { + Map belPinToPhysicalNet = new HashMap<>(); + Set netNames = new HashSet<>(); + for (PhysNet.Reader physNet : physNetlist.getPhysNets()) { for (PhysNetlist.RouteBranch.Reader routeBranch : physNet.getSources()) { - mapBelPinsToPhysicalNets(belPinToPhysicalNet, physNet, routeBranch, strings); + mapBelPinsToPhysicalNets(belPinToPhysicalNet, physNet, routeBranch); } for (PhysNetlist.RouteBranch.Reader routeBranch : physNet.getStubs()) { - mapBelPinsToPhysicalNets(belPinToPhysicalNet, physNet, routeBranch, strings); + mapBelPinsToPhysicalNets(belPinToPhysicalNet, physNet, routeBranch); } if (!netNames.add(physNet.getName())) { @@ -709,8 +852,8 @@ private static void checkConstantRoutingAndNetNaming(PhysNetlist.Reader Physical } // Iterate over placements and map cell pins to physical nets. - Map cellPinToPhysicalNet = new HashMap(); - for (CellPlacement.Reader placement : PhysicalNetlist.getPlacements()) { + Map cellPinToPhysicalNet = new HashMap<>(); + for (CellPlacement.Reader placement : physNetlist.getPlacements()) { for (PinMapping.Reader pinMap : placement.getPinMap()) { String key = strings.get(placement.getSite()) + "/" + strings.get(pinMap.getBel()) + "/" + strings.get(pinMap.getBelPin()); PhysNet.Reader net = belPinToPhysicalNet.get(key); @@ -757,12 +900,15 @@ private static void checkConstantRoutingAndNetNaming(PhysNetlist.Reader Physical /** * Examines a design to ensure that the provided macro placement is consistent with the * macro definition in the library. - * @param design The placed design to be checked */ - private static void checkMacros(Design design) { + protected void checkMacros() { EDIFNetlist netlist = design.getNetlist(); + if (netlist == null) { + throw new RuntimeException("No EDIFNetlist supplied"); + } + List leaves = netlist.getTopCell().getAllLeafDescendants(); - EDIFLibrary macros = Design.getMacroPrimitives(design.getDevice().getSeries()); + EDIFLibrary macros = Design.getMacroPrimitives(device.getSeries()); for (EDIFHierCellInst leaf : leaves) { if (macros.containsCell(leaf.getCellType())) { EDIFCell macro = macros.getCell(leaf.getCellName()); diff --git a/src/com/xilinx/rapidwright/interchange/PhysNetlistWriter.java b/src/com/xilinx/rapidwright/interchange/PhysNetlistWriter.java index 35dc979dc..ef36242ff 100644 --- a/src/com/xilinx/rapidwright/interchange/PhysNetlistWriter.java +++ b/src/com/xilinx/rapidwright/interchange/PhysNetlistWriter.java @@ -30,6 +30,7 @@ import com.xilinx.rapidwright.design.SiteInst; import com.xilinx.rapidwright.design.SitePinInst; import com.xilinx.rapidwright.device.BEL; +import com.xilinx.rapidwright.device.BELClass; import com.xilinx.rapidwright.device.BELPin; import com.xilinx.rapidwright.device.Node; import com.xilinx.rapidwright.device.PIP; @@ -53,6 +54,7 @@ import com.xilinx.rapidwright.interchange.PhysicalNetlist.PhysNetlist.RouteBranch.RouteSegment; import com.xilinx.rapidwright.interchange.PhysicalNetlist.PhysNetlist.SiteInstance; import com.xilinx.rapidwright.interchange.RouteBranchNode.RouteSegmentType; +import com.xilinx.rapidwright.tests.CodePerfTracker; import org.capnproto.MessageBuilder; import org.capnproto.PrimitiveList; import org.capnproto.StructList; @@ -72,13 +74,29 @@ public class PhysNetlistWriter { - // By default, routing for physical nets will be written as a list of (connected) - // trees of routing resources. Disabling this feature will save runtime but write - // out the same set of routing resources as an unordered list of stubs instead. + /** + * By default, routing for physical nets will be written as a list of (connected) + * trees of routing resources. Disabling this feature will save runtime but write + * out the same set of routing resources as an unordered list of stubs instead. + */ public static boolean BUILD_ROUTING_GRAPH_ON_EXPORT = true; - private static void writeSiteInsts(PhysNetlist.Builder physNetlist, Design design, - StringEnumerator strings) { + /** + * The Interchange format allows for all physical routing resources to be + * specified, e.g. + * ... -> PIP -> SitePin -> BELPin(output) -> BELPin(input) -> SitePIP -> BELPin(output) -> BELPin(input) + * It may not be necessary to use specify all such resources, as many are implied: + * ... -> PIP -> SitePin -> (implied) -> (implied) -> SitePIP -> (implied) -> (implied) + * Disabling this flag allows such implied resources to be omitted. + */ + public static boolean VERBOSE_PHYSICAL_NET_ROUTING = true; + + public static final String LOCKED = ""; + public static final String PORT = ""; + + + protected static void writeSiteInsts(PhysNetlist.Builder physNetlist, Design design, + StringEnumerator strings) { Builder siteInsts = physNetlist.initSiteInsts(design.getSiteInsts().size()); int i=0; for (SiteInst si : design.getSiteInsts()) { @@ -87,13 +105,9 @@ private static void writeSiteInsts(PhysNetlist.Builder physNetlist, Design desig siBuilder.setType(strings.getIndex(si.getSiteTypeEnum().name())); i++; } - } - public static final String LOCKED = ""; - public static final String PORT = ""; - - protected static String getUniqueLockedCellName(Cell cell, HashMap physCells) { + protected static String getUniqueLockedCellName(Cell cell, Map physCells) { String cellName = cell.getName(); if (cellName.equals(LOCKED)) { cellName = cell.getSiteName() + "_" + cell.getBELName() + "_" + LOCKED; @@ -104,17 +118,16 @@ protected static String getUniqueLockedCellName(Cell cell, HashMap siteInsts) { - HashMap physCells = new HashMap<>(); - ArrayList allCells = new ArrayList(); - HashMap> multiBelCells = new HashMap<>(); + StringEnumerator strings, Collection siteInsts) { + Map physCells = new HashMap<>(); + ArrayList allCells = new ArrayList<>(); + Map> multiBelCells = new HashMap<>(); int i=0; for (SiteInst siteInst : siteInsts) { if (!siteInst.isPlaced()) continue; @@ -161,8 +174,7 @@ public static void writePlacement(PhysNetlist.Builder physNetlist, Design design } Builder pinMap = physCell.initPinMap(cell.getPinMappingsP2L().size() + additionalPinMappings); - Integer idx = 0; - idx = addCellPinMappings(cell, strings, pinMap, 0); + int idx = addCellPinMappings(cell, strings, pinMap, 0); if (otherBels != null) { for (Cell c : otherBels) { idx = addCellPinMappings(c, strings, pinMap, idx); @@ -212,75 +224,53 @@ private static int addCellPinMappings(Cell cell, StringEnumerator strings, return idx; } - public static Map> extractSiteRouting(Collection siteInsts, - List nullNetStubs) - { - // Extract out site routing first, for partially routed designs... - Map> netSiteRouting = new HashMap<>(); - for (SiteInst siteInst : siteInsts) { + private static void writePhysNets(PhysNetlist.Builder physNetlist, Design design, + StringEnumerator strings) { + writeNullNet(physNetlist, design, strings); + + int physNetCount = design.getNets().size(); + Builder nets = physNetlist.initPhysNets(physNetCount); + Net[] keys = design.getNets().toArray(new Net[design.getNets().size()]); + writePhysNetsRange(nets, keys, design, strings, 0, keys.length - 1); + } + + protected static void writePhysNetsRange(Builder nets, Net[] keys, + Design design, StringEnumerator strings, int start, + int end) { + for (int i = start; i <= end; i++) { + String netName = keys[i].getName(); + Net net = design.getNet(netName); + assert(net != null); + PhysNet.Builder physNet = nets.get(i - start); + buildNet(net, physNet, strings); + } + } + + protected static void writeNullNet(PhysNetlist.Builder physNetlist, Design design, + StringEnumerator strings) { + List nullNetStubs = new ArrayList<>(); + for (SiteInst siteInst : design.getSiteInsts()) { Site site = siteInst.getSite(); for (SitePIP sitePIP : siteInst.getUsedSitePIPs()) { String siteWire = sitePIP.getInputPin().getSiteWireName(); - Net net = siteInst.getNetFromSiteWire(siteWire); - if (net == null) { - String sitePinName = sitePIP.getInputPin().getConnectedSitePinName(); - SitePinInst spi = siteInst.getSitePinInst(sitePinName); - if (spi != null) { - net = spi.getNet(); - } - } - SitePIPStatus status = siteInst.getSitePIPStatus(sitePIP); - if (net == null) { - nullNetStubs.add(new RouteBranchNode(site, sitePIP, status.isFixed())); + if (siteInst.getNetFromSiteWire(siteWire) != null) { continue; } - List segments = netSiteRouting.computeIfAbsent(net, (n) -> new ArrayList<>()); - segments.add(new RouteBranchNode(site, sitePIP, status.isFixed())); - } - - for (Entry> e : siteInst.getNetToSiteWiresMap().entrySet()) { - List segments = netSiteRouting.computeIfAbsent(e.getKey(), - (k) -> new ArrayList<>()); - if (e.getValue() != null && e.getValue().size() > 0) { - for (String siteWire : e.getValue()) { - BELPin[] belPins = siteInst.getSiteWirePins(siteWire); - for (BELPin belPin : belPins) { - BEL bel = belPin.getBEL(); - Cell cell = siteInst.getCell(bel); - boolean routethru = false; - if (belPin.isInput()) { - // Skip if no BEL placed here - if (cell == null) { - continue; - } - // Skip if pin not used (e.g. A1 connects to A[56]LUT.A1; - // both cells can exist but not both need be using this pin) - if (cell.getLogicalPinMapping(belPin.getName()) == null) { - continue; - } - } else { - routethru = cell != null && cell.isRoutethru(); - } - segments.add(new RouteBranchNode(site, belPin, routethru)); - } - } + String sitePinName = sitePIP.getInputPin().getConnectedSitePinName(); + SitePinInst spi = siteInst.getSitePinInst(sitePinName); + if (spi != null && spi.getNet() != null) { + continue; } + + SitePIPStatus status = siteInst.getSitePIPStatus(sitePIP); + nullNetStubs.add(new RouteBranchNode(site, sitePIP, status.isFixed())); } } - return netSiteRouting; - } - - private static void writePhysNets(PhysNetlist.Builder physNetlist, Design design, - StringEnumerator strings) { - - List nullNetStubs = new ArrayList<>(); - Map> netSiteRouting = extractSiteRouting(design.getSiteInsts(), nullNetStubs); - PhysNet.Builder nullNet = physNetlist.getNullNet(); Builder stubs = nullNet.initStubs(nullNetStubs.size()); - int i=0; + int i = 0; for (RouteBranchNode node : nullNetStubs) { RouteBranch.Builder stub = stubs.get(i); PhysSitePIP.Builder physSitePIP = stub.initRouteSegment().initSitePIP(); @@ -291,57 +281,145 @@ private static void writePhysNets(PhysNetlist.Builder physNetlist, Design design physSitePIP.setIsFixed(sitePIP.isFixed); i++; } + } - int physNetCount = design.getNets().size(); - Builder nets = physNetlist.initPhysNets(physNetCount); - i=0; - for (Net net : design.getNets()) { - PhysNet.Builder physNet = nets.get(i); - physNet.setName(strings.getIndex(net.getName())); - switch (net.getType()) { - case GND: - physNet.setType(PhysNetlist.NetType.GND); - break; - case VCC: - physNet.setType(PhysNetlist.NetType.VCC); - break; - default: - physNet.setType(PhysNetlist.NetType.SIGNAL); + private static void buildNet(Net net, PhysNet.Builder physNet, StringEnumerator strings) { + physNet.setName(strings.getIndex(net.getName())); + switch (net.getType()) { + case GND: + physNet.setType(PhysNetlist.NetType.GND); + break; + case VCC: + physNet.setType(PhysNetlist.NetType.VCC); + break; + default: + physNet.setType(PhysNetlist.NetType.SIGNAL); + } + + // We need to traverse the net inside sites to fully populate routing spec + List routingSources = new ArrayList<>(); + List stubPIPs = new ArrayList<>(); + for (PIP p : net.getPIPs()) { + if (p.isEndWireNull() || p.isStub()) { + stubPIPs.add(p); + + if (p.isEndWireNull()) { + continue; + } } - // We need to traverse the net inside sites to fully populate routing spec - ArrayList routingSources = new ArrayList<>(); - List stubNodes = new ArrayList<>(); - for (PIP p : net.getPIPs()) { - if (p.getEndWireName() == null) { - stubNodes.add(p); + routingSources.add(new RouteBranchNode(p)); + } + for (SitePinInst spi : net.getPins()) { + routingSources.add(new RouteBranchNode(spi)); + } + + for (SiteInst siteInst : net.getSiteInsts()) { + extractIntraSiteRouting(net, routingSources, siteInst); + } + + populateRouting(routingSources, physNet, strings); + + if (stubPIPs.size() > 0) { + StructList.Builder physNodes = physNet.initStubNodes(stubPIPs.size()); + for (int j = 0; j < stubPIPs.size(); j++) { + PhysNode.Builder physNode = physNodes.get(j); + PIP stubPIP = stubPIPs.get(j); + physNode.setTile(strings.getIndex(stubPIP.getTile().getName())); + if (stubPIP.isEndWireNull()) { + physNode.setWire(strings.getIndex(stubPIP.getStartWireName())); } else { - routingSources.add(new RouteBranchNode(p)); + assert(stubPIP.isStub()); + physNode.setWire(strings.getIndex(stubPIP.getEndWireName())); } + physNode.setIsFixed(stubPIP.isPIPFixed()); } - for (SitePinInst spi : net.getPins()) { - routingSources.add(new RouteBranchNode(spi)); - } - List segments = netSiteRouting.remove(net); - if (segments != null) routingSources.addAll(segments); - populateRouting(routingSources, physNet, strings); - if (stubNodes.size() > 0) { - StructList.Builder physNodes = physNet.initStubNodes(stubNodes.size()); - for (int j=0; j < stubNodes.size(); j++) { - PhysNode.Builder physNode = physNodes.get(j); - PIP stubPIP = stubNodes.get(j); - physNode.setTile(strings.getIndex(stubPIP.getTile().getName())); - physNode.setWire(stubPIP.getStartWireIndex()); - physNode.setIsFixed(stubPIP.isPIPFixed()); + } + } + + public static void extractIntraSiteRouting(Net net, List nodes, SiteInst siteInst) { + Site site = siteInst.getSite(); + for (String siteWire : siteInst.getSiteWiresFromNet(net)) { + BELPin[] belPins = siteInst.getSiteWirePins(siteWire); + for (BELPin belPin : belPins) { + BEL bel = belPin.getBEL(); + Cell cell = siteInst.getCell(bel); + boolean routethru = false; + if (belPin.isInput()) { + if (bel.getBELClass() == BELClass.BEL) { + if (cell == null) { + // Skip if nothing placed here + continue; + } + if (!VERBOSE_PHYSICAL_NET_ROUTING && !cell.isRoutethru()) { + // Skip if cell is not a routethru + continue; + } + if (cell.getLogicalPinMapping(belPin.getName()) == null) { + // Skip if pin not used (e.g. A1 connects to A[56]LUT.A1; + // both cells can exist but not both need be using this pin) + continue; + } + + // Fall through + } else if (bel.getBELClass() == BELClass.RBEL) { + SitePIP sitePIP = siteInst.getSitePIP(belPin); + SitePIPStatus status = siteInst.getSitePIPStatus(sitePIP); + if (!status.isUsed()) { + continue; + } + + nodes.add(new RouteBranchNode(site, sitePIP, status.isFixed())); + + if (!VERBOSE_PHYSICAL_NET_ROUTING) { + // Skip input pins to SitePIPs + continue; + } + } else { + assert(bel.getBELClass() == BELClass.PORT); + SitePinInst spi = siteInst.getSitePinInst(siteWire); + if (spi == null) { + // Skip if pin is not used by site port + continue; + } + assert(spi.getNet() == net); + + if (!VERBOSE_PHYSICAL_NET_ROUTING) { + // Skip input pins to site ports (will be set when site pin is added + // onto site instance) + continue; + } + } + } else { + if (bel.getBELClass() == BELClass.BEL) { + routethru = cell != null && cell.isRoutethru(); + + // Fall through + } else if (bel.getBELClass() == BELClass.RBEL) { + if (siteInst.getUsedSitePIP(belPin) != null) { + if (!VERBOSE_PHYSICAL_NET_ROUTING) { + // Skip output pins on SitePIPs + continue; + } + } else { + assert(bel.isStaticSource()); + } + } else { + assert(bel.getBELClass() == BELClass.PORT); + + if (!VERBOSE_PHYSICAL_NET_ROUTING) { + // Skip output pins on site ports (will be set when site pin is added + // onto site instance) + continue; + } + } } + + nodes.add(new RouteBranchNode(site, belPin, routethru)); } - i++; } - - assert(netSiteRouting.isEmpty()); } - @SuppressWarnings("unused") private static void debugPrintRouteBranchNodes(List nodes, String prefix) { for (RouteBranchNode n : nodes) { @@ -353,10 +431,13 @@ private static void debugPrintRouteBranchNodes(List nodes, Stri private static void populateRouting(List routingBranches, PhysNet.Builder physNet, StringEnumerator strings) { - List sources = new ArrayList<>(); - List stubs = new ArrayList<>(); + List sources; + List stubs; if (BUILD_ROUTING_GRAPH_ON_EXPORT) { + sources = new ArrayList<>(); + stubs = new ArrayList<>(); + Map map = new HashMap<>(); for (RouteBranchNode rb : routingBranches) { map.put(rb.toString(), rb); @@ -403,13 +484,14 @@ private static void populateRouting(List routingBranches, } } } else { + sources = null; stubs = routingBranches; } //if (strings.get(physNet.getName()).equals("")) debugPrintRouteBranchNodes(sources, ""); // Serialize... - if (sources.size() > 0) { + if (sources != null && sources.size() > 0) { Builder routeSrcs = physNet.initSources(sources.size()); for (int i=0; i < sources.size(); i++) { RouteBranch.Builder srcBuilder = routeSrcs.get(i); @@ -428,7 +510,7 @@ private static void populateRouting(List routingBranches, } public static void writeRouteBranch(RouteBranch.Builder srcBuilder, RouteBranchNode src, - StringEnumerator strings) { + StringEnumerator strings) { RouteSegment.Builder segment = srcBuilder.getRouteSegment(); switch(src.getType()) { case PIP:{ @@ -480,7 +562,7 @@ public static void writeRouteBranch(RouteBranch.Builder srcBuilder, RouteBranchN } } - private static void writeDesignProperties(PhysNetlist.Builder physNetlist, Design design, + protected static void writeDesignProperties(PhysNetlist.Builder physNetlist, Design design, StringEnumerator strings) { StructList.Builder props = physNetlist.initProperties(2); Property.Builder autoIOs = props.get(0); @@ -501,22 +583,33 @@ public static void writeStrings(PhysNetlist.Builder physNetlist, StringEnumerato } public static void writePhysNetlist(Design design, String fileName) throws IOException { + CodePerfTracker t = new CodePerfTracker("Write PhysNetlist"); + + t.start("Initialize"); MessageBuilder message = new MessageBuilder(); PhysNetlist.Builder physNetlist = message.initRoot(PhysNetlist.factory); StringEnumerator strings = new StringEnumerator(); physNetlist.setPart(design.getPartName()); + t.stop().start("Write SiteInsts"); writeSiteInsts(physNetlist, design, strings); + t.stop().start("Write Placement"); writePlacement(physNetlist, design, strings); + t.stop().start("Write Routing"); writePhysNets(physNetlist, design, strings); + t.stop().start("Write Design Props"); writeDesignProperties(physNetlist, design, strings); + t.stop().start("Write Strings"); writeStrings(physNetlist, strings); + t.stop().start("Write File"); Interchange.writeInterchangeFile(fileName, message); + + t.stop().printSummary(); } } diff --git a/test/src/com/xilinx/rapidwright/interchange/TestPhysNetlistWriter.java b/test/src/com/xilinx/rapidwright/interchange/TestPhysNetlistWriter.java index 8a72ed0c5..9e4202f31 100644 --- a/test/src/com/xilinx/rapidwright/interchange/TestPhysNetlistWriter.java +++ b/test/src/com/xilinx/rapidwright/interchange/TestPhysNetlistWriter.java @@ -26,6 +26,7 @@ import java.io.IOException; import java.nio.file.Path; import java.util.Arrays; +import java.util.List; import com.xilinx.rapidwright.design.Cell; import com.xilinx.rapidwright.design.Design; @@ -49,7 +50,7 @@ import org.capnproto.StructList; public class TestPhysNetlistWriter { - private void testAllRouteSegmentsEndInBELInputPins(Design design, RouteBranch.Reader routeBranch, StringEnumerator strings) { + private void testAllRouteSegmentsEndInBELInputPins(Design design, RouteBranch.Reader routeBranch, List strings) { StructList.Reader branches = routeBranch.getBranches(); int branchesCount = branches.size(); if (branchesCount == 0) { @@ -89,7 +90,7 @@ public void testAllRouteSegmentsEndInBELInputPins(@TempDir Path tempDir) throws PhysNetlist.Reader physNetlist = readMsg.getRoot(PhysNetlist.factory); - StringEnumerator allStrings = PhysNetlistReader.readAllStrings(physNetlist); + List allStrings = PhysNetlistReader.readAllStrings(physNetlist); for (PhysNet.Reader physNet : physNetlist.getPhysNets()) { if (physNet.getType() == NetType.GND || physNet.getType() == NetType.VCC) { @@ -122,7 +123,7 @@ public void testNoLutRoutethruCells(@TempDir Path tempDir) throws IOException { PhysNetlist.Reader physNetlist = readMsg.getRoot(PhysNetlist.factory); - StringEnumerator allStrings = PhysNetlistReader.readAllStrings(physNetlist); + List allStrings = PhysNetlistReader.readAllStrings(physNetlist); for (CellPlacement.Reader placement : physNetlist.getPlacements()) { SiteInst siteInst = design.getSiteInstFromSiteName(allStrings.get(placement.getSite()));