-
Notifications
You must be signed in to change notification settings - Fork 121
Add ability to constrain flop harness to specific side of PBlock #1318
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: array_builder
Are you sure you want to change the base?
Changes from 3 commits
04776e0
35c8c33
7b0734e
df12be1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -40,6 +40,8 @@ | |
| 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 +96,103 @@ 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<EDIFPort, PBlockSide> 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<SiteInst> siteInstsToRoute = new HashSet<>(); | ||
|
|
||
| for (Map.Entry<EDIFPort, PBlockSide> 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); | ||
| if (port.isBus()) { | ||
| for (int i : port.getBitBlastedIndicies()) { | ||
|
||
| EDIFPortInst inst = port.getInternalPortInstFromIndex(i); | ||
| if (allLeavesAreIBUF(design, inst)) { | ||
| continue; | ||
| } | ||
|
|
||
| Iterator<Site> siteItr = ECOPlacementHelper.spiralOutFrom(shiftedSite, keepOut, exclude).iterator(); | ||
| siteItr.next(); // Skip the first site, as we are suggesting one inside the pblock | ||
| Pair<Site, BEL> loc = nextAvailPlacement(design, siteItr, null); | ||
| Cell flop = createAndPlaceFlopInlineOnTopPortInst(design, inst, loc, clk); | ||
| siteInstsToRoute.add(flop.getSiteInst()); | ||
| } | ||
| } else { | ||
| EDIFPortInst inst = port.getInternalPortInst(); | ||
| if (inst != null) { | ||
| if (allLeavesAreIBUF(design, inst)) { | ||
| continue; | ||
| } | ||
|
|
||
| Iterator<Site> siteItr = ECOPlacementHelper.spiralOutFrom(shiftedSite, keepOut, exclude).iterator(); | ||
| siteItr.next(); // Skip the first site, as we are suggesting one inside the pblock | ||
| Pair<Site, BEL> loc = nextAvailPlacement(design, siteItr, null); | ||
| 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 +213,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<Site> 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); | ||
|
|
||
|
|
@@ -135,7 +232,9 @@ private static void createAndPlaceFlopsInlineOnTopPorts(Design design, String cl | |
| if (centroidPlacement) { | ||
| netCentroidFlipFlopPlacement(design, inst, keepOut, clk, siteInstsToRoute); | ||
| } else { | ||
| Pair<Site, BEL> loc = nextAvailPlacement(design, siteItr); | ||
| Iterator<Site> siteItr = ECOPlacementHelper.spiralOutFrom(start, keepOut, exclude).iterator(); | ||
abutt-amd marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| siteItr.next(); // Skip the first site, as we are suggesting one inside the pblock | ||
| Pair<Site, BEL> loc = nextAvailPlacement(design, siteItr, null); | ||
| Cell flop = createAndPlaceFlopInlineOnTopPortInst(design, inst, loc, clk); | ||
| siteInstsToRoute.add(flop.getSiteInst()); | ||
| } | ||
|
|
@@ -150,7 +249,9 @@ private static void createAndPlaceFlopsInlineOnTopPorts(Design design, String cl | |
| if (centroidPlacement) { | ||
| netCentroidFlipFlopPlacement(design, inst, keepOut, clk, siteInstsToRoute); | ||
| } else { | ||
| Pair<Site, BEL> loc = nextAvailPlacement(design, siteItr); | ||
| Iterator<Site> siteItr = ECOPlacementHelper.spiralOutFrom(start, keepOut, exclude).iterator(); | ||
| siteItr.next(); // Skip the first site, as we are suggesting one inside the pblock | ||
| Pair<Site, BEL> loc = nextAvailPlacement(design, siteItr, null); | ||
| Cell flop = createAndPlaceFlopInlineOnTopPortInst(design, inst, loc, clk); | ||
| siteInstsToRoute.add(flop.getSiteInst()); | ||
| } | ||
|
|
@@ -174,6 +275,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<SiteInst> siteInstsToRoute) { | ||
| EDIFHierCellInst topInst = design.getNetlist().getTopHierCellInst(); | ||
|
|
@@ -192,17 +351,23 @@ private static void netCentroidFlipFlopPlacement(Design design, EDIFPortInst ins | |
| if (!points.isEmpty()) { | ||
| Site centroid = ECOPlacementHelper.getCentroidOfPoints(design.getDevice(), points, | ||
| VALID_CENTROID_SITE_TYPES); | ||
| Iterator<Site> siteItr = ECOPlacementHelper.spiralOutFrom(centroid, keepOut, true).iterator(); | ||
| siteItr.next(); | ||
| Pair<Site, BEL> loc = nextAvailPlacement(design, siteItr); | ||
| Site shiftedCentroid = getSiteOnPBlockEdgeClosestToSite(design.getDevice(), centroid, keepOut); | ||
| Iterator<Site> siteItr = ECOPlacementHelper.spiralOutFrom(shiftedCentroid, keepOut, true).iterator(); | ||
| if (keepOut.containsTile(shiftedCentroid.getTile())) { | ||
| siteItr.next(); | ||
| } | ||
| Pair<Site, BEL> loc = nextAvailPlacement(design, siteItr, shiftedCentroid.getTile().getSLR()); | ||
| Cell flop = createAndPlaceFlopInlineOnTopPortInst(design, inst, loc, clk); | ||
| siteInstsToRoute.add(flop.getSiteInst()); | ||
| } | ||
| } | ||
|
|
||
| private static Pair<Site, BEL> nextAvailPlacement(Design design, Iterator<Site> itr) { | ||
| private static Pair<Site, BEL> nextAvailPlacement(Design design, Iterator<Site> itr, SLR slr) { | ||
| while (itr.hasNext()) { | ||
| Site curr = itr.next(); | ||
| if (slr != null && curr.getTile().getSLR() != slr) { | ||
| continue; | ||
| } | ||
| SiteInst candidate = design.getSiteInstFromSite(curr); | ||
| List<BEL> usedFFs = new ArrayList<>(); | ||
| if (candidate != null) { | ||
|
|
@@ -272,14 +437,17 @@ public static void removeInlineFlops(Design design) { | |
| Net vcc = design.getVccNet(); | ||
| Set<SitePinInst> vccPins = new HashSet<>(); | ||
| pinsToRemove.put(vcc, vccPins); | ||
| String[] staticPins = new String[]{"CKEN1", design.getSeries() == Series.Versal ? "RST" : "SRST1"}; | ||
| String[] staticPins = new String[]{"CKEN1", "CKEN2", design.getSeries() == Series.Versal ? "RST" : "SRST1"}; | ||
abutt-amd marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| for (EDIFCellInst inst : design.getTopEDIFCell().getCellInsts()) { | ||
| if (inst.getName().endsWith(INLINE_SUFFIX)) { | ||
| Cell flop = design.getCell(inst.getName()); | ||
| SiteInst si = flop.getSiteInst(); | ||
| // 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 +460,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 +469,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,6 +504,13 @@ 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); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public static void main(String[] args) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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.tools; | ||
|
|
||
| public enum PBlockSide { | ||
| LEFT, | ||
| RIGHT, | ||
| TOP, | ||
| BOTTOM | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.