Skip to content

Commit

Permalink
Creating a standalone entry point to relocate DCPs (#1047)
Browse files Browse the repository at this point in the history
* Creating a standalone entry point to relocate DCPs

Signed-off-by: Chris Lavin <[email protected]>

* Fix arg checking

Signed-off-by: Chris Lavin <[email protected]>

* Missing step

Signed-off-by: Chris Lavin <[email protected]>

* Add useful info for valid relocation options

Signed-off-by: Chris Lavin <[email protected]>

* Add smoke test, cleanup

Signed-off-by: Chris Lavin <[email protected]>

* Print out tile and site name

Signed-off-by: Chris Lavin <[email protected]>

* Fix backward (negative) tile coordinate suggestions

Signed-off-by: Chris Lavin <[email protected]>

* Clarifying use cases and behavior.

Signed-off-by: Chris Lavin <[email protected]>

---------

Signed-off-by: Chris Lavin <[email protected]>
  • Loading branch information
clavin-xlnx authored Sep 3, 2024
1 parent 6c4996c commit bb99f28
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 9 deletions.
2 changes: 2 additions & 0 deletions src/com/xilinx/rapidwright/MainEntrypoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import com.xilinx.rapidwright.design.blocks.PBlockGenerator;
import com.xilinx.rapidwright.design.merge.MergeDesigns;
import com.xilinx.rapidwright.design.tools.LUTTools;
import com.xilinx.rapidwright.design.tools.RelocationTools;
import com.xilinx.rapidwright.device.IntentCode;
import com.xilinx.rapidwright.device.PseudoPIPHelper;
import com.xilinx.rapidwright.device.browser.DeviceBrowser;
Expand Down Expand Up @@ -178,6 +179,7 @@ private static void addFunction(String name, MainStyleFunction<?> func) {
addFunction("PrintEDIFInstances", PrintEDIFInstances::main);
addFunction("ProbeRouter", ProbeRouter::main);
addFunction("PseudoPIPHelper", PseudoPIPHelper::main);
addFunction("RelocationTools", RelocationTools::main);
addFunction("ReplaceEDIFInDCP", ReplaceEDIFInDCP::main);
addFunction("ReportDevicePerformance", ReportDevicePerformance::main);
addFunction("ReportTimingExample", ReportTimingExample::main);
Expand Down
140 changes: 132 additions & 8 deletions src/com/xilinx/rapidwright/design/tools/RelocationTools.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,21 @@

package com.xilinx.rapidwright.design.tools;

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
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.Module;
import com.xilinx.rapidwright.design.Net;
import com.xilinx.rapidwright.design.SiteInst;
import com.xilinx.rapidwright.design.SitePinInst;
Expand All @@ -35,16 +47,9 @@
import com.xilinx.rapidwright.device.Tile;
import com.xilinx.rapidwright.edif.EDIFHierCellInst;
import com.xilinx.rapidwright.edif.EDIFNetlist;
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 @@ -316,4 +321,123 @@ private static void revertPlacement(Map<SiteInst, Site> oldSite) {
e.getKey().place(e.getValue());
}
}

/**
* Based on the provided design, calculates all of the valid locations that the
* implemented component could be relocated to on the currently targeted device.
*
* @param design The design to evaluate for relocation options.
* @return A pair, where the first element is the anchor site selected in the
* design and the second element is a sorted map of placement options
* where the keys are ordered by increasing Manhattan distance (in tile
* (X,Y) coordinate values) from the original anchor site and the value
* is the potential relocated anchor site.
*/
public static Pair<Site, Map<Integer, Site>> getValidRelocationOptions(Design design) {
ArrayList<Site> validLocs = null;
Site anchor = null;

Module m = new Module(design);
anchor = m.getAnchor();
validLocs = m.calculateAllValidPlacements(m.getDevice());

if (validLocs == null || validLocs.size() < 2) {
return null;
}
Map<Integer, Site> options = new TreeMap<>();
for (Site s : validLocs) {
int validXOffset = anchor.getTile().getTileXCoordinate() - s.getTile().getTileXCoordinate();
int validYOffset = anchor.getTile().getTileYCoordinate() - s.getTile().getTileYCoordinate();
if (validXOffset == 0 && validYOffset == 0) {
continue;
}
options.put(Math.abs(validXOffset) + Math.abs(validYOffset), s);
}

return new Pair<Site, Map<Integer, Site>>(anchor, options);
}

/**
* Prints out valid relocation options produced by
* {@link #getValidRelocationOptions(Design)}.
*
* @param options The relocation options.
* @param limit Limit the number of printed options to this value.
*/
public static void printValidRelocationOptions(Pair<Site, Map<Integer, Site>> options, int limit, PrintStream ps) {
Site anchor = options.getFirst();
Map<Integer, Site> map = options.getSecond();
for (Entry<Integer, Site> e : map.entrySet()) {
int validXOffset = e.getValue().getTile().getTileXCoordinate() - anchor.getTile().getTileXCoordinate();
int validYOffset = e.getValue().getTile().getTileYCoordinate() - anchor.getTile().getTileYCoordinate();
ps.printf(" tileXOffset=%4d, tileYOffset=%4d anchorSite=%s/%s, newAnchorSite=%s/%s\n", validXOffset,
validYOffset, anchor.getTile(), anchor, e.getValue().getTile(), e.getValue());
if (limit-- == 0) {
break;
}
}
}

/**
* Offers a command line accessible way to relocate a design implementation. It
* can provide a list of valid relocation options for which full relocation is
* possible by providing just a single DCP as an option. Or, it will perform a
* best effort relocation (relocating as much as possible and
* unplacing/unrouting incompatible cells/routes) when provided a DCP, output
* location and set of offsets.
*
* @param args Two modes, for listing relocation options args[0]==<input.dcp>;
* for relocation (full or best effort partial)
* args[0]==<input.dcp>, args[1]==<output.dcp>,
* args[2]==<tile_x_offset>, args[3]==<tile_y_offset>.
*/
public static void main(String[] args) {
if (args.length != 4 && args.length != 1) {
System.out.println("USAGE (query valid relocation options): <input.dcp>");
System.out.println("USAGE (design relocation (full or partial): "
+ "<input.dcp> <output.dcp> <tile_x_offset> <tile_y_offset>");
return;
}
String inputDCPName = args[0];
Design d = Design.readCheckpoint(inputDCPName);
if (args.length == 1) {
Pair<Site, Map<Integer, Site>> options = getValidRelocationOptions(d);
if (options == null || options.getSecond().size() < 2) {
System.out.println("No valid relocation options for the provided DCP '" + inputDCPName + "'");
} else {
System.out.println("Possible Valid Relocation Options:");
printValidRelocationOptions(options, Integer.MAX_VALUE, System.out);
}
return;
}
String outputDCPName = args[1];
int tileXOffset = Integer.parseInt(args[2]);
int tileYOffset = Integer.parseInt(args[3]);

boolean success = relocate(d, "", tileXOffset, tileYOffset);

if (!success) {
Pair<Site, Map<Integer, Site>> options = null;
try {
options = getValidRelocationOptions(d);
} catch (Exception e) {
// Failed to identify any valid options, skip to throwing the error below
}

if (options != null && options.getSecond().size() > 1) {
System.err.println("Could not relocate to tileXOffset=" + tileXOffset + ", tileYOffset="
+ tileYOffset + ", here are some other valid options:");
int numOfValidSuggestions = 6;
printValidRelocationOptions(options, numOfValidSuggestions, System.err);
System.exit(1);
} else {
throw new RuntimeException("ERROR: Relocation of DCP '" + inputDCPName
+ "' has failed. It is possible that the tile X and Y offsets "
+ "are incompatible with the target device ("
+ d.getPartName() + ").");
}
}

d.writeCheckpoint(outputDCPName);
}
}
46 changes: 45 additions & 1 deletion 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-2023, Advanced Micro Devices, Inc.
* Copyright (c) 2022-2024, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Author: Eddie Hung, Xilinx Research Labs.
Expand All @@ -23,11 +23,13 @@

package com.xilinx.rapidwright.design;

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand All @@ -46,6 +48,8 @@
import com.xilinx.rapidwright.util.ReportRouteStatusResult;
import com.xilinx.rapidwright.util.VivadoTools;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
Expand Down Expand Up @@ -252,4 +256,44 @@ public static Stream<Arguments> testMicroBlazeAndILA() {
);
}

@Test
public void testRelocationTools(@TempDir Path dir) {
Design d = RapidWrightDCP.loadDCP("picoblaze_ooc_X10Y235_2022_1.dcp");
d.getNet("clk").unroute();
Path dcpName = dir.resolve("picoblaze_unrouted_clk.dcp");
d.writeCheckpoint(dcpName);

int xOffset = 0;
int yOffset = 5;

Path outputDCP = dir.resolve("output.dcp");

// Smoke test for valid location report mode
RelocationTools.main(new String[] { dcpName.toString() });

RelocationTools.main(new String[] {dcpName.toString(), outputDCP.toString(),
Integer.toString(xOffset), Integer.toString(yOffset)});

Design testOutput = Design.readCheckpoint(outputDCP);

for (SiteInst s : d.getSiteInsts()) {
Tile origin = s.getTile();
Tile relocated = origin.getTileXYNeighbor(xOffset, yOffset);
Site relocatedSite = relocated.getSites()[s.getSite().getSiteIndexInTile()];
SiteInst relocatedSiteInst = testOutput.getSiteInstFromSite(relocatedSite);
Assertions.assertNotNull(relocatedSiteInst);
Assertions.assertEquals(relocatedSiteInst.getCells().size(), s.getCells().size());
}
}

@Test
public void testGetValidRelocationOptions() {
Design d = RapidWrightDCP.loadDCP("picoblaze_ooc_X10Y235_2022_1.dcp");
d.getNet("clk").unroute();

Pair<Site, Map<Integer, Site>> relocOptions = RelocationTools.getValidRelocationOptions(d);

Assertions.assertNotNull(relocOptions);
Assertions.assertEquals(215, relocOptions.getSecond().size());
}
}

0 comments on commit bb99f28

Please sign in to comment.