Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 188 additions & 13 deletions src/com/xilinx/rapidwright/design/tools/InlineFlopTools.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a lot of duplicated code. I realize this is partly due to the nature of bussed vs. single bit ports. One way to work around this is to use this pattern:

            for (int i : (port.isBus() ? port.getBitBlastedIndicies() : new int[] { 0 })) {
                EDIFPortInst portInst = port.getInternalPortInstNameFromIndex(i));

A better solution might be to modify EDIFPort.getBitBlastedIndicies() so that for the single bit case it returns a static new int[] { 0 }.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We decided that getBitBlastedIndicies should be updated to return { 0 } when called on a non-bused port. I will refactor further once this change has been made.

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
Expand All @@ -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);

Expand All @@ -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();
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());
}
Expand All @@ -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());
}
Expand All @@ -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();
Expand All @@ -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) {
Expand Down Expand Up @@ -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"};
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) {
Expand All @@ -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"};
Expand All @@ -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");
Expand Down Expand Up @@ -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) {
Expand Down
31 changes: 31 additions & 0 deletions src/com/xilinx/rapidwright/design/tools/PBlockSide.java
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
}
Loading