From e57f71de2a5108f5ec467dc75ed0ed81bae9f933 Mon Sep 17 00:00:00 2001 From: Chris Lavin Date: Wed, 27 Sep 2023 22:30:37 -0600 Subject: [PATCH 1/3] Enable RWRoute to load Interchange designs from main() Signed-off-by: Chris Lavin --- .../interchange/DcpToInterchange.java | 5 +- .../rapidwright/interchange/Interchange.java | 155 ++++++++++++++++++ .../xilinx/rapidwright/rwroute/RWRoute.java | 22 ++- .../xilinx/rapidwright/util/StringTools.java | 14 ++ .../rapidwright/rwroute/TestRWRoute.java | 43 +++++ .../rapidwright/util/TestStringTools.java | 36 ++++ 6 files changed, 266 insertions(+), 9 deletions(-) create mode 100644 test/src/com/xilinx/rapidwright/util/TestStringTools.java diff --git a/src/com/xilinx/rapidwright/interchange/DcpToInterchange.java b/src/com/xilinx/rapidwright/interchange/DcpToInterchange.java index f03de20ad..a187b2f42 100644 --- a/src/com/xilinx/rapidwright/interchange/DcpToInterchange.java +++ b/src/com/xilinx/rapidwright/interchange/DcpToInterchange.java @@ -24,7 +24,6 @@ import java.io.FileOutputStream; import java.io.IOException; -import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; @@ -43,8 +42,8 @@ public static void main(String[] args) throws IOException { Design design = Design.readCheckpoint(args[0]); String baseName = Paths.get(args[0]).getFileName().toString(); baseName = FileTools.removeFileExtension(baseName); - String logNetlistName = baseName + ".netlist"; - String physNetlistName = baseName + ".phys"; + String logNetlistName = baseName + Interchange.LOG_NETLIST_EXT; + String physNetlistName = baseName + Interchange.PHYS_NETLIST_EXT; String xdcName = baseName + ".xdc"; LogNetlistWriter.writeLogNetlist(design.getNetlist(), logNetlistName); diff --git a/src/com/xilinx/rapidwright/interchange/Interchange.java b/src/com/xilinx/rapidwright/interchange/Interchange.java index a3350f87c..d7150708a 100644 --- a/src/com/xilinx/rapidwright/interchange/Interchange.java +++ b/src/com/xilinx/rapidwright/interchange/Interchange.java @@ -23,10 +23,12 @@ package com.xilinx.rapidwright.interchange; +import com.xilinx.rapidwright.design.ConstraintGroup; import com.xilinx.rapidwright.design.Design; import com.xilinx.rapidwright.edif.EDIFNetlist; import com.xilinx.rapidwright.tests.CodePerfTracker; import com.xilinx.rapidwright.util.FileTools; +import com.xilinx.rapidwright.util.StringTools; import org.capnproto.MessageBuilder; import org.capnproto.MessageReader; import org.capnproto.ReaderOptions; @@ -36,11 +38,15 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; +import java.nio.charset.Charset; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.List; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; @@ -50,6 +56,155 @@ public class Interchange { public static boolean IS_PACKED = false; /** Flag indicating that files are gzipped on output */ public static boolean IS_GZIPPED = true; + /** Standard file extension for a logical netlist in the FPGA Interchange Format */ + public static final String LOG_NETLIST_EXT = ".netlist"; + /** Standard file extension for a physical netlist in the FPGA Interchange Format */ + public static final String PHYS_NETLIST_EXT = ".phys"; + + /** + * Reads an FPGA Interchange Format design from a specified file. The file could + * be a logical netlist or physical netlist and this method will assume the + * corresponding file with the same root name to load as a companion. If the + * provided name is a logical netlist and no physical netlist is found, it will + * only load the logical netlist. It will also load any XDC file with the same + * root name. + * + * @param fileName The logical or physical netlist filename. + * @return The loaded design. + */ + public static Design readInterchangeDesign(String fileName) { + String logFileName = fileName.endsWith(LOG_NETLIST_EXT) ? fileName : getExistingCompanionFile(fileName); + String physFileName = fileName.endsWith(PHYS_NETLIST_EXT) ? fileName : getExistingCompanionFile(fileName); + + if (logFileName == null) { + throw new RuntimeException("ERROR: Could not find logical netlist file: " + logFileName); + } + + String xdcFileName = StringTools.replaceExtension(logFileName, ".xdc"); + + return readInterchangeDesign(logFileName, physFileName, xdcFileName, false, null); + } + + /** + * Gets the existing Interchange companion file name based on the provided + * filename. For example, if the logical netlist file name is provided, it will + * return the physical netlist filename if it exists. If the physical netlist is + * provided, it returns the logical netlist filename if the file exists. + * + * @param fileName Name of an existing FPGA Interchange file (logical netlist + * with the {@link #LOG_NETLIST_EXT} extension or physical + * netlist with the {@link #PHYS_NETLIST_EXT}) + * @return The companion file if it exists or null if it could not be found. + */ + private static String getExistingCompanionFile(String fileName) { + String lowerFileName = fileName.toLowerCase(); + if (lowerFileName.endsWith(LOG_NETLIST_EXT)) { + String physFileName = StringTools.replaceExtension(fileName, PHYS_NETLIST_EXT); + if (new File(physFileName).exists()) { + return physFileName; + } + } else if (lowerFileName.endsWith(PHYS_NETLIST_EXT)) { + String logFileName = StringTools.replaceExtension(fileName, LOG_NETLIST_EXT); + if (new File(logFileName).exists()) { + return logFileName; + } + } + return null; + } + + /** + * Reads a set of existing FPGA Interchange files and returns a new design. + * + * @param logFileName The logical netlist file to be loaded. + * @param physFileName The physical netlist file to be loaded, this can be + * null for no placement or routing information. + * @param xdcFileName The constraints to associate with the design, this can + * be null for no constraints. + * @param isOutOfContext A flag indicating if the design should be marked out of + * context. + * @param t If using an existing CodePerfTracker, this allows + * continuity otherwise the default is null (an instance + * will be created each time) and will track runtime of + * each loading step. To silence this measurement, provide + * {@link CodePerfTracker#SILENT}). + * @return The newly created design based on the provided files. + */ + public static Design readInterchangeDesign(String logFileName, String physFileName, String xdcFileName, + boolean isOutOfContext, CodePerfTracker t) { + String msg = "Reading Interchange: " + logFileName; + CodePerfTracker tt = t == null ? new CodePerfTracker(msg, true) : t; + Design design = null; + try { + tt.start("Read Logical Netlist"); + EDIFNetlist n = LogNetlistReader.readLogNetlist(logFileName); + if (physFileName != null) { + tt.stop().start("Read Physical Netlist"); + design = PhysNetlistReader.readPhysNetlist(physFileName, n); + } else { + // No physical netlist information, let's attach the logical netlist to a new + // design + design = new Design(n); + } + if (xdcFileName != null) { + File xdcFile = new File(xdcFileName); + if (xdcFile.exists()) { + // Add XDC constraints + tt.stop().start("Read Constraints"); + List lines = Files.readAllLines(xdcFile.toPath(), Charset.defaultCharset()); + design.setXDCConstraints(lines, ConstraintGroup.NORMAL); + } + } + if (isOutOfContext) { + design.setAutoIOBuffers(false); + design.setDesignOutOfContext(true); + } + tt.stop().printSummary(); + return design; + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + /** + * Writes out a set of interchange files for the given design. It will write up + * to 3 files with the logical netlist always being written out. The two + * optional files are the physical netlist and XDC (constraints) file. + * + * @param design The design in memory to write out. + * @param rootFileName The root or common name among the output files. + */ + public static void writeDesignToInterchange(Design design, String rootFileName) { + String logFileName = rootFileName + LOG_NETLIST_EXT; + try { + LogNetlistWriter.writeLogNetlist(design.getNetlist(), logFileName); + + if (design.getSiteInsts().size() > 0 || design.getNets().size() > 0) { + String physFileName = rootFileName + PHYS_NETLIST_EXT; + PhysNetlistWriter.writePhysNetlist(design, physFileName); + } + + if (!design.getXDCConstraints(ConstraintGroup.NORMAL).isEmpty()) { + String xdcFileName = rootFileName + ".xdc"; + FileTools.writeLinesToTextFile(design.getXDCConstraints(ConstraintGroup.NORMAL), xdcFileName); + } + + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + /** + * Checks if the provided file name is a logical or physical FPGA Interchange + * file. + * + * @param fileName The file name in question. + * @return True if the file name matches the logical or physical netlist file + * name type. + */ + public static boolean isInterchangeFile(String fileName) { + String lowerFileName = fileName.toLowerCase(); + return lowerFileName.endsWith(LOG_NETLIST_EXT) || lowerFileName.endsWith(PHYS_NETLIST_EXT); + } /** * Common method to write out Interchange files diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index bd6a781b5..f63e77bc6 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -53,6 +53,7 @@ import com.xilinx.rapidwright.device.Tile; import com.xilinx.rapidwright.device.TileTypeEnum; import com.xilinx.rapidwright.edif.EDIFHierNet; +import com.xilinx.rapidwright.interchange.Interchange; import com.xilinx.rapidwright.router.RouteThruHelper; import com.xilinx.rapidwright.tests.CodePerfTracker; import com.xilinx.rapidwright.timing.ClkRouteTiming; @@ -1886,13 +1887,16 @@ protected static Design routeDesign(Design design, RWRoute router) { } /** - * The main interface of {@link RWRoute} that reads in a {@link Design} checkpoint, - * and parses the arguments for the {@link RWRouteConfig} object of the router. - * @param args An array of strings that are used to create a {@link RWRouteConfig} object for the router. + * The main interface of {@link RWRoute} that reads in a {@link Design} design + * (DCP or FPGA Interchange), and parses the arguments for the + * {@link RWRouteConfig} object of the router. + * + * @param args An array of strings that are used to create a + * {@link RWRouteConfig} object for the router. */ public static void main(String[] args) { if (args.length < 2) { - System.out.println("USAGE: "); + System.out.println("USAGE: "); return; } // Reads the output directory and set the output design checkpoint file name @@ -1900,9 +1904,15 @@ public static void main(String[] args) { CodePerfTracker t = new CodePerfTracker("RWRoute", true); - // Reads in a design checkpoint and routes it + // Reads in a design and routes it String[] rwrouteArgs = Arrays.copyOfRange(args, 2, args.length); - Design routed = routeDesignWithUserDefinedArguments(Design.readCheckpoint(args[0]), rwrouteArgs); + Design input = null; + if (Interchange.isInterchangeFile(args[0])) { + input = Interchange.readInterchangeDesign(args[0]); + } else { + input = Design.readCheckpoint(args[0]); + } + Design routed = routeDesignWithUserDefinedArguments(input, rwrouteArgs); // Writes out the routed design checkpoint routed.writeCheckpoint(routedDCPfileName,t); diff --git a/src/com/xilinx/rapidwright/util/StringTools.java b/src/com/xilinx/rapidwright/util/StringTools.java index 42924a50a..3edb5d839 100644 --- a/src/com/xilinx/rapidwright/util/StringTools.java +++ b/src/com/xilinx/rapidwright/util/StringTools.java @@ -159,6 +159,20 @@ public static String removeLastSeparator(String s) { return s; } + /** + * Replaces the file extension of the provided file name. The current extension + * includes the final period '.' and all characters following it. If the file + * has no extension, it will add it as a suffix to the filename. + * + * @param fileName Name of the file to receive the updated extension. + * @param newExtension The new extension (should include starting period '.') + * @return The newly updated file name. + */ + public static String replaceExtension(String fileName, String newExtension) { + int idx = fileName.lastIndexOf('.'); + return fileName.substring(0, idx == -1 ? fileName.length() : idx) + newExtension; + } + /** * Sorts strings using the 'natural' sort approach where numbers are sorted by * their magnitudes, i.e. {1,2,3,4,5,6,7,8,9,10,...} as opposed to strict ASCII diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java index ec00cc863..ef363ff08 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java @@ -23,6 +23,8 @@ package com.xilinx.rapidwright.rwroute; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -32,21 +34,26 @@ import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Disabled; 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.CsvSource; import org.junit.jupiter.params.provider.EnumSource; +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.Unisim; import com.xilinx.rapidwright.device.Device; import com.xilinx.rapidwright.device.Node; import com.xilinx.rapidwright.device.PIP; import com.xilinx.rapidwright.device.Part; import com.xilinx.rapidwright.device.PartNameTools; import com.xilinx.rapidwright.device.Series; +import com.xilinx.rapidwright.edif.EDIFTools; +import com.xilinx.rapidwright.interchange.Interchange; import com.xilinx.rapidwright.support.LargeTest; import com.xilinx.rapidwright.support.RapidWrightDCP; import com.xilinx.rapidwright.util.FileTools; @@ -316,4 +323,40 @@ public void testBug701() { Assertions.assertEquals(0, rrs.unroutedNets); } } + + private Design generateSmallPlacedDesign() { + Design d = new Design("HelloWorld", Device.KCU105); + + Cell and2 = d.createAndPlaceCell("and2", Unisim.AND2, "SLICE_X100Y100/A6LUT"); + Net net0 = d.createNet("button0_IBUF"); + net0.connect(and2, "O"); + net0.connect(and2, "I0"); + net0.connect(and2, "I1"); + + // Route site internal nets + d.routeSites(); + + EDIFTools.ensureCorrectPartInEDIF(d.getNetlist(), d.getPartName()); + return d; + } + + @Test + public void testRWRouteInterchange(@TempDir Path dir) { + Path rootFile = dir.resolve("interchange-design"); + Interchange.writeDesignToInterchange(generateSmallPlacedDesign(), rootFile.toString()); + Path outputFile = dir.resolve("output.dcp"); + RWRoute.main(new String[] { + rootFile.toString() + Interchange.LOG_NETLIST_EXT, + outputFile.toString(), + "--nonTimingDriven" + }); + Assertions.assertTrue(Files.exists(outputFile)); + Path outputFile2 = dir.resolve("output2.dcp"); + RWRoute.main(new String[] { + rootFile.toString() + Interchange.PHYS_NETLIST_EXT, + outputFile2.toString(), + "--nonTimingDriven", + }); + Assertions.assertTrue(Files.exists(outputFile2)); + } } diff --git a/test/src/com/xilinx/rapidwright/util/TestStringTools.java b/test/src/com/xilinx/rapidwright/util/TestStringTools.java new file mode 100644 index 000000000..4a95df469 --- /dev/null +++ b/test/src/com/xilinx/rapidwright/util/TestStringTools.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023, Advanced Micro Devices, Inc. + * All rights reserved. + * + * Author: Chris Lavin, AMD Research and Advanced 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.util; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TestStringTools { + + @Test + public void testReplaceExtension() { + Assertions.assertEquals("mydesign.phys", StringTools.replaceExtension("mydesign.netlist", ".phys")); + Assertions.assertEquals("mydesign.phys", StringTools.replaceExtension("mydesign", ".phys")); + Assertions.assertEquals("my.design.phys", StringTools.replaceExtension("my.design.dcp", ".phys")); + } +} From 9d3eee992c599b526e93712af07fdc8461a0f8dd Mon Sep 17 00:00:00 2001 From: Chris Lavin Date: Wed, 27 Sep 2023 22:34:22 -0600 Subject: [PATCH 2/3] Add back missing import Signed-off-by: Chris Lavin --- src/com/xilinx/rapidwright/interchange/Interchange.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/xilinx/rapidwright/interchange/Interchange.java b/src/com/xilinx/rapidwright/interchange/Interchange.java index d7150708a..74fb06ed2 100644 --- a/src/com/xilinx/rapidwright/interchange/Interchange.java +++ b/src/com/xilinx/rapidwright/interchange/Interchange.java @@ -35,6 +35,7 @@ import org.capnproto.Serialize; import org.capnproto.SerializePacked; +import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; From 5833173c284c4408c0afa938a2cf6fb0c2871731 Mon Sep 17 00:00:00 2001 From: Chris Lavin Date: Thu, 28 Sep 2023 11:34:49 -0600 Subject: [PATCH 3/3] Address review comments, remove redundant method Signed-off-by: Chris Lavin --- .../rapidwright/interchange/Interchange.java | 66 ++++++++++++------- .../xilinx/rapidwright/rwroute/RWRoute.java | 2 +- .../xilinx/rapidwright/util/FileTools.java | 10 ++- .../xilinx/rapidwright/util/StringTools.java | 14 ---- .../rapidwright/rwroute/TestRWRoute.java | 10 +-- .../rapidwright/util/TestStringTools.java | 36 ---------- 6 files changed, 52 insertions(+), 86 deletions(-) delete mode 100644 test/src/com/xilinx/rapidwright/util/TestStringTools.java diff --git a/src/com/xilinx/rapidwright/interchange/Interchange.java b/src/com/xilinx/rapidwright/interchange/Interchange.java index 74fb06ed2..76d33e631 100644 --- a/src/com/xilinx/rapidwright/interchange/Interchange.java +++ b/src/com/xilinx/rapidwright/interchange/Interchange.java @@ -23,18 +23,6 @@ package com.xilinx.rapidwright.interchange; -import com.xilinx.rapidwright.design.ConstraintGroup; -import com.xilinx.rapidwright.design.Design; -import com.xilinx.rapidwright.edif.EDIFNetlist; -import com.xilinx.rapidwright.tests.CodePerfTracker; -import com.xilinx.rapidwright.util.FileTools; -import com.xilinx.rapidwright.util.StringTools; -import org.capnproto.MessageBuilder; -import org.capnproto.MessageReader; -import org.capnproto.ReaderOptions; -import org.capnproto.Serialize; -import org.capnproto.SerializePacked; - import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -51,6 +39,18 @@ import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; +import org.capnproto.MessageBuilder; +import org.capnproto.MessageReader; +import org.capnproto.ReaderOptions; +import org.capnproto.Serialize; +import org.capnproto.SerializePacked; + +import com.xilinx.rapidwright.design.ConstraintGroup; +import com.xilinx.rapidwright.design.Design; +import com.xilinx.rapidwright.edif.EDIFNetlist; +import com.xilinx.rapidwright.tests.CodePerfTracker; +import com.xilinx.rapidwright.util.FileTools; + public class Interchange { /** Flag indicating use of Packed Cap'n Proto Serialization */ @@ -70,20 +70,36 @@ public class Interchange { * only load the logical netlist. It will also load any XDC file with the same * root name. * - * @param fileName The logical or physical netlist filename. + * @param fileName The name of the logical or physical netlist file. * @return The loaded design. */ public static Design readInterchangeDesign(String fileName) { - String logFileName = fileName.endsWith(LOG_NETLIST_EXT) ? fileName : getExistingCompanionFile(fileName); - String physFileName = fileName.endsWith(PHYS_NETLIST_EXT) ? fileName : getExistingCompanionFile(fileName); + return readInterchangeDesign(Paths.get(fileName)); + } + + /** + * Reads an FPGA Interchange Format design from a specified file. The file could + * be a logical netlist or physical netlist and this method will assume the + * corresponding file with the same root name to load as a companion. If the + * provided name is a logical netlist and no physical netlist is found, it will + * only load the logical netlist. It will also load any XDC file with the same + * root name. + * + * @param filePath The path to the logical or physical netlist file. + * @return The loaded design. + */ + public static Design readInterchangeDesign(Path filePath) { + String lowerName = filePath.toString().toLowerCase(); + Path logFileName = lowerName.endsWith(LOG_NETLIST_EXT) ? filePath : getExistingCompanionFile(filePath); + Path physFileName = lowerName.endsWith(PHYS_NETLIST_EXT) ? filePath : getExistingCompanionFile(filePath); if (logFileName == null) { throw new RuntimeException("ERROR: Could not find logical netlist file: " + logFileName); } - String xdcFileName = StringTools.replaceExtension(logFileName, ".xdc"); + String xdcFileName = FileTools.replaceExtension(logFileName, ".xdc").toString(); - return readInterchangeDesign(logFileName, physFileName, xdcFileName, false, null); + return readInterchangeDesign(logFileName.toString(), physFileName.toString(), xdcFileName, false, null); } /** @@ -92,21 +108,21 @@ public static Design readInterchangeDesign(String fileName) { * return the physical netlist filename if it exists. If the physical netlist is * provided, it returns the logical netlist filename if the file exists. * - * @param fileName Name of an existing FPGA Interchange file (logical netlist + * @param filePath Path of an existing FPGA Interchange file (logical netlist * with the {@link #LOG_NETLIST_EXT} extension or physical * netlist with the {@link #PHYS_NETLIST_EXT}) * @return The companion file if it exists or null if it could not be found. */ - private static String getExistingCompanionFile(String fileName) { - String lowerFileName = fileName.toLowerCase(); + private static Path getExistingCompanionFile(Path filePath) { + String lowerFileName = filePath.toString().toLowerCase(); if (lowerFileName.endsWith(LOG_NETLIST_EXT)) { - String physFileName = StringTools.replaceExtension(fileName, PHYS_NETLIST_EXT); - if (new File(physFileName).exists()) { + Path physFileName = FileTools.replaceExtension(filePath, PHYS_NETLIST_EXT); + if (Files.exists(physFileName)) { return physFileName; } } else if (lowerFileName.endsWith(PHYS_NETLIST_EXT)) { - String logFileName = StringTools.replaceExtension(fileName, LOG_NETLIST_EXT); - if (new File(logFileName).exists()) { + Path logFileName = FileTools.replaceExtension(filePath, LOG_NETLIST_EXT); + if (Files.exists(logFileName)) { return logFileName; } } @@ -167,7 +183,7 @@ public static Design readInterchangeDesign(String logFileName, String physFileNa } /** - * Writes out a set of interchange files for the given design. It will write up + * Writes out a set of Interchange files for the given design. It will write up * to 3 files with the logical netlist always being written out. The two * optional files are the physical netlist and XDC (constraints) file. * diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index f63e77bc6..3d4d2bcbe 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1896,7 +1896,7 @@ protected static Design routeDesign(Design design, RWRoute router) { */ public static void main(String[] args) { if (args.length < 2) { - System.out.println("USAGE: "); + System.out.println("USAGE: "); return; } // Reads the output directory and set the output design checkpoint file name diff --git a/src/com/xilinx/rapidwright/util/FileTools.java b/src/com/xilinx/rapidwright/util/FileTools.java index 190c90918..06786b02b 100644 --- a/src/com/xilinx/rapidwright/util/FileTools.java +++ b/src/com/xilinx/rapidwright/util/FileTools.java @@ -1997,7 +1997,15 @@ public static Path appendExtension(Path path, String extension) { return path.resolveSibling(path.getFileName().toString()+extension); } - + /** + * Replaces the file extension of the provided file name. The current extension + * includes the final period '.' and all characters following it. If the file + * has no extension, it will add it as a suffix to the filename. + * + * @param path Name of the file to receive the updated extension. + * @param newExtension The new extension (should include starting period '.') + * @return The newly updated file path. + */ public static Path replaceExtension(Path path, String newExtension) { String fn = path.getFileName().toString(); int idx = fn.lastIndexOf('.'); diff --git a/src/com/xilinx/rapidwright/util/StringTools.java b/src/com/xilinx/rapidwright/util/StringTools.java index 3edb5d839..42924a50a 100644 --- a/src/com/xilinx/rapidwright/util/StringTools.java +++ b/src/com/xilinx/rapidwright/util/StringTools.java @@ -159,20 +159,6 @@ public static String removeLastSeparator(String s) { return s; } - /** - * Replaces the file extension of the provided file name. The current extension - * includes the final period '.' and all characters following it. If the file - * has no extension, it will add it as a suffix to the filename. - * - * @param fileName Name of the file to receive the updated extension. - * @param newExtension The new extension (should include starting period '.') - * @return The newly updated file name. - */ - public static String replaceExtension(String fileName, String newExtension) { - int idx = fileName.lastIndexOf('.'); - return fileName.substring(0, idx == -1 ? fileName.length() : idx) + newExtension; - } - /** * Sorts strings using the 'natural' sort approach where numbers are sorted by * their magnitudes, i.e. {1,2,3,4,5,6,7,8,9,10,...} as opposed to strict ASCII diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java index ef363ff08..389892527 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java @@ -326,7 +326,6 @@ public void testBug701() { private Design generateSmallPlacedDesign() { Design d = new Design("HelloWorld", Device.KCU105); - Cell and2 = d.createAndPlaceCell("and2", Unisim.AND2, "SLICE_X100Y100/A6LUT"); Net net0 = d.createNet("button0_IBUF"); net0.connect(and2, "O"); @@ -346,17 +345,10 @@ public void testRWRouteInterchange(@TempDir Path dir) { Interchange.writeDesignToInterchange(generateSmallPlacedDesign(), rootFile.toString()); Path outputFile = dir.resolve("output.dcp"); RWRoute.main(new String[] { - rootFile.toString() + Interchange.LOG_NETLIST_EXT, + rootFile.toString() + Interchange.PHYS_NETLIST_EXT, outputFile.toString(), "--nonTimingDriven" }); Assertions.assertTrue(Files.exists(outputFile)); - Path outputFile2 = dir.resolve("output2.dcp"); - RWRoute.main(new String[] { - rootFile.toString() + Interchange.PHYS_NETLIST_EXT, - outputFile2.toString(), - "--nonTimingDriven", - }); - Assertions.assertTrue(Files.exists(outputFile2)); } } diff --git a/test/src/com/xilinx/rapidwright/util/TestStringTools.java b/test/src/com/xilinx/rapidwright/util/TestStringTools.java deleted file mode 100644 index 4a95df469..000000000 --- a/test/src/com/xilinx/rapidwright/util/TestStringTools.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2023, Advanced Micro Devices, Inc. - * All rights reserved. - * - * Author: Chris Lavin, AMD Research and Advanced 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.util; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class TestStringTools { - - @Test - public void testReplaceExtension() { - Assertions.assertEquals("mydesign.phys", StringTools.replaceExtension("mydesign.netlist", ".phys")); - Assertions.assertEquals("mydesign.phys", StringTools.replaceExtension("mydesign", ".phys")); - Assertions.assertEquals("my.design.phys", StringTools.replaceExtension("my.design.dcp", ".phys")); - } -}