diff --git a/src/com/xilinx/rapidwright/interchange/DeviceResourcesExample.java b/src/com/xilinx/rapidwright/interchange/DeviceResourcesExample.java index d95b4e4a8..c9fc1e156 100644 --- a/src/com/xilinx/rapidwright/interchange/DeviceResourcesExample.java +++ b/src/com/xilinx/rapidwright/interchange/DeviceResourcesExample.java @@ -31,21 +31,28 @@ public class DeviceResourcesExample { public static final String SKIP_ROUTE_RESOURCES_OPTION = "--skip_route_resources"; + public static final String VERIFY_OPTION = "--verify"; public static void main(String[] args) throws IOException { - if (args.length != 1 && args.length != 2) { - System.out.println("USAGE: [" + SKIP_ROUTE_RESOURCES_OPTION + "]"); + if (args.length < 1 || args.length > 3) { + System.out.println("USAGE: [" + SKIP_ROUTE_RESOURCES_OPTION + "] [" + VERIFY_OPTION + "]"); System.out.println(" Example dump of device information for interchange format."); return; } boolean skipRouteResources = false; - if (args.length == 2 && args[1].equals(SKIP_ROUTE_RESOURCES_OPTION)) { - skipRouteResources = true; + boolean verify = false; + for (int i = 1; i < args.length; i++) { + if (args[i].equals(SKIP_ROUTE_RESOURCES_OPTION)) { + skipRouteResources = true; + } else if (args[i].equals(VERIFY_OPTION)) { + verify = true; + } } CodePerfTracker t = new CodePerfTracker("Device Resources Dump: " + args[0]); - t.useGCToTrackMemory(true); + t.setReportingCurrOSMemUsage(true); + t.setTrackOSMemUsage(true); // Create device resource file if it doesn't exist String capnProtoFileName = args[0] + ".device"; @@ -56,10 +63,12 @@ public static void main(String[] args) throws IOException { DeviceResourcesWriter.writeDeviceResourcesFile(args[0], device, t, capnProtoFileName, skipRouteResources); Device.releaseDeviceReferences(); - t.start("Verify file"); - // Verify device resources - DeviceResourcesVerifier.verifyDeviceResources(capnProtoFileName, args[0]); + if (verify) { + // Verify device resources + DeviceResourcesVerifier.verifyDeviceResources(capnProtoFileName, args[0], t); + } - t.stop().printSummary(); + t.printSummary(); + System.out.println("Device resources file '" + capnProtoFileName + "' written successfully"); } } diff --git a/src/com/xilinx/rapidwright/interchange/DeviceResourcesVerifier.java b/src/com/xilinx/rapidwright/interchange/DeviceResourcesVerifier.java index 7bc81d3ea..b75312052 100644 --- a/src/com/xilinx/rapidwright/interchange/DeviceResourcesVerifier.java +++ b/src/com/xilinx/rapidwright/interchange/DeviceResourcesVerifier.java @@ -23,7 +23,11 @@ package com.xilinx.rapidwright.interchange; +import java.io.BufferedWriter; +import java.io.FileWriter; import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.channels.ReadableByteChannel; import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collections; @@ -55,6 +59,7 @@ import com.xilinx.rapidwright.device.Device; import com.xilinx.rapidwright.device.Grade; import com.xilinx.rapidwright.device.IOStandard; +import com.xilinx.rapidwright.device.Node; import com.xilinx.rapidwright.device.PIP; import com.xilinx.rapidwright.device.PIPType; import com.xilinx.rapidwright.device.Package; @@ -66,6 +71,7 @@ import com.xilinx.rapidwright.device.SiteTypeEnum; import com.xilinx.rapidwright.device.Tile; import com.xilinx.rapidwright.device.TileTypeEnum; +import com.xilinx.rapidwright.device.Wire; import com.xilinx.rapidwright.edif.EDIFCell; import com.xilinx.rapidwright.edif.EDIFCellInst; import com.xilinx.rapidwright.edif.EDIFDesign; @@ -90,6 +96,7 @@ import com.xilinx.rapidwright.interchange.LogicalNetlist.Netlist; import com.xilinx.rapidwright.interchange.LogicalNetlist.Netlist.Direction; import com.xilinx.rapidwright.interchange.LogicalNetlist.Netlist.PropertyMap; +import com.xilinx.rapidwright.tests.CodePerfTracker; import com.xilinx.rapidwright.util.Pair; public class DeviceResourcesVerifier { @@ -130,7 +137,9 @@ private static void verifyBelPin(StructList.Reader(); @@ -143,11 +152,13 @@ public static boolean verifyDeviceResources(String devResFileName, String device DeviceResources.Device.Reader dReader = null; ReaderOptions readerOptions = new ReaderOptions(1024L * 1024L * 1024L * 64L, 64); MessageReader readMsg = null; - readMsg = Interchange.readInterchangeFile(devResFileName, readerOptions); + ReadableByteChannel rbc = Interchange.getReadableByteChannel(devResFileName); + + readMsg = Interchange.readMessageFromChannel(rbc, readerOptions); dReader = readMsg.getRoot(DeviceResources.Device.factory); - boolean containsRoutingResources = dReader.getNodes().size() > 0; + boolean containsMultiMessageRoutingResources = !dReader.hasNodes(); int strCount = dReader.getStrList().size(); TextList.Reader reader = dReader.getStrList(); @@ -156,6 +167,8 @@ public static boolean verifyDeviceResources(String devResFileName, String device allStrings.addObject(str); } + t.stop().start("*Verify Tiles & Sites"); + // Create a lookup map for tile types Map tileTypeMap = new HashMap(); Map tileTypeEnumMap = new HashMap(); @@ -477,13 +490,15 @@ public static boolean verifyDeviceResources(String devResFileName, String device } } + t.stop().start("*Verify Libraries"); + Netlist.Reader primLibs = dReader.getPrimLibs(); LogNetlistReader netlistReader = new LogNetlistReader(allStrings, new HashMap() {{ put(LogNetlistWriter.DEVICE_PRIMITIVES_LIB, EDIFTools.EDIF_LIBRARY_HDI_PRIMITIVES_NAME); }} ); EDIFNetlist primsAndMacros = netlistReader.readLogNetlist(primLibs, - /*skipTopStuff=*/true, /*expandMacros=*/false); + /* skipTopStuff= */true, /* expandMacros= */false, CodePerfTracker.SILENT); Set libsFound = new HashSet(); libsFound.addAll(primsAndMacros.getLibrariesMap().keySet()); @@ -617,16 +632,87 @@ public static boolean verifyDeviceResources(String devResFileName, String device } } + t.stop().start("*Verify CellBelPins"); verifyCellBelPinMaps(allStrings, dReader, design); + t.stop().start("*Verify Packages"); verifyPackages(allStrings, dReader, device); - - if (containsRoutingResources) { - ConstantDefinitions.verifyConstants(allStrings, device, design, siteTypes, dReader.getConstants(), tileTypeEnumMap); + t.stop(); + + if (containsMultiMessageRoutingResources) { + t.start("*Verify Constants"); + ConstantDefinitions.verifyConstants(allStrings, device, design, siteTypes, + dReader.getConstants(), tileTypeEnumMap); + t.stop().start("*Verify Nodes & Wires"); + verifyWireAndNodeMultiMessage(device, allStrings, rbc, readerOptions); + t.stop(); } + rbc.close(); return true; } + + private static void verifyWireAndNodeMultiMessage(Device device, StringEnumerator allStrings, + ReadableByteChannel rbc, ReaderOptions options) { + int numOfMessages = device.getRows(); + + for (int row = 0; row < numOfMessages; row++) { + LongEnumerator allWires = new LongEnumerator(); + DeviceResources.Device.Reader deviceReader = null; + try { + MessageReader mReader = Interchange.readMessageFromChannel(rbc, options); + deviceReader = mReader.getRoot(DeviceResources.Device.factory); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + StructList.Reader wires = deviceReader.getWires(); + StructList.Reader nodeList = deviceReader.getNodes(); + + int wireIdx = 0; + int nodeIdx = 0; + for (Tile tile : device.getTiles()[row]) { + for (int i = 0; i < tile.getWireCount(); i++) { + Node node = Node.getNode(tile, i); + if (node == null) { + long nodeWireKey = DeviceResourcesWriter.makeKey(tile, i); + Integer test = allWires.maybeGetIndex(nodeWireKey); + if (test == null) { + allWires.addObject(nodeWireKey); + DeviceResources.Device.Wire.Reader readWire = wires.get(wireIdx++); + expect(tile.getName(), allStrings.get(readWire.getTile())); + expect(tile.getWireName(i), allStrings.get(readWire.getWire())); + expect(tile.getWireIntentCode(i).ordinal(), readWire.getType()); + } + }else if (node.getTile() == tile && node.getWireIndex() == i) { + Wire[] nodeWires = node.getAllWiresInNode(); + for (Wire w : nodeWires) { + long nodeWireKey = DeviceResourcesWriter.makeKey(w.getTile(), w.getWireIndex()); + Integer test = allWires.maybeGetIndex(nodeWireKey); + if (test == null) { + allWires.addObject(nodeWireKey); + DeviceResources.Device.Wire.Reader readWire = wires.get(wireIdx++); + expect(w.getTile().getName(), allStrings.get(readWire.getTile())); + expect(w.getWireName(), allStrings.get(readWire.getWire())); + expect(w.getIntentCode().ordinal(), readWire.getType()); + } + } + DeviceResources.Device.Node.Reader readNode = nodeList.get(nodeIdx++); + PrimitiveList.Int.Reader readNodeWires = readNode.getWires(); + expect(nodeWires.length, readNodeWires.size()); + for (int j = 0; j < nodeWires.length; j++) { + int wireKey = readNodeWires.get(j); + Long wireEntry = allWires.get(wireKey); + int tIdx = (int) (wireEntry >>> 32); + int wIdx = (int) (wireEntry & 0xFFFFFFFF); + expect(nodeWires[j].getTile().getUniqueAddress(), tIdx); + expect(nodeWires[j].getWireIndex(), wIdx); + } + } + } + } + } + } + private static HashSet verifiedSiteTypes; diff --git a/src/com/xilinx/rapidwright/interchange/DeviceResourcesWriter.java b/src/com/xilinx/rapidwright/interchange/DeviceResourcesWriter.java index dece8cbf3..2e0e3da6c 100644 --- a/src/com/xilinx/rapidwright/interchange/DeviceResourcesWriter.java +++ b/src/com/xilinx/rapidwright/interchange/DeviceResourcesWriter.java @@ -24,6 +24,8 @@ package com.xilinx.rapidwright.interchange; import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.channels.WritableByteChannel; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -297,10 +299,17 @@ public static void writeDeviceResourcesFile(String part, Device device, CodePerf t.stop().start("Tiles"); writeAllTilesToBuilder(device, devBuilder, tileTypeIndicies); - t.stop().start("Wires&Nodes"); - writeAllWiresAndNodesToBuilder(device, devBuilder, skipRouteResources); + if (skipRouteResources) { + // Let's set wires and nodes to size 0 + devBuilder.initWires(0); + devBuilder.initNodes(0); + } else { + // We'll add them as multiple messages after the main device message, one row of + // tiles' worth of wires and nodes at a time. We'll leave the wires and node + // field as an indicator that more messages will be present. + } - t.stop().start("Prims&Macros"); + t.stop().start("Prims & Macros"); // Create an EDIFNetlist populated with just primitive and macro libraries EDIFLibrary prims = Design.getPrimitivesLibrary(device.getName()); EDIFLibrary macros = Design.getMacroPrimitives(series); @@ -469,8 +478,15 @@ public static void writeDeviceResourcesFile(String part, Device device, CodePerf t.stop().start("Strings"); writeAllStringsToBuilder(devBuilder); - t.stop().start("Write File"); - Interchange.writeInterchangeFile(fileName, message); + t.stop().start("Write Device (single message)"); + WritableByteChannel wbc = Interchange.getWritableByteChannel(fileName); + Interchange.writeMessageToChannel(wbc, message); + + if (!skipRouteResources) { + t.stop().start("Write Wires & Nodes (multi-message)"); + writeAllWiresAndNodesToMultipleMessages(device, wbc); + } + wbc.close(); t.stop(); } @@ -809,12 +825,72 @@ public static void writeAllTilesToBuilder(Device device, DeviceResources.Device. } - private static long makeKey(Tile tile, int wire) { + protected static long makeKey(Tile tile, int wire) { long key = wire; key = (((long)tile.getUniqueAddress()) << 32) | key; return key; } + public static void writeAllWiresAndNodesToMultipleMessages(Device device, WritableByteChannel wbc) { + // Write one message for each row of tiles in the device + int numOfMessages = device.getRows(); + + for (int m = 0; m < numOfMessages; m++) { + MessageBuilder message = new MessageBuilder(); + DeviceResources.Device.Builder devBuilder = message.initRoot(DeviceResources.Device.factory); + + LongEnumerator allWires = new LongEnumerator(); + ArrayList allNodes = new ArrayList<>(); + + for (Tile tile : device.getTiles()[m]) { + for (int i = 0; i < tile.getWireCount(); i++) { + Node node = Node.getNode(tile, i); + if (node == null) { + allWires.addObject(makeKey(tile, i)); + } else if (node.getTile() == tile && node.getWireIndex() == i) { + allNodes.add(makeKey(node.getTile(), node.getWireIndex())); + Wire[] nodeWires = node.getAllWiresInNode(); + for (Wire w : nodeWires) { + allWires.addObject(makeKey(w.getTile(), w.getWireIndex())); + } + } + } + } + + StructList.Builder wireBuilders = devBuilder + .initWires(allWires.size()); + + for (int i = 0; i < allWires.size(); i++) { + DeviceResources.Device.Wire.Builder wireBuilder = wireBuilders.get(i); + long wireKey = allWires.get(i); + Wire wire = new Wire(device.getTile((int) (wireKey >>> 32)), (int) (wireKey & 0xffffffff)); + // Wire wire = allWires.get(i); + wireBuilder.setTile(allStrings.getIndex(wire.getTile().getName())); + wireBuilder.setWire(allStrings.getIndex(wire.getWireName())); + wireBuilder.setType(wire.getIntentCode().ordinal()); + } + + StructList.Builder nodeBuilders = devBuilder + .initNodes(allNodes.size()); + for (int i = 0; i < allNodes.size(); i++) { + DeviceResources.Device.Node.Builder nodeBuilder = nodeBuilders.get(i); + long nodeKey = allNodes.get(i); + Node node = Node.getNode(device.getTile((int) (nodeKey >>> 32)), (int) (nodeKey & 0xffffffff)); + Wire[] wires = node.getAllWiresInNode(); + PrimitiveList.Int.Builder wBuilders = nodeBuilder.initWires(wires.length); + for (int k = 0; k < wires.length; k++) { + wBuilders.set(k, allWires.maybeGetIndex(makeKey(wires[k].getTile(), wires[k].getWireIndex()))); + } + } + + try { + Interchange.writeMessageToChannel(wbc, message); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + } + public static void writeAllWiresAndNodesToBuilder(Device device, DeviceResources.Device.Builder devBuilder, boolean skipRouteResources) { LongEnumerator allWires = new LongEnumerator(); @@ -862,6 +938,7 @@ public static void writeAllWiresAndNodesToBuilder(Device device, DeviceResources } } } + private static void populatePackages(StringEnumerator allStrings, Device device, DeviceResources.Device.Builder devBuilder) { Set packages = device.getPackages(); List packagesList = new ArrayList(); diff --git a/src/com/xilinx/rapidwright/interchange/Interchange.java b/src/com/xilinx/rapidwright/interchange/Interchange.java index 76d33e631..5dba373cb 100644 --- a/src/com/xilinx/rapidwright/interchange/Interchange.java +++ b/src/com/xilinx/rapidwright/interchange/Interchange.java @@ -25,6 +25,7 @@ import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.UncheckedIOException; @@ -230,8 +231,14 @@ public static boolean isInterchangeFile(String fileName) { * @throws IOException */ public static void writeInterchangeFile(String fileName, MessageBuilder message) throws IOException { + WritableByteChannel wbc = getWritableByteChannel(fileName); + writeMessageToChannel(wbc, message); + wbc.close(); + } + + public static WritableByteChannel getWritableByteChannel(String fileName) + throws FileNotFoundException, IOException { WritableByteChannel wbc = null; - if (IS_GZIPPED) { GZIPOutputStream go = new GZIPOutputStream(new FileOutputStream(fileName)); wbc = Channels.newChannel(go); @@ -240,13 +247,15 @@ public static void writeInterchangeFile(String fileName, MessageBuilder message) FileOutputStream fo = new java.io.FileOutputStream(fileName); wbc = fo.getChannel(); } + return wbc; + } + + public static void writeMessageToChannel(WritableByteChannel wbc, MessageBuilder message) throws IOException { if (IS_PACKED) { SerializePacked.writeToUnbuffered(wbc, message); } else { Serialize.write(wbc, message); - } - - wbc.close(); + } } /** @@ -257,6 +266,14 @@ public static void writeInterchangeFile(String fileName, MessageBuilder message) * @throws IOException */ public static MessageReader readInterchangeFile(String fileName, ReaderOptions readOptions) throws IOException { + ReadableByteChannel channel = getReadableByteChannel(fileName); + MessageReader readMsg = readMessageFromChannel(channel, readOptions); + + channel.close(); + return readMsg; + } + + public static ReadableByteChannel getReadableByteChannel(String fileName) throws FileNotFoundException, IOException { ReadableByteChannel channel = null; if (IS_GZIPPED) { GZIPInputStream gis = new GZIPInputStream(new FileInputStream(fileName)); @@ -265,14 +282,17 @@ public static MessageReader readInterchangeFile(String fileName, ReaderOptions r FileInputStream fis = new java.io.FileInputStream(fileName); channel = fis.getChannel(); } + return channel; + } + + public static MessageReader readMessageFromChannel(ReadableByteChannel channel, ReaderOptions readOptions) + throws IOException { MessageReader readMsg = null; if (IS_PACKED) { readMsg = SerializePacked.readFromUnbuffered(channel, readOptions); } else { readMsg = Serialize.read(channel, readOptions); } - - channel.close(); return readMsg; } diff --git a/test/src/com/xilinx/rapidwright/interchange/TestDeviceResources.java b/test/src/com/xilinx/rapidwright/interchange/TestDeviceResources.java index 805ab3795..790393ad5 100644 --- a/test/src/com/xilinx/rapidwright/interchange/TestDeviceResources.java +++ b/test/src/com/xilinx/rapidwright/interchange/TestDeviceResources.java @@ -43,7 +43,7 @@ public void testDeviceResources(@TempDir Path tempDir) throws IOException { DeviceResourcesWriter.writeDeviceResourcesFile( TEST_DEVICE, device, CodePerfTracker.SILENT, capnProtoFile.toString()); Device.releaseDeviceReferences(); - DeviceResourcesVerifier.verifyDeviceResources(capnProtoFile.toString(), TEST_DEVICE); + DeviceResourcesVerifier.verifyDeviceResources(capnProtoFile.toString(), TEST_DEVICE, CodePerfTracker.SILENT); }