Skip to content
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

RelocationTools fixes and more robust testing #863

Merged
merged 3 commits into from
Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
74 changes: 34 additions & 40 deletions src/com/xilinx/rapidwright/design/tools/RelocationTools.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2021-2022, Xilinx, Inc.
* Copyright (c) 2022, Advanced Micro Devices, Inc.
* Copyright (c) 2022-2023, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Author: Eddie Hung, Xilinx Research Labs.
Expand All @@ -23,32 +23,29 @@

package com.xilinx.rapidwright.design.tools;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import com.xilinx.rapidwright.design.Cell;
import com.xilinx.rapidwright.design.Design;
import com.xilinx.rapidwright.design.DesignTools;
import com.xilinx.rapidwright.design.Net;
import com.xilinx.rapidwright.design.SiteInst;
import com.xilinx.rapidwright.design.SitePinInst;
import com.xilinx.rapidwright.design.blocks.PBlock;
import com.xilinx.rapidwright.device.PIP;
import com.xilinx.rapidwright.device.Site;
import com.xilinx.rapidwright.device.SiteTypeEnum;
import com.xilinx.rapidwright.device.Tile;
import com.xilinx.rapidwright.edif.EDIFHierCellInst;
import com.xilinx.rapidwright.edif.EDIFNetlist;
import com.xilinx.rapidwright.interchange.PhysNetlistWriter;
import com.xilinx.rapidwright.util.Pair;
import com.xilinx.rapidwright.util.Utils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
* A collection of tools to help relocate designs.
*
Expand Down Expand Up @@ -238,25 +235,27 @@ public static boolean relocate(Design design,
return false;
}

List<Pair<Net, List<PIP>>> oldRoute = new ArrayList<>();
boolean revertRouting = false;

DesignTools.createMissingSitePinInsts(design);

for (Net n : design.getNets()) {
if (!n.hasPIPs()) {
continue;
}

Collection<SitePinInst> pins = n.getPins();
SitePinInst src = n.getSource();
if (src != null && !oldSite.containsKey(src.getSiteInst())) {
System.out.println("INFO: Unrouting Net '" + n.getName() + "' since output SiteInstPin '" +
src + "' does not belong to SiteInsts to be relocated");
n.unroute();
for (SitePinInst spi : pins) {
if (oldSite.containsKey(spi.getSiteInst())) {
// Source is not reloacted, but at least one pin inside site insts to be relocated
System.out.println("INFO: Unrouting Net '" + n.getName() + "' since output SiteInstPin '" +
src + "' does not belong to SiteInsts to be relocated");
n.unroute();
}
}
continue;
}

Collection<SitePinInst> pins = n.getPins();
Collection<SitePinInst> nonMatchingPins = pins.stream()
.filter((spi) -> !oldSite.containsKey(spi.getSiteInst()))
// Filter out SPIs on a "STATIC_SOURCE" SiteInst that would have been unplaced above
Expand All @@ -266,19 +265,23 @@ public static boolean relocate(Design design,
continue;
}

oldRoute.add(new Pair<>(n, n.getPIPs()));

if (!nonMatchingPins.isEmpty()) {
for (SitePinInst spi : nonMatchingPins) {
System.out.println("INFO: Unrouting SitePinInst '" + spi + "' branch of Net '" + n.getName() +
"' since it does not belong to SiteInsts to be relocated");
if (n.isStaticNet()) {
// Since static nets are global if there are any pins on SiteInsts that are not to be relocated,
// unroute the whole net as it's not obvious how to relocate the relevant subset of its PIPs
// instead of all of them
n.unroute();
} else {
for (SitePinInst spi : nonMatchingPins) {
System.out.println("INFO: Unrouting SitePinInst '" + spi + "' branch of Net '" + n.getName() +
"' since it does not belong to SiteInsts to be relocated");
}
DesignTools.unroutePins(n, nonMatchingPins);
}

DesignTools.unroutePins(n, nonMatchingPins);
}

boolean isClockNet = n.isClockNet() || n.hasGapRouting();
for (PIP sp : n.getPIPs()) {
n.getPIPs().removeIf((sp) -> {
Tile st = sp.getTile();
Tile dt = st.getTileXYNeighbor(tileColOffset, tileRowOffset);
if (dt == null) {
Expand All @@ -288,8 +291,9 @@ public static boolean relocate(Design design,
String destTileName = st.getRootName() + "_X" + (st.getTileXCoordinate() + tileColOffset)
+ "Y" + (st.getTileYCoordinate() + tileRowOffset);
if (sp.isStub()) {
System.out.println("INFO: Skipping stub PIP '" + sp + "' that failed to move to Tile '" + destTileName +
System.out.println("INFO: Removing stub PIP '" + sp + "' that failed to move to Tile '" + destTileName +
"' (Net '" + n.getName() + "')");
return true;
} else {
throw new RuntimeException("ERROR: Failed to move PIP '" + sp + "' to Tile '" + destTileName +
"' (Net '" + n.getName() + "')");
Expand All @@ -299,23 +303,13 @@ public static boolean relocate(Design design,
assert (st.getTileTypeEnum() == dt.getTileTypeEnum());
sp.setTile(dt);
}
}
}

if (revertRouting) {
revertPlacement(oldSite);
revertRouting(oldRoute);
return false;
return false;
});
}

return true;
}

private static void revertRouting(List<Pair<Net, List<PIP>>> oldRoute) {
for (Pair<Net,List<PIP>> e : oldRoute) {
e.getFirst().setPIPs(e.getSecond());
}
}

private static void revertPlacement(Map<SiteInst, Site> oldSite) {
for (Map.Entry<SiteInst, Site> e : oldSite.entrySet()) {
Expand Down
77 changes: 42 additions & 35 deletions test/src/com/xilinx/rapidwright/design/TestRelocationTools.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2021-2022, Xilinx, Inc.
* Copyright (c) 2022, Advanced Micro Devices, Inc.
* Copyright (c) 2022-2023, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Author: Eddie Hung, Xilinx Research Labs.
Expand Down Expand Up @@ -41,15 +41,18 @@
import com.xilinx.rapidwright.edif.EDIFTools;
import com.xilinx.rapidwright.support.RapidWrightDCP;
import com.xilinx.rapidwright.tests.CodePerfTracker;
import com.xilinx.rapidwright.util.FileTools;
import com.xilinx.rapidwright.util.Pair;
import com.xilinx.rapidwright.util.ReportRouteStatusResult;
import com.xilinx.rapidwright.util.VivadoTools;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

public class TestRelocationTools {

private void relocateModuleInstsAndCompare(int colOffset, int rowOffset, boolean expectSuccess, Design design1, Design design2, Collection<ModuleInst> moduleInsts) {
private void relocateModuleInstsAndCompare(int colOffset, int rowOffset, boolean expectSuccess, Design design1, Collection<ModuleInst> moduleInsts) {
List<Pair<ModuleInst,Site>> newSite = new ArrayList<>();
for (ModuleInst mi : moduleInsts) {
Assertions.assertTrue(mi.isPlaced());
Expand Down Expand Up @@ -84,31 +87,31 @@ private void relocateModuleInstsAndCompare(int colOffset, int rowOffset, boolean
Assertions.assertEquals(c1.getSite(), c2.getSite());
}
}
}

for (Net n2 : mi.getNets()) {
Net n1 = design1.getNet(n2.getName());
if (n1 == null && n2.getName().startsWith(mi.getName() + EDIFTools.EDIF_HIER_SEP)) {
// Retry without ModuleInst hierarchy in case it was flattened
n1 = design1.getNet(n2.getName().substring(mi.getName().length() + 1));
}
Assertions.assertNotNull(n1);
for (Net n2 : mi.getNets()) {
Net n1 = design1.getNet(n2.getName());
if (n1 == null && n2.getName().startsWith(mi.getName() + EDIFTools.EDIF_HIER_SEP)) {
// Retry without ModuleInst hierarchy in case it was flattened
n1 = design1.getNet(n2.getName().substring(mi.getName().length() + 1));
}
Assertions.assertNotNull(n1);

if (n1.isClockNet() || n1.hasGapRouting()) {
// Module relocation unroutes all clock nets?
Assertions.assertFalse(n2.hasPIPs());
continue;
}
if (n1.isClockNet() || n1.hasGapRouting()) {
// Module relocation unroutes all clock nets?
Assertions.assertFalse(n2.hasPIPs());
continue;
}

Set<PIP> p1 = new HashSet<>(n1.getPIPs());
Set<PIP> p2 = new HashSet<>(n2.getPIPs());
if (!n1.isStaticNet()) {
Assertions.assertEquals(p1, p2);
} else {
// For static nets, ModuleInst.place() will merge its
// static PIPs into the parent Design's static net, so
// check that it is contained within
Assertions.assertTrue(p1.containsAll(p2));
}
Set<PIP> p1 = new HashSet<>(n1.getPIPs());
Set<PIP> p2 = new HashSet<>(n2.getPIPs());
if (!n1.isStaticNet()) {
Assertions.assertEquals(p1, p2);
} else {
// For static nets, ModuleInst.place() will merge its
// static PIPs into the parent Design's static net, so
// check that it is contained within
Assertions.assertTrue(p1.containsAll(p2));
}
}
}
Expand All @@ -131,7 +134,7 @@ public void testPicoblazeOOC(String instanceName, int colOffset, int rowOffset,
mi.placeOnOriginalAnchor();
Collection<ModuleInst> moduleInsts = Arrays.asList(mi);

relocateModuleInstsAndCompare(colOffset, rowOffset, expectSuccess, design1, design2, moduleInsts);
relocateModuleInstsAndCompare(colOffset, rowOffset, expectSuccess, design1, moduleInsts);
}
}

Expand Down Expand Up @@ -169,13 +172,12 @@ public void testPicoblaze4OOC(String instanceName, int colOffset, int rowOffset,
if (instanceName.isEmpty()) {
moduleInsts = design2.getModuleInsts();
} else {
moduleInsts = new ArrayList<>();
ModuleInst mi = design2.getModuleInst(instanceName);
Assertions.assertNotNull(mi);
moduleInsts = Arrays.asList(mi);
}

relocateModuleInstsAndCompare(colOffset, rowOffset, expectSuccess, design1, design2, moduleInsts);
relocateModuleInstsAndCompare(colOffset, rowOffset, expectSuccess, design1, moduleInsts);
}

public static Stream<Arguments> testPicoblaze4OOC() {
Expand Down Expand Up @@ -210,7 +212,7 @@ public void testPicoblaze4OOC_PBlock(PBlock pblock, int colOffset, int rowOffset

Collection<ModuleInst> moduleInsts2 = moduleInsts1.stream().map((mi) -> design2.getModuleInst(mi.getName()))
.collect(Collectors.toList());
relocateModuleInstsAndCompare(colOffset, rowOffset, expectSuccess, design1, design2, moduleInsts2);
relocateModuleInstsAndCompare(colOffset, rowOffset, expectSuccess, design1, moduleInsts2);
}

public static Stream<Arguments> testPicoblaze4OOC_PBlock() {
Expand All @@ -225,23 +227,28 @@ public static Stream<Arguments> testPicoblaze4OOC_PBlock() {

@ParameterizedTest(name = "Relocate MicroBlazeAndILA ''{0}'' ({1},{2})")
@MethodSource()
public void testMicroBlazeAndILA(String instanceName, int colOffset, int rowOffset, boolean expectSuccess) {
public void testMicroBlazeAndILA(String instanceName, int colOffset, int rowOffset, boolean expectSuccess, int expectedNetsWithRoutingErrors) {
String dcpPath = RapidWrightDCP.getString("microblazeAndILA_3pblocks.dcp");

Design design1 = Design.readCheckpoint(dcpPath, CodePerfTracker.SILENT);

Assertions.assertEquals(RelocationTools.relocate(design1, instanceName, colOffset, rowOffset),
expectSuccess);

if (expectSuccess && FileTools.isVivadoOnPath()) {
ReportRouteStatusResult rrs = VivadoTools.reportRouteStatus(design1);
Assertions.assertEquals(expectedNetsWithRoutingErrors, rrs.netsWithRoutingErrors);
}
}

public static Stream<Arguments> testMicroBlazeAndILA() {
return Stream.of(
Arguments.of("", 0, 5, true)
, Arguments.of("", 0, 60, true)
, Arguments.of("base_mb_i", 0, 10, true)
, Arguments.of("dbg_hub", 0, 20, true)
, Arguments.of("u_ila_0", 0, 30, true)
, Arguments.of("dbg_hub", 16, 0, false) // placement conflict
Arguments.of("", 0, 5, true, 0)
, Arguments.of("", 0, 60, true, 0)
, Arguments.of("base_mb_i", 0, 10, true, 26 /* unrouted pins and resource conflicts */ )
, Arguments.of("dbg_hub", 0, 20, true, 19 /* unrouted pins */)
, Arguments.of("u_ila_0", 0, 30, true, 0)
, Arguments.of("dbg_hub", 16, 0, false, -1) // placement conflict
);
}

Expand Down