diff --git a/src/com/xilinx/rapidwright/design/NetTools.java b/src/com/xilinx/rapidwright/design/NetTools.java index 0bda3e432..5dcc924fa 100644 --- a/src/com/xilinx/rapidwright/design/NetTools.java +++ b/src/com/xilinx/rapidwright/design/NetTools.java @@ -33,10 +33,14 @@ import java.util.Set; import java.util.function.Function; +import com.xilinx.rapidwright.design.blocks.PBlock; import com.xilinx.rapidwright.device.IntentCode; import com.xilinx.rapidwright.device.Node; import com.xilinx.rapidwright.device.PIP; import com.xilinx.rapidwright.device.SiteTypeEnum; +import com.xilinx.rapidwright.edif.EDIFHierNet; +import com.xilinx.rapidwright.edif.EDIFPort; +import com.xilinx.rapidwright.edif.EDIFPortInst; public class NetTools { public static final String CONTINUE_ELBOW = "\u251c\u2500 "; @@ -517,4 +521,41 @@ public static Node findClockRootVRoute(Net net) { return deepestVRoute; } + + /** + * Unroute top-level port nets that have PIPs outside the specified PBlock. Vivado can potentially create designs + * where the top-level port nets leave the PBlock if the InlineFlopTools flop harness was used and the top-level + * port net also has a sink inside the PBlock. + * + * @param d The design to unroute nets from. + * @param pBlock The bounding box for the placed and routed design. + */ + public static void unrouteTopLevelNetsThatLeavePBlock(Design d, PBlock pBlock) { + DesignTools.makePhysNetNamesConsistent(d); + d.getNetlist().resetParentNetMap(); + d.getNetlist().expandMacroUnisims(); + for (EDIFPort p : d.getNetlist().getTopCell().getPorts()) { + int[] indices = p.isBus() ? p.getBitBlastedIndicies() : new int[]{0}; + for (int i : indices) { + EDIFPortInst portInst = p.getInternalPortInstFromIndex(i); + if (portInst == null) { + continue; + } + EDIFHierNet hierNet = new EDIFHierNet(d.getNetlist().getTopHierCellInst(), portInst.getNet()); + EDIFHierNet parentNet = d.getNetlist().getParentNet(hierNet); + Net net = d.getNet(parentNet.getHierarchicalNetName()); + + boolean leavesPBlock = false; + for (PIP pip : net.getPIPs()) { + if (!pBlock.containsTile(pip.getTile())) { + leavesPBlock = true; + break; + } + } + if (leavesPBlock) { + net.unroute(); + } + } + } + } } diff --git a/src/com/xilinx/rapidwright/design/blocks/PBlockSide.java b/src/com/xilinx/rapidwright/design/blocks/PBlockSide.java new file mode 100644 index 000000000..fccd60daa --- /dev/null +++ b/src/com/xilinx/rapidwright/design/blocks/PBlockSide.java @@ -0,0 +1,31 @@ +/* + * + * Copyright (c) 2025, Advanced Micro Devices, Inc. + * All rights reserved. + * + * Author: Andrew Butt, AMD Advanced Research and Development. + * + * 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.blocks; + +public enum PBlockSide { + LEFT, + RIGHT, + TOP, + BOTTOM +} diff --git a/src/com/xilinx/rapidwright/design/tools/InlineFlopTools.java b/src/com/xilinx/rapidwright/design/tools/InlineFlopTools.java index 67f0f41a2..1a32fd2a1 100644 --- a/src/com/xilinx/rapidwright/design/tools/InlineFlopTools.java +++ b/src/com/xilinx/rapidwright/design/tools/InlineFlopTools.java @@ -24,6 +24,7 @@ import java.util.*; import java.util.stream.Collectors; +import java.util.Map.Entry; import com.xilinx.rapidwright.design.Cell; import com.xilinx.rapidwright.design.Design; @@ -33,13 +34,17 @@ import com.xilinx.rapidwright.design.SitePinInst; import com.xilinx.rapidwright.design.Unisim; import com.xilinx.rapidwright.design.blocks.PBlock; +import com.xilinx.rapidwright.design.blocks.PBlockSide; import com.xilinx.rapidwright.device.*; import com.xilinx.rapidwright.eco.ECOPlacementHelper; import com.xilinx.rapidwright.edif.*; import com.xilinx.rapidwright.placer.blockplacer.Point; +import com.xilinx.rapidwright.util.FileTools; import com.xilinx.rapidwright.util.Pair; import com.xilinx.rapidwright.util.StringTools; +import static com.xilinx.rapidwright.util.Utils.isCLB; + /** * Set of tools to add/remove flip flops inline to top level port connections. * This is targeted at kernel replication preparation prior to routing to ensure @@ -94,6 +99,92 @@ public static void createAndPlaceFlopsInlineOnTopPortsNearPins(Design design, St createAndPlaceFlopsInlineOnTopPorts(design, clkNet, keepOut, true); } + private static Site shiftSiteToSide(Device device, Site site, PBlock pblock, PBlockSide side) { + Tile topLeftTile = pblock.getTopLeftTile(); + Tile bottomRightTile = pblock.getBottomRightTile(); + Tile siteTile = site.getTile(); + int pBlockTop = topLeftTile.getRow(); + int pBlockLeft = topLeftTile.getColumn(); + int pBlockRight = bottomRightTile.getColumn(); + int pBlockBottom = bottomRightTile.getRow(); + int siteTileCol = siteTile.getColumn(); + int siteTileRow = siteTile.getRow(); + + Tile shiftedTile; + if (side == PBlockSide.TOP) { + // Shift tile up + shiftedTile = shiftTileUntilSlice(device, pBlockTop, siteTileCol, true, true); + } else if (side == PBlockSide.LEFT) { + // Shift tile left + shiftedTile = shiftTileUntilSlice(device, siteTileRow, pBlockLeft, false, true); + } else if (side == PBlockSide.RIGHT) { + // Shift tile right + shiftedTile = shiftTileUntilSlice(device, siteTileRow, pBlockRight, false, false); + } else { + // Shift tile down + shiftedTile = shiftTileUntilSlice(device, pBlockBottom, siteTileCol, true, false); + } + Site shiftedSite = site.getCorrespondingSite(site.getSiteTypeEnum(), shiftedTile); + if (shiftedSite == null) { + // Can't find a site on the edge of the PBlock, return the original site + return site; + } + + return shiftedSite; + } + + /** + * Add flip-flops inline on all the top-level ports of an out-of-context design. + * This is useful for out-of-context kernels so that after the flops have been + * placed, the router is forced to route connections of each of the ports to + * each of the flops. This can help alleviate congestion when the kernels are + * placed/relocated in context. + * + * @param design The design to modify + * @param clkNet Name of the clock net to use on which to add the flops + * @param keepOut The pblock used to contain the kernel and the added flops will + * not be placed inside this area. + * @param portSideMap Map from ports to side of the pblock the flop should be placed on + */ + public static void createAndPlacePortFlopsOnSide(Design design, String clkNet, PBlock keepOut, + Map portSideMap) { + assert (design.getSiteInsts().isEmpty()); + Site start = keepOut.getAllSites("SLICE").iterator().next(); // TODO this is a bit wasteful + boolean exclude = true; + + EDIFHierNet clk = design.getNetlist().getHierNetFromName(clkNet); + + Set siteInstsToRoute = new HashSet<>(); + + for (Entry entry : portSideMap.entrySet()) { + EDIFPort port = entry.getKey(); + PBlockSide side = entry.getValue(); + if (port.getName().equals(clkNet)) { + continue; + } + Site shiftedSite = shiftSiteToSide(design.getDevice(), start, keepOut, side); + int[] indices = port.isBus() ? port.getBitBlastedIndicies() : new int[] { 0 }; + for (int i : indices) { + EDIFPortInst inst = port.getInternalPortInstFromIndex(i); + if (allLeavesAreIBUF(design, inst)) { + continue; + } + + Iterator siteItr = ECOPlacementHelper.spiralOutFrom(shiftedSite, keepOut, exclude).iterator(); + siteItr.next(); // Skip the first site, as we are suggesting one inside the pblock + Pair loc = nextAvailPlacement(design, siteItr, null); + if (loc == null) { + throw new RuntimeException("Failed to find valid placement location for flip-flop"); + } + Cell flop = createAndPlaceFlopInlineOnTopPortInst(design, inst, loc, clk); + siteInstsToRoute.add(flop.getSiteInst()); + } + } + for (SiteInst si : siteInstsToRoute) { + si.routeSite(); + } + } + /** * Add flip-flops inline on all the top-level ports of an out-of-context design. * This is useful for out-of-context kernels so that after the flops have been @@ -114,8 +205,6 @@ private static void createAndPlaceFlopsInlineOnTopPorts(Design design, String cl EDIFCell top = design.getTopEDIFCell(); Site start = keepOut.getAllSites("SLICE").iterator().next(); // TODO this is a bit wasteful boolean exclude = true; - Iterator siteItr = ECOPlacementHelper.spiralOutFrom(start, keepOut, exclude).iterator(); - siteItr.next(); // Skip the first site, as we are suggesting one inside the pblock EDIFHierNet clk = design.getNetlist().getHierNetFromName(clkNet); @@ -125,35 +214,21 @@ private static void createAndPlaceFlopsInlineOnTopPorts(Design design, String cl if (port.getName().equals(clkNet)) { continue; } - if (port.isBus()) { - for (int i : port.getBitBlastedIndicies()) { - EDIFPortInst inst = port.getInternalPortInstFromIndex(i); - if (allLeavesAreIBUF(design, inst)) { - continue; - } - - if (centroidPlacement) { - netCentroidFlipFlopPlacement(design, inst, keepOut, clk, siteInstsToRoute); - } else { - Pair loc = nextAvailPlacement(design, siteItr); - Cell flop = createAndPlaceFlopInlineOnTopPortInst(design, inst, loc, clk); - siteInstsToRoute.add(flop.getSiteInst()); - } + int[] indices = port.isBus() ? port.getBitBlastedIndicies() : new int[] { 0 }; + for (int i : indices) { + EDIFPortInst inst = port.getInternalPortInstFromIndex(i); + if (allLeavesAreIBUF(design, inst)) { + continue; } - } else { - EDIFPortInst inst = port.getInternalPortInst(); - if (inst != null) { - if (allLeavesAreIBUF(design, inst)) { - continue; - } - if (centroidPlacement) { - netCentroidFlipFlopPlacement(design, inst, keepOut, clk, siteInstsToRoute); - } else { - Pair loc = nextAvailPlacement(design, siteItr); - Cell flop = createAndPlaceFlopInlineOnTopPortInst(design, inst, loc, clk); - siteInstsToRoute.add(flop.getSiteInst()); - } + if (centroidPlacement) { + netCentroidFlipFlopPlacement(design, inst, keepOut, clk, siteInstsToRoute); + } else { + Iterator siteItr = ECOPlacementHelper.spiralOutFrom(start, keepOut, exclude).iterator(); + siteItr.next(); // Skip the first site, as we are suggesting one inside the pblock + Pair loc = nextAvailPlacement(design, siteItr, null); + Cell flop = createAndPlaceFlopInlineOnTopPortInst(design, inst, loc, clk); + siteInstsToRoute.add(flop.getSiteInst()); } } } @@ -174,6 +249,64 @@ private static boolean allLeavesAreIBUF(Design design, EDIFPortInst inst) { return allLeavesAreIBUF; } + private static Tile shiftTileUntilSlice(Device device, int row, int col, boolean shiftRow, boolean negativeShift) { + int offset = negativeShift ? -1 : 1; + Tile shiftedTile = null; + while (shiftedTile == null || !isCLB(shiftedTile.getTileTypeEnum())) { + int shiftedRow = shiftRow ? row + offset : row; + int shiftedCol = !shiftRow ? col + offset : col; + if (shiftRow && (shiftedRow < 0 || shiftedRow > device.getRows())) { + shiftedTile = null; + break; + } + if (!shiftRow && (shiftedCol < 0 || shiftedCol > device.getColumns())) { + shiftedTile = null; + break; + } + shiftedTile = device.getTile(shiftedRow, shiftedCol); + offset = negativeShift ? offset - 1 : offset + 1; + } + return shiftedTile; + } + + private static Site getSiteOnPBlockEdgeClosestToSite(Device device, Site site, PBlock pblock) { + Tile topLeftTile = pblock.getTopLeftTile(); + Tile bottomRightTile = pblock.getBottomRightTile(); + Tile siteTile = site.getTile(); + int pBlockTop = topLeftTile.getRow(); + int pBlockLeft = topLeftTile.getColumn(); + int pBlockRight = bottomRightTile.getColumn(); + int pBlockBottom = bottomRightTile.getRow(); + int siteTileCol = siteTile.getColumn(); + int siteTileRow = siteTile.getRow(); + int topDist = siteTileRow - pBlockTop; + int bottomDist = pBlockBottom - siteTileRow; + int leftDist = siteTileCol - pBlockLeft; + int rightDist = pBlockRight - siteTileCol; + + Tile shiftedTile = null; + if (topDist <= leftDist && topDist <= rightDist && topDist <= bottomDist) { + // Shift tile up + shiftedTile = shiftTileUntilSlice(device, pBlockTop, siteTileCol, true, true); + } else if (leftDist <= topDist && leftDist <= rightDist && leftDist <= bottomDist) { + // Shift tile left + shiftedTile = shiftTileUntilSlice(device, siteTileRow, pBlockLeft, false, true); + } else if (rightDist <= topDist && rightDist <= leftDist && rightDist <= bottomDist) { + // Shift tile right + shiftedTile = shiftTileUntilSlice(device, siteTileRow, pBlockRight, false, false); + } else { + // Shift tile down + shiftedTile = shiftTileUntilSlice(device, pBlockBottom, siteTileCol, true, false); + } + Site shiftedSite = site.getCorrespondingSite(site.getSiteTypeEnum(), shiftedTile); + if (shiftedSite == null) { + // Can't find a site on the edge of the PBlock, return the original site + return site; + } + + return shiftedSite; + } + private static void netCentroidFlipFlopPlacement(Design design, EDIFPortInst inst, PBlock keepOut, EDIFHierNet clk, Set siteInstsToRoute) { EDIFHierCellInst topInst = design.getNetlist().getTopHierCellInst(); @@ -192,17 +325,23 @@ private static void netCentroidFlipFlopPlacement(Design design, EDIFPortInst ins if (!points.isEmpty()) { Site centroid = ECOPlacementHelper.getCentroidOfPoints(design.getDevice(), points, VALID_CENTROID_SITE_TYPES); - Iterator siteItr = ECOPlacementHelper.spiralOutFrom(centroid, keepOut, true).iterator(); - siteItr.next(); - Pair loc = nextAvailPlacement(design, siteItr); + Site shiftedCentroid = getSiteOnPBlockEdgeClosestToSite(design.getDevice(), centroid, keepOut); + Iterator siteItr = ECOPlacementHelper.spiralOutFrom(shiftedCentroid, keepOut, true).iterator(); + if (keepOut.containsTile(shiftedCentroid.getTile())) { + siteItr.next(); + } + Pair loc = nextAvailPlacement(design, siteItr, shiftedCentroid.getTile().getSLR()); Cell flop = createAndPlaceFlopInlineOnTopPortInst(design, inst, loc, clk); siteInstsToRoute.add(flop.getSiteInst()); } } - private static Pair nextAvailPlacement(Design design, Iterator itr) { + private static Pair nextAvailPlacement(Design design, Iterator itr, SLR slr) { while (itr.hasNext()) { Site curr = itr.next(); + if (slr != null && curr.getTile().getSLR() != slr) { + continue; + } SiteInst candidate = design.getSiteInstFromSite(curr); List usedFFs = new ArrayList<>(); if (candidate != null) { @@ -272,7 +411,16 @@ public static void removeInlineFlops(Design design) { Net vcc = design.getVccNet(); Set vccPins = new HashSet<>(); pinsToRemove.put(vcc, vccPins); - String[] staticPins = new String[]{"CKEN1", design.getSeries() == Series.Versal ? "RST" : "SRST1"}; + String[] versalStaticPins = new String[]{"CKEN1", "CKEN2", "CKEN3", "CKEN4", "RST"}; + String[] ultrascaleStaticPins = new String[]{"CKEN1", "CKEN2", "CKEN3", "CKEN4", "SRST1", "SRST2"}; + String[] series7StaticPins = new String[]{"CE", "SR"}; + if (design.getSeries() != Series.Versal && design.getSeries() != Series.UltraScale + && design.getSeries() != Series.UltraScalePlus && design.getSeries() != Series.Series7) { + throw new RuntimeException("Unsupported device series for removing inline flops"); + } + String[] staticPins = design.getSeries() == Series.Versal ? versalStaticPins : + design.getSeries() == Series.UltraScalePlus + || design.getSeries() == Series.UltraScale ? ultrascaleStaticPins : series7StaticPins; for (EDIFCellInst inst : design.getTopEDIFCell().getCellInsts()) { if (inst.getName().endsWith(INLINE_SUFFIX)) { Cell flop = design.getCell(inst.getName()); @@ -280,6 +428,9 @@ public static void removeInlineFlops(Design design) { // Assume we only placed one flop per SiteInst siteInstToRemove.add(si); for (SitePinInst pin : si.getSitePinInsts()) { + if (pin.getNet().isGNDNet()) { + continue; + } pinsToRemove.computeIfAbsent(pin.getNet(), p -> new HashSet<>()).add(pin); } for (String staticPin : staticPins) { @@ -292,9 +443,7 @@ public static void removeInlineFlops(Design design) { } } - for (SiteInst si : siteInstToRemove) { - design.removeSiteInst(si); - } + DesignTools.batchRemoveSitePins(pinsToRemove, true); String[] ctrlPins = new String[]{"C", "R", "CE"}; @@ -303,7 +452,9 @@ public static void removeInlineFlops(Design design) { // Remove control set pins for (String pin : ctrlPins) { EDIFPortInst p = c.getPortInst(pin); - p.getNet().removePortInst(p); + if (p != null && p.getNet() != null) { + p.getNet().removePortInst(p); + } } // Merge 'D' sources and 'Q' sinks, restore original net EDIFPortInst d = c.getPortInst("D"); @@ -336,8 +487,52 @@ public static void removeInlineFlops(Design design) { design.removeCell(c.getName()); } + for (SiteInst si : siteInstToRemove) { + boolean isStaticSource = si.getSitePinInsts().stream() + .anyMatch((p) -> p.getNet().isGNDNet() && p.isOutPin()); + if (!isStaticSource) { + design.removeSiteInst(si); + } + } + } + + /** + * Parses the PBlock side map into a map from EDIFPorts to PBlockSide enums. The input file should be made up of + * some number of lines where each line contains a port name regex and a PBlockSide separated by a space. An + * example file: + *
+     * example_inputs.* TOP
+     * reset LEFT
+     * example_outputs.* BOTTOM
+     * 
+ * + * @param netlist The netlist that the side map will be created for. + * @param filename The name of the input side map file. + * @return A map from EDIFPort to the PBlockSide the inline flop should be placed on. + */ + public static Map parseSideMap(EDIFNetlist netlist, String filename) { + Map externalRoutabilitySideMap = new HashMap<>(); + List lines = FileTools.getLinesFromTextFile(filename); + + for (String line : lines) { + String[] splitLine = line.split("\\s+"); + String portRegex = splitLine[0]; + String pblockSide = splitLine[1].toUpperCase(); + for (EDIFPort port : netlist.getTopCell().getPorts()) { + if (port.getBusName().matches(portRegex) || + port.getName().matches("\\" + EDIFTools.VIVADO_PRESERVE_PORT_INTERFACE + portRegex)) { + if (externalRoutabilitySideMap.containsKey(port)) { + throw new RuntimeException("Port " + port + " matches multiple expressions in side map"); + } + PBlockSide side = PBlockSide.valueOf(pblockSide); + externalRoutabilitySideMap.put(port, side); + } + } + } + return externalRoutabilitySideMap; } + public static void main(String[] args) { if (args.length < 3 || args.length > 4) { System.out.println("USAGE (to add flops) : " + CLK_OPT + "= " + PBLOCK_OPT + "="); diff --git a/src/com/xilinx/rapidwright/util/PerformanceExplorer.java b/src/com/xilinx/rapidwright/util/PerformanceExplorer.java index 89f53ba5b..adc668930 100644 --- a/src/com/xilinx/rapidwright/util/PerformanceExplorer.java +++ b/src/com/xilinx/rapidwright/util/PerformanceExplorer.java @@ -37,9 +37,13 @@ import com.xilinx.rapidwright.design.ConstraintGroup; import com.xilinx.rapidwright.design.Design; +import com.xilinx.rapidwright.design.NetTools; import com.xilinx.rapidwright.design.blocks.PBlock; import com.xilinx.rapidwright.design.tools.InlineFlopTools; +import com.xilinx.rapidwright.design.blocks.PBlockSide; +import com.xilinx.rapidwright.edif.EDIFPort; +import com.xilinx.rapidwright.edif.EDIFTools; import joptsimple.OptionParser; import joptsimple.OptionSet; @@ -105,6 +109,10 @@ public class PerformanceExplorer { private boolean ensureExternalRoutability; + private String externalRoutabilitySideFile; + + Map externalRoutabilitySideMap = null; + public PerformanceExplorer(Design d, String testDir, String clkName, double targetPeriod) { init(d, testDir, clkName, targetPeriod, null); } @@ -288,6 +296,14 @@ public void setEnsureExternalRoutability(boolean ensureExternalRoutability) { this.ensureExternalRoutability = ensureExternalRoutability; } + public String getExternalRoutabilitySideFile() { + return externalRoutabilitySideFile; + } + + public void setExternalRoutabilitySideFile(String externalRoutabilitySideFile) { + this.externalRoutabilitySideFile = externalRoutabilitySideFile; + } + public PBlock getPBlock(int i) { return pblockLookup[i]; } @@ -388,14 +404,25 @@ public void explorePerformance() { int pb = 0; int jobsStarted = 0; - int maxConcurrentJobs = JobQueue.isLSFAvailable() ? JobQueue.MAX_LSF_CONCURRENT_JOBS : JobQueue.MAX_LOCAL_CONCURRENT_JOBS; + int maxConcurrentJobs = JobQueue.isLSFAvailable() ? JobQueue.MAX_LSF_CONCURRENT_JOBS + : JobQueue.MAX_LOCAL_CONCURRENT_JOBS; pblockLookup = new PBlock[pblocks.size()]; for (Entry e : pblocks.entrySet()) { PBlock pblock = e.getKey(); String pblockDcpName = dcpName; if (ensureExternalRoutability()) { - InlineFlopTools.createAndPlaceFlopsInlineOnTopPortsArbitrarily(design, clkName, pblock); + EDIFTools.removeVivadoBusPreventionAnnotations(design.getNetlist()); + design.getNetlist().resetParentNetMap(); + if (getExternalRoutabilitySideFile() == null) { + InlineFlopTools.createAndPlaceFlopsInlineOnTopPortsArbitrarily(design, clkName, pblock); + } else { + Map sideMap = + InlineFlopTools.parseSideMap(design.getNetlist(), + getExternalRoutabilitySideFile()); + InlineFlopTools.createAndPlacePortFlopsOnSide(design, clkName, pblock, sideMap); + } + EDIFTools.ensurePreservedInterfaceVivado(design.getNetlist()); pblockDcpName = runDirectory + File.separator + "pblock" + pb + "_" + INITIAL_DCP_NAME; design.writeCheckpoint(pblockDcpName); } @@ -412,7 +439,7 @@ public void explorePerformance() { String instDir = runDirectory + File.separator + uniqueID; FileTools.makeDir(instDir); String encryptedTcl = null; - boolean encrypted = !design.getNetlist().getEncryptedCells().isEmpty(); + boolean encrypted = design.getNetlist().hasEncryptedCells(); if (encrypted) { encryptedTcl = runDirectory + File.separator + "pblock" + pb + "_" + INITIAL_ENCRYPTED_TCL_NAME; @@ -420,7 +447,7 @@ public void explorePerformance() { ArrayList tcl = createTclScript(pblockDcpName, instDir, p, r, roundedC, e, encryptedTcl); String scriptName = instDir + File.separator + RUN_TCL_NAME; - if (!reusePreviousResults) { + if (!reusePreviousResults()) { FileTools.writeLinesToTextFile(tcl, scriptName); Job j = JobQueue.createJob(); j.setRunDir(instDir); @@ -506,12 +533,15 @@ public void getBestDesignPerPBlock() { System.out.println("No implementation passes timing for " + pblock); } + System.out.println("Best result found at: " + bestPath); Design d = Design.readCheckpoint(bestPath + File.separator + "routed.dcp"); if (ensureExternalRoutability()) { InlineFlopTools.removeInlineFlops(d); + NetTools.unrouteTopLevelNetsThatLeavePBlock(d, getPBlock(pblockNum)); } + EDIFTools.ensurePreservedInterfaceVivado(d.getNetlist()); d.writeCheckpoint(runDirectory + File.separator + pblock + "_best.dcp"); } } @@ -556,7 +586,7 @@ private static OptionParser createOptionParser() { accepts(VIVADO_PATH_OPT).withOptionalArg().defaultsTo(DEFAULT_VIVADO).describedAs("Specifies vivado path"); accepts(CONTAIN_ROUTING_OPT).withOptionalArg().ofType(Boolean.class).defaultsTo(DEFAULT_CONTAIN_ROUTING).describedAs("Sets attribute on pblock to contain routing"); accepts(MAX_CONCURRENT_JOBS_OPT).withOptionalArg().ofType(Integer.class).defaultsTo(JobQueue.MAX_LOCAL_CONCURRENT_JOBS).describedAs("Max number of concurrent job when run locally"); - accepts(ENSURE_EXT_ROUTABILITY, "Ensure all I/O are routable outside the pblock"); + accepts(ENSURE_EXT_ROUTABILITY).withOptionalArg().describedAs("Ensure all I/O are routable outside the pblock. Optionally provide a text file specifying which side of the pblock each top-level port should route to."); accepts(COLLECT_RESULTS_OPT,"Collect results into output csv"); accepts(REUSE_PREVIOUS_RESULTS, "Reuse previous results if they exist"); acceptsAll( Arrays.asList(HELP_OPT, "?"), "Print Help" ).forHelp(); @@ -580,7 +610,6 @@ private static void printHelp(OptionParser p) { return; } - public static String printNS(double num) { return df.format(num); } @@ -600,6 +629,7 @@ public static void main(String[] args) { String runDir = opts.hasArgument(RUN_DIR_OPT) ? (String) opts.valueOf(RUN_DIR_OPT) : System.getProperty("user.dir"); Design d = Design.readCheckpoint(dcpInputName); + EDIFTools.ensurePreservedInterfaceVivado(d.getNetlist()); PerformanceExplorer pe = new PerformanceExplorer(d, runDir, clkName, targetPeriod); if (opts.hasArgument(MAX_CONCURRENT_JOBS_OPT)) { @@ -625,6 +655,9 @@ public static void main(String[] args) { pe.setGetBestPerPBlock(opts.has(COLLECT_RESULTS_OPT)); pe.setReusePreviousResults(opts.has(REUSE_PREVIOUS_RESULTS)); pe.setEnsureExternalRoutability(opts.has(ENSURE_EXT_ROUTABILITY)); + if (opts.hasArgument(ENSURE_EXT_ROUTABILITY)) { + pe.setExternalRoutabilitySideFile((String) opts.valueOf(ENSURE_EXT_ROUTABILITY)); + } if (opts.hasArgument(PBLOCK_FILE_OPT)) { String fileName = (String) opts.valueOf(PBLOCK_FILE_OPT);