diff --git a/RELEASE_NOTES.TXT b/RELEASE_NOTES.TXT index 140573219..1adb8e48f 100644 --- a/RELEASE_NOTES.TXT +++ b/RELEASE_NOTES.TXT @@ -1,3 +1,20 @@ +============= RapidWright 2022.1.4-beta released on 2022-11-03 ================ +Notes: + * Can now load EDIF netlist in parallel with placement and routing when reading a DCP + * Allows the Design object to detach the corresponding EDIFNetlist to save working memory + * Restores the original EDIFPort.getBusName() behavior + * Changes EDIFPortInstList duplicate behavior from prohibit to overwrite + * Net.removePin() to unset alternate source + * Fix Net.removePin() for static nets under preserveOtherRoutes + * Option to track process peak memory usage + * Fix for #548, #572, #564 + * Fixes intrasite routing to CARRY pins from LUT outputs on UltraScale/+ + - API Additions: + - com.xilinx.rapidwright.design.Cell "public void setEDIFHierCellInst(EDIFHierCellInst inst)" + - com.xilinx.rapidwright.design.Design "public void detachNetlist()" + - com.xilinx.rapidwright.device.Node "public Collection getAllDownhillNodes(Collection nodes)" + - com.xilinx.rapidwright.device.Node "public Collection getAllUphillNodes(Collection nodes)" + ============= RapidWright 2022.1.3-beta released on 2022-09-19 ================ Notes: * Adds support for partition pins, several new APIs added as seen below diff --git a/python/setup.py b/python/setup.py index 6f998282b..7d2fa0942 100644 --- a/python/setup.py +++ b/python/setup.py @@ -24,7 +24,7 @@ setup( name='rapidwright', - version='2022.1.3', + version='2022.1.4', license='Apache 2.0 and Others', description='Xilinx RapidWright Framework Wrapped for Python.', long_description='', diff --git a/python/src/rapidwright/rapidwright.py b/python/src/rapidwright/rapidwright.py index ca5e5a789..733a2d4e7 100644 --- a/python/src/rapidwright/rapidwright.py +++ b/python/src/rapidwright/rapidwright.py @@ -24,7 +24,7 @@ from typing import List, Optional import os, urllib.request, platform -version='2022.1.3' +version='2022.1.4' def start_jvm(): os_str = 'lin64' diff --git a/src/com/xilinx/rapidwright/design/DesignTools.java b/src/com/xilinx/rapidwright/design/DesignTools.java index 927bb904f..5a24d12fa 100644 --- a/src/com/xilinx/rapidwright/design/DesignTools.java +++ b/src/com/xilinx/rapidwright/design/DesignTools.java @@ -817,7 +817,8 @@ public static List findRoutingPath(RouteNode start, RouteNode end) { */ public static String resolveNetNameFromSiteWire(SiteInst inst, int siteWire) { String parentNetName = null; - Map parentNetMap = inst.getDesign().getNetlist().getParentNetMapNames(); + EDIFNetlist netlist = inst.getDesign().getNetlist(); + Map parentNetMap = netlist != null ? netlist.getParentNetMapNames() : Collections.emptyMap(); BELPin[] pins = inst.getSite().getBELPins(siteWire); for (BELPin pin : pins) { if (pin.isSitePort()) continue; @@ -827,7 +828,7 @@ public static String resolveNetNameFromSiteWire(SiteInst inst, int siteWire) { if (currNet == null) { continue; } else { - return parentNetMap.get(currNet.getName()); + return parentNetMap.getOrDefault(currNet.getName(), currNet.getName()); } } String logPinName = c.getLogicalPinMapping(pin.getName()); @@ -835,7 +836,7 @@ public static String resolveNetNameFromSiteWire(SiteInst inst, int siteWire) { if (portInst == null) continue; EDIFNet net = portInst.getNet(); String netName = c.getParentHierarchicalInstName() + EDIFTools.EDIF_HIER_SEP + net.getName(); - parentNetName = parentNetMap.get(netName); + parentNetName = parentNetMap.getOrDefault(netName, netName); } return parentNetName; } @@ -845,7 +846,7 @@ private static String createInformativeCellInterfaceMismatchMessage(String hierC Map cellPorts = new HashMap<>(target.getPortMap()); StringBuilder sb = new StringBuilder(); for (EDIFPort p : src.getPorts()) { - EDIFPort otherPort = cellPorts.remove(p.getBusName()); + EDIFPort otherPort = cellPorts.remove(p.getBusName(true)); if (otherPort == null) { otherPort = cellPorts.remove(p.getName()); if (otherPort == null) { @@ -1100,7 +1101,7 @@ public static Set unrouteSourcePin(SitePinInst src) { Map> pipMap = new HashMap<>(); for (PIP pip : src.getNet().getPIPs()) { - Node node = pip.getStartNode(); + Node node = pip.isReversed() ? pip.getEndNode() : pip.getStartNode(); pipMap.computeIfAbsent(node, k -> new ArrayList<>()).add(pip); } @@ -1116,7 +1117,7 @@ public static Set unrouteSourcePin(SitePinInst src) { List pips = pipMap.get(curr); if (pips != null) { for (PIP p : pips) { - Node endNode = p.getEndNode(); + Node endNode = p.isReversed() ? p.getStartNode() : p.getEndNode(); q.add(endNode); pipsToRemove.add(p); SitePinInst sink = sinkNodes.get(endNode); @@ -1144,44 +1145,23 @@ public static Set unrouteSourcePin(SitePinInst src) { public static Set getTrimmablePIPsFromPins(Net net, Collection pins) { // Map listing the PIPs that drive a Node Map> reverseConns = new HashMap<>(); - Map> reverseConnsStart = new HashMap<>(); Map fanout = new HashMap<>(); Set nodeSinkPins = new HashSet<>(); for (SitePinInst sinkPin : net.getSinkPins()) { nodeSinkPins.add(sinkPin.getConnectedNode()); } for (PIP pip : net.getPIPs()) { - Node endNode = pip.getEndNode(); - Node startNode = pip.getStartNode(); + Node endNode = pip.isReversed() ? pip.getStartNode() : pip.getEndNode(); + Node startNode = pip.isReversed() ? pip.getEndNode() : pip.getStartNode(); - ArrayList rPips = reverseConns.get(endNode); - if (rPips == null) { - rPips = new ArrayList<>(); - reverseConns.put(endNode, rPips); - } + ArrayList rPips = reverseConns.computeIfAbsent(endNode, (n) -> new ArrayList<>()); rPips.add(pip); - int endNodeFanout = 0; - if (pip.isBidirectional()) { - rPips = reverseConnsStart.get(startNode); - if (rPips == null) { - rPips = new ArrayList<>(); - reverseConnsStart.put(startNode, rPips); - } - rPips.add(pip); + fanout.merge(startNode, 1, Integer::sum); - endNodeFanout = 1; - } else if (nodeSinkPins.contains(endNode)) { - endNodeFanout = 1; - } - if (endNodeFanout > 0) { - fanout.merge(endNode, endNodeFanout, Integer::sum); + if (nodeSinkPins.contains(endNode)) { + fanout.merge(endNode, 1, Integer::sum); } - - // If a site pin was found and it belongs to this net, add an extra fanout to - // reflect that it was both used for downstream connection as well as this site pin - int startNodeFanout = nodeSinkPins.contains(startNode) ? 2 : 1; - fanout.merge(startNode, startNodeFanout, Integer::sum); } HashSet toRemove = new HashSet<>(); @@ -1191,74 +1171,48 @@ public static Set getTrimmablePIPsFromPins(Net net, Collection if (p.getSiteInst() == null || p.getSite() == null) continue; if (p.getNet() != net) continue; Node sink = p.getConnectedNode(); - Integer fanoutCount = fanout.getOrDefault(sink, 0); - if (fanoutCount > 1) { - // This node is also used to connect another downstream pin, no more - // analysis necessary - updateFanout.add(sink); + Integer fanoutCount = fanout.get(sink); + if (fanoutCount == null) { + // Pin is not routed } else { - ArrayList curr = reverseConns.get(sink); - boolean atReversedBidirectionalPip = false; - if (curr == null) { - // must be at a reversed bidirectional PIP - curr = reverseConnsStart.get(sink); - fanoutCount--; - atReversedBidirectionalPip = true; - } - updateFanout.clear(); - while (curr != null && curr.size() == 1 && fanoutCount < 2) { - PIP pip = curr.get(0); - - toRemove.add(pip); - Node startNode = pip.getStartNode(); - updateFanout.add(startNode); - if (atReversedBidirectionalPip) { - updateFanout.add(pip.getEndNode()); - } - if (new Node(pip.getTile(), pip.getStartWireIndex()).equals(sink) && !atReversedBidirectionalPip) { - // reached the source and there is another branch starting with a reversed - // bidirectional PIP ... don't traverse it - break; + assert(fanoutCount >= 1); + updateFanout.add(sink); + + if (fanoutCount > 1) { + // This node is also used to connect another downstream pin, no more + // analysis necessary + } else { + ArrayList curr = reverseConns.get(sink); + while (curr != null && curr.size() == 1 && fanoutCount < 2) { + PIP pip = curr.get(0); + toRemove.add(pip); + updateFanout.add(pip.isReversed() ? pip.getEndNode() : pip.getStartNode()); + sink = new Node(pip.getTile(), pip.isReversed() ? pip.getEndWireIndex() : + pip.getStartWireIndex()); + curr = reverseConns.get(sink); + fanoutCount = fanout.getOrDefault(sink, 0); } - sink = new Node(pip.getTile(), atReversedBidirectionalPip ? pip.getEndWireIndex() : - pip.getStartWireIndex()); - curr = reverseConns.get(sink); - if (curr != null && curr.size() > 1 && atReversedBidirectionalPip) { - for (PIP reversePIP : toRemove) { - curr.remove(reversePIP); + if (curr == null && fanout.size() == 1 && !net.isStaticNet()) { + // We got all the way back to the source site. It is likely that + // the net is using dual exit points from the site as is common in + // SLICEs -- we should unroute the sitenet + SitePin sPin = sink.getSitePin(); + if (net.getSource() != null) { + SiteInst si = net.getSource().getSiteInst(); + BELPin belPin = sPin.getBELPin(); + si.unrouteIntraSiteNet(belPin, belPin); } } - atReversedBidirectionalPip = false; - fanoutCount = fanout.getOrDefault(sink, 0); - SitePin sitePin = sink.getSitePin(); - if (curr == null && !(sitePin != null || sink.getWireName().contains(Net.VCC_WIRE_NAME) || - sink.getWireName().contains(Net.GND_WIRE_NAME))) { - // curr should only be null when we're at the source site, so we've hit a reversed bidirectional PIP - // on our linear path - curr = reverseConnsStart.get(sink); - curr.remove(pip); - fanoutCount--; - atReversedBidirectionalPip = true; - } - } - if (curr == null && fanout.size() == 1 && !net.isStaticNet()) { - // We got all the way back to the source site. It is likely that - // the net is using dual exit points from the site as is common in - // SLICEs -- we should unroute the sitenet - SitePin sPin = sink.getSitePin(); - if (net.getSource() != null) { - SiteInst si = net.getSource().getSiteInst(); - BELPin belPin = sPin.getBELPin(); - si.unrouteIntraSiteNet(belPin, belPin); - } } } for (Node startNode : updateFanout) { - fanout.compute(startNode, ($,v) -> { + fanout.compute(startNode, (k,v) -> { if (v == null) throw new RuntimeException(); - return v-1; + assert(v > 0); + return (--v == 0) ? null : v; }); } + updateFanout.clear(); } return toRemove; } @@ -2732,98 +2686,6 @@ private static boolean isUltraScale(Cell cell) { return s == Series.UltraScale || s == Series.UltraScalePlus; } - private static Set unroutePin(SitePinInst pin, Net net) { - Node sink = pin.getConnectedNode(); - List pips = net.getPIPs(); - Map> reverseConns = new HashMap<>(); - Map> reverseConnsStart = new HashMap<>(); - Map fanout = new HashMap<>(); - for (PIP pip : pips) { - Node endNode = pip.getEndNode(); - Node startNode = pip.getStartNode(); - - ArrayList rPips = reverseConns.get(endNode); - if (rPips == null) { - rPips = new ArrayList<>(); - reverseConns.put(endNode, rPips); - } - rPips.add(pip); - - if (pip.isBidirectional()) { - rPips = reverseConnsStart.get(startNode); - if (rPips == null) { - rPips = new ArrayList<>(); - reverseConnsStart.put(startNode, rPips); - } - rPips.add(pip); - } - - Integer count = fanout.get(startNode); - if (count == null) { - fanout.put(startNode, 1); - } else { - fanout.put(startNode, count+1); - } - } - ArrayList curr = reverseConns.get(sink); - Integer fanoutCount = fanout.get(sink); - fanoutCount = fanoutCount == null ? 0 : fanoutCount; - boolean atReversedBidirectionalPip = false; - if (curr == null) { - // must be at a reversed bidirectional PIP - curr = reverseConnsStart.get(sink); - fanoutCount--; - atReversedBidirectionalPip = true; - } - HashSet toRemove = new HashSet<>(); - while (curr != null && curr.size() == 1 && fanoutCount < 2) { - PIP pip = curr.get(0); - toRemove.add(pip); - if (new Node(pip.getTile(), pip.getStartWireIndex()).equals(sink)) { - // reached the source and there is another branch starting with a reversed - // bidirectional PIP ... don't traverse it - break; - } - sink = new Node(pip.getTile(), atReversedBidirectionalPip ? pip.getEndWireIndex() : - pip.getStartWireIndex()); - atReversedBidirectionalPip = false; - curr = reverseConns.get(sink); - fanoutCount = fanout.get(sink); - fanoutCount = fanoutCount == null ? 0 : fanoutCount; - SitePin sitePin = sink.getSitePin(); - if (curr == null && !(sitePin != null || sink.getWireName().contains(Net.VCC_WIRE_NAME) || - sink.getWireName().contains(Net.GND_WIRE_NAME))) { - // curr should only be null when we're at the source site, so we've hit a reversed bidirectional PIP - // on our linear path - curr = reverseConnsStart.get(sink); - curr.remove(pip); - fanoutCount--; - atReversedBidirectionalPip = true; - } - if (sitePin != null && sitePin.isInput()) { - SiteInst si = net.getSource().getSiteInst().getDesign().getSiteInstFromSite(sitePin.getSite()); - if (si != null) { - if (net.equals(si.getNetFromSiteWire(sitePin.getPinName()))) { - fanoutCount = 2; - } - } - } - } - if (curr == null && fanout.size() == 1 && !net.isStaticNet()) { - // We got all the way back to the source site. It is likely that - // the net is using dual exit points from the site as is common in - // SLICEs -- we should unroute the sitenet - SitePin sPin = sink.getSitePin(); - SiteInst si = net.getSource().getSiteInst(); - if (!si.unrouteIntraSiteNet(sPin.getBELPin(), sPin.getBELPin())) { - throw new RuntimeException("ERROR: Improperly routed net state while unrouting pin " + - " of net " + net.getName()); - } - } - - return toRemove; - } - public static void printSiteInstInfo(SiteInst siteInst, PrintStream ps) { ps.println("====================================================================="); ps.println(siteInst.getSiteName() + " :"); diff --git a/src/com/xilinx/rapidwright/edif/BinaryEDIFWriter.java b/src/com/xilinx/rapidwright/edif/BinaryEDIFWriter.java index 0fe382048..b2f48be0a 100644 --- a/src/com/xilinx/rapidwright/edif/BinaryEDIFWriter.java +++ b/src/com/xilinx/rapidwright/edif/BinaryEDIFWriter.java @@ -111,7 +111,7 @@ public static Map createStringMap(EDIFNetlist netlist) { for (EDIFNet net : cell.getNets()) { addObjectToStringMap(net, stringMap); for (EDIFPortInst pi : net.getPortInsts()) { - String name = pi.getPort().isBus() ? pi.getPort().getBusName() : pi.getName(); + String name = pi.getPort().isBus() ? pi.getPort().getBusName(true) : pi.getName(); addStringToStringMap(name, stringMap); } } @@ -276,7 +276,7 @@ private static String getPortInstKey(EDIFPortInst portInst) { if (port.isBus()) { EDIFCell cell = portInst.getCellInst() == null ? portInst.getParentCell() : portInst.getCellInst().getCellType(); EDIFPort portCollision = cell.getPort(portInst.getPort().getName()); - returnValue = portCollision != null ? port.getName() : port.getBusName(); + returnValue = portCollision != null ? port.getName() : port.getBusName(true); } else { returnValue = portInst.getName(); } diff --git a/src/com/xilinx/rapidwright/edif/EDIFCell.java b/src/com/xilinx/rapidwright/edif/EDIFCell.java index 3b750c6cd..4201b6c54 100644 --- a/src/com/xilinx/rapidwright/edif/EDIFCell.java +++ b/src/com/xilinx/rapidwright/edif/EDIFCell.java @@ -112,12 +112,12 @@ public EDIFCell(EDIFLibrary lib, EDIFCell orig, String newCellName) { EDIFPort newPort = null; if (prototype.getCellInst() != null) { newPortInst.setCellInst(getCellInst(prototype.getCellInst().getName())); - newPort = newPortInst.getCellInst().getCellType().getPort(prototype.getPort().getBusName()); + newPort = newPortInst.getCellInst().getCellType().getPort(prototype.getPort().getBusName(true)); if (newPort == null || newPort.getWidth() != prototype.getPort().getWidth()) { newPort = newPortInst.getCellInst().getCellType().getPort(prototype.getPort().getName()); } } else { - newPort = getPort(prototype.getPort().getBusName()); + newPort = getPort(prototype.getPort().getBusName(true)); if (newPort == null || newPort.getWidth() != prototype.getPort().getWidth()) { newPort = getPort(prototype.getPort().getName()); } @@ -238,7 +238,7 @@ public EDIFNet removeNet(String name) { public EDIFPort addPort(EDIFPort port) { if (ports == null) ports = getNewMap(); port.setParentCell(this); - EDIFPort collision = ports.put(port.getBusName(), port); + EDIFPort collision = ports.put(port.getBusName(true), port); if (collision != null && port != collision) { throw new RuntimeException("ERROR: Port name collision on EDIFCell " + getName() + ", trying to add port " + port @@ -487,7 +487,7 @@ public boolean hasCompatibleInterface(EDIFCell cell) { if (portMap.size() != cell.getPortMap().size()) return false; for (EDIFPort port : cell.getPorts()) { - EDIFPort match = portMap.remove(port.getBusName()); + EDIFPort match = portMap.remove(port.getBusName(true)); if (match == null) { match = portMap.remove(port.getName()); if (match == null) { diff --git a/src/com/xilinx/rapidwright/edif/EDIFCellInst.java b/src/com/xilinx/rapidwright/edif/EDIFCellInst.java index fbabdb021..7e890be9c 100644 --- a/src/com/xilinx/rapidwright/edif/EDIFCellInst.java +++ b/src/com/xilinx/rapidwright/edif/EDIFCellInst.java @@ -238,7 +238,7 @@ public void setCellType(EDIFCell cellType) { setCellTypeRaw(cellType); for (EDIFPortInst portInst : getPortInsts()) { EDIFPort origPort = portInst.getPort(); - EDIFPort port = cellType.getPort(origPort.getBusName()); + EDIFPort port = cellType.getPort(origPort.getBusName(true)); if (port == null || port.getWidth() != origPort.getWidth()) { port = cellType.getPort(origPort.getName()); } diff --git a/src/com/xilinx/rapidwright/edif/EDIFPort.java b/src/com/xilinx/rapidwright/edif/EDIFPort.java index 35ea59e3a..98bb8acf3 100644 --- a/src/com/xilinx/rapidwright/edif/EDIFPort.java +++ b/src/com/xilinx/rapidwright/edif/EDIFPort.java @@ -146,10 +146,17 @@ public void setWidth(int width) { } public String getBusName() { + return getBusName(false); + } + + public String getBusName(boolean keepOpenBracket) { if (busName == null) { int idx = EDIFTools.lengthOfNameWithoutBus(getName().toCharArray(), true); busName = getName().substring(0, idx); } + if (!keepOpenBracket && busName.charAt(busName.length() - 1) == '[') { + return busName.substring(0, busName.length() - 1); + } return busName; } @@ -233,7 +240,7 @@ public EDIFNet getInternalNet() { public String getPortInstNameFromPort(int index) { if (!isBus()) return getBusName(); index = getPortIndexFromNameIndex(index); - return getBusName() + index + "]"; + return getBusName(true) + index + "]"; } /** @@ -300,7 +307,7 @@ public void setParentCell(EDIFCell parentCell) { * @return */ public boolean isBus() { - return width > 1 || !getName().equals(getBusName()); + return width > 1 || !getName().equals(busName); } public int[] getBitBlastedIndicies() { diff --git a/src/com/xilinx/rapidwright/edif/EDIFPortInst.java b/src/com/xilinx/rapidwright/edif/EDIFPortInst.java index fa731d178..9686908e0 100644 --- a/src/com/xilinx/rapidwright/edif/EDIFPortInst.java +++ b/src/com/xilinx/rapidwright/edif/EDIFPortInst.java @@ -110,7 +110,7 @@ public EDIFPortInst(EDIFPort port, EDIFNet parentNet, int index, EDIFCellInst ce + "need index for bussed port " + port.getName()); } if (cellInst != null) { - if (!port.equals(cellInst.getPort(port.getBusName()))) { + if (!port.equals(cellInst.getPort(port.getBusName(true)))) { // check for name collision if (!port.equals(cellInst.getPort(port.getName()))) { throw new RuntimeException("ERROR: Provided port '"+ diff --git a/src/com/xilinx/rapidwright/edif/EDIFPortInstList.java b/src/com/xilinx/rapidwright/edif/EDIFPortInstList.java index 72ebb5985..541a0fcbc 100644 --- a/src/com/xilinx/rapidwright/edif/EDIFPortInstList.java +++ b/src/com/xilinx/rapidwright/edif/EDIFPortInstList.java @@ -29,8 +29,8 @@ /** * Customized ArrayList for the {@link EDIFNet} and {@link EDIFCellInst} classes. - * Maintains a sorted list to allow for a O(log n) retrieval lookup by name. Does not allow - * duplicate entries. + * Maintains a sorted list to allow for a O(log n) retrieval lookup by name. Overwrites + * existing entries with most recent value. */ public class EDIFPortInstList extends ArrayList { @@ -38,12 +38,19 @@ public class EDIFPortInstList extends ArrayList { public static final EDIFPortInstList EMPTY = new EDIFPortInstList(); + /** + * Inserts the port inst into the list such that the list remains sorted. If an identical + * element is already in the list, it is overwritten with the new port instance provided. + * @param e The port inst to add to the sorted list + * @return True if the list changed as a result of this call, false otherwise. + */ @Override public boolean add(EDIFPortInst e) { int insertionPoint = binarySearch(e.getCellInst(), e.getName()); - // Do not allow duplicates + // Overwrite duplicates if (insertionPoint >= 0) { - return false; + super.set(insertionPoint, e); + return true; } super.add(insertionPoint >= 0 ? insertionPoint : ~insertionPoint, e); return true; diff --git a/test/RapidWrightDCP b/test/RapidWrightDCP index a1da12afd..c057f0cd7 160000 --- a/test/RapidWrightDCP +++ b/test/RapidWrightDCP @@ -1 +1 @@ -Subproject commit a1da12afd2d5119c75d5e2672f0df2e187a798e1 +Subproject commit c057f0cd7181d1edfc8464d43c8b2b2423b4ceb9 diff --git a/test/src/com/xilinx/rapidwright/design/TestDCPWrite.java b/test/src/com/xilinx/rapidwright/design/TestDCPWrite.java new file mode 100644 index 000000000..7f6e7fae8 --- /dev/null +++ b/test/src/com/xilinx/rapidwright/design/TestDCPWrite.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022, Advanced Micro Devices, Inc. + * All rights reserved. + * + * Author: Chris Lavin, Xilinx Research Labs. + * + * 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.design; + +import java.nio.file.Path; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import com.xilinx.rapidwright.support.RapidWrightDCP; + +public class TestDCPWrite { + + @Test + public void testVersalDualOutputCOUT(@TempDir Path dir) { + // Tests a dual-output scenario COUT and HQ2 in Versal (See Xilinx/RapidWright#572) + Design d = RapidWrightDCP.loadDCP("versal_cout_hq2.dcp"); + d.writeCheckpoint(dir.resolve("output.dcp")); + } +} diff --git a/test/src/com/xilinx/rapidwright/design/TestDesignTools.java b/test/src/com/xilinx/rapidwright/design/TestDesignTools.java index 6ca825ab7..f68ce4946 100644 --- a/test/src/com/xilinx/rapidwright/design/TestDesignTools.java +++ b/test/src/com/xilinx/rapidwright/design/TestDesignTools.java @@ -38,6 +38,7 @@ 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.edif.EDIFHierCellInst; import com.xilinx.rapidwright.edif.EDIFNetlist; import com.xilinx.rapidwright.edif.EDIFTools; @@ -166,10 +167,12 @@ public void testCopyImplementation() { testCopyImplementationHelper(keepStaticRouting, numPIPs); } - @Test - public void testBatchRemoveSitePins() { - Path dcpPath = RapidWrightDCP.getPath("picoblaze_ooc_X10Y235.dcp"); - Design design = Design.readCheckpoint(dcpPath); + @ParameterizedTest + @ValueSource(strings = {"picoblaze_ooc_X10Y235.dcp", + "picoblaze_partial.dcp", // contains a routed clock net, with (many) bidir PIPs + }) + public void testBatchRemoveSitePins(String path) { + Design design = RapidWrightDCP.loadDCP(path); SiteInst si = design.getSiteInstFromSiteName("SLICE_X14Y238"); Assertions.assertNotNull(si); @@ -299,7 +302,7 @@ public void testGetTrimmablePIPsFromPinsBidir(boolean unrouteAll) { Net net = createTestNet(design, "net", new String[]{ "INT_X102Y428/INT.LOGIC_OUTS_W30->>INT_NODE_IMUX_60_INT_OUT1", // EQ output "INT_X102Y428/INT.INT_NODE_IMUX_60_INT_OUT1->>BYPASS_W14", - "INT_X102Y428/INT.INT_NODE_IMUX_50_INT_OUT0<<->>BYPASS_W14", // (bidir PIP!) + "INT_X102Y428/INT.INT_NODE_IMUX_50_INT_OUT0<<->>BYPASS_W14", // (reversed PIP) "INT_X102Y428/INT.INT_NODE_IMUX_50_INT_OUT0->>BOUNCE_W_13_FT0", "INT_X102Y429/INT.BOUNCE_W_BLN_13_FT1->>INT_NODE_IMUX_62_INT_OUT0", "INT_X102Y429/INT.INT_NODE_IMUX_62_INT_OUT0->>BYPASS_W5", // B_I input @@ -309,6 +312,11 @@ public void testGetTrimmablePIPsFromPinsBidir(boolean unrouteAll) { "INT_X102Y429/INT.INODE_W_BLN_60_FT1->>IMUX_W2", // E1 input }); + for (PIP pip : net.getPIPs()) { + if (pip.toString().equals("INT_X102Y428/INT.INT_NODE_IMUX_50_INT_OUT0<<->>BYPASS_W14")) + pip.setIsReversed(true); + } + SiteInst si = design.createSiteInst(design.getDevice().getSite("SLICE_X196Y428")); SitePinInst EQ = net.createPin("EQ", si); EQ.setRouted(true); @@ -360,10 +368,15 @@ public void testGetTrimmablePIPsFromPinsBidirEndNode() { "INT_X127Y235/INT.INT_NODE_SDQ_78_INT_OUT0->>WW2_W_BEG5", "INT_X126Y235/INT.WW2_W_END5->>INT_NODE_IMUX_49_INT_OUT1", "INT_X126Y235/INT.INT_NODE_IMUX_49_INT_OUT1->>BYPASS_W8", // EX input - "INT_X126Y235/INT.INT_NODE_IMUX_37_INT_OUT0<<->>BYPASS_W8", + "INT_X126Y235/INT.INT_NODE_IMUX_37_INT_OUT0<<->>BYPASS_W8", // (reversed PIP) "INT_X126Y235/INT.INT_NODE_IMUX_37_INT_OUT0->>BYPASS_W7" // D_I input }); + for (PIP pip : net.getPIPs()) { + if (pip.toString().equals("INT_X126Y235/INT.INT_NODE_IMUX_37_INT_OUT0<<->>BYPASS_W8")) + pip.setIsReversed(true); + } + SiteInst si = design.createSiteInst(design.getDevice().getSite("SLICE_X242Y235")); SitePinInst DQ2 = net.createPin("DQ2", si); DQ2.setRouted(true); @@ -429,6 +442,92 @@ public void testGetTrimmablePIPsFromPinsBidirSinkNode() { ))); } + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void testGetTrimmablePIPsFromPinsBidirBounceNode(boolean createBounceSink) { + Design design = new Design("test", "xcvu19p-fsva3824-1-e"); + Device device = design.getDevice(); + + Net net = createTestNet(design, "net", new String[]{ + "INT_X196Y535/INT.LOGIC_OUTS_E10->INT_NODE_SDQ_12_INT_OUT1", // DQ + "INT_X196Y535/INT.INT_NODE_SDQ_12_INT_OUT1->>INT_INT_SDQ_73_INT_OUT0", + "INT_X196Y535/INT.INT_INT_SDQ_73_INT_OUT0->>INT_NODE_GLOBAL_1_INT_OUT1", + "INT_X196Y535/INT.INT_NODE_GLOBAL_1_INT_OUT1->>INT_NODE_IMUX_5_INT_OUT0", + "INT_X196Y535/INT.INT_NODE_IMUX_5_INT_OUT0<<->>BYPASS_E8", // bounce (EX) + "INT_X196Y535/INT.BYPASS_E8->>INT_NODE_IMUX_4_INT_OUT1", + "INT_X196Y535/INT.INT_NODE_IMUX_4_INT_OUT1->>BYPASS_E3", // DX + "INT_X196Y535/INT.INT_NODE_IMUX_5_INT_OUT0->>BYPASS_E7", // D_I + }); + + SiteInst si = design.createSiteInst(design.getDevice().getSite("SLICE_X376Y535")); + SitePinInst DQ = net.createPin("DQ", si); + DQ.setRouted(true); + SitePinInst DX = net.createPin("DX", si); + DX.setRouted(true); + SitePinInst D_I = net.createPin("D_I", si); + D_I.setRouted(true); + if (createBounceSink) { + SitePinInst EX = net.createPin("EX", si); + EX.setRouted(true); + } + + List pinsToUnroute = new ArrayList<>(); + pinsToUnroute.add(DX); + Set trimmable = DesignTools.getTrimmablePIPsFromPins(net, pinsToUnroute); + if (createBounceSink) { + Assertions.assertEquals(2, trimmable.size()); + Assertions.assertTrue(trimmable.containsAll(Arrays.asList( + device.getPIP("INT_X196Y535/INT.BYPASS_E8->>INT_NODE_IMUX_4_INT_OUT1"), + device.getPIP("INT_X196Y535/INT.INT_NODE_IMUX_4_INT_OUT1->>BYPASS_E3") + ))); + } else { + Assertions.assertEquals(3, trimmable.size()); + Assertions.assertTrue(trimmable.containsAll(Arrays.asList( + device.getPIP("INT_X196Y535/INT.INT_NODE_IMUX_5_INT_OUT0<<->>BYPASS_E8"), + device.getPIP("INT_X196Y535/INT.BYPASS_E8->>INT_NODE_IMUX_4_INT_OUT1"), + device.getPIP("INT_X196Y535/INT.INT_NODE_IMUX_4_INT_OUT1->>BYPASS_E3") + ))); + } + } + + @Test + public void testUnrouteSourcePinBidir() { + Design design = new Design("test", "xcvu19p-fsva3824-1-e"); + + Net net = createTestNet(design, "net", new String[]{ + "INT_X193Y606/INT.LOGIC_OUTS_W27->INT_NODE_SDQ_87_INT_OUT0", + "INT_X193Y606/INT.INT_NODE_SDQ_87_INT_OUT0->>NN1_W_BEG6", + "INT_X193Y607/INT.NN1_W_END6->INT_NODE_SDQ_83_INT_OUT0", + "INT_X193Y607/INT.INT_NODE_SDQ_83_INT_OUT0->>WW1_W_BEG5", + "INT_X192Y607/INT.WW1_W_END5->INT_NODE_SDQ_34_INT_OUT0", + "INT_X192Y607/INT.INT_NODE_SDQ_34_INT_OUT0->>EE1_E_BEG5", + "INT_X193Y607/INT.EE1_E_END5->INT_NODE_SDQ_79_INT_OUT0", + "INT_X193Y607/INT.INT_NODE_SDQ_79_INT_OUT0->>SS1_W_BEG5", + "INT_X193Y606/INT.SS1_W_END5->>INT_NODE_IMUX_49_INT_OUT1", + "INT_X193Y606/INT.INT_NODE_IMUX_49_INT_OUT1->>BYPASS_W8", + "INT_X193Y606/INT.BYPASS_W8->>INT_NODE_IMUX_36_INT_OUT1", + "INT_X193Y606/INT.INT_NODE_IMUX_36_INT_OUT1->>BYPASS_W3", // DX + "INT_X193Y606/INT.INT_NODE_IMUX_37_INT_OUT0<<->>BYPASS_W8", // (reversed PIP) + "INT_X193Y606/INT.INT_NODE_IMUX_37_INT_OUT0->>BYPASS_W7", // D_I + }); + + for (PIP pip : net.getPIPs()) { + if (pip.toString().equals("INT_X193Y606/INT.INT_NODE_IMUX_37_INT_OUT0<<->>BYPASS_W8")) + pip.setIsReversed(true); + } + + SiteInst si = design.createSiteInst(design.getDevice().getSite("SLICE_X369Y606")); + SitePinInst DQ2 = net.createPin("DQ2", si); + DQ2.setRouted(true); + SitePinInst DX = net.createPin("DX", si); + DX.setRouted(true); + SitePinInst D_I = net.createPin("D_I", si); + D_I.setRouted(true); + + DesignTools.unrouteSourcePin(DQ2); + Assertions.assertTrue(net.getPIPs().isEmpty()); + } + public static void addPIPs(Net net, String[] pips) { Device device = net.getDesign().getDevice(); for (String pip : pips) { @@ -538,7 +637,7 @@ public void testRemoveSourcePin(boolean useUnroutePins) { SitePinInst altSrc = net3.createPin("H_O", si); altSrc.setRouted(true); Assertions.assertNotNull(net3.getAlternateSource()); - Assertions.assertTrue(net3.getAlternateSource().getName().equals("H_O")); + Assertions.assertEquals("H_O", net3.getAlternateSource().getName()); si = design.createSiteInst(design.getDevice().getSite("SLICE_X64Y158")); SitePinInst snk = net3.createPin("SRST_B2", si); snk.setRouted(true); @@ -578,4 +677,19 @@ void testCreateA1A6ToStaticNetsFracturedLUT(boolean createLUT6, boolean createLU Assertions.assertTrue(design.getVccNet().getPins().isEmpty()); } } + + @Test + public void testResolveNetNameFromSiteWireWithoutNetlist() { + Design design = new Design(); // This constructor does not create a netlist + design.setPartName(Device.KCU105); + + Site site = design.getDevice().getSite("SLICE_X0Y0"); + SiteInst si = design.createSiteInst(site); + Assertions.assertNull(DesignTools.resolveNetNameFromSiteWire(si, site.getSiteWireIndex("A1"))); + + Net net = new Net("net"); + BELPin bp = si.getBELPin("A1", "A1"); + si.routeIntraSiteNet(net, bp, bp); + Assertions.assertEquals("net", DesignTools.resolveNetNameFromSiteWire(si, site.getSiteWireIndex("A1"))); + } } diff --git a/test/src/com/xilinx/rapidwright/edif/TestEDIFPort.java b/test/src/com/xilinx/rapidwright/edif/TestEDIFPort.java index bcd2583be..56340954b 100644 --- a/test/src/com/xilinx/rapidwright/edif/TestEDIFPort.java +++ b/test/src/com/xilinx/rapidwright/edif/TestEDIFPort.java @@ -32,6 +32,8 @@ import com.xilinx.rapidwright.design.Design; import com.xilinx.rapidwright.device.Device; import com.xilinx.rapidwright.support.RapidWrightDCP; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; public class TestEDIFPort { @@ -129,4 +131,26 @@ public void testCreatePort() { Assertions.assertEquals(busPort, cell.getPort("foo[0][")); Assertions.assertNotEquals(busPort, cell.getPort("foo[0]")); } + + @ParameterizedTest + @CsvSource({ + "bus[7:0],bus,8", + "bus[0:7],bus,8", + "bus[15][15:0],bus[15],8", + "foo,foo,1", + "foo[0],foo[0],1", + "foo[1],foo[1],1", + "foo[2][2],foo[2][2],1", + "foo[3][3:3],foo[3],1", + }) + void testGetBusName(String portName, String busName, int width) { + String designName = "design"; + final EDIFNetlist netlist = EDIFTools.createNewNetlist(designName); + final Design design = new Design(designName, Device.KCU105); + design.setNetlist(netlist); + + EDIFCell cell = new EDIFCell(netlist.getWorkLibrary(), "cell_1"); + EDIFPort busOutput = cell.createPort(portName, EDIFDirection.OUTPUT, width); + Assertions.assertEquals(busName, busOutput.getBusName()); + } } diff --git a/test/src/com/xilinx/rapidwright/edif/TestEDIFPortInstList.java b/test/src/com/xilinx/rapidwright/edif/TestEDIFPortInstList.java index b24a54000..e569cf912 100644 --- a/test/src/com/xilinx/rapidwright/edif/TestEDIFPortInstList.java +++ b/test/src/com/xilinx/rapidwright/edif/TestEDIFPortInstList.java @@ -33,6 +33,38 @@ public class TestEDIFPortInstList { + @Test + public void testEDIFPortInstListDuplicateBehavior() { + + String designName = "design"; + final EDIFNetlist netlist = EDIFTools.createNewNetlist(designName); + + EDIFCell ec = new EDIFCell(netlist.getWorkLibrary(), "foo"); + EDIFPort port = ec.createPort("in", EDIFDirection.INPUT, 1); + + + EDIFCell top = netlist.getTopCell(); + EDIFCellInst cell = ec.createCellInst("a", top); + + EDIFNet netA = top.createNet("netA"); + EDIFNet netB = top.createNet("netB"); + + + netA.createPortInst(port, cell); + netA.removePortInst(netA.getPortInsts().iterator().next()); + + // At this point, cell has an EDIFPortInst 'a/in', even though it was removed from netA + + // By creating another EDIFPortInst 'a/in' on netB, we introduce a duplicate EDIFPortInst + // on cell + netB.createPortInst(port, cell); + + // If the EDIFPortInstList is truly replacing existing equivalent port instances, the port + // instance on the cell and netB should be the same object + EDIFPortInst epi = cell.getPortInsts().iterator().next(); + Assertions.assertEquals(netB, epi.getNet()); + } + public EDIFPortInst makeEDIFPortInst(String portInstName) { EDIFPortInst portInst = new EDIFPortInst(); portInst.setName(portInstName); @@ -190,10 +222,17 @@ public void testEDIFPortInstListSorting() { HashSet uniqueSet = new HashSet<>(); for (String name : allNames) { - // Test to ensure duplicates are not allowed - boolean success = list.add(makeEDIFPortInst(name)); + // Test to ensure duplicates are overwritten + EDIFPortInst portInst = makeEDIFPortInst(name); + EDIFPortInst existingPortInst = list.get(portInst.getCellInst(), portInst.getName()); + Assertions.assertTrue(list.add(portInst)); boolean isDuplicate = uniqueSet.add(name); - Assertions.assertEquals(success, isDuplicate); + if (isDuplicate) { + EDIFPortInst currPortInst = list.get(portInst.getCellInst(), portInst.getName()); + Assertions.assertTrue(currPortInst == portInst); + Assertions.assertTrue(existingPortInst != currPortInst); + } + } Assertions.assertEquals(uniqueSet.size(), list.size());