From 4be67a642e24f1bb2fc48722943715f5b616703b Mon Sep 17 00:00:00 2001 From: eddieh-xlnx Date: Thu, 24 Oct 2024 15:39:55 -0700 Subject: [PATCH 01/71] Add ReportRouteStatus utility (#1087) * Add ReportRouteStatus utility Signed-off-by: Eddie Hung * Address review comments Signed-off-by: Eddie Hung * Update comments Signed-off-by: Eddie Hung * Add test Signed-off-by: Eddie Hung * Populate ReportRouteStatusResult.logicalNets Signed-off-by: Eddie Hung * Address review comments Signed-off-by: Eddie Hung * Tidy up Signed-off-by: Eddie Hung --------- Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/MainEntrypoint.java | 4 +- .../rapidwright/util/ReportRouteStatus.java | 121 ++++++++++++++++++ .../util/ReportRouteStatusResult.java | 71 ++++++++-- .../util/TestReportRouteStatus.java | 48 +++++++ 4 files changed, 229 insertions(+), 15 deletions(-) create mode 100644 src/com/xilinx/rapidwright/util/ReportRouteStatus.java create mode 100644 test/src/com/xilinx/rapidwright/util/TestReportRouteStatus.java diff --git a/src/com/xilinx/rapidwright/MainEntrypoint.java b/src/com/xilinx/rapidwright/MainEntrypoint.java index 12d80c350..6daad6dd1 100644 --- a/src/com/xilinx/rapidwright/MainEntrypoint.java +++ b/src/com/xilinx/rapidwright/MainEntrypoint.java @@ -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: Jakob Wenzel, Xilinx Research Labs. @@ -103,6 +103,7 @@ import com.xilinx.rapidwright.util.PartPrinter; import com.xilinx.rapidwright.util.PerformanceExplorer; import com.xilinx.rapidwright.util.ReplaceEDIFInDCP; +import com.xilinx.rapidwright.util.ReportRouteStatus; import com.xilinx.rapidwright.util.StringTools; import com.xilinx.rapidwright.util.Unzip; import com.xilinx.rapidwright.util.performance_evaluation.PerformanceEvaluation; @@ -186,6 +187,7 @@ private static void addFunction(String name, MainStyleFunction func) { addFunction("RelocationTools", RelocationTools::main); addFunction("ReplaceEDIFInDCP", ReplaceEDIFInDCP::main); addFunction("ReportDevicePerformance", ReportDevicePerformance::main); + addFunction("ReportRouteStatus", ReportRouteStatus::main); addFunction("ReportTimingExample", ReportTimingExample::main); addFunction("Router", Router::main); addFunction("RouteThruHelper", RouteThruHelper::main); diff --git a/src/com/xilinx/rapidwright/util/ReportRouteStatus.java b/src/com/xilinx/rapidwright/util/ReportRouteStatus.java new file mode 100644 index 000000000..74cf22f43 --- /dev/null +++ b/src/com/xilinx/rapidwright/util/ReportRouteStatus.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2024, Advanced Micro Devices, Inc. + * All rights reserved. + * + * Author: Eddie Hung, Advanced Micro Devices, Inc. + * + * 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 com.xilinx.rapidwright.design.Design; +import com.xilinx.rapidwright.design.DesignTools; +import com.xilinx.rapidwright.design.Net; +import com.xilinx.rapidwright.design.SitePinInst; +import com.xilinx.rapidwright.device.Node; +import com.xilinx.rapidwright.device.PIP; +import com.xilinx.rapidwright.rwroute.RouterHelper; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class ReportRouteStatus { + /** + * Compute the route status of given Design's physical nets by examining the + * {@link SitePinInst#isRouted()} state of each net's pins, as well as to discovering node conflicts + * between each net's PIPs. + * Freshly loaded designs, as well as designs that are not up-to-date, can call + * {@link DesignTools#updatePinsIsRouted(Design)} for recomputing the SitePinInst.isRouted() state. + * Note that currently this method does not check the Design's logical netlist nor its physical + * placement --- these are assumed to be correct. + * @param design Design to examine. + * @return ReportRouteStatusResult object. + */ + public static ReportRouteStatusResult reportRouteStatus(Design design) { + ReportRouteStatusResult rrs = new ReportRouteStatusResult(); + + Map nodesUsedByDesign = new HashMap<>(); + Set conflictingNets = new HashSet<>(); + + Collection nets = design.getNets(); + for (Net net : nets) { + if (!net.isStaticNet() && !RouterHelper.isRoutableNetWithSourceSinks(net)) { + rrs.netsNotNeedingRouting++; + continue; + } + rrs.routableNets++; + + boolean isFullyRouted = true; + boolean isPartiallyRouted = false; + for (SitePinInst spi : net.getPins()) { + if (spi.isRouted()) { + isPartiallyRouted = true; + continue; + } + isFullyRouted = false; + } + + boolean isConflictFree = true; + for (PIP pip : net.getPIPs()) { + Node endNode = pip.isReversed() ? pip.getStartNode() : pip.getEndNode(); + Net conflictingNet = nodesUsedByDesign.putIfAbsent(endNode, net); + if (conflictingNet != null && conflictingNet != net) { + conflictingNets.add(conflictingNet); + isConflictFree = false; + } + } + + if (!isConflictFree) { + conflictingNets.add(net); + } else if (!isFullyRouted) { + if (isPartiallyRouted) { + rrs.netsWithSomeUnroutedPins++; + } else { + rrs.unroutedNets++; + } + } + } + + rrs.logicalNets = nets.size(); + rrs.netsWithResourceConflicts = conflictingNets.size(); + rrs.netsWithRoutingErrors = rrs.netsWithSomeUnroutedPins + rrs.netsWithResourceConflicts; + rrs.fullyRoutedNets = rrs.routableNets - rrs.unroutedNets - rrs.netsWithRoutingErrors; + return rrs; + } + + public static void main(String[] args) { + if (args.length != 1) { + System.out.println("USAGE: ReportRouteStatus "); + System.exit(1); + } + + Design design = Design.readCheckpoint(args[0]); + + DesignTools.updatePinsIsRouted(design); + + ReportRouteStatusResult rrs = reportRouteStatus(design); + + System.out.println(); + System.out.println(rrs.toString("RapidWright Design Route Status")); + if (!rrs.isFullyRouted()) { + throw new RuntimeException("Design is not fully routed"); + } + } +} diff --git a/src/com/xilinx/rapidwright/util/ReportRouteStatusResult.java b/src/com/xilinx/rapidwright/util/ReportRouteStatusResult.java index a0de23aa7..0c3ee8228 100644 --- a/src/com/xilinx/rapidwright/util/ReportRouteStatusResult.java +++ b/src/com/xilinx/rapidwright/util/ReportRouteStatusResult.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Advanced Micro Devices, Inc. + * Copyright (c) 2023-2024, Advanced Micro Devices, Inc. * All rights reserved. * * Author: Zak Nafziger, Advanced Micro Devices, Inc. @@ -26,19 +26,20 @@ public class ReportRouteStatusResult { - public final int logicalNets; - public final int netsWithNoPlacedPins; - public final int netsNotNeedingRouting; - public final int internallyRoutedNets; - public final int netsWithNoLoads; - public final int implicitlyRoutedPorts; - public final int routableNets; - public final int unroutedNets; - public final int fullyRoutedNets; - public final int netsWithNoDriver; - public final int netsWithRoutingErrors; - public final int netsWithSomeUnplacedPins; - public final int netsWithSomeUnroutedPins; + public int logicalNets; + public int netsWithNoPlacedPins; + public int netsNotNeedingRouting; + public int internallyRoutedNets; + public int netsWithNoLoads; + public int implicitlyRoutedPorts; + public int routableNets; + public int unroutedNets; + public int fullyRoutedNets; + public int netsWithNoDriver; + public int netsWithRoutingErrors; + public int netsWithSomeUnplacedPins; + public int netsWithSomeUnroutedPins; + public int netsWithResourceConflicts; private static int parseLog(List log, String key) { List matchingLines = VivadoTools.searchVivadoLog(log, key); @@ -49,6 +50,9 @@ private static int parseLog(List log, String key) { return Integer.parseInt(matchingLines.get(0).replaceAll("[^\\d]", "")); } + public ReportRouteStatusResult() { + } + /** * Analyze a log file produced by Vivado's `report_route_status` * command. @@ -69,10 +73,49 @@ public ReportRouteStatusResult(List log) { netsWithRoutingErrors = parseLog(log, "# of nets with routing errors"); netsWithSomeUnplacedPins = parseLog(log, "# of nets with some unplaced pins"); netsWithSomeUnroutedPins = parseLog(log, "# of nets with some unrouted pins"); + netsWithResourceConflicts = parseLog(log, "# of nets with resource conflicts"); } public boolean isFullyRouted() { return logicalNets > 0 && unroutedNets == 0 && netsWithRoutingErrors == 0; } + @Override + public String toString() { + return toString("Design Route Status"); + } + + public String toString(String title) { + StringBuilder sb = new StringBuilder(); + sb.append(title); + sb.append("\n"); + sb.append(" : # nets :\n"); + sb.append(" ------------------------------------------- : ----------- :\n"); + sb.append(String.format(" # of logical nets.......................... : %11d :\n", logicalNets)); + sb.append(String.format(" # of nets not needing routing.......... : %11d :\n", netsNotNeedingRouting)); + if (internallyRoutedNets > 0) { + sb.append(String.format(" # of internally routed nets........ : %11d :\n", internallyRoutedNets)); + } + if (netsWithNoLoads > 0) { + sb.append(String.format(" # of nets with no loads............ : %11d :\n", netsWithNoLoads)); + } + if (implicitlyRoutedPorts > 0) { + sb.append(String.format(" # of implicitly routed ports....... : %11d :\n", implicitlyRoutedPorts)); + } + sb.append(String.format(" # of routable nets..................... : %11d :\n", routableNets)); + if (unroutedNets > 0) { + sb.append(String.format(" # of unrouted nets................. : %11d :\n", unroutedNets)); + } + sb.append(String.format(" # of fully routed nets............. : %11d :\n", fullyRoutedNets)); + sb.append(String.format(" # of nets with routing errors.......... : %11d :\n", netsWithRoutingErrors)); + if (netsWithSomeUnroutedPins > 0) { + sb.append(String.format(" # of nets with some unrouted pins.. : %11d :\n", netsWithSomeUnroutedPins)); + } + if (netsWithResourceConflicts > 0) { + sb.append(String.format(" # of nets with resource conflicts.. : %11d :\n", netsWithResourceConflicts)); + } + sb.append(" ------------------------------------------- : ----------- :"); + return sb.toString(); + } + } diff --git a/test/src/com/xilinx/rapidwright/util/TestReportRouteStatus.java b/test/src/com/xilinx/rapidwright/util/TestReportRouteStatus.java new file mode 100644 index 000000000..2b67bf4bf --- /dev/null +++ b/test/src/com/xilinx/rapidwright/util/TestReportRouteStatus.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024, Advanced Micro Devices, Inc. + * All rights reserved. + * + * Author: Eddie Hung, Advanced Micro Devices, Inc. + * + * 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 com.xilinx.rapidwright.design.Design; +import com.xilinx.rapidwright.design.DesignTools; +import com.xilinx.rapidwright.support.RapidWrightDCP; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TestReportRouteStatus { + @Test + public void testReportRouteStatusMain() { + String path = RapidWrightDCP.getString("picoblaze_ooc_X10Y235.dcp"); + ReportRouteStatus.main(new String[]{path}); + } + + @Test + public void testReportRouteStatus() { + Design design = RapidWrightDCP.loadDCP("optical-flow.dcp"); + DesignTools.createMissingSitePinInsts(design); + ReportRouteStatusResult rrs = ReportRouteStatus.reportRouteStatus(design); + Assertions.assertEquals(185996, rrs.logicalNets); + Assertions.assertEquals(58865, rrs.routableNets); + Assertions.assertEquals(58865, rrs.unroutedNets); + Assertions.assertEquals(0, rrs.netsWithRoutingErrors); + } +} From 94832b919664b8aa6498d2851d8549d2475131bd Mon Sep 17 00:00:00 2001 From: eddieh-xlnx Date: Fri, 25 Oct 2024 13:16:12 -0700 Subject: [PATCH 02/71] [EDIFWriteLegalNameCache] busCollisionRenames to be a ConcurrentHashMap (#1088) * [EDIFWriteLegalNameCache] busCollisionRenames to be a ConcurrentHashMap Signed-off-by: Eddie Hung * Use Supplier, bump copyright year Signed-off-by: Eddie Hung --------- Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/edif/EDIFWriteLegalNameCache.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/xilinx/rapidwright/edif/EDIFWriteLegalNameCache.java b/src/com/xilinx/rapidwright/edif/EDIFWriteLegalNameCache.java index b83662c57..4caef51b0 100644 --- a/src/com/xilinx/rapidwright/edif/EDIFWriteLegalNameCache.java +++ b/src/com/xilinx/rapidwright/edif/EDIFWriteLegalNameCache.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2022, Xilinx, Inc. - * Copyright (c) 2022, Advanced Micro Devices, Inc. + * Copyright (c) 2022, 2024, Advanced Micro Devices, Inc. * All rights reserved. * * Author: Jakob Wenzel, Xilinx Research Labs. @@ -60,7 +60,7 @@ private EDIFWriteLegalNameCache(Map usedRenames, Supplier(); + this.busCollisionRenames = renameSupplier.get(); } protected abstract int getAndIncrement(String rename); From 7d74c700496a719b33f1d125296f6ab8a9dfe981 Mon Sep 17 00:00:00 2001 From: eddieh-xlnx Date: Mon, 28 Oct 2024 17:29:50 -0700 Subject: [PATCH 03/71] [YosysTools] Add synthXilinx() wrapper for Yosys (#1086) * [FileTools] Add runCommand(String[] command, ...) overload Signed-off-by: Eddie Hung * [FileTools] Refactor getVivadoPath() into more general getPath() Signed-off-by: Eddie Hung * [YosysTools] Initial run() and synthXilinx() methods Signed-off-by: Eddie Hung * [TestYosysTools] Initial tests Signed-off-by: Eddie Hung * [FileTools] Smarter verbose printing Signed-off-by: Eddie Hung * Tidy up Signed-off-by: Eddie Hung * [FileTools] Add runCommand(String[] ...) & getPath(String) - FileTools.runCommand(String[] command, ...) is an array overload of FileTools.runCommand(String command, ...) for arguments with spaces in - FileTools.getPath(String) is the generalized guts of FileTools.getVivadoPath() Signed-off-by: Eddie Hung * Update copyright year Signed-off-by: Eddie Hung * Add javadoc Signed-off-by: Eddie Hung * Revert FileTools.java Signed-off-by: Eddie Hung * Revert "Update copyright year" This reverts commit 5482bfba0513e59d3641b25cbc0505bd3599ca97. Signed-off-by: Eddie Hung * Add and use YosysTools.isYosysOnPath() Signed-off-by: Eddie Hung * [FileTools] getPath -> getExecutablePath() Signed-off-by: Eddie Hung * Update to getExecutablePath() Signed-off-by: Eddie Hung * Add $scopeinfo workaround Signed-off-by: Eddie Hung * Use yosysExec Signed-off-by: Eddie Hung * Add comment Signed-off-by: Eddie Hung --------- Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/edif/YosysTools.java | 144 ++++++++++++++++++ .../rapidwright/edif/TestYosysTools.java | 127 +++++++++++++++ 2 files changed, 271 insertions(+) create mode 100644 src/com/xilinx/rapidwright/edif/YosysTools.java create mode 100644 test/src/com/xilinx/rapidwright/edif/TestYosysTools.java diff --git a/src/com/xilinx/rapidwright/edif/YosysTools.java b/src/com/xilinx/rapidwright/edif/YosysTools.java new file mode 100644 index 000000000..a88529ef7 --- /dev/null +++ b/src/com/xilinx/rapidwright/edif/YosysTools.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2024, Advanced Micro Devices, Inc. + * All rights reserved. + * + * Author: Eddie Hung, Advanced Micro Devices, Inc. + * + * 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.edif; + +import com.xilinx.rapidwright.util.FileTools; + +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +public class YosysTools { + public static final String yosysExec = "yosys"; + + public static final String SYNTH_XILINX = "synth_xilinx"; + + public static final String SYNTH_XILINX_FLAG_FAMILY_XCUP = " -family xcup"; + public static final String SYNTH_XILINX_FLAG_EDIF = " -edif "; + public static final String SYNTH_XILINX_FLAG_FLATTEN = " -flatten"; + public static final String SYNTH_XILINX_FLAG_OUT_OF_CONTEXT = " -noclkbuf -noiopad"; + + /** + * Run the given command string in Yosys, on the files given. + * @param command Yosys command(s), separated by ';' + * @param workDir Working directory + * @param paths Path objects of input files + */ + public static void run(String command, Path workDir, Path... paths) { + List exec = new ArrayList<>(); + exec.add(FileTools.getExecutablePath(yosysExec)); + exec.add("-p"); + exec.add(command); + for (Path path : paths) { + exec.add(path.toString()); + } + + boolean verbose = true; + String[] environ = null; + Integer exitCode = FileTools.runCommand(exec.toArray(new String[0]), verbose, environ, workDir.toFile()); + if (exitCode != 0) { + throw new RuntimeException("Yosys exited with code: " + exitCode); + } + } + + /** + * Call Yosys' 'synth_xilinx' command with the given flags on the files given. + * @param flags String with flags to be provided to 'synth_xilinx', in addition to + * '-edif /output.edf'. + * @param workDir Working directory + * @param paths Path objects of input files + * @return EDIFNetlist object of Yosys' result + */ + public static EDIFNetlist synthXilinxWithWorkDir(String flags, Path workDir, Path... paths) { + final Path edf = workDir.resolve("output.edf"); + String command = SYNTH_XILINX; + command += flags; + + // Workaround an issue in Yosys' EDIF writer where it may incorrectly emit $scopeinfo cells + // created during -flatten + // BEGIN WORKAROUND + command += "; delete t:$scopeinfo; "; + command += SYNTH_XILINX; + command += " -run edif:"; + // END WORKAROUND + + command += SYNTH_XILINX_FLAG_EDIF + edf; + run(command, workDir, paths); + return EDIFTools.readEdifFile(edf); + } + + /** + * Call Yosys' 'synth_xilinx' command with the default flags '-family xcvup -flatten + * -edif /output.edf' on the files given. + * @param workDir Working directory + * @param paths Path objects of input files + * @return EDIFNetlist object of Yosys' result + */ + public static EDIFNetlist synthXilinxWithWorkDir(Path workDir, Path... paths) { + return synthXilinxWithWorkDir(SYNTH_XILINX_FLAG_FAMILY_XCUP + SYNTH_XILINX_FLAG_FLATTEN, workDir, paths); + } + + /** + * Call Yosys' 'synth_xilinx' command with the given flags on the files given. + * @param flags String with flags to be provided to 'synth_xilinx', in addition to + * '-edif /output.edf'. + * @param paths Path objects of input files + * @return EDIFNetlist object of Yosys' result + */ + public static EDIFNetlist synthXilinx(String flags, Path... paths) { + final Path workDir = FileSystems.getDefault() + .getPath("yosysToolsWorkdir" + FileTools.getUniqueProcessAndHostID()); + workDir.toFile().mkdirs(); + + EDIFNetlist netlist = synthXilinxWithWorkDir(flags, workDir, paths); + + FileTools.deleteFolder(workDir.toString()); + return netlist; + } + + /** + * Call Yosys' 'synth_xilinx' command with the default flags '-family xcvup -flatten + * -edif /output.edf' on the files given. + * @param paths Path objects of input files + * @return EDIFNetlist object of Yosys' result + */ + public static EDIFNetlist synthXilinx(Path... paths) { + final Path workDir = FileSystems.getDefault() + .getPath("yosysToolsWorkdir" + FileTools.getUniqueProcessAndHostID()); + workDir.toFile().mkdirs(); + + EDIFNetlist netlist = synthXilinxWithWorkDir(workDir, paths); + + FileTools.deleteFolder(workDir.toString()); + return netlist; + } + + /** + * Checks if yosys is available on current PATH (uses unix 'which' or windows 'where'). + * @return true if yosys is on current PATH, false otherwise. + */ + public static boolean isYosysOnPath() { + return FileTools.isExecutableOnPath(yosysExec); + } +} diff --git a/test/src/com/xilinx/rapidwright/edif/TestYosysTools.java b/test/src/com/xilinx/rapidwright/edif/TestYosysTools.java new file mode 100644 index 000000000..02ed3d4f0 --- /dev/null +++ b/test/src/com/xilinx/rapidwright/edif/TestYosysTools.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2024, Advanced Micro Devices, Inc. + * All rights reserved. + * + * Author: Eddie Hung, Advanced Micro Devices, Inc. + * + * 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.edif; + +import com.xilinx.rapidwright.util.FileTools; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.nio.file.Path; +import java.util.Collection; + +public class TestYosysTools { + final String verilogFd = "" + + "module top(input clk, input d, output q);\n" + + "always @(posedge clk)\n" + + " q <= d;\n" + + "endmodule\n" + + ""; + + @Test + void testSynthXilinx(@TempDir Path workDir) { + // Skip test if yosys is not on PATH + Assumptions.assumeTrue(YosysTools.isYosysOnPath()); + + Path input = workDir.resolve("input.v"); + FileTools.writeStringToTextFile(verilogFd, input.toString()); + EDIFNetlist netlist = YosysTools.synthXilinxWithWorkDir(workDir, input); + EDIFCell top = netlist.getTopCell(); + Collection cellInsts = top.getCellInsts(); + Assertions.assertEquals(7, cellInsts.size()); + for (EDIFCellInst eci : cellInsts) { + String cellTypeName = eci.getCellType().getName(); + // 1xGND, 1xVCC + if (cellTypeName.equals("GND") || cellTypeName.equals("VCC")) { + continue; + } + // 2xIBUF, 1xOBUF + if (cellTypeName.equals("IBUF") || cellTypeName.equals("OBUF")) { + continue; + } + // 1xBUFG + if (cellTypeName.equals("BUFG")) { + continue; + } + // 1xFDRE + Assertions.assertEquals("FDRE", cellTypeName); + Assertions.assertEquals("$iopadmap$clk", eci.getPortInst("C").getNet().getName()); + Assertions.assertEquals("$iopadmap$d", eci.getPortInst("D").getNet().getName()); + Assertions.assertEquals("$iopadmap$q", eci.getPortInst("Q").getNet().getName()); + Assertions.assertEquals("GND_NET", eci.getPortInst("R").getNet().getName()); + Assertions.assertEquals("VCC_NET", eci.getPortInst("CE").getNet().getName()); + } + } + + final String verilogHier1 = "" + + "module top(input [5:0] i, output o);\n" + + "wire a;\n" + + "foo f(i, a);\n" + + "assign o = ~a;\n" + + "endmodule\n" + + ""; + + final String verilogHier2 = "" + + "module foo(input [5:0] i, output o);\n" + + "assign o = &i;\n" + + "endmodule\n" + + ""; + + @Test + void testSynthXilinxMultiFile(@TempDir Path workDir) { + // Skip test if yosys is not on PATH + Assumptions.assumeTrue(YosysTools.isYosysOnPath()); + + Path input1 = workDir.resolve("input1.v"); + FileTools.writeStringToTextFile(verilogHier1, input1.toString()); + + Path input2 = workDir.resolve("input2.v"); + FileTools.writeStringToTextFile(verilogHier2, input2.toString()); + + EDIFNetlist netlist = YosysTools.synthXilinxWithWorkDir(YosysTools.SYNTH_XILINX_FLAG_FAMILY_XCUP + + YosysTools.SYNTH_XILINX_FLAG_FLATTEN + + YosysTools.SYNTH_XILINX_FLAG_OUT_OF_CONTEXT, + workDir, input2, input1); + EDIFCell top = netlist.getTopCell(); + Assertions.assertEquals("top", top.getName()); + Collection cellInsts = top.getCellInsts(); + Assertions.assertEquals(3, cellInsts.size()); + for (EDIFCellInst eci : cellInsts) { + String cellTypeName = eci.getCellType().getName(); + if (cellTypeName.equals("GND") || cellTypeName.equals("VCC")) { + continue; + } + Assertions.assertEquals("LUT6", cellTypeName); + Assertions.assertEquals("f.i[0]", eci.getPortInst("I0").getNet().getName()); + Assertions.assertEquals("f.i[1]", eci.getPortInst("I1").getNet().getName()); + Assertions.assertEquals("f.i[2]", eci.getPortInst("I2").getNet().getName()); + Assertions.assertEquals("f.i[3]", eci.getPortInst("I3").getNet().getName()); + Assertions.assertEquals("f.i[4]", eci.getPortInst("I4").getNet().getName()); + Assertions.assertEquals("f.i[5]", eci.getPortInst("I5").getNet().getName()); + Assertions.assertEquals("o", eci.getPortInst("O").getNet().getName()); + // 6-input NAND + Assertions.assertEquals("string(64'h7fffffffffffffff)", eci.getProperty("INIT").toString()); + } + } +} From 191a9496e0de916f9c6d2738d5e984f2dd6f3322 Mon Sep 17 00:00:00 2001 From: eddieh-xlnx Date: Wed, 30 Oct 2024 20:43:51 -0700 Subject: [PATCH 04/71] [NetTools] Add getNodeTrees() method and NodeTree class (#1089) * [NetTools] Add getRouteTrees() method, and NodeTree class Signed-off-by: Eddie Hung * Add TestNetTools.testGetRouteTrees() Signed-off-by: Eddie Hung * [DesignTools] updatePinIsRouted() to use NetTools.getRouteTrees() Signed-off-by: Eddie Hung * Add javadoc and comments Signed-off-by: Eddie Hung * Skip source pins with no fanout Signed-off-by: Eddie Hung * Rename to NetTools.getNodeTrees() Signed-off-by: Eddie Hung --------- Signed-off-by: Eddie Hung --- .../rapidwright/design/DesignTools.java | 42 ++------ .../xilinx/rapidwright/design/NetTools.java | 98 +++++++++++++++++++ .../rapidwright/design/TestNetTools.java | 84 ++++++++++++++++ 3 files changed, 192 insertions(+), 32 deletions(-) diff --git a/src/com/xilinx/rapidwright/design/DesignTools.java b/src/com/xilinx/rapidwright/design/DesignTools.java index e3e00ad57..54d747d44 100644 --- a/src/com/xilinx/rapidwright/design/DesignTools.java +++ b/src/com/xilinx/rapidwright/design/DesignTools.java @@ -4317,49 +4317,27 @@ public static void updatePinsIsRouted(Net net) { return; } - Queue queue = new ArrayDeque<>(); - Map> node2fanout = new HashMap<>(); - for (PIP pip : net.getPIPs()) { - boolean isReversed = pip.isReversed(); - Node startNode = isReversed ? pip.getEndNode() : pip.getStartNode(); - Node endNode = isReversed ? pip.getStartNode() : pip.getEndNode(); - node2fanout.computeIfAbsent(startNode, k -> new ArrayList<>()) - .add(endNode); - if (pip.isBidirectional()) { - node2fanout.computeIfAbsent(endNode, k -> new ArrayList<>()) - .add(startNode); - } - - if ((net.getType() == NetType.GND && startNode.isTiedToGnd()) || - (net.getType() == NetType.VCC && startNode.isTiedToVcc())) { - queue.add(startNode); - } - } - Map node2spi = new HashMap<>(); for (SitePinInst spi : net.getPins()) { Node node = spi.getConnectedNode(); - if (spi.isOutPin()) { - if (node2fanout.get(node) == null) { - // Skip source pins with no fanout - continue; - } - queue.add(node); - } node2spi.put(node, spi); } + Queue queue = new ArrayDeque<>(); + for (NetTools.NodeTree node : NetTools.getNodeTrees(net)) { + if (node.fanouts.isEmpty()) { + // Skip source pins with no fanout + continue; + } + queue.add(node); + } while (!queue.isEmpty()) { - Node node = queue.poll(); + NetTools.NodeTree node = queue.poll(); SitePinInst spi = node2spi.get(node); if (spi != null) { spi.setRouted(true); } - - List fanouts = node2fanout.remove(node); - if (fanouts != null) { - queue.addAll(fanouts); - } + queue.addAll(node.fanouts); } } diff --git a/src/com/xilinx/rapidwright/design/NetTools.java b/src/com/xilinx/rapidwright/design/NetTools.java index a4b9996b9..827a6d18e 100644 --- a/src/com/xilinx/rapidwright/design/NetTools.java +++ b/src/com/xilinx/rapidwright/design/NetTools.java @@ -22,9 +22,16 @@ package com.xilinx.rapidwright.design; +import java.util.ArrayList; +import java.util.Collections; import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.Set; +import com.xilinx.rapidwright.device.Node; +import com.xilinx.rapidwright.device.PIP; import com.xilinx.rapidwright.device.SiteTypeEnum; public class NetTools { @@ -46,4 +53,95 @@ public static boolean isGlobalClock(Net net) { return clkSrcSiteTypeEnums.contains(srcSpi.getSiteTypeEnum()); } + + public static class NodeTree extends Node { + public List fanouts = Collections.emptyList(); + public NodeTree(Node node) { + super(node); + } + + public void addFanout(NodeTree node) { + if (fanouts.isEmpty()) { + fanouts = new ArrayList<>(1); + } + fanouts.add(node); + } + + private void buildString(StringBuilder sb, + boolean subtreeStart, + boolean branchStart, + boolean branchEndIfNoFanouts, + boolean subTreeEndIfNoFanouts) { + // Adopt the same spacing as Vivado's report_route_status + sb.append(" "); + sb.append(subtreeStart ? "[" : " "); + sb.append(branchStart ? "{" : " "); + sb.append(" "); + boolean branchEnd = branchEndIfNoFanouts && fanouts.isEmpty(); + sb.append(branchEnd ? "}" : " "); + boolean subtreeEnd = subTreeEndIfNoFanouts && branchEnd; + sb.append(subtreeEnd ? "]" : " "); + sb.append(String.format(" %30s", super.toString())); + sb.append("\n"); + + subtreeStart = false; + for (int i = 0; i < fanouts.size(); i++) { + NodeTree fanout = fanouts.get(i); + boolean lastFanout = (i == fanouts.size() - 1); + branchStart = !lastFanout && (fanouts.size() > 1); + branchEndIfNoFanouts = lastFanout || branchStart; + fanout.buildString(sb, subtreeStart, branchStart, branchEndIfNoFanouts, + subTreeEndIfNoFanouts && !branchStart && lastFanout); + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + boolean subtreeStart = true; + boolean branchStart = true; + boolean branchEndIfNoFanouts = true; + boolean subTreeEndIfNoFanouts = true; + buildString(sb, branchStart, subtreeStart, branchEndIfNoFanouts, subTreeEndIfNoFanouts); + return sb.toString(); + } + } + + /** + * Compute the node routing tree of the given Net by examining its PIPs. + * Note that this method: (a) assumes that no loops are present, (b) only discovers subtrees that start at an + * output SitePinInst or a node tied to VCC/GND (i.e. gaps and islands will be ignored). + * @param net Net to analyze + * @return A list of NodeTree objects, corresponding to the root of each subtree. + */ + public static List getNodeTrees(Net net) { + List subtrees = new ArrayList<>(); + Map nodeMap = new HashMap<>(); + for (PIP pip : net.getPIPs()) { + if (pip.isEndWireNull()) { + continue; + } + boolean isReversed = pip.isReversed(); + NodeTree startNode = nodeMap.computeIfAbsent(isReversed ? pip.getEndNode() : pip.getStartNode(), NodeTree::new); + NodeTree endNode = nodeMap.computeIfAbsent(isReversed ? pip.getStartNode() : pip.getEndNode(), NodeTree::new); + startNode.addFanout(endNode); + if (!pip.isBidirectional()) { + if ((net.getType() == NetType.GND && startNode.isTiedToGnd()) || + (net.getType() == NetType.VCC && startNode.isTiedToVcc())) { + subtrees.add(startNode); + } + } + } + + for (SitePinInst spi : net.getPins()) { + if (!spi.isOutPin()) { + continue; + } + Node node = spi.getConnectedNode(); + NodeTree nodeTree = nodeMap.computeIfAbsent(node, NodeTree::new); + subtrees.add(nodeTree); + } + + return subtrees; + } } diff --git a/test/src/com/xilinx/rapidwright/design/TestNetTools.java b/test/src/com/xilinx/rapidwright/design/TestNetTools.java index ec397b6a9..c3acdddc9 100644 --- a/test/src/com/xilinx/rapidwright/design/TestNetTools.java +++ b/test/src/com/xilinx/rapidwright/design/TestNetTools.java @@ -22,8 +22,10 @@ package com.xilinx.rapidwright.design; import java.util.HashSet; +import java.util.List; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; @@ -110,4 +112,86 @@ public void testisGlobalClock(String pathAndlobalClockNames) { } Assertions.assertEquals(globalClockNamesFromVivado,globalClockNamesFromNetTools); } + + @Test + public void testGetRouteTrees() { + Design design = RapidWrightDCP.loadDCP("picoblaze_ooc_X10Y235.dcp"); + Net net = design.getNet("processor/data_path_loop[0].output_data.sy_kk_mux_lut/O5"); + List trees = NetTools.getNodeTrees(net); + Assertions.assertEquals(1, trees.size()); + + // Taken directly from Vivado's report_route_status + String[] expected = new String( + " [{ CLEL_R_X10Y236/CLE_CLE_L_SITE_0_AMUX (65535) \n" + + " { INT_X10Y236/INT_NODE_SDQ_27_INT_OUT1 ( 3) INT_X10Y236/INT.LOGIC_OUTS_E21->INT_NODE_SDQ_27_INT_OUT1\n" + + " INT_X10Y236/SS1_E_BEG5 ( 0) INT_X10Y236/INT.INT_NODE_SDQ_27_INT_OUT1->>SS1_E_BEG5\n" + + " { INT_X10Y235/INT_NODE_IMUX_16_INT_OUT0 ( 5) INT_X10Y235/INT.SS1_E_END5->>INT_NODE_IMUX_16_INT_OUT0\n" + + " INT_X10Y235/BYPASS_E10 ( 3) INT_X10Y235/INT.INT_NODE_IMUX_16_INT_OUT0->>BYPASS_E10\n" + + " { INT_X10Y235/INT_NODE_IMUX_9_INT_OUT1 ( 0) INT_X10Y235/INT.BYPASS_E10->>INT_NODE_IMUX_9_INT_OUT1\n" + + " } INT_X10Y235/IMUX_E23 ( 6) INT_X10Y235/INT.INT_NODE_IMUX_9_INT_OUT1->>IMUX_E23\n" + + " INT_X10Y235/INT_NODE_IMUX_8_INT_OUT1 ( 0) INT_X10Y235/INT.BYPASS_E10->>INT_NODE_IMUX_8_INT_OUT1\n" + + " } INT_X10Y235/IMUX_E26 ( 6) INT_X10Y235/INT.INT_NODE_IMUX_8_INT_OUT1->>IMUX_E26\n" + + " { INT_X10Y235/INT_NODE_SDQ_28_INT_OUT0 ( 2) INT_X10Y235/INT.SS1_E_END5->INT_NODE_SDQ_28_INT_OUT0\n" + + " INT_X10Y235/EE1_E_BEG4 ( 3) INT_X10Y235/INT.INT_NODE_SDQ_28_INT_OUT0->>EE1_E_BEG4\n" + + " INT_X11Y235/INT_NODE_IMUX_48_INT_OUT0 ( 1) INT_X11Y235/INT.EE1_E_END4->>INT_NODE_IMUX_48_INT_OUT0\n" + + " } INT_X11Y235/IMUX_W37 ( 3) INT_X11Y235/INT.INT_NODE_IMUX_48_INT_OUT0->>IMUX_W37\n" + + " INT_X10Y235/INT_NODE_IMUX_16_INT_OUT1 ( 5) INT_X10Y235/INT.SS1_E_END5->>INT_NODE_IMUX_16_INT_OUT1\n" + + " { } INT_X10Y235/IMUX_E30 ( 3) INT_X10Y235/INT.INT_NODE_IMUX_16_INT_OUT1->>IMUX_E30\n" + + " } INT_X10Y235/IMUX_E31 ( 3) INT_X10Y235/INT.INT_NODE_IMUX_16_INT_OUT1->>IMUX_E31\n" + + " INT_X10Y236/INT_NODE_SDQ_29_INT_OUT1 ( 1) INT_X10Y236/INT.LOGIC_OUTS_E21->INT_NODE_SDQ_29_INT_OUT1\n" + + " { INT_X10Y236/NN2_E_BEG5 ( 0) INT_X10Y236/INT.INT_NODE_SDQ_29_INT_OUT1->>NN2_E_BEG5\n" + + " { INT_X10Y238/INT_NODE_IMUX_18_INT_OUT1 ( 4) INT_X10Y238/INT.NN2_E_END5->>INT_NODE_IMUX_18_INT_OUT1\n" + + " } INT_X10Y238/IMUX_E10 ( 4) INT_X10Y238/INT.INT_NODE_IMUX_18_INT_OUT1->>IMUX_E10\n" + + " { INT_X10Y238/INT_NODE_SDQ_30_INT_OUT1 ( 2) INT_X10Y238/INT.NN2_E_END5->INT_NODE_SDQ_30_INT_OUT1\n" + + " INT_X10Y238/EE1_E_BEG5 ( 0) INT_X10Y238/INT.INT_NODE_SDQ_30_INT_OUT1->>EE1_E_BEG5\n" + + " { INT_X11Y238/INT_NODE_SDQ_79_INT_OUT0 ( 0) INT_X11Y238/INT.EE1_E_END5->INT_NODE_SDQ_79_INT_OUT0\n" + + " INT_X11Y238/SS1_W_BEG5 ( 2) INT_X11Y238/INT.INT_NODE_SDQ_79_INT_OUT0->>SS1_W_BEG5\n" + + " INT_X11Y237/INT_NODE_IMUX_49_INT_OUT1 ( 4) INT_X11Y237/INT.SS1_W_END5->>INT_NODE_IMUX_49_INT_OUT1\n" + + " INT_X11Y237/BYPASS_W8 ( 5) INT_X11Y237/INT.INT_NODE_IMUX_49_INT_OUT1->>BYPASS_W8\n" + + " { INT_X11Y237/INT_NODE_IMUX_36_INT_OUT0 ( 0) INT_X11Y237/INT.BYPASS_W8->>INT_NODE_IMUX_36_INT_OUT0\n" + + " } INT_X11Y237/IMUX_W6 ( 2) INT_X11Y237/INT.INT_NODE_IMUX_36_INT_OUT0->>IMUX_W6\n" + + " { INT_X11Y237/INT_NODE_IMUX_37_INT_OUT0 ( 0) INT_X11Y237/INT.INT_NODE_IMUX_37_INT_OUT0<<->>BYPASS_W8\n" + + " } INT_X11Y237/IMUX_W7 ( 1) INT_X11Y237/INT.INT_NODE_IMUX_37_INT_OUT0->>IMUX_W7\n" + + " INT_X11Y237/INT_NODE_IMUX_36_INT_OUT1 ( 0) INT_X11Y237/INT.BYPASS_W8->>INT_NODE_IMUX_36_INT_OUT1\n" + + " { } INT_X11Y237/IMUX_W2 ( 4) INT_X11Y237/INT.INT_NODE_IMUX_36_INT_OUT1->>IMUX_W2\n" + + " { } INT_X11Y237/IMUX_W3 ( 2) INT_X11Y237/INT.INT_NODE_IMUX_36_INT_OUT1->>IMUX_W3\n" + + " INT_X11Y237/BOUNCE_W_2_FT1 ( 4) INT_X11Y237/INT.INT_NODE_IMUX_36_INT_OUT1->>BOUNCE_W_2_FT1\n" + + " INT_X11Y236/INODE_W_58_FT0 ( 0) INT_X11Y236/INT.BOUNCE_W_BLS_2_FT0->>INODE_W_58_FT0\n" + + " { } INT_X11Y237/IMUX_W0 ( 4) INT_X11Y237/INT.INODE_W_BLN_58_FT1->>IMUX_W0\n" + + " } INT_X11Y237/IMUX_W1 ( 2) INT_X11Y237/INT.INODE_W_BLN_58_FT1->>IMUX_W1\n" + + " INT_X11Y238/INT_NODE_IMUX_50_INT_OUT1 ( 1) INT_X11Y238/INT.EE1_E_END5->>INT_NODE_IMUX_50_INT_OUT1\n" + + " { INT_X11Y238/BYPASS_W10 ( 4) INT_X11Y238/INT.INT_NODE_IMUX_50_INT_OUT1->>BYPASS_W10\n" + + " INT_X11Y238/INT_NODE_IMUX_40_INT_OUT1 ( 0) INT_X11Y238/INT.BYPASS_W10->>INT_NODE_IMUX_40_INT_OUT1\n" + + " } INT_X11Y238/IMUX_W26 ( 4) INT_X11Y238/INT.INT_NODE_IMUX_40_INT_OUT1->>IMUX_W26\n" + + " } INT_X11Y238/IMUX_W36 ( 4) INT_X11Y238/INT.INT_NODE_IMUX_50_INT_OUT1->>IMUX_W36\n" + + " INT_X10Y238/INT_NODE_SDQ_30_INT_OUT0 ( 3) INT_X10Y238/INT.NN2_E_END5->INT_NODE_SDQ_30_INT_OUT0\n" + + " INT_X10Y238/NN1_E_BEG5 ( 2) INT_X10Y238/INT.INT_NODE_SDQ_30_INT_OUT0->>NN1_E_BEG5\n" + + " INT_X10Y239/INT_NODE_SDQ_30_INT_OUT0 ( 2) INT_X10Y239/INT.NN1_E_END5->INT_NODE_SDQ_30_INT_OUT0\n" + + " INT_X10Y239/EE2_E_BEG5 ( 3) INT_X10Y239/INT.INT_NODE_SDQ_30_INT_OUT0->>EE2_E_BEG5\n" + + " INT_X11Y239/INT_NODE_SDQ_27_INT_OUT0 ( 0) INT_X11Y239/INT.EE2_E_END5->INT_NODE_SDQ_27_INT_OUT0\n" + + " INT_X11Y239/INT_INT_SDQ_74_INT_OUT0 ( 2) INT_X11Y239/INT.INT_NODE_SDQ_27_INT_OUT0->>INT_INT_SDQ_74_INT_OUT0\n" + + " INT_X11Y239/INT_NODE_SDQ_73_INT_OUT0 ( 0) INT_X11Y239/INT.INT_INT_SDQ_74_INT_OUT0->INT_NODE_SDQ_73_INT_OUT0\n" + + " INT_X11Y239/SS1_W_BEG4 ( 3) INT_X11Y239/INT.INT_NODE_SDQ_73_INT_OUT0->>SS1_W_BEG4\n" + + " INT_X11Y238/INT_NODE_SDQ_72_INT_OUT0 ( 2) INT_X11Y238/INT.SS1_W_END4->INT_NODE_SDQ_72_INT_OUT0\n" + + " INT_X11Y238/SS1_W_BEG4 ( 2) INT_X11Y238/INT.INT_NODE_SDQ_72_INT_OUT0->>SS1_W_BEG4\n" + + " INT_X11Y237/INT_NODE_IMUX_46_INT_OUT0 ( 4) INT_X11Y237/INT.SS1_W_END4->>INT_NODE_IMUX_46_INT_OUT0\n" + + " { } INT_X11Y237/IMUX_W10 ( 2) INT_X11Y237/INT.INT_NODE_IMUX_46_INT_OUT0->>IMUX_W10\n" + + " } INT_X11Y237/IMUX_W11 ( 2) INT_X11Y237/INT.INT_NODE_IMUX_46_INT_OUT0->>IMUX_W11\n" + + " INT_X10Y236/INT_INT_SDQ_34_INT_OUT1 ( 0) INT_X10Y236/INT.INT_NODE_SDQ_29_INT_OUT1->>INT_INT_SDQ_34_INT_OUT1\n" + + " INT_X10Y236/INT_NODE_SDQ_82_INT_OUT0 ( 0) INT_X10Y236/INT.INT_INT_SDQ_34_INT_OUT1->INT_NODE_SDQ_82_INT_OUT0\n" + + " INT_X10Y236/INT_INT_SDQ_6_INT_OUT0 ( 2) INT_X10Y236/INT.INT_NODE_SDQ_82_INT_OUT0->>INT_INT_SDQ_6_INT_OUT0\n" + + " { INT_X10Y236/INT_NODE_GLOBAL_6_INT_OUT1 ( 4) INT_X10Y236/INT.INT_INT_SDQ_6_INT_OUT0->>INT_NODE_GLOBAL_6_INT_OUT1\n" + + " INT_X10Y236/INT_NODE_IMUX_9_INT_OUT0 ( 2) INT_X10Y236/INT.INT_NODE_GLOBAL_6_INT_OUT1->>INT_NODE_IMUX_9_INT_OUT0\n" + + " } INT_X10Y236/IMUX_E30 ( 6) INT_X10Y236/INT.INT_NODE_IMUX_9_INT_OUT0->>IMUX_E30\n" + + " INT_X10Y236/INT_NODE_IMUX_18_INT_OUT1 ( 1) INT_X10Y236/INT.INT_INT_SDQ_6_INT_OUT0->>INT_NODE_IMUX_18_INT_OUT1\n" + + " }] INT_X10Y236/IMUX_E35 ( 3) INT_X10Y236/INT.INT_NODE_IMUX_18_INT_OUT1->>IMUX_E35\n").split("\n"); + String[] actual = trees.get(0).toString().split("\n"); + Assertions.assertEquals(expected.length, actual.length); + for (int i = 0; i < expected.length; i++) { + // Remove all text after the first round bracket + int firstRoundBracket = expected[i].indexOf("("); + String expectedNodeOnly = expected[i].substring(0, firstRoundBracket - 1); + Assertions.assertEquals(expectedNodeOnly, actual[i]); + } + } } From b0487b0ac21a0f7f3d8b8ac1a235ce345831c818 Mon Sep 17 00:00:00 2001 From: Chris Lavin Date: Wed, 30 Oct 2024 21:48:29 -0600 Subject: [PATCH 05/71] [LUTTools] Add zero padding to LUT INIT strings (#1090) * Add zero padding to LUT INIT strings Signed-off-by: Chris Lavin * Ensure at least length 1 Signed-off-by: Chris Lavin --------- Signed-off-by: Chris Lavin --- .../xilinx/rapidwright/design/tools/LUTTools.java | 3 ++- .../rapidwright/design/tools/TestLUTTools.java | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/com/xilinx/rapidwright/design/tools/LUTTools.java b/src/com/xilinx/rapidwright/design/tools/LUTTools.java index 25101355d..3916c1edf 100644 --- a/src/com/xilinx/rapidwright/design/tools/LUTTools.java +++ b/src/com/xilinx/rapidwright/design/tools/LUTTools.java @@ -353,7 +353,8 @@ public static String getLUTInitFromEquation(String equation, int lutSize) { boolean result = b.eval(i); if (result) init = setBit(init,i); } - return length + "'h" + Long.toUnsignedString(init, 16).toUpperCase(); + int initLength = Integer.max(1, length >>> 2); + return length + "'h" + String.format("%0" + initLength + "x", init).toUpperCase(); } /** diff --git a/test/src/com/xilinx/rapidwright/design/tools/TestLUTTools.java b/test/src/com/xilinx/rapidwright/design/tools/TestLUTTools.java index fac3b1df2..7cabb2d9c 100644 --- a/test/src/com/xilinx/rapidwright/design/tools/TestLUTTools.java +++ b/test/src/com/xilinx/rapidwright/design/tools/TestLUTTools.java @@ -171,4 +171,16 @@ public void testUpdateLutPinSwapsFromPIPsWithRWRoute(String path, boolean lutPin System.setProperty("rapidwright.rwroute.lutPinSwapping.deferIntraSiteRoutingUpdates", "false"); } } + + @ParameterizedTest + @CsvSource({ + "O=I0 & !I1 & I2 & !I3 + !I0 & I1 & I2 & !I3 + I0 & !I1 & !I2 & I3 + !I0 & I1 & !I2 & I3,16'h0660,4", + "O=I0 & !I1 + !I0 & I1,4'h6,2", + "O=!I0 & !I1 & !I2 & !I3 + I0 & I1 & !I2 & !I3 + !I0 & !I1 & I2 & I3 + I0 & I1 & I2 & I3,16'h9009,4", + "O=I0 & I1 & I2 & I3 & I4 & I5,64'h8000000000000000,6", + "O=!I0 & !I1 & !I2 & !I3 & !I4 & !I5,64'h0000000000000001,6", + }) + public void testGetLUTInitFromEquation(String equation, String init, int lutSize) { + Assertions.assertEquals(init, LUTTools.getLUTInitFromEquation(equation, lutSize)); + } } From afed02838de104d2e95833117a1faf1f09cdffdd Mon Sep 17 00:00:00 2001 From: Chris Lavin Date: Fri, 1 Nov 2024 15:56:43 -0600 Subject: [PATCH 06/71] [HandPlacer] Cleanup snapping code in hand placer (#1091) * Cleanup snapping code in hand placer Signed-off-by: Chris Lavin * Fix PolynomialGenerator example line connection visualization Signed-off-by: Chris Lavin --------- Signed-off-by: Chris Lavin --- .../examples/PolynomialGenerator.java | 7 ++-- .../xilinx/rapidwright/gui/GUIModuleInst.java | 34 ++++++------------- src/com/xilinx/rapidwright/gui/TileScene.java | 3 ++ .../placer/handplacer/HandPlacer.java | 2 +- 4 files changed, 19 insertions(+), 27 deletions(-) diff --git a/src/com/xilinx/rapidwright/examples/PolynomialGenerator.java b/src/com/xilinx/rapidwright/examples/PolynomialGenerator.java index 9f7ec78aa..a3600f325 100644 --- a/src/com/xilinx/rapidwright/examples/PolynomialGenerator.java +++ b/src/com/xilinx/rapidwright/examples/PolynomialGenerator.java @@ -42,7 +42,6 @@ import com.xilinx.rapidwright.edif.EDIFCell; import com.xilinx.rapidwright.edif.EDIFCellInst; import com.xilinx.rapidwright.edif.EDIFDirection; -import com.xilinx.rapidwright.edif.EDIFLibrary; import com.xilinx.rapidwright.edif.EDIFNet; import com.xilinx.rapidwright.edif.EDIFNetlist; import com.xilinx.rapidwright.edif.EDIFPort; @@ -138,7 +137,7 @@ public static void buildOperatorTree(String[] tokens, Design d, EDIFPortInst[] r buildOperatorTree(left,d,inputA); - buildOperatorTree(right,d,inputB); + buildOperatorTree(right, d, inputB); } private static void ensureCellTypesSet(Module module) { @@ -379,6 +378,10 @@ public static Design generatePolynomial(String polynomial, String name, int widt buildOperatorTree(p, d, results); + // This is redundant if the design will be routed later, but is necessary + // for correct visualization in the Hand Placer tool + RWRoute.preprocess(d); + releaseOperators(); d.addXDCConstraint(ConstraintGroup.LATE, "create_clock -name "+CLK_NAME+" -period 1.291 [get_ports "+CLK_NAME+"]"); diff --git a/src/com/xilinx/rapidwright/gui/GUIModuleInst.java b/src/com/xilinx/rapidwright/gui/GUIModuleInst.java index 62e3946ba..02850874f 100644 --- a/src/com/xilinx/rapidwright/gui/GUIModuleInst.java +++ b/src/com/xilinx/rapidwright/gui/GUIModuleInst.java @@ -66,6 +66,8 @@ public class GUIModuleInst extends QGraphicsPolygonItem { private ArrayList occupiedTilesY; private ArrayList myLines; + public static int SNAPPING_DISTANCE = 100; + public GUIModuleInst(ModuleInst modInst, TileScene scene, boolean movable) { this.moduleInst = modInst; this.scene = scene; @@ -438,32 +440,22 @@ public void mouseDoubleClickEvent(QGraphicsSceneMouseEvent event) { public Object itemChange(GraphicsItemChange change, Object value) { if (change == GraphicsItemChange.ItemSelectedHasChanged) { selected.emit(QVariant.toBoolean(value)); - } else if (change == GraphicsItemChange.ItemPositionHasChanged - && scene() != null) { + } else if (change == GraphicsItemChange.ItemPositionHasChanged && scene() != null) { moved.emit(); - } else if (change == GraphicsItemChange.ItemPositionChange - && scene() != null) { + } else if (change == GraphicsItemChange.ItemPositionChange && scene() != null) { // value is the new position. - return makeValidPosition((QPointF) value); } return super.itemChange(change, value); } private Tile toTile(QPointF newPos) { - - //newPos = newPos.subtract(grabOffset); - - - QRectF rect = scene().sceneRect(); double width = this.boundingRect().width(); width = Math.floor(width / scene.tileSize); double height = this.boundingRect().height(); height = Math.floor(height / scene.tileSize); QPointF p = rect.bottomRight(); - //p.setX((fpScene.device.getColumns() - width) * fpScene.tileSize); - //p.setY((fpScene.device.getRows() - height) * fpScene.tileSize); p.setX((scene.cols - width) * scene.tileSize); p.setY((scene.rows - height) * scene.tileSize); @@ -479,30 +471,24 @@ private Tile toTile(QPointF newPos) { } private QPointF makeValidPosition(QPointF newPos) { - final Tile target = toTile(newPos); Tile result = null; - float bestDistance = Float.POSITIVE_INFINITY; + float closestValidPlacement = Float.POSITIVE_INFINITY; for (Site placement : moduleInst.getModule().getAllValidPlacements()) { float xDiff = placement.getTile().getColumn() - target.getColumn(); float yDiff = placement.getTile().getRow() - target.getRow(); float dist = xDiff * xDiff + yDiff * yDiff; - if (dist < bestDistance) { - bestDistance = dist; + if (dist < closestValidPlacement) { + closestValidPlacement = dist; result = placement.getTile(); } } - //Only snap to valid placement if it is close - if (bestDistance > 200) { - result = target; - } - - return new QPointF(scene.getDrawnTileX(result)*scene.tileSize, scene.getDrawnTileY(result)*scene.tileSize) - .subtract(getAnchorOffset()); - + // Only snap to valid placement if it is close + return closestValidPlacement > SNAPPING_DISTANCE ? scene.getTilePoint(target) + : scene.getTilePoint(result).subtract(getAnchorOffset()); } public boolean isGrabbed() { diff --git a/src/com/xilinx/rapidwright/gui/TileScene.java b/src/com/xilinx/rapidwright/gui/TileScene.java index 4e08a01b9..1d1a27fef 100644 --- a/src/com/xilinx/rapidwright/gui/TileScene.java +++ b/src/com/xilinx/rapidwright/gui/TileScene.java @@ -416,6 +416,9 @@ public int getDrawnTileY(Tile tile) { return tmp; } + public QPointF getTilePoint(Tile tile) { + return new QPointF(getDrawnTileX(tile) * tileSize, getDrawnTileY(tile) * tileSize); + } public Design getDesign() { return design; diff --git a/src/com/xilinx/rapidwright/placer/handplacer/HandPlacer.java b/src/com/xilinx/rapidwright/placer/handplacer/HandPlacer.java index a21e6f986..a9092ac84 100644 --- a/src/com/xilinx/rapidwright/placer/handplacer/HandPlacer.java +++ b/src/com/xilinx/rapidwright/placer/handplacer/HandPlacer.java @@ -79,7 +79,7 @@ public class HandPlacer extends QMainWindow { Device device; private QComboBox netViewCombo; - private static String title = "Hand HMPlacer"; + private static String title = "Hand Placer"; private String currOpenFileName = null; From f89c96e2f89d73acd62aea43ddd57ca626e3dab7 Mon Sep 17 00:00:00 2001 From: Wenhao Lin Date: Sun, 3 Nov 2024 23:30:42 -0700 Subject: [PATCH 07/71] Add optimization of signal routing Signed-off-by: Wenhao Lin --- .../xilinx/rapidwright/rwroute/RWRoute.java | 3 ++ .../rapidwright/rwroute/RouteNodeGraph.java | 53 +++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index d44b7edd4..2f2a72b89 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1802,6 +1802,9 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { if (!routingGraph.isAccessible(childRNode, connection)) { continue; } + if (!routingGraph.isAccessibleINODEAndCNODEOnVersal(rnode, childRNode, connection)) { + continue; + } if (!config.isUseUTurnNodes() && childRNode.getDelay() > 10000) { // To filter out those nodes that are considered to be excluded with the masking resource approach, // such as U-turn shape nodes near the boundary diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index e68ad6d8c..f5630a662 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -594,6 +594,59 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { return Math.abs(childTile.getTileYCoordinate() - sinkTile.getTileYCoordinate()) <= 1; } + public boolean isAccessibleINODEAndCNODEOnVersal(RouteNode rnode, RouteNode childRnode, Connection connection){ + // Below situations should not be skipped + if (design.getSeries() != Series.Versal) { + return true; + } + + RouteNode sinkRnode = connection.getSinkRnode(); + Tile sinkTile = sinkRnode.getTile(); + IntentCode childIntentCode = childRnode.getIntentCode(); + switch (childIntentCode) { + case NODE_INODE: + // Block access to all INODEs outside the sink tile, since NODE_INODE -> NODE_IMUX -> NODE_PINFEED (or NODE_INODE _> NODE_PINBOUNCE) + if (childRnode.getTile() != sinkTile) { + return false; + } + assert(sinkRnode.getIntentCode() == IntentCode.NODE_IMUX || sinkRnode.getIntentCode() == IntentCode.NODE_PINBOUNCE); + break; + case NODE_CLE_CNODE: + // Block access to all CNODEs outside the sink tile, since NODE_CLE_CNODE -> NODE_CLE_CTRL + if (childRnode.getTile() != sinkTile) { + return false; + } + assert(sinkRnode.getIntentCode() == IntentCode.NODE_CLE_CTRL); + break; + case NODE_INTF_CNODE: + // Block access to all CNODEs outside the sink tile, since NODE_INTF_CNODE -> NODE_INTF_CTRL + if (childRnode.getTile() != sinkTile) { + return false; + } + assert(sinkRnode.getIntentCode() == IntentCode.NODE_INTF_CTRL); + break; + default: + break; + } + + // TODO: Do we want to block NODE_PINBOUNCE if not in the sink INT tile? + // We have already blocked them in RWRoute.isAccessiblePinbounce. + + // TODO: Do we want to block all exploration of TileTypeEnum.CLE_BC_CORE and TileTypeEnum.INTF_[LR]OCF_[TB][LR]_TILE + // unless our sink is in that tile? (or is this already done by NODE_{CLE,INTF}_CNODE blocking above) + // No, we also need to take those neighbor CLE_BC_CORE tiles of the source tile. + // Furthermore, even if we don't take them into consideration, this is done by blocking CNODEs and BNODEs. + + // TODO: Is there any value in blocking NODE_{CLE,INTF}_BNODEs? + // We have already done this. Here is an invariant that NODE_{CLE, INTF}_BNODE -> {NODE_INODE, NODE_CLE_CTRL}, + // where NODE_CLE_CTRL must be a node that connects to the sink control pin. + // Since the sink rnode must not be the target, we only have INODEs here. However, those INODEs not located in the sink tile have been blocked. + + // TODO: What's special about nodes with wirename INT/OUT_[NESW]NODE_[EW]_*? + // Nothing special is found yet. + return true; + } + protected boolean allowRoutethru(Node head, Node tail) { if (!Utils.isCLB(tail.getTile().getTileTypeEnum())) { return false; From 57f39dfedf45744126eee4012f31161f287d5556 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 4 Nov 2024 09:49:10 -0800 Subject: [PATCH 08/71] Merge new method into RoutingGraph.isAccessible() Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/rwroute/RWRoute.java | 3 - .../rapidwright/rwroute/RouteNodeGraph.java | 114 +++++++++--------- 2 files changed, 57 insertions(+), 60 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 2f2a72b89..d44b7edd4 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1802,9 +1802,6 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { if (!routingGraph.isAccessible(childRNode, connection)) { continue; } - if (!routingGraph.isAccessibleINODEAndCNODEOnVersal(rnode, childRNode, connection)) { - continue; - } if (!config.isUseUTurnNodes() && childRNode.getDelay() > 10000) { // To filter out those nodes that are considered to be excluded with the masking resource approach, // such as U-turn shape nodes near the boundary diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index f5630a662..66deec30b 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -37,7 +37,6 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; import com.xilinx.rapidwright.design.Design; import com.xilinx.rapidwright.design.Net; @@ -109,10 +108,12 @@ public class RouteNodeGraph { /** Map indicating the wire indices corresponding to the [A-H]MUX output */ protected final Map muxWires; - /** Flag for whether LUT routethrus are to be considered - */ + /** Flag for whether LUT routethrus are to be considered */ protected final boolean lutRoutethru; + /** Flag for whether design targets the Versal series */ + protected final boolean isVersal; + public RouteNodeGraph(Design design, RWRouteConfig config) { this(design, config, new HashMap<>()); } @@ -286,6 +287,8 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map pins) { String pinName = pin.getName(); char lutLetter = pinName.charAt(0); String otherPinName = null; - String otherPinNameSuffix = design.getSeries() == Series.Versal ? "Q" : "MUX"; + String otherPinNameSuffix = isVersal ? "Q" : "MUX"; if (pinName.endsWith(otherPinNameSuffix)) { otherPinName = lutLetter + "_O"; } else if (pinName.endsWith("_O")) { @@ -573,6 +576,56 @@ public int averageChildren() { } public boolean isAccessible(RouteNode childRnode, Connection connection) { + if (isVersal) { + RouteNode sinkRnode = connection.getSinkRnode(); + Tile sinkTile = sinkRnode.getTile(); + IntentCode childIntentCode = childRnode.getIntentCode(); + switch (childIntentCode) { + case NODE_INODE: + // Block access to all INODEs outside the sink tile, since NODE_INODE -> NODE_IMUX -> NODE_PINFEED (or NODE_INODE _> NODE_PINBOUNCE) + if (childRnode.getTile() != sinkTile) { + return false; + } + assert(sinkRnode.getIntentCode() == IntentCode.NODE_IMUX || sinkRnode.getIntentCode() == IntentCode.NODE_PINBOUNCE); + break; + case NODE_CLE_CNODE: + // Block access to all CNODEs outside the sink tile, since NODE_CLE_CNODE -> NODE_CLE_CTRL + if (childRnode.getTile() != sinkTile) { + return false; + } + assert(sinkRnode.getIntentCode() == IntentCode.NODE_CLE_CTRL); + break; + case NODE_INTF_CNODE: + // Block access to all CNODEs outside the sink tile, since NODE_INTF_CNODE -> NODE_INTF_CTRL + if (childRnode.getTile() != sinkTile) { + return false; + } + assert(sinkRnode.getIntentCode() == IntentCode.NODE_INTF_CTRL); + break; + default: + break; + } + + // TODO: Do we want to block NODE_PINBOUNCE if not in the sink INT tile? + // We have already blocked them in RWRoute.isAccessiblePinbounce. + + // TODO: Do we want to block all exploration of TileTypeEnum.CLE_BC_CORE and TileTypeEnum.INTF_[LR]OCF_[TB][LR]_TILE + // unless our sink is in that tile? (or is this already done by NODE_{CLE,INTF}_CNODE blocking above) + // No, we also need to take those neighbor CLE_BC_CORE tiles of the source tile. + // Furthermore, even if we don't take them into consideration, this is done by blocking CNODEs and BNODEs. + + // TODO: Is there any value in blocking NODE_{CLE,INTF}_BNODEs? + // We have already done this. Here is an invariant that NODE_{CLE, INTF}_BNODE -> {NODE_INODE, NODE_CLE_CTRL}, + // where NODE_CLE_CTRL must be a node that connects to the sink control pin. + // Since the sink rnode must not be the target, we only have INODEs here. However, those INODEs not located in the sink tile have been blocked. + + // TODO: What's special about nodes with wirename INT/OUT_[NESW]NODE_[EW]_*? + // Nothing special is found yet. + return true; + } + + assert(design.getDevice().getSeries() == Series.UltraScale || design.getDevice().getSeries() == Series.UltraScalePlus); + Tile childTile = childRnode.getTile(); TileTypeEnum childTileType = childTile.getTileTypeEnum(); BitSet bs = accessibleWireOnlyIfAboveBelowTarget.get(childTileType); @@ -594,59 +647,6 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { return Math.abs(childTile.getTileYCoordinate() - sinkTile.getTileYCoordinate()) <= 1; } - public boolean isAccessibleINODEAndCNODEOnVersal(RouteNode rnode, RouteNode childRnode, Connection connection){ - // Below situations should not be skipped - if (design.getSeries() != Series.Versal) { - return true; - } - - RouteNode sinkRnode = connection.getSinkRnode(); - Tile sinkTile = sinkRnode.getTile(); - IntentCode childIntentCode = childRnode.getIntentCode(); - switch (childIntentCode) { - case NODE_INODE: - // Block access to all INODEs outside the sink tile, since NODE_INODE -> NODE_IMUX -> NODE_PINFEED (or NODE_INODE _> NODE_PINBOUNCE) - if (childRnode.getTile() != sinkTile) { - return false; - } - assert(sinkRnode.getIntentCode() == IntentCode.NODE_IMUX || sinkRnode.getIntentCode() == IntentCode.NODE_PINBOUNCE); - break; - case NODE_CLE_CNODE: - // Block access to all CNODEs outside the sink tile, since NODE_CLE_CNODE -> NODE_CLE_CTRL - if (childRnode.getTile() != sinkTile) { - return false; - } - assert(sinkRnode.getIntentCode() == IntentCode.NODE_CLE_CTRL); - break; - case NODE_INTF_CNODE: - // Block access to all CNODEs outside the sink tile, since NODE_INTF_CNODE -> NODE_INTF_CTRL - if (childRnode.getTile() != sinkTile) { - return false; - } - assert(sinkRnode.getIntentCode() == IntentCode.NODE_INTF_CTRL); - break; - default: - break; - } - - // TODO: Do we want to block NODE_PINBOUNCE if not in the sink INT tile? - // We have already blocked them in RWRoute.isAccessiblePinbounce. - - // TODO: Do we want to block all exploration of TileTypeEnum.CLE_BC_CORE and TileTypeEnum.INTF_[LR]OCF_[TB][LR]_TILE - // unless our sink is in that tile? (or is this already done by NODE_{CLE,INTF}_CNODE blocking above) - // No, we also need to take those neighbor CLE_BC_CORE tiles of the source tile. - // Furthermore, even if we don't take them into consideration, this is done by blocking CNODEs and BNODEs. - - // TODO: Is there any value in blocking NODE_{CLE,INTF}_BNODEs? - // We have already done this. Here is an invariant that NODE_{CLE, INTF}_BNODE -> {NODE_INODE, NODE_CLE_CTRL}, - // where NODE_CLE_CTRL must be a node that connects to the sink control pin. - // Since the sink rnode must not be the target, we only have INODEs here. However, those INODEs not located in the sink tile have been blocked. - - // TODO: What's special about nodes with wirename INT/OUT_[NESW]NODE_[EW]_*? - // Nothing special is found yet. - return true; - } - protected boolean allowRoutethru(Node head, Node tail) { if (!Utils.isCLB(tail.getTile().getTileTypeEnum())) { return false; From 74df32407f4711fca20b742abaaf3d7352cb4f6d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 4 Nov 2024 10:22:51 -0800 Subject: [PATCH 09/71] Fix typo Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 66deec30b..056eedaa4 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -582,7 +582,7 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { IntentCode childIntentCode = childRnode.getIntentCode(); switch (childIntentCode) { case NODE_INODE: - // Block access to all INODEs outside the sink tile, since NODE_INODE -> NODE_IMUX -> NODE_PINFEED (or NODE_INODE _> NODE_PINBOUNCE) + // Block access to all INODEs outside the sink tile, since NODE_INODE -> NODE_IMUX -> NODE_PINFEED (or NODE_INODE -> NODE_PINBOUNCE) if (childRnode.getTile() != sinkTile) { return false; } From 3bf9cb9cd58cd8b9ad63c2f17d8eb48806c57629 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 4 Nov 2024 10:23:02 -0800 Subject: [PATCH 10/71] Add TestNode.testNodeReachabilityVersal() to check assumptions Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/device/TestNode.java | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/test/src/com/xilinx/rapidwright/device/TestNode.java b/test/src/com/xilinx/rapidwright/device/TestNode.java index 2b24b6544..bcfb0ba22 100644 --- a/test/src/com/xilinx/rapidwright/device/TestNode.java +++ b/test/src/com/xilinx/rapidwright/device/TestNode.java @@ -145,6 +145,7 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str if (!Utils.isInterConnect(downhill.getTile().getTileTypeEnum())) { continue; } + // Check that they are all in the same column Assertions.assertEquals(baseTile.getTileXCoordinate(), downhill.getTile().getTileXCoordinate()); queue.add(downhill); @@ -153,6 +154,68 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str System.out.println("visited.size() = " + visited.size()); } + @ParameterizedTest + @CsvSource({ + "xcvp1002,INT_X38Y220,NODE_PINBOUNCE", + "xcvp1002,INT_X38Y220,NODE_INODE", + "xcvp1002,INT_X38Y220,NODE_IMUX", + "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_BNODE", + "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_CNODE", + }) + public void testNodeReachabilityVersal(String partName, String tileName, String intentCodeName) { + Device device = Device.getDevice(partName); + Tile baseTile = device.getTile(tileName); + Queue queue = new ArrayDeque<>(); + IntentCode ic = IntentCode.valueOf(intentCodeName); + for (int wireIdx = 0; wireIdx < baseTile.getWireCount(); wireIdx++) { + if (baseTile.getWireIntentCode(wireIdx) != ic) { + continue; + } + queue.add(Node.getNode(baseTile, wireIdx)); + } + System.out.println("Initial queue.size() = " + queue.size()); + System.out.println("Initial queue = " + queue); + + // Print out the intent code of nodes that are immediately uphill of this intent code + System.out.println("Immediately uphill:"); + queue.stream().map(Node::getAllUphillNodes).flatMap(List::stream).map(Node::getIntentCode) + .distinct() + .sorted() + .forEachOrdered(s -> System.out.println("\t" + s)); + + // Print out the intent code of nodes that are immediately downhill of this intent code + System.out.println("Immediately downhill:"); + queue.stream().map(Node::getAllDownhillNodes).flatMap(List::stream).map(Node::getIntentCode) + .distinct() + .sorted() + .forEachOrdered(s -> System.out.println("\t" + s)); + + Set visited = new HashSet<>(); + while (!queue.isEmpty()) { + Node node = queue.poll(); + for (Node downhill : node.getAllDownhillNodes()) { + if (!visited.add(downhill)) { + continue; + } + if (!Utils.isInterConnect(downhill.getTile().getTileTypeEnum())) { + continue; + } + // All INT-to-INT connections should be to the same tile + if (baseTile.getTileTypeEnum() == TileTypeEnum.CLE_BC_CORE) { + // Except CLE_BC_CORE tiles which spans two adjacent INT tiles + if (baseTile != downhill.getTile()) { + Assertions.assertTrue(1 >= Math.abs(baseTile.getTileXCoordinate() - downhill.getTile().getTileXCoordinate())); + Assertions.assertEquals(TileTypeEnum.INT, downhill.getTile().getTileTypeEnum()); + } + } else { + Assertions.assertEquals(baseTile, downhill.getTile()); + } + queue.add(downhill); + } + } + System.out.println("visited.size() = " + visited.size()); + } + @ParameterizedTest @CsvSource({ // https://github.com/Xilinx/RapidWright/issues/983 From bf4d0763f45cfdeb0200db607b312a1fa8d96674 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 4 Nov 2024 10:47:05 -0800 Subject: [PATCH 11/71] Add NODE_CLE_OUTPUT too Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/device/TestNode.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/test/src/com/xilinx/rapidwright/device/TestNode.java b/test/src/com/xilinx/rapidwright/device/TestNode.java index bcfb0ba22..952b83c35 100644 --- a/test/src/com/xilinx/rapidwright/device/TestNode.java +++ b/test/src/com/xilinx/rapidwright/device/TestNode.java @@ -24,6 +24,7 @@ import java.util.ArrayDeque; import java.util.Collection; +import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Queue; @@ -161,6 +162,8 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str "xcvp1002,INT_X38Y220,NODE_IMUX", "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_BNODE", "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_CNODE", + "xcvp1002,CLE_E_CORE_X38Y220,NODE_CLE_OUTPUT", + "xcvp1002,CLE_W_CORE_X38Y220,NODE_CLE_OUTPUT", }) public void testNodeReachabilityVersal(String partName, String tileName, String intentCodeName) { Device device = Device.getDevice(partName); @@ -190,6 +193,7 @@ public void testNodeReachabilityVersal(String partName, String tileName, String .sorted() .forEachOrdered(s -> System.out.println("\t" + s)); + TileTypeEnum baseTileTypeEnum = baseTile.getTileTypeEnum(); Set visited = new HashSet<>(); while (!queue.isEmpty()) { Node node = queue.poll(); @@ -200,8 +204,24 @@ public void testNodeReachabilityVersal(String partName, String tileName, String if (!Utils.isInterConnect(downhill.getTile().getTileTypeEnum())) { continue; } + if (Utils.isCLB(baseTileTypeEnum)) { + if (EnumSet.of(IntentCode.NODE_VLONG7, IntentCode.NODE_VLONG12, IntentCode.NODE_HLONG10, IntentCode.NODE_HLONG6).contains(downhill.getIntentCode())) { + // Ignore long wires that obviously leave the tile + } else { + // All other wires should have the same X coordinate, if not the same Y + Assertions.assertEquals(baseTile.getTileXCoordinate(), downhill.getTile().getTileXCoordinate()); + if (baseTile.getTileYCoordinate() != downhill.getTile().getTileYCoordinate()) { + // Only exception for Y are specific NODE_SDQNODEs with the following wire name + Assertions.assertTrue(downhill.getWireName().matches("OUT_[NEWS]NODE_[EW]_\\d+")); + Assertions.assertEquals(IntentCode.NODE_SDQNODE, downhill.getIntentCode()); + Assertions.assertTrue(1 >= Math.abs(baseTile.getTileYCoordinate() - downhill.getTile().getTileYCoordinate())); + } + } + // Do not descend further + continue; + } // All INT-to-INT connections should be to the same tile - if (baseTile.getTileTypeEnum() == TileTypeEnum.CLE_BC_CORE) { + if (baseTileTypeEnum == TileTypeEnum.CLE_BC_CORE) { // Except CLE_BC_CORE tiles which spans two adjacent INT tiles if (baseTile != downhill.getTile()) { Assertions.assertTrue(1 >= Math.abs(baseTile.getTileXCoordinate() - downhill.getTile().getTileXCoordinate())); From 1f8a9d3105846529bb70f01c163e28298981d9fb Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 4 Nov 2024 15:06:49 -0800 Subject: [PATCH 12/71] Expand TestNode.testNodeReachabilityUltraScale() Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/device/TestNode.java | 81 +++++++++++++------ 1 file changed, 56 insertions(+), 25 deletions(-) diff --git a/test/src/com/xilinx/rapidwright/device/TestNode.java b/test/src/com/xilinx/rapidwright/device/TestNode.java index 2b24b6544..301e39e90 100644 --- a/test/src/com/xilinx/rapidwright/device/TestNode.java +++ b/test/src/com/xilinx/rapidwright/device/TestNode.java @@ -24,6 +24,7 @@ import java.util.ArrayDeque; import java.util.Collection; +import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Queue; @@ -83,45 +84,61 @@ public void testUphillNodeIsInvalid() { @ParameterizedTest @CsvSource({ // UltraScale+ part - "xcvu3p,INT_X37Y220,BOUNCE_", - "xcvu3p,INT_X37Y220,BYPASS_", - "xcvu3p,INT_X37Y220,INT_NODE_GLOBAL_", - "xcvu3p,INT_X37Y220,INT_NODE_IMUX_", - "xcvu3p,INT_X37Y220,INODE_", - // These nodes fanout to NESW nodes in the tile above or below - // "xcvu3p,INT_X37Y220,SDQNODE_", + "xcvu3p,INT_X37Y220,BOUNCE_.*", + "xcvu3p,INT_X37Y220,BYPASS_.*", + "xcvu3p,INT_X37Y220,INT_NODE_GLOBAL_.*", + "xcvu3p,INT_X37Y220,INT_NODE_IMUX_.*", + "xcvu3p,INT_X37Y220,INODE_.*", + "xcvu3p,INT_X37Y220,INT_INT_SDQ_.*", // IntentCode.NODE_SINGLE + "xcvu3p,INT_X37Y220,INT_NODE_SDQ_.*", + "xcvu3p,INT_X37Y220,SDQNODE_.*", + "xcvu3p,INT_X37Y220,IMUX_.*", + "xcvu3p,INT_X37Y220,CTRL_.*", + "xcvu3p,CLEM_X37Y220,CLE_CLE_M_SITE_0_[A-H](_O|Q|Q2|MUX)", // UltraScale part - "xcvu065,INT_X38Y220,BOUNCE_", - "xcvu065,INT_X38Y220,BYPASS_", - "xcvu065,INT_X38Y220,INT_NODE_GLOBAL_", - "xcvu065,INT_X38Y220,INT_NODE_IMUX_", - "xcvu065,INT_X38Y220,INODE_", - // "xcvu065,INT_X38Y220,QLND", - // "xcvu065,INT_X38Y220,SDND", + "xcvu065,INT_X38Y220,BOUNCE_.*", + "xcvu065,INT_X38Y220,BYPASS_.*", + "xcvu065,INT_X38Y220,INT_NODE_GLOBAL_.*", + "xcvu065,INT_X38Y220,INT_NODE_IMUX_.*", + "xcvu065,INT_X38Y220,INODE_.*", + "xcvu065,INT_X38Y220,INT_INT_SINGLE_.*", // IntentCode.NODE_SINGLE + "xcvu065,INT_X38Y220,INT_NODE_SINGLE_DOUBLE_.*", + "xcvu065,INT_X38Y220,INT_NODE_QUAD_LONG_.*", + "xcvu065,INT_X38Y220,IMUX_.*", + "xcvu065,INT_X38Y220,CTRL_.*", + "xcvu065,INT_X38Y220,QLND.*", + "xcvu065,INT_X38Y220,SDND.*", + "xcvu065,CLE_M_X38Y220,CLE_CLE_M_SITE_0_[A-H](_O|Q|Q2|MUX)", }) - public void testNodeReachabilityUltraScale(String partName, String tileName, String wirePrefix) { + public void testNodeReachabilityUltraScale(String partName, String tileName, String wireRegex) { Device device = Device.getDevice(partName); Tile baseTile = device.getTile(tileName); Queue queue = new ArrayDeque<>(); + Set intentCodes = EnumSet.noneOf(IntentCode.class); for (String wireName : baseTile.getWireNames()) { - if (!wireName.startsWith(wirePrefix)) { + if (!wireName.matches(wireRegex)) { continue; } - queue.add(Node.getNode(baseTile, wireName)); + Node node = Node.getNode(baseTile, wireName); + queue.add(node); + intentCodes.add(node.getIntentCode()); } System.out.println("Initial queue.size() = " + queue.size()); + System.out.println("Intent codes = " + intentCodes); // Print out the prefixes of nodes that are immediately uphill of these wire prefixes // (i.e. "BOUNCE_E_0_FT1" -> "BOUNCE_") System.out.println("Immediately uphill:"); - queue.stream().map(Node::getAllUphillNodes).flatMap(List::stream).map(Node::getWireName) - .map(s -> s.replaceFirst("((BOUNCE|BYPASS|CTRL|INT_NODE_[^_]+|INODE)_).*", "$1")) + boolean ultraScalePlus = partName.endsWith("p"); + queue.stream().map(Node::getAllUphillNodes).flatMap(List::stream) + .map(n -> n.getWireName() + " (" + n.getIntentCode() + ")") + .map(s -> s.replaceFirst("((BOUNCE|BYPASS|CTRL|INT_NODE_[^_]+|INODE|IMUX|SDQNODE)_)[^\\(]+", "$1")) .map(s -> s.replaceFirst( - // UltraScale+ - (partName.endsWith("p")) ? "((CLE_CLE_[LM]_SITE_0|CLK_LEAF_SITES|EE[124]|INT_INT_SDQ|NN[12]|SS[12]|WW[124])_).*" - // UltraScale - : "((CLE_CLE_[LM]_SITE_0|CLK_BUFCE_LEAF_X16_1_CLK|EE[124]|INT_INT_SINGLE|NN[12]|SS[12]|WW[124])_).*", + // UltraScale+ + ultraScalePlus ? "((CLE_CLE_[LM]_SITE_0|CLK_LEAF_SITES|INT_INT_SDQ|(NN|EE|SS|WW)(1|2|4|12))_)[^\\(]+" + // UltraScale + : "((CLE_CLE_[LM]_SITE_0|CLK_BUFCE_LEAF_X16_1_CLK|EE[124]|INT_INT_SINGLE|(NN|SS)(1|2|4|5|12|16)|(EE|WW)(1|2|4|12)|SDND[NS]W)_)[^\\(]+", "$1")) .distinct() .sorted() @@ -129,8 +146,15 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str // Print out the prefixes of nodes that are immediately downhill of these wire prefixes System.out.println("Immediately downhill:"); - queue.stream().map(Node::getAllDownhillNodes).flatMap(List::stream).map(Node::getWireName) - .map(s -> s.replaceFirst("((BOUNCE|BYPASS|CTRL|IMUX|INT_NODE_[^_]+|INODE)_).*", "$1")) + queue.stream().map(Node::getAllDownhillNodes).flatMap(List::stream) + .map(n -> n.getWireName() + " (" + n.getIntentCode() + ")") + .map(s -> s.replaceFirst("((BOUNCE|BYPASS|CTRL|IMUX|INT_NODE_[^_]+|INODE|SDQNODE)_)[^\\(]+", "$1")) + .map(s -> s.replaceFirst( + // UltraScale+ + ultraScalePlus ? "((CLE_CLE_[LM]_SITE_0|INT_INT_SDQ|(NN|EE|SS|WW)(1|2|4|12))_)[^\\(]+" + // UltraScale + : "((INT_INT_SINGLE|(NN|SS)(1|2|4|5|12|16)|(EE|WW)(1|2|4|12)|QLND(NW|SE)|SDND[NS]W)_)[^\\(]+", + "$1")) .distinct() .sorted() .forEachOrdered(s -> System.out.println("\t" + s)); @@ -138,6 +162,13 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str Set visited = new HashSet<>(); while (!queue.isEmpty()) { Node node = queue.poll(); + String wireName = node.getWireName(); + if ((ultraScalePlus && wireName.matches("(INT_NODE_SDQ|SDQNODE)_.*")) || // UltraScale+ + (!ultraScalePlus && wireName.matches("(INT_NODE_(SINGLE_DOUBLE|QUAD_LONG)|QLND(NW|SE|SW)|SDND[NS]W)_.*")) // UltraScale + ) { + // Do not desccend into SDQNODEs + continue; + } for (Node downhill : node.getAllDownhillNodes()) { if (!visited.add(downhill)) { continue; From bba91e13ccdddc589d613146850392193ce9cc9c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 4 Nov 2024 16:00:02 -0800 Subject: [PATCH 13/71] More Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/device/TestNode.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/test/src/com/xilinx/rapidwright/device/TestNode.java b/test/src/com/xilinx/rapidwright/device/TestNode.java index 301e39e90..3bdb07caf 100644 --- a/test/src/com/xilinx/rapidwright/device/TestNode.java +++ b/test/src/com/xilinx/rapidwright/device/TestNode.java @@ -94,6 +94,10 @@ public void testUphillNodeIsInvalid() { "xcvu3p,INT_X37Y220,SDQNODE_.*", "xcvu3p,INT_X37Y220,IMUX_.*", "xcvu3p,INT_X37Y220,CTRL_.*", + "xcvu3p,INT_X37Y220,(NN|EE|SS|WW)1_.*", + "xcvu3p,INT_X37Y220,(NN|EE|SS|WW)2_.*", + "xcvu3p,INT_X37Y220,(NN|EE|SS|WW)4_.*", + "xcvu3p,INT_X37Y220,(NN|EE|SS|WW)12_.*", "xcvu3p,CLEM_X37Y220,CLE_CLE_M_SITE_0_[A-H](_O|Q|Q2|MUX)", // UltraScale part @@ -107,6 +111,12 @@ public void testUphillNodeIsInvalid() { "xcvu065,INT_X38Y220,INT_NODE_QUAD_LONG_.*", "xcvu065,INT_X38Y220,IMUX_.*", "xcvu065,INT_X38Y220,CTRL_.*", + "xcvu065,INT_X37Y220,(NN|EE|SS|WW)1_.*", + "xcvu065,INT_X37Y220,(NN|EE|SS|WW)2_.*", + "xcvu065,INT_X37Y220,(NN|EE|SS|WW)4_.*", + "xcvu065,INT_X37Y220,(NN|EE|SS|WW)5_.*", + "xcvu065,INT_X37Y220,(NN|EE|SS|WW)12_.*", + "xcvu065,INT_X37Y220,(NN|EE|SS|WW)16_.*", "xcvu065,INT_X38Y220,QLND.*", "xcvu065,INT_X38Y220,SDND.*", "xcvu065,CLE_M_X38Y220,CLE_CLE_M_SITE_0_[A-H](_O|Q|Q2|MUX)", @@ -138,7 +148,7 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str // UltraScale+ ultraScalePlus ? "((CLE_CLE_[LM]_SITE_0|CLK_LEAF_SITES|INT_INT_SDQ|(NN|EE|SS|WW)(1|2|4|12))_)[^\\(]+" // UltraScale - : "((CLE_CLE_[LM]_SITE_0|CLK_BUFCE_LEAF_X16_1_CLK|EE[124]|INT_INT_SINGLE|(NN|SS)(1|2|4|5|12|16)|(EE|WW)(1|2|4|12)|SDND[NS]W)_)[^\\(]+", + : "((CLE_CLE_[LM]_SITE_0|CLK_BUFCE_LEAF_X16_1_CLK|EE[124]|INT_INT_SINGLE|(NN|SS)(1|2|4|5|12|16)|(EE|WW)(1|2|4|12)|QLND(NW|SE|SW)|SDND[NS]W)_)[^\\(]+", "$1")) .distinct() .sorted() @@ -153,7 +163,7 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str // UltraScale+ ultraScalePlus ? "((CLE_CLE_[LM]_SITE_0|INT_INT_SDQ|(NN|EE|SS|WW)(1|2|4|12))_)[^\\(]+" // UltraScale - : "((INT_INT_SINGLE|(NN|SS)(1|2|4|5|12|16)|(EE|WW)(1|2|4|12)|QLND(NW|SE)|SDND[NS]W)_)[^\\(]+", + : "((CLE_CLE_[LM]_SITE_0|INT_INT_SINGLE|(NN|SS)(1|2|4|5|12|16)|(EE|WW)(1|2|4|12)|QLND(NW|S[EW])|SDND[NS]W)_)[^\\(]+", "$1")) .distinct() .sorted() @@ -163,10 +173,11 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str while (!queue.isEmpty()) { Node node = queue.poll(); String wireName = node.getWireName(); - if ((ultraScalePlus && wireName.matches("(INT_NODE_SDQ|SDQNODE)_.*")) || // UltraScale+ - (!ultraScalePlus && wireName.matches("(INT_NODE_(SINGLE_DOUBLE|QUAD_LONG)|QLND(NW|SE|SW)|SDND[NS]W)_.*")) // UltraScale + if ((ultraScalePlus && wireName.matches("(INT_NODE_SDQ|SDQNODE)_.*")) || // UltraScale+ + (!ultraScalePlus && wireName.matches("(INT_NODE_(SINGLE_DOUBLE|QUAD_LONG)|QLND(NW|SE|SW)|SDND[NS]W)_.*") || // UltraScale + wireName.matches("(NN|EE|SS|WW)\\d+(_[EW])?_BEG\\d+")) ) { - // Do not desccend into SDQNODEs + // Do not desccend into SDQNODEs or SDQLs continue; } for (Node downhill : node.getAllDownhillNodes()) { From 16720fac93abb5ae11cb73d5af9bf17257adea00 Mon Sep 17 00:00:00 2001 From: eddieh-xlnx Date: Mon, 4 Nov 2024 16:09:08 -0800 Subject: [PATCH 14/71] Update actions and do not limit to 5G RAM (#1092) * [Actions] Move from checkout@v2 to @v4 To eliminate warning Signed-off-by: Eddie Hung * Do not reduce maxHeapSize to 5G on GitHub Actions Since GitHub-hosted runners now have 16G RAM Signed-off-by: Eddie Hung * Move to cache@v4 too Signed-off-by: Eddie Hung * [Actions] Remove wrapper-validation, up setup-java & setup-python Signed-off-by: Eddie Hung --------- Signed-off-by: Eddie Hung --- .github/workflows/build.yml | 10 ++++------ common.gradle | 6 +----- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b7ac8d492..65b5d7839 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,25 +15,23 @@ jobs: single_threaded: [multi-threaded, single-threaded] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 - - - uses: gradle/wrapper-validation-action@e6e38bacfdf1a337459f332974bb2327a31aaf4b + - uses: actions/checkout@v4 - name: Setup JDK 1.11 - uses: actions/setup-java@v2 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '11' cache: 'gradle' - name: Setup Python 3.7 - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: 3.7 - name: Cache Jars & Data id: cache-rapidwright - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: | data diff --git a/common.gradle b/common.gradle index fe48f9f07..260d1cff8 100644 --- a/common.gradle +++ b/common.gradle @@ -65,11 +65,7 @@ configurations.testFixturesImplementation.canBeResolved = true configurations.api.canBeResolved = true tasks.withType(Test) { - if (System.getenv("GITHUB_ACTION")) { - maxHeapSize = "5G" - } else { - maxHeapSize = "10G" - } + maxHeapSize = "10G" //Propagate JVM settings to test JVM jvmArgs applicationDefaultJvmArgs From 4356b036e1993e05c092644ffb7c3763e2c7ee5d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 4 Nov 2024 17:16:34 -0800 Subject: [PATCH 15/71] Add and use RouteNodeType.LOCAL Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/rwroute/RWRoute.java | 6 +- .../xilinx/rapidwright/rwroute/RouteNode.java | 9 +- .../rapidwright/rwroute/RouteNodeGraph.java | 103 ++++++++---------- .../rapidwright/rwroute/RouteNodeInfo.java | 29 +++-- .../rapidwright/rwroute/RouteNodeType.java | 3 +- 5 files changed, 77 insertions(+), 73 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index d44b7edd4..81098d23c 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -56,7 +56,6 @@ import com.xilinx.rapidwright.util.Pair; import com.xilinx.rapidwright.util.RuntimeTracker; import com.xilinx.rapidwright.util.RuntimeTrackerTree; -import com.xilinx.rapidwright.util.Utils; import java.util.ArrayList; import java.util.Arrays; @@ -1798,6 +1797,11 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { continue; } switch (childRNode.getType()) { + case LOCAL: + if (!routingGraph.isAccessible(childRNode, connection)) { + continue; + } + break; case WIRE: if (!routingGraph.isAccessible(childRNode, connection)) { continue; diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index 1dbc5f4c6..30dcc32d7 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -92,7 +92,7 @@ public class RouteNode extends Node implements Comparable { protected RouteNode(RouteNodeGraph routingGraph, Node node, RouteNodeType type) { super(node); - RouteNodeInfo nodeInfo = RouteNodeInfo.get(this, routingGraph.lagunaI); + RouteNodeInfo nodeInfo = RouteNodeInfo.get(this, routingGraph); this.type = (type == null) ? nodeInfo.type : type; endTileXCoordinate = nodeInfo.endTileXCoordinate; endTileYCoordinate = nodeInfo.endTileYCoordinate; @@ -118,6 +118,9 @@ public int compareTo(RouteNode that) { private void setBaseCost() { baseCost = 0.4f; switch (type) { + case LOCAL: + assert(length <= 1); + break; case LAGUNA_I: // Make all approaches to SLLs zero-cost to encourage exploration // Assigning a base cost of zero would normally break congestion resolution @@ -139,10 +142,10 @@ private void setBaseCost() { case NODE_LAGUNA_OUTPUT: // LAG_LAG.{LAG_MUX_ATOM_*_TXOUT,RXD*} (US+) case NODE_LAGUNA_DATA: // LAG_LAG.UBUMP* super long lines for u-turns at the boundary of the device (US+) case NODE_PINFEED: + case INTENT_DEFAULT: // INT.VCC_WIRE assert(length == 0); break; - case NODE_LOCAL: // US and US+ - case INTENT_DEFAULT: + case NODE_LOCAL: // US and US+ assert(length <= 1); break; case NODE_VSINGLE: // Versal-only diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index e68ad6d8c..a934df8f3 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -37,7 +37,6 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; import com.xilinx.rapidwright.design.Design; import com.xilinx.rapidwright.design.Net; @@ -100,19 +99,15 @@ public class RouteNodeGraph { */ protected final Map lagunaI; - /** Map indicating which wire indices within an INT tile should be considered - * accessible only if it is within the same column (same X tile coordinate) as - * the target tile. - */ - protected final Map accessibleWireOnlyIfAboveBelowTarget; - /** Map indicating the wire indices corresponding to the [A-H]MUX output */ protected final Map muxWires; - /** Flag for whether LUT routethrus are to be considered - */ + /** Flag for whether LUT routethrus are to be considered */ protected final boolean lutRoutethru; + /** Map indicating the wire indices that have a local intent code, but is what RWRoute considers to be non-local */ + protected final Map nonLocalWires; + public RouteNodeGraph(Design design, RWRouteConfig config) { this(design, config, new HashMap<>()); } @@ -142,55 +137,39 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map(TileTypeEnum.class); + nonLocalWires = new EnumMap<>(TileTypeEnum.class); BitSet wires = new BitSet(); Tile intTile = device.getArbitraryTileOfType(TileTypeEnum.INT); // Device.getArbitraryTileOfType() typically gives you the North-Western-most // tile (with minimum X, maximum Y). Analyze the tile just below that. intTile = intTile.getTileXYNeighbor(0, -1); + nonLocalWires.put(intTile.getTileTypeEnum(), wires); Series series = device.getSeries(); - for (int wireIndex = 0; wireIndex < intTile.getWireCount(); wireIndex++) { - Node baseNode = Node.getNode(intTile, wireIndex); - if (baseNode == null) { - continue; - } - Tile baseTile = baseNode.getTile(); - String wireName = baseNode.getWireName(); - if (wireName.startsWith("BOUNCE_")) { - assert(baseNode.getIntentCode() == IntentCode.NODE_PINBOUNCE); - assert(baseTile.getTileXCoordinate() == intTile.getTileXCoordinate()); - // Uphill from INT_NODE_IMUX_* in tile above/below and INODE_* in above/target or below/target tiles - // Downhill to INT_NODE_IMUX_* and INODE_* to above/below tile - } else if (wireName.startsWith("BYPASS_")) { - assert(baseNode.getIntentCode() == IntentCode.NODE_PINBOUNCE); - assert(baseTile == intTile); - assert(wireIndex == baseNode.getWireIndex()); - // Uphill and downhill are INT_NODE_IMUX_* in the target tile and INODE_* to above/below tiles - } else if (wireName.startsWith("INT_NODE_GLOBAL_")) { - assert(baseNode.getIntentCode() == IntentCode.NODE_LOCAL); - assert(baseTile == intTile); - assert(wireIndex == baseNode.getWireIndex()); - // Downhill to CTRL_* in the target tile, INODE_* to above/below tile, INT_NODE_IMUX_* in target tile - } else if (wireName.startsWith("INT_NODE_IMUX_") && - // Do not block INT_NODE_IMUX node accessibility when LUT routethrus are considered - !lutRoutethru) { - assert(((series == Series.UltraScale || series == Series.UltraScalePlus) && baseNode.getIntentCode() == IntentCode.NODE_LOCAL) || - (series == Series.Versal && baseNode.getIntentCode() == IntentCode.NODE_INODE)); - assert(baseTile == intTile); - assert(wireIndex == baseNode.getWireIndex()); - // Downhill to BOUNCE_* in the above/below/target tile, BYPASS_* in the base tile, IMUX_* in target tile - } else if (wireName.startsWith("INODE_")) { - assert(baseNode.getIntentCode() == IntentCode.NODE_LOCAL); - assert(baseTile.getTileXCoordinate() == intTile.getTileXCoordinate()); - // Uphill from nodes in above/target or below/target tiles - // Downhill to BOUNCE_*/BYPASS_*/IMUX_* in above/target or below/target tiles - } else { - continue; + if (series == Series.UltraScale || series == Series.UltraScalePlus) { + for (int wireIndex = 0; wireIndex < intTile.getWireCount(); wireIndex++) { + Node baseNode = Node.getNode(intTile, wireIndex); + if (baseNode == null) { + continue; + } + if (baseNode.getIntentCode() != IntentCode.NODE_LOCAL) { + continue; + } + String wireName = baseNode.getWireName(); + if (!wireName.startsWith("INT_NODE_SDQ_") && !wireName.startsWith("SDQNODE_")) { + continue; + } + Tile baseTile = baseNode.getTile(); + if (baseTile != intTile) { + if (wireName.endsWith("_FT0")) { + assert(baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() - 1); + } else { + assert(wireName.endsWith("_FT1")); + assert(baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() + 1); + } + } + wires.set(baseNode.getWireIndex()); } - - wires.set(baseNode.getWireIndex()); } - accessibleWireOnlyIfAboveBelowTarget.put(intTile.getTileTypeEnum(), wires); if (lutRoutethru) { assert(design.getSeries() == Series.UltraScale || design.getSeries() == Series.UltraScalePlus); @@ -573,25 +552,29 @@ public int averageChildren() { } public boolean isAccessible(RouteNode childRnode, Connection connection) { + // Only consider LOCAL nodes when: + // (a) considering LUT routethrus + if (childRnode.getType() != RouteNodeType.LOCAL || lutRoutethru) { + return true; + } + + // (b) in the sink tile Tile childTile = childRnode.getTile(); - TileTypeEnum childTileType = childTile.getTileTypeEnum(); - BitSet bs = accessibleWireOnlyIfAboveBelowTarget.get(childTileType); - if (bs == null || !bs.get(childRnode.getWireIndex())) { + Tile sinkTile = connection.getSinkRnode().getTile(); + if (childTile == sinkTile) { return true; } + // (c) connection crosses SLR and this is a Laguna column int childX = childTile.getTileXCoordinate(); if (connection.isCrossSLR() && nextLagunaColumn[childX] == childX) { - // Connection crosses SLR and this is a Laguna column - return true; - } - Tile sinkTile = connection.getSinkRnode().getTile(); - if (childX != sinkTile.getTileXCoordinate()) { - return false; + return true; } - return Math.abs(childTile.getTileYCoordinate() - sinkTile.getTileYCoordinate()) <= 1; + // (d) when in row above/below the sink tile + return childX == sinkTile.getTileXCoordinate() && + Math.abs(childTile.getTileYCoordinate() - sinkTile.getTileYCoordinate()) <= 1; } protected boolean allowRoutethru(Node head, Node tail) { diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java index 264c5726f..d994de8ea 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java @@ -29,7 +29,6 @@ import com.xilinx.rapidwright.device.Wire; import java.util.BitSet; -import java.util.Map; public class RouteNodeInfo { public final RouteNodeType type; @@ -47,7 +46,7 @@ private RouteNodeInfo(RouteNodeType type, this.length = length; } - public static RouteNodeInfo get(Node node, Map lagunaI) { + public static RouteNodeInfo get(Node node, RouteNodeGraph routingGraph) { Wire[] wires = node.getAllWiresInNode(); Tile baseTile = node.getTile(); TileTypeEnum baseTileType = baseTile.getTileTypeEnum(); @@ -66,7 +65,7 @@ public static RouteNodeInfo get(Node node, Map lagunaI) { endTile = node.getTile(); } - RouteNodeType type = getType(node, endTile, lagunaI); + RouteNodeType type = getType(node, endTile, routingGraph); short endTileXCoordinate = getEndTileXCoordinate(node, type, (short) endTile.getTileXCoordinate()); short endTileYCoordinate = (short) endTile.getTileYCoordinate(); short length = getLength(baseTile, type, endTileXCoordinate, endTileYCoordinate); @@ -126,19 +125,33 @@ private static short getEndTileXCoordinate(Node node, RouteNodeType type, short return endTileXCoordinate; } - private static RouteNodeType getType(Node node, Tile endTile, Map lagunaI) { + private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph routingGraph) { // NOTE: IntentCode is device-dependent IntentCode ic = node.getIntentCode(); switch (ic) { case NODE_PINBOUNCE: return RouteNodeType.PINBOUNCE; - case NODE_PINFEED: - BitSet bs = (lagunaI != null) ? lagunaI.get(node.getTile()) : null; - if (bs != null && bs.get(node.getWireIndex())) { - return RouteNodeType.LAGUNA_I; + case NODE_LOCAL: { + assert(node.getTile().getTileTypeEnum() == TileTypeEnum.INT); + if (routingGraph != null) { + BitSet bs = routingGraph.nonLocalWires.get(node.getTile().getTileTypeEnum()); + if (!bs.get(node.getWireIndex())) { + return RouteNodeType.LOCAL; + } + break; + } + } + + case NODE_PINFEED: { + if (routingGraph != null && routingGraph.lagunaI != null) { + BitSet bs = routingGraph.lagunaI.get(node.getTile()); + if (bs != null && bs.get(node.getWireIndex())) { + return RouteNodeType.LAGUNA_I; + } } break; + } case NODE_LAGUNA_OUTPUT: // UltraScale+ only assert(node.getTile().getTileTypeEnum() == TileTypeEnum.LAG_LAG); diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java index d81176409..edf61b2fe 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java @@ -61,6 +61,7 @@ public enum RouteNodeType { * Denotes other wiring {@link RouteNode} Objects * that are created for routing {@link Connection} Objects. */ - WIRE + WIRE, + LOCAL } From 7e7015a3fb38f1eb5d85b0a6be0035c92f667e29 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 4 Nov 2024 17:29:26 -0800 Subject: [PATCH 16/71] Merge RouteNodeType.PINBOUNCE into LOCAL; rename WIRE, PINFEED_{I,O} Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/Connection.java | 6 ++-- .../rapidwright/rwroute/NetWrapper.java | 2 +- .../rapidwright/rwroute/PartialRouter.java | 6 ++-- .../xilinx/rapidwright/rwroute/RWRoute.java | 35 +++++-------------- .../xilinx/rapidwright/rwroute/RouteNode.java | 29 +++++++-------- .../rapidwright/rwroute/RouteNodeGraph.java | 16 ++------- .../rapidwright/rwroute/RouteNodeInfo.java | 8 ++--- .../rapidwright/rwroute/RouteNodeType.java | 23 ++---------- .../rwroute/TimingAndWirelengthReport.java | 6 ++-- 9 files changed, 42 insertions(+), 89 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/Connection.java b/src/com/xilinx/rapidwright/rwroute/Connection.java index 69aef1b90..aad68f0ed 100644 --- a/src/com/xilinx/rapidwright/rwroute/Connection.java +++ b/src/com/xilinx/rapidwright/rwroute/Connection.java @@ -305,9 +305,9 @@ public void addAltSinkRnode(RouteNode sinkRnode) { } else { assert(!altSinkRnodes.contains(sinkRnode)); } - assert(sinkRnode.getType() == RouteNodeType.PINFEED_I || + assert(sinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK || // Can be a WIRE if node is not exclusive a sink - sinkRnode.getType() == RouteNodeType.WIRE); + sinkRnode.getType() == RouteNodeType.NON_LOCAL); altSinkRnodes.add(sinkRnode); } @@ -487,7 +487,7 @@ public void setAllTargets(RWRoute.ConnectionState state) { // where the same physical pin services more than one logical pin if (rnode.countConnectionsOfUser(netWrapper) == 0 || // Except if it is not a PINFEED_I - rnode.getType() != RouteNodeType.PINFEED_I) { + rnode.getType() != RouteNodeType.EXCLUSIVE_SINK) { assert(rnode.getIntentCode() != IntentCode.NODE_PINBOUNCE); rnode.markTarget(state); } diff --git a/src/com/xilinx/rapidwright/rwroute/NetWrapper.java b/src/com/xilinx/rapidwright/rwroute/NetWrapper.java index 200bbf7c6..05dc3eff8 100644 --- a/src/com/xilinx/rapidwright/rwroute/NetWrapper.java +++ b/src/com/xilinx/rapidwright/rwroute/NetWrapper.java @@ -171,7 +171,7 @@ public SitePinInst getOrCreateAlternateSource(RouteNodeGraph routingGraph) { return null; } - altSourceRnode = routingGraph.getOrCreate(altSourceNode, RouteNodeType.PINFEED_O); + altSourceRnode = routingGraph.getOrCreate(altSourceNode, RouteNodeType.EXCLUSIVE_SOURCE); } assert(altSourceRnode != null); return altSource; diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index 1ad73e55d..871637153 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -256,7 +256,7 @@ protected void determineRoutingTargets() { preservedNet = routingGraph.getPreservedNet(sinkRnode); if (preservedNet != null && preservedNet != net) { unpreserveNets.add(preservedNet); - assert(sinkRnode.getType() == RouteNodeType.PINFEED_I); + assert(sinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK); } } @@ -598,8 +598,8 @@ protected void unpreserveNet(Net net) { assert(!connection.isDirect()); RouteNode sourceRnode = connection.getSourceRnode(); RouteNode sinkRnode = connection.getSinkRnode(); - assert(sourceRnode.getType() == RouteNodeType.PINFEED_O); - assert(sinkRnode.getType() == RouteNodeType.PINFEED_I); + assert(sourceRnode.getType() == RouteNodeType.EXCLUSIVE_SOURCE); + assert(sinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK); // Even though this connection is not expected to have any routing yet, // perform a rip up anyway in order to release any exclusive sinks diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 81098d23c..05348b723 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -588,7 +588,7 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { if (connection.getSourceRnode() == null) { assert(sourceINTNode != null); if (sourceINTRnode == null) { - sourceINTRnode = routingGraph.getOrCreate(sourceINTNode, RouteNodeType.PINFEED_O); + sourceINTRnode = routingGraph.getOrCreate(sourceINTNode, RouteNodeType.EXCLUSIVE_SOURCE); // Where only a single primary source exists, always preserve // its projected-to-INT source node, since it could // be a projection from LAGUNA/RXQ* -> RXD* (node for INT/LOGIC_OUTS_*) @@ -600,8 +600,8 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { } indirectConnections.add(connection); - RouteNode sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.PINFEED_I); - sinkRnode.setType(RouteNodeType.PINFEED_I); + RouteNode sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK); + sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK); connection.setSinkRnode(sinkRnode); // Where appropriate, allow all 6 LUT pins to be swapped to begin with @@ -650,8 +650,8 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { if (routingGraph.isPreserved(node)) { continue; } - RouteNode altSinkRnode = routingGraph.getOrCreate(node, RouteNodeType.PINFEED_I); - assert(altSinkRnode.getType() == RouteNodeType.PINFEED_I); + RouteNode altSinkRnode = routingGraph.getOrCreate(node, RouteNodeType.EXCLUSIVE_SINK); + assert(altSinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK); connection.addAltSinkRnode(altSinkRnode); } @@ -1802,7 +1802,7 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { continue; } break; - case WIRE: + case NON_LOCAL: if (!routingGraph.isAccessible(childRNode, connection)) { continue; } @@ -1812,14 +1812,7 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { continue; } break; - case PINBOUNCE: - // A PINBOUNCE can only be a target if this connection has an alternate sink - assert(!childRNode.isTarget() || connection.getAltSinkRnodes().isEmpty()); - if (!isAccessiblePinbounce(childRNode, connection)) { - continue; - } - break; - case PINFEED_I: + case EXCLUSIVE_SINK: if (!isAccessiblePinfeedI(childRNode, connection)) { continue; } @@ -1858,25 +1851,13 @@ protected boolean isAccessible(RouteNode child, Connection connection) { return !config.isUseBoundingBox() || child.isInConnectionBoundingBox(connection); } - /** - * Checks if a NODE_PINBOUNCE is suitable to be used for routing to a target. - * @param child The PINBOUNCE rnode in question. - * @param connection The connection to route. - * @return true, if the PINBOUNCE rnode is in the same column as the target and within one INT tile of the target. - */ - protected boolean isAccessiblePinbounce(RouteNode child, Connection connection) { - assert(child.getType() == RouteNodeType.PINBOUNCE); - - return routingGraph.isAccessible(child, connection); - } - protected boolean isAccessiblePinfeedI(RouteNode child, Connection connection) { // When LUT pin swapping is enabled, PINFEED_I are not exclusive anymore return isAccessiblePinfeedI(child, connection, !lutPinSwapping); } protected boolean isAccessiblePinfeedI(RouteNode child, Connection connection, boolean assertOnOveruse) { - assert(child.getType() == RouteNodeType.PINFEED_I); + assert(child.getType() == RouteNodeType.EXCLUSIVE_SINK); assert(!assertOnOveruse || !child.isOverUsed()); if (child.isTarget()) { diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index 30dcc32d7..d0186fada 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -27,6 +27,7 @@ import com.xilinx.rapidwright.design.Net; import com.xilinx.rapidwright.device.IntentCode; import com.xilinx.rapidwright.device.Node; +import com.xilinx.rapidwright.device.Series; import com.xilinx.rapidwright.device.Tile; import com.xilinx.rapidwright.device.TileTypeEnum; import com.xilinx.rapidwright.util.RuntimeTracker; @@ -98,7 +99,7 @@ protected RouteNode(RouteNodeGraph routingGraph, Node node, RouteNodeType type) endTileYCoordinate = nodeInfo.endTileYCoordinate; length = nodeInfo.length; children = null; - setBaseCost(); + setBaseCost(routingGraph.design.getSeries()); presentCongestionCost = initialPresentCongestionCost; historicalCongestionCost = initialHistoricalCongestionCost; usersConnectionCounts = null; @@ -115,11 +116,17 @@ public int compareTo(RouteNode that) { return (int) Math.signum(this.lowerBoundTotalPathCost - that.lowerBoundTotalPathCost); } - private void setBaseCost() { + private void setBaseCost(Series series) { baseCost = 0.4f; switch (type) { + case EXCLUSIVE_SOURCE: + assert(length == 0); + break; + case EXCLUSIVE_SINK: case LOCAL: - assert(length <= 1); + assert(length == 0 || + length == 1 && (getIntentCode() == IntentCode.NODE_PINBOUNCE || (type == RouteNodeType.LOCAL && getWireName().matches("INODE_[EW]_\\d+_FT[01]"))) + && (series == Series.UltraScale || series == Series.UltraScalePlus)); break; case LAGUNA_I: // Make all approaches to SLLs zero-cost to encourage exploration @@ -132,7 +139,7 @@ private void setBaseCost() { assert(length == RouteNodeGraph.SUPER_LONG_LINE_LENGTH_IN_TILES); baseCost = 0.3f * length; break; - case WIRE: + case NON_LOCAL: // NOTE: IntentCode is device-dependent IntentCode ic = getIntentCode(); switch(ic) { @@ -218,12 +225,6 @@ private void setBaseCost() { throw new RuntimeException(ic.toString()); } break; - case PINFEED_I: - case PINBOUNCE: - break; - case PINFEED_O: - baseCost = 1f; - break; default: throw new RuntimeException(type.toString()); } @@ -351,11 +352,11 @@ public RouteNodeType getType() { */ public void setType(RouteNodeType type) { assert(this.type == type || - // Support demotion from PINFEED_I to PINBOUNCE since they have the same base cost - (this.type == RouteNodeType.PINFEED_I && type == RouteNodeType.PINBOUNCE) || - // Or promotion from PINBOUNCE to PINFEED_I (by PartialRouter when PINBOUNCE on + // Support demotion from EXCLUSIVE_SINK to LOCAL since they have the same base cost + (this.type == RouteNodeType.EXCLUSIVE_SINK && type == RouteNodeType.LOCAL) || + // Or promotion from LOCAL to EXCLUSIVE_SINK (by PartialRouter when NODE_PINBOUNCE on // preserved net needs to become a PINFEED_I) - (this.type == RouteNodeType.PINBOUNCE && type == RouteNodeType.PINFEED_I)); + (this.type == RouteNodeType.LOCAL && type == RouteNodeType.EXCLUSIVE_SINK)); this.type = type; } diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index a934df8f3..f21cc2fba 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -416,9 +416,9 @@ protected boolean isExcluded(RouteNode parent, Node child) { // PINFEEDs can lead to a site pin, or into a Laguna tile RouteNode childRnode = getNode(child); if (childRnode != null) { - assert(childRnode.getType() == RouteNodeType.PINFEED_I || + assert(childRnode.getType() == RouteNodeType.EXCLUSIVE_SINK || childRnode.getType() == RouteNodeType.LAGUNA_I || - (lutRoutethru && childRnode.getType() == RouteNodeType.WIRE)); + (lutRoutethru && childRnode.getType() == RouteNodeType.NON_LOCAL)); } else if (!lutRoutethru) { // child does not already exist in our routing graph, meaning it's not a used site pin // in our design, but it could be a LAGUNA_I @@ -513,17 +513,7 @@ public int numNodes() { } protected RouteNode create(Node node, RouteNodeType type) { - RouteNode rnode = new RouteNode(this, node, type); - // PINFEED_I should have zero length, except for on US/US+ where the PINFEED_I can be a PINBOUNCE node. - assert(rnode.getType() != RouteNodeType.PINFEED_I || - rnode.getLength() == 0 || - (rnode.getLength() == 1 && (design.getSeries() == Series.UltraScale || design.getSeries() == Series.UltraScalePlus) && - rnode.getIntentCode() == IntentCode.NODE_PINBOUNCE)); - // PINBOUNCE should have zero length, except for on US/US+ - assert(rnode.getType() != RouteNodeType.PINBOUNCE || - rnode.getLength() == 0 || - (rnode.getLength() == 1 && design.getSeries() == Series.UltraScale || design.getSeries() == Series.UltraScalePlus)); - return rnode; + return new RouteNode(this, node, type); } public RouteNode getOrCreate(Node node) { diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java index d994de8ea..cc16ff2cc 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java @@ -129,9 +129,6 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou // NOTE: IntentCode is device-dependent IntentCode ic = node.getIntentCode(); switch (ic) { - case NODE_PINBOUNCE: - return RouteNodeType.PINBOUNCE; - case NODE_LOCAL: { assert(node.getTile().getTileTypeEnum() == TileTypeEnum.INT); if (routingGraph != null) { @@ -143,6 +140,9 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou } } + case NODE_PINBOUNCE: + return RouteNodeType.LOCAL; + case NODE_PINFEED: { if (routingGraph != null && routingGraph.lagunaI != null) { BitSet bs = routingGraph.lagunaI.get(node.getTile()); @@ -183,6 +183,6 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou break; } - return RouteNodeType.WIRE; + return RouteNodeType.NON_LOCAL; } } diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java index edf61b2fe..02b7f9fcf 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java @@ -29,21 +29,8 @@ import com.xilinx.rapidwright.device.Node; public enum RouteNodeType { - /** - * Denotes {@link RouteNode} objects that correspond to the output pins of {@link Net} Objects, - * typically the source {@link RouteNode} Objects of {@link Connection} Objects. - */ - PINFEED_O, - /** - * Denotes {@link RouteNode} objects that correspond to input pins of {@link Net} Objects, - * typically the sink {@link RouteNode} Objects of {@link Connection} Objects. - */ - PINFEED_I, - /** - * Denotes {@link RouteNode} objects that are created based on {@link Node} Objects - * that have an {@link IntentCode} of NODE_PINBOUNCE. - */ - PINBOUNCE, + EXCLUSIVE_SOURCE, + EXCLUSIVE_SINK, /** * Denotes {@link RouteNode} objects that correspond to a super long line {@link Node}, @@ -57,11 +44,7 @@ public enum RouteNodeType { */ LAGUNA_I, - /** - * Denotes other wiring {@link RouteNode} Objects - * that are created for routing {@link Connection} Objects. - */ - WIRE, + NON_LOCAL, LOCAL } diff --git a/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java b/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java index 7da5a405f..c51cc6789 100644 --- a/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java +++ b/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java @@ -25,7 +25,6 @@ package com.xilinx.rapidwright.rwroute; import java.util.HashMap; -import java.util.List; import java.util.Map; import com.xilinx.rapidwright.design.Design; @@ -35,7 +34,6 @@ import com.xilinx.rapidwright.design.SitePinInst; import com.xilinx.rapidwright.device.IntentCode; import com.xilinx.rapidwright.device.Node; -import com.xilinx.rapidwright.device.TileTypeEnum; import com.xilinx.rapidwright.timing.TimingManager; import com.xilinx.rapidwright.timing.TimingVertex; import com.xilinx.rapidwright.timing.delayestimator.DelayEstimatorBase; @@ -130,11 +128,11 @@ private NetWrapper createNetWrapper(Net net) { if (sinkINTNode == null) { connection.setDirect(true); } else { - connection.setSinkRnode(routingGraph.getOrCreate(sinkINTNode, RouteNodeType.PINFEED_I)); + connection.setSinkRnode(routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK)); if (sourceINTNode == null) { sourceINTNode = RouterHelper.projectOutputPinToINTNode(source); } - connection.setSourceRnode(routingGraph.getOrCreate(sourceINTNode, RouteNodeType.PINFEED_O)); + connection.setSourceRnode(routingGraph.getOrCreate(sourceINTNode, RouteNodeType.EXCLUSIVE_SOURCE)); connection.setDirect(false); } } From b9ff45f71e2a7d39a26ca66f7eb4e2eeea1b6721 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 4 Nov 2024 17:38:08 -0800 Subject: [PATCH 17/71] LUT routethru fixes Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RWRoute.java | 5 ++++- src/com/xilinx/rapidwright/rwroute/RouteNode.java | 2 +- .../xilinx/rapidwright/rwroute/RouteNodeGraph.java | 4 ++-- .../xilinx/rapidwright/rwroute/RouteNodeInfo.java | 12 ++++++------ .../xilinx/rapidwright/rwroute/RouteNodeType.java | 4 +--- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 05348b723..b17198c66 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1803,6 +1803,9 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { } break; case NON_LOCAL: + assert(rnode.getType() != RouteNodeType.LOCAL || + routingGraph.lutRoutethru && rnode.getIntentCode() == IntentCode.NODE_PINFEED); + if (!routingGraph.isAccessible(childRNode, connection)) { continue; } @@ -1817,7 +1820,7 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { continue; } break; - case LAGUNA_I: + case LAGUNA_PINFEED: if (!connection.isCrossSLR() || connection.getSinkRnode().getSLRIndex(routingGraph) == childRNode.getSLRIndex(routingGraph)) { // Do not consider approaching a SLL if not needing to cross diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index d0186fada..e66d95938 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -128,7 +128,7 @@ private void setBaseCost(Series series) { length == 1 && (getIntentCode() == IntentCode.NODE_PINBOUNCE || (type == RouteNodeType.LOCAL && getWireName().matches("INODE_[EW]_\\d+_FT[01]"))) && (series == Series.UltraScale || series == Series.UltraScalePlus)); break; - case LAGUNA_I: + case LAGUNA_PINFEED: // Make all approaches to SLLs zero-cost to encourage exploration // Assigning a base cost of zero would normally break congestion resolution // (since RWroute.getNodeCost() would return zero) but doing it here should be diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index f21cc2fba..224d4f913 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -417,8 +417,8 @@ protected boolean isExcluded(RouteNode parent, Node child) { RouteNode childRnode = getNode(child); if (childRnode != null) { assert(childRnode.getType() == RouteNodeType.EXCLUSIVE_SINK || - childRnode.getType() == RouteNodeType.LAGUNA_I || - (lutRoutethru && childRnode.getType() == RouteNodeType.NON_LOCAL)); + childRnode.getType() == RouteNodeType.LAGUNA_PINFEED || + (lutRoutethru && childRnode.getType() == RouteNodeType.LOCAL)); } else if (!lutRoutethru) { // child does not already exist in our routing graph, meaning it's not a used site pin // in our design, but it could be a LAGUNA_I diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java index cc16ff2cc..0ee5c1625 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java @@ -92,7 +92,7 @@ private static short getLength(Tile baseTile, RouteNodeType type, short endTileX } break; case INT: - if (type == RouteNodeType.LAGUNA_I) { + if (type == RouteNodeType.LAGUNA_PINFEED) { assert(length == 0); } break; @@ -111,7 +111,7 @@ private static short getEndTileXCoordinate(Node node, RouteNodeType type, short // fanout nodes of the SLL are marked as) unless it is a fanin (LAGUNA_I) // (i.e. do not apply it to the fanout nodes). // Nor apply it to VCC_WIREs since their end tiles are INT tiles. - if ((node.getIntentCode() != IntentCode.NODE_LAGUNA_OUTPUT || type == RouteNodeType.LAGUNA_I) && + if ((node.getIntentCode() != IntentCode.NODE_LAGUNA_OUTPUT || type == RouteNodeType.LAGUNA_PINFEED) && !node.isTiedToVcc()) { assert(baseTile.getTileXCoordinate() == endTileXCoordinate); endTileXCoordinate++; @@ -147,16 +147,16 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou if (routingGraph != null && routingGraph.lagunaI != null) { BitSet bs = routingGraph.lagunaI.get(node.getTile()); if (bs != null && bs.get(node.getWireIndex())) { - return RouteNodeType.LAGUNA_I; + return RouteNodeType.LAGUNA_PINFEED; } } - break; + return RouteNodeType.LOCAL; } case NODE_LAGUNA_OUTPUT: // UltraScale+ only assert(node.getTile().getTileTypeEnum() == TileTypeEnum.LAG_LAG); if (node.getWireName().endsWith("_TXOUT")) { - return RouteNodeType.LAGUNA_I; + return RouteNodeType.LAGUNA_PINFEED; } break; @@ -177,7 +177,7 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou return RouteNodeType.SUPER_LONG_LINE; } else if (wireName.endsWith("_TXOUT")) { // This is the inner LAGUNA_I, mark it so it gets a base cost discount - return RouteNodeType.LAGUNA_I; + return RouteNodeType.LAGUNA_PINFEED; } } break; diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java index 02b7f9fcf..2510b4701 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java @@ -24,8 +24,6 @@ package com.xilinx.rapidwright.rwroute; -import com.xilinx.rapidwright.design.Net; -import com.xilinx.rapidwright.device.IntentCode; import com.xilinx.rapidwright.device.Node; public enum RouteNodeType { @@ -42,7 +40,7 @@ public enum RouteNodeType { * Denotes {@link RouteNode} objects that correspond to {@link Node} objects that enter * a Laguna tile from an INT tile, or those Laguna tile nodes leading to a SUPER_LONG_LINE. */ - LAGUNA_I, + LAGUNA_PINFEED, NON_LOCAL, From aabab3c9ea31cb4ca5201bd75e10b6ec8c26646f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 5 Nov 2024 08:35:16 -0800 Subject: [PATCH 18/71] Add testNodeReachabilityVersal() Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/device/TestNode.java | 105 +++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-) diff --git a/test/src/com/xilinx/rapidwright/device/TestNode.java b/test/src/com/xilinx/rapidwright/device/TestNode.java index 3bdb07caf..08617bba0 100644 --- a/test/src/com/xilinx/rapidwright/device/TestNode.java +++ b/test/src/com/xilinx/rapidwright/device/TestNode.java @@ -175,7 +175,8 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str String wireName = node.getWireName(); if ((ultraScalePlus && wireName.matches("(INT_NODE_SDQ|SDQNODE)_.*")) || // UltraScale+ (!ultraScalePlus && wireName.matches("(INT_NODE_(SINGLE_DOUBLE|QUAD_LONG)|QLND(NW|SE|SW)|SDND[NS]W)_.*") || // UltraScale - wireName.matches("(NN|EE|SS|WW)\\d+(_[EW])?_BEG\\d+")) + EnumSet.of(IntentCode.NODE_SINGLE, IntentCode.NODE_DOUBLE, IntentCode.NODE_HQUAD, IntentCode.VQUAD, IntentCode.HLONG, IntentCode. VLONG) + .contains(node.getIntentCode())) ) { // Do not desccend into SDQNODEs or SDQLs continue; @@ -195,6 +196,108 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str System.out.println("visited.size() = " + visited.size()); } + @ParameterizedTest + @CsvSource({ + "xcvp1002,INT_X38Y220,NODE_PINBOUNCE", + "xcvp1002,INT_X38Y220,NODE_INODE", + "xcvp1002,INT_X38Y220,NODE_IMUX", + "xcvp1002,INT_X38Y220,NODE_SDQNODE", + "xcvp1002,INT_X38Y220,NODE_HSINGLE", + "xcvp1002,INT_X38Y220,NODE_VSINGLE", + "xcvp1002,INT_X38Y220,NODE_HDOUBLE", + "xcvp1002,INT_X38Y220,NODE_VDOUBLE", + "xcvp1002,INT_X38Y220,NODE_HQUAD", + "xcvp1002,INT_X38Y220,NODE_VQUAD", + "xcvp1002,INT_X38Y220,NODE_HLONG6", + "xcvp1002,INT_X38Y220,NODE_HLONG10", + "xcvp1002,INT_X38Y220,NODE_VLONG7", + "xcvp1002,INT_X38Y220,NODE_VLONG12", + "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_BNODE", + "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_CNODE", + "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_CTRL", + "xcvp1002,CLE_W_CORE_X38Y220,NODE_PINFEED", + "xcvp1002,CLE_E_CORE_X38Y220,NODE_CLE_OUTPUT", + "xcvp1002,CLE_W_CORE_X38Y220,NODE_CLE_OUTPUT", + }) + public void testNodeReachabilityVersal(String partName, String tileName, String intentCodeName) { + Device device = Device.getDevice(partName); + Tile baseTile = device.getTile(tileName); + Queue queue = new ArrayDeque<>(); + IntentCode ic = IntentCode.valueOf(intentCodeName); + for (int wireIdx = 0; wireIdx < baseTile.getWireCount(); wireIdx++) { + if (baseTile.getWireIntentCode(wireIdx) != ic) { + continue; + } + queue.add(Node.getNode(baseTile, wireIdx)); + } + System.out.println("Initial queue.size() = " + queue.size()); + System.out.println("Initial queue = " + queue); + + // Print out the intent code of nodes that are immediately uphill of this intent code + System.out.println("Immediately uphill:"); + queue.stream().map(Node::getAllUphillNodes).flatMap(List::stream).map(Node::getIntentCode) + .distinct() + .sorted() + .forEachOrdered(s -> System.out.println("\t" + s)); + + // Print out the intent code of nodes that are immediately downhill of this intent code + System.out.println("Immediately downhill:"); + queue.stream().map(Node::getAllDownhillNodes).flatMap(List::stream).map(Node::getIntentCode) + .distinct() + .sorted() + .forEachOrdered(s -> System.out.println("\t" + s)); + + TileTypeEnum baseTileTypeEnum = baseTile.getTileTypeEnum(); + Set visited = new HashSet<>(); + while (!queue.isEmpty()) { + Node node = queue.poll(); + if (EnumSet.of(IntentCode.NODE_SDQNODE, IntentCode.NODE_HSINGLE, IntentCode.NODE_VSINGLE, + IntentCode.NODE_HDOUBLE, IntentCode.NODE_VDOUBLE, + IntentCode.NODE_HQUAD, IntentCode.NODE_VQUAD, + IntentCode.NODE_HLONG10, IntentCode.NODE_HLONG6, + IntentCode.NODE_VLONG12, IntentCode.NODE_VLONG7).contains(node.getIntentCode())) { + // Do not desccend into SDQNODEs or any SDQLs + continue; + } + for (Node downhill : node.getAllDownhillNodes()) { + if (!visited.add(downhill)) { + continue; + } + if (!Utils.isInterConnect(downhill.getTile().getTileTypeEnum())) { + continue; + } + if (Utils.isCLB(baseTileTypeEnum)) { + if (EnumSet.of(IntentCode.NODE_VLONG7, IntentCode.NODE_VLONG12, IntentCode.NODE_HLONG10, IntentCode.NODE_HLONG6).contains(downhill.getIntentCode())) { + // Ignore long wires that obviously leave the tile + } else { + // All other wires should have the same X coordinate, if not the same Y + Assertions.assertEquals(baseTile.getTileXCoordinate(), downhill.getTile().getTileXCoordinate()); + if (baseTile.getTileYCoordinate() != downhill.getTile().getTileYCoordinate()) { + // Only exception for Y are specific NODE_SDQNODEs with the following wire name + Assertions.assertTrue(downhill.getWireName().matches("OUT_[NEWS]NODE_[EW]_\\d+")); + Assertions.assertEquals(IntentCode.NODE_SDQNODE, downhill.getIntentCode()); + Assertions.assertTrue(1 >= Math.abs(baseTile.getTileYCoordinate() - downhill.getTile().getTileYCoordinate())); + } + } + // Do not descend further + continue; + } + // All INT-to-INT connections should be to the same tile + if (baseTileTypeEnum == TileTypeEnum.CLE_BC_CORE) { + // Except CLE_BC_CORE tiles which spans two adjacent INT tiles + if (baseTile != downhill.getTile()) { + Assertions.assertTrue(1 >= Math.abs(baseTile.getTileXCoordinate() - downhill.getTile().getTileXCoordinate())); + Assertions.assertEquals(TileTypeEnum.INT, downhill.getTile().getTileTypeEnum()); + } + } else { + Assertions.assertEquals(baseTile, downhill.getTile()); + } + queue.add(downhill); + } + } + System.out.println("visited.size() = " + visited.size()); + } + @ParameterizedTest @CsvSource({ // https://github.com/Xilinx/RapidWright/issues/983 From 9929603a3faa5057c7bf913065ad488fc8286eac Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 5 Nov 2024 08:52:23 -0800 Subject: [PATCH 19/71] Support UltraScale Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/rwroute/RWRoute.java | 5 +- .../xilinx/rapidwright/rwroute/RouteNode.java | 11 +++-- .../rapidwright/rwroute/RouteNodeGraph.java | 49 +++++++++++++------ .../rapidwright/rwroute/RouteNodeInfo.java | 2 +- 4 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index b17198c66..712d199f2 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1803,8 +1803,11 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { } break; case NON_LOCAL: + // LOCALs cannot connect to NON_LOCALs except via a LUT routethru assert(rnode.getType() != RouteNodeType.LOCAL || - routingGraph.lutRoutethru && rnode.getIntentCode() == IntentCode.NODE_PINFEED); + routingGraph.lutRoutethru && rnode.getIntentCode() == IntentCode.NODE_PINFEED || + // FIXME: + design.getSeries() == Series.Versal); if (!routingGraph.isAccessible(childRNode, connection)) { continue; diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index e66d95938..ed9eb82b1 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -120,13 +120,18 @@ private void setBaseCost(Series series) { baseCost = 0.4f; switch (type) { case EXCLUSIVE_SOURCE: - assert(length == 0); + assert(length == 0 || + (length <= 3 && series == Series.Versal)); break; case EXCLUSIVE_SINK: case LOCAL: assert(length == 0 || - length == 1 && (getIntentCode() == IntentCode.NODE_PINBOUNCE || (type == RouteNodeType.LOCAL && getWireName().matches("INODE_[EW]_\\d+_FT[01]"))) - && (series == Series.UltraScale || series == Series.UltraScalePlus)); + (length == 1 && (series == Series.UltraScalePlus || series == Series.UltraScale) && + (getIntentCode() == IntentCode.NODE_PINBOUNCE || + (series == Series.UltraScalePlus && type == RouteNodeType.LOCAL && getWireName().matches("INODE_[EW]_\\d+_FT[01]")) || + (series == Series.UltraScale && type == RouteNodeType.LOCAL && getWireName().matches("INODE_[12]_[EW]_\\d+_FT[NS]")) + )) + ); break; case LAGUNA_PINFEED: // Make all approaches to SLLs zero-cost to encourage exploration diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 224d4f913..cc17a4b3b 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -145,20 +145,23 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map(TileTypeEnum.class); for (TileTypeEnum tileTypeEnum : Utils.getCLBTileTypes()) { @@ -199,9 +218,9 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map Date: Tue, 5 Nov 2024 11:15:25 -0800 Subject: [PATCH 20/71] Extend RouteNodeType.LOCAL to Versal Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/rwroute/RWRoute.java | 14 +++---- .../xilinx/rapidwright/rwroute/RouteNode.java | 26 ++++-------- .../rapidwright/rwroute/RouteNodeGraph.java | 40 +++++++++++++++---- .../rapidwright/rwroute/RouteNodeInfo.java | 9 +++++ 4 files changed, 56 insertions(+), 33 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 712d199f2..289241c08 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1805,9 +1805,7 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { case NON_LOCAL: // LOCALs cannot connect to NON_LOCALs except via a LUT routethru assert(rnode.getType() != RouteNodeType.LOCAL || - routingGraph.lutRoutethru && rnode.getIntentCode() == IntentCode.NODE_PINFEED || - // FIXME: - design.getSeries() == Series.Versal); + routingGraph.lutRoutethru && rnode.getIntentCode() == IntentCode.NODE_PINFEED); if (!routingGraph.isAccessible(childRNode, connection)) { continue; @@ -1819,7 +1817,7 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { } break; case EXCLUSIVE_SINK: - if (!isAccessiblePinfeedI(childRNode, connection)) { + if (!isAccessibleSink(childRNode, connection)) { continue; } break; @@ -1857,12 +1855,12 @@ protected boolean isAccessible(RouteNode child, Connection connection) { return !config.isUseBoundingBox() || child.isInConnectionBoundingBox(connection); } - protected boolean isAccessiblePinfeedI(RouteNode child, Connection connection) { - // When LUT pin swapping is enabled, PINFEED_I are not exclusive anymore - return isAccessiblePinfeedI(child, connection, !lutPinSwapping); + protected boolean isAccessibleSink(RouteNode child, Connection connection) { + // When LUT pin swapping is enabled, EXCLUSIVE_SINK-s are not exclusive anymore + return isAccessibleSink(child, connection, !lutPinSwapping); } - protected boolean isAccessiblePinfeedI(RouteNode child, Connection connection, boolean assertOnOveruse) { + protected boolean isAccessibleSink(RouteNode child, Connection connection, boolean assertOnOveruse) { assert(child.getType() == RouteNodeType.EXCLUSIVE_SINK); assert(!assertOnOveruse || !child.isOverUsed()); diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index ed9eb82b1..63e7cb0dd 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -33,6 +33,7 @@ import com.xilinx.rapidwright.util.RuntimeTracker; import java.util.ArrayList; +import java.util.EnumSet; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; @@ -124,12 +125,15 @@ private void setBaseCost(Series series) { (length <= 3 && series == Series.Versal)); break; case EXCLUSIVE_SINK: + assert(length == 0); + break; case LOCAL: assert(length == 0 || - (length == 1 && (series == Series.UltraScalePlus || series == Series.UltraScale) && - (getIntentCode() == IntentCode.NODE_PINBOUNCE || - (series == Series.UltraScalePlus && type == RouteNodeType.LOCAL && getWireName().matches("INODE_[EW]_\\d+_FT[01]")) || - (series == Series.UltraScale && type == RouteNodeType.LOCAL && getWireName().matches("INODE_[12]_[EW]_\\d+_FT[NS]")) + (length == 1 && ( + ((series == Series.UltraScalePlus || series == Series.UltraScale) && getIntentCode() == IntentCode.NODE_PINBOUNCE) || + (series == Series.UltraScalePlus && getWireName().matches("INODE_[EW]_\\d+_FT[01]")) || + (series == Series.UltraScale && getWireName().matches("INODE_[12]_[EW]_\\d+_FT[NS]")) || + (series == Series.Versal && EnumSet.of(IntentCode.NODE_CLE_BNODE, IntentCode.NODE_CLE_CNODE).contains(getIntentCode())) )) ); break; @@ -212,20 +216,6 @@ private void setBaseCost(Series series) { // Feedthrough nodes to reach tiles immediately above/below (length == 1 && getWireName().matches("OUT_[NESW]NODE_[EW]_\\d+"))); break; - case NODE_INODE: // INT.INT_NODE_IMUX_ATOM_*_INT_OUT[01] - case NODE_IMUX: // INT.IMUX_B_[EW]* - case NODE_CLE_CTRL: // CLE_BC_CORE*.CTRL_[LR]_B* - case NODE_INTF_CTRL: // INTF_[LR]OCF_[TB][LR]_TILE.INTF_IRI* - assert(length == 0); - break; - case NODE_CLE_BNODE: // CLE_BC_CORE*.BNODE_OUTS_[EW]* - case NODE_CLE_CNODE: // CLE_BC_CORE*.CNODE_OUTS_[EW]* - case NODE_INTF_BNODE: // INTF_[LR]OCF_[TB][LR]_TILE.IF_INT_BNODE_OUTS* - case NODE_INTF_CNODE: // INTF_[LR]OCF_[TB][LR]_TILE.IF_INT_CNODE_OUTS* - // length == 1 because one side of BCNODE-s are shared between CLE_W_CORE_XaYb and CLE_E_CORE_X(a+1)Yb - // or CLE_W_CORE_X(a-1)Yb and CLE_E_CORE_XaYb - assert(length <= 1); - break; default: throw new RuntimeException(ic.toString()); } diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 724326cf6..ef908c356 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -108,6 +108,9 @@ public class RouteNodeGraph { /** Map indicating the wire indices that have a local intent code, but is what RWRoute considers to be non-local */ protected final Map nonLocalWires; + /** Flag for whether design targets the Versal series */ + protected final boolean isVersal; + public RouteNodeGraph(Design design, RWRouteConfig config) { this(design, config, new HashMap<>()); } @@ -147,7 +150,7 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map Date: Tue, 5 Nov 2024 11:30:56 -0800 Subject: [PATCH 21/71] Exclude Versal's NODE_IMUX/NODE_{CLE,INTF}_CTRL if not in RRG Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/RouteNodeGraph.java | 63 +++++++++---------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index ef908c356..590a24cfe 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -23,10 +23,8 @@ package com.xilinx.rapidwright.rwroute; -import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; -import java.util.Collection; import java.util.EnumMap; import java.util.EnumSet; import java.util.HashMap; @@ -79,11 +77,6 @@ public class RouteNodeGraph { */ private final CountUpDownLatch asyncPreserveOutstanding; - /** - * Visited rnodes data during connection routing - */ - private final Collection targets; - private long createRnodeTime; public static final short SUPER_LONG_LINE_LENGTH_IN_TILES = 60; @@ -124,7 +117,6 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map(); preservedMapSize = new AtomicInteger(); asyncPreserveOutstanding = new CountUpDownLatch(); - targets = new ArrayList<>(); createRnodeTime = 0; Device device = design.getDevice(); @@ -290,7 +282,6 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map Date: Tue, 5 Nov 2024 17:55:03 -0800 Subject: [PATCH 22/71] [RWRoute] Divide nodes into LOCAL and NON_LOCAL (#1095) * Expand TestNode.testNodeReachabilityUltraScale() Signed-off-by: Eddie Hung * More Signed-off-by: Eddie Hung * Add and use RouteNodeType.LOCAL Signed-off-by: Eddie Hung * Merge RouteNodeType.PINBOUNCE into LOCAL; rename WIRE, PINFEED_{I,O} Signed-off-by: Eddie Hung * LUT routethru fixes Signed-off-by: Eddie Hung * Add testNodeReachabilityVersal() Signed-off-by: Eddie Hung * Support UltraScale Signed-off-by: Eddie Hung * Fix intent codes Signed-off-by: Eddie Hung * Cleanup Signed-off-by: Eddie Hung * Tidy up Signed-off-by: Eddie Hung * Fix assertion Signed-off-by: Eddie Hung * Check for tile exit Signed-off-by: Eddie Hung * Address review Signed-off-by: Eddie Hung --------- Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/Connection.java | 8 +- .../rapidwright/rwroute/NetWrapper.java | 2 +- .../rapidwright/rwroute/PartialRouter.java | 6 +- .../xilinx/rapidwright/rwroute/RWRoute.java | 59 +++-- .../xilinx/rapidwright/rwroute/RouteNode.java | 48 +++-- .../rapidwright/rwroute/RouteNodeGraph.java | 170 +++++++-------- .../rapidwright/rwroute/RouteNodeInfo.java | 43 ++-- .../rapidwright/rwroute/RouteNodeType.java | 28 +-- .../rwroute/TimingAndWirelengthReport.java | 6 +- .../xilinx/rapidwright/device/TestNode.java | 204 +++++++++++++++--- 10 files changed, 355 insertions(+), 219 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/Connection.java b/src/com/xilinx/rapidwright/rwroute/Connection.java index 69aef1b90..6c08342dc 100644 --- a/src/com/xilinx/rapidwright/rwroute/Connection.java +++ b/src/com/xilinx/rapidwright/rwroute/Connection.java @@ -305,9 +305,9 @@ public void addAltSinkRnode(RouteNode sinkRnode) { } else { assert(!altSinkRnodes.contains(sinkRnode)); } - assert(sinkRnode.getType() == RouteNodeType.PINFEED_I || + assert(sinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK || // Can be a WIRE if node is not exclusive a sink - sinkRnode.getType() == RouteNodeType.WIRE); + sinkRnode.getType() == RouteNodeType.NON_LOCAL); altSinkRnodes.add(sinkRnode); } @@ -486,8 +486,8 @@ public void setAllTargets(RWRoute.ConnectionState state) { // if it's not already in use by the current net to prevent the case // where the same physical pin services more than one logical pin if (rnode.countConnectionsOfUser(netWrapper) == 0 || - // Except if it is not a PINFEED_I - rnode.getType() != RouteNodeType.PINFEED_I) { + // Except if it is not an EXCLUSIVE_SINK + rnode.getType() != RouteNodeType.EXCLUSIVE_SINK) { assert(rnode.getIntentCode() != IntentCode.NODE_PINBOUNCE); rnode.markTarget(state); } diff --git a/src/com/xilinx/rapidwright/rwroute/NetWrapper.java b/src/com/xilinx/rapidwright/rwroute/NetWrapper.java index 200bbf7c6..05dc3eff8 100644 --- a/src/com/xilinx/rapidwright/rwroute/NetWrapper.java +++ b/src/com/xilinx/rapidwright/rwroute/NetWrapper.java @@ -171,7 +171,7 @@ public SitePinInst getOrCreateAlternateSource(RouteNodeGraph routingGraph) { return null; } - altSourceRnode = routingGraph.getOrCreate(altSourceNode, RouteNodeType.PINFEED_O); + altSourceRnode = routingGraph.getOrCreate(altSourceNode, RouteNodeType.EXCLUSIVE_SOURCE); } assert(altSourceRnode != null); return altSource; diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index 1ad73e55d..871637153 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -256,7 +256,7 @@ protected void determineRoutingTargets() { preservedNet = routingGraph.getPreservedNet(sinkRnode); if (preservedNet != null && preservedNet != net) { unpreserveNets.add(preservedNet); - assert(sinkRnode.getType() == RouteNodeType.PINFEED_I); + assert(sinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK); } } @@ -598,8 +598,8 @@ protected void unpreserveNet(Net net) { assert(!connection.isDirect()); RouteNode sourceRnode = connection.getSourceRnode(); RouteNode sinkRnode = connection.getSinkRnode(); - assert(sourceRnode.getType() == RouteNodeType.PINFEED_O); - assert(sinkRnode.getType() == RouteNodeType.PINFEED_I); + assert(sourceRnode.getType() == RouteNodeType.EXCLUSIVE_SOURCE); + assert(sinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK); // Even though this connection is not expected to have any routing yet, // perform a rip up anyway in order to release any exclusive sinks diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index d44b7edd4..4d2f363d5 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -56,7 +56,6 @@ import com.xilinx.rapidwright.util.Pair; import com.xilinx.rapidwright.util.RuntimeTracker; import com.xilinx.rapidwright.util.RuntimeTrackerTree; -import com.xilinx.rapidwright.util.Utils; import java.util.ArrayList; import java.util.Arrays; @@ -589,7 +588,7 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { if (connection.getSourceRnode() == null) { assert(sourceINTNode != null); if (sourceINTRnode == null) { - sourceINTRnode = routingGraph.getOrCreate(sourceINTNode, RouteNodeType.PINFEED_O); + sourceINTRnode = routingGraph.getOrCreate(sourceINTNode, RouteNodeType.EXCLUSIVE_SOURCE); // Where only a single primary source exists, always preserve // its projected-to-INT source node, since it could // be a projection from LAGUNA/RXQ* -> RXD* (node for INT/LOGIC_OUTS_*) @@ -601,8 +600,8 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { } indirectConnections.add(connection); - RouteNode sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.PINFEED_I); - sinkRnode.setType(RouteNodeType.PINFEED_I); + RouteNode sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK); + sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK); connection.setSinkRnode(sinkRnode); // Where appropriate, allow all 6 LUT pins to be swapped to begin with @@ -651,8 +650,8 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { if (routingGraph.isPreserved(node)) { continue; } - RouteNode altSinkRnode = routingGraph.getOrCreate(node, RouteNodeType.PINFEED_I); - assert(altSinkRnode.getType() == RouteNodeType.PINFEED_I); + RouteNode altSinkRnode = routingGraph.getOrCreate(node, RouteNodeType.EXCLUSIVE_SINK); + assert(altSinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK); connection.addAltSinkRnode(altSinkRnode); } @@ -1798,7 +1797,18 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { continue; } switch (childRNode.getType()) { - case WIRE: + case LOCAL: + if (!routingGraph.isAccessible(childRNode, connection)) { + continue; + } + break; + case NON_LOCAL: + // LOCALs cannot connect to NON_LOCALs except via a LUT routethru + assert(rnode.getType() != RouteNodeType.LOCAL || + routingGraph.lutRoutethru && rnode.getIntentCode() == IntentCode.NODE_PINFEED || + // FIXME: + design.getSeries() == Series.Versal); + if (!routingGraph.isAccessible(childRNode, connection)) { continue; } @@ -1808,19 +1818,12 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { continue; } break; - case PINBOUNCE: - // A PINBOUNCE can only be a target if this connection has an alternate sink - assert(!childRNode.isTarget() || connection.getAltSinkRnodes().isEmpty()); - if (!isAccessiblePinbounce(childRNode, connection)) { - continue; - } - break; - case PINFEED_I: - if (!isAccessiblePinfeedI(childRNode, connection)) { + case EXCLUSIVE_SINK: + if (!isAccessibleSink(childRNode, connection)) { continue; } break; - case LAGUNA_I: + case LAGUNA_PINFEED: if (!connection.isCrossSLR() || connection.getSinkRnode().getSLRIndex(routingGraph) == childRNode.getSLRIndex(routingGraph)) { // Do not consider approaching a SLL if not needing to cross @@ -1854,25 +1857,13 @@ protected boolean isAccessible(RouteNode child, Connection connection) { return !config.isUseBoundingBox() || child.isInConnectionBoundingBox(connection); } - /** - * Checks if a NODE_PINBOUNCE is suitable to be used for routing to a target. - * @param child The PINBOUNCE rnode in question. - * @param connection The connection to route. - * @return true, if the PINBOUNCE rnode is in the same column as the target and within one INT tile of the target. - */ - protected boolean isAccessiblePinbounce(RouteNode child, Connection connection) { - assert(child.getType() == RouteNodeType.PINBOUNCE); - - return routingGraph.isAccessible(child, connection); - } - - protected boolean isAccessiblePinfeedI(RouteNode child, Connection connection) { - // When LUT pin swapping is enabled, PINFEED_I are not exclusive anymore - return isAccessiblePinfeedI(child, connection, !lutPinSwapping); + protected boolean isAccessibleSink(RouteNode child, Connection connection) { + // When LUT pin swapping is enabled, EXCLUSIVE_SINK-s are not exclusive anymore + return isAccessibleSink(child, connection, !lutPinSwapping); } - protected boolean isAccessiblePinfeedI(RouteNode child, Connection connection, boolean assertOnOveruse) { - assert(child.getType() == RouteNodeType.PINFEED_I); + protected boolean isAccessibleSink(RouteNode child, Connection connection, boolean assertOnOveruse) { + assert(child.getType() == RouteNodeType.EXCLUSIVE_SINK); assert(!assertOnOveruse || !child.isOverUsed()); if (child.isTarget()) { diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index 1dbc5f4c6..c70a18000 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -27,6 +27,7 @@ import com.xilinx.rapidwright.design.Net; import com.xilinx.rapidwright.device.IntentCode; import com.xilinx.rapidwright.device.Node; +import com.xilinx.rapidwright.device.Series; import com.xilinx.rapidwright.device.Tile; import com.xilinx.rapidwright.device.TileTypeEnum; import com.xilinx.rapidwright.util.RuntimeTracker; @@ -92,13 +93,13 @@ public class RouteNode extends Node implements Comparable { protected RouteNode(RouteNodeGraph routingGraph, Node node, RouteNodeType type) { super(node); - RouteNodeInfo nodeInfo = RouteNodeInfo.get(this, routingGraph.lagunaI); + RouteNodeInfo nodeInfo = RouteNodeInfo.get(this, routingGraph); this.type = (type == null) ? nodeInfo.type : type; endTileXCoordinate = nodeInfo.endTileXCoordinate; endTileYCoordinate = nodeInfo.endTileYCoordinate; length = nodeInfo.length; children = null; - setBaseCost(); + setBaseCost(routingGraph.design.getSeries()); presentCongestionCost = initialPresentCongestionCost; historicalCongestionCost = initialHistoricalCongestionCost; usersConnectionCounts = null; @@ -115,10 +116,27 @@ public int compareTo(RouteNode that) { return (int) Math.signum(this.lowerBoundTotalPathCost - that.lowerBoundTotalPathCost); } - private void setBaseCost() { + private void setBaseCost(Series series) { baseCost = 0.4f; switch (type) { - case LAGUNA_I: + case EXCLUSIVE_SOURCE: + assert(length == 0 || + (length <= 3 && series == Series.Versal)); + break; + case EXCLUSIVE_SINK: + assert(length == 0 || + (length == 1 && (series == Series.UltraScalePlus || series == Series.UltraScale) && getIntentCode() == IntentCode.NODE_PINBOUNCE)); + break; + case LOCAL: + assert(length == 0 || + (length == 1 && ( + ((series == Series.UltraScalePlus || series == Series.UltraScale) && getIntentCode() == IntentCode.NODE_PINBOUNCE) || + (series == Series.UltraScalePlus && getWireName().matches("INODE_[EW]_\\d+_FT[01]")) || + (series == Series.UltraScale && getWireName().matches("INODE_[12]_[EW]_\\d+_FT[NS]")) + )) + ); + break; + case LAGUNA_PINFEED: // Make all approaches to SLLs zero-cost to encourage exploration // Assigning a base cost of zero would normally break congestion resolution // (since RWroute.getNodeCost() would return zero) but doing it here should be @@ -129,7 +147,7 @@ private void setBaseCost() { assert(length == RouteNodeGraph.SUPER_LONG_LINE_LENGTH_IN_TILES); baseCost = 0.3f * length; break; - case WIRE: + case NON_LOCAL: // NOTE: IntentCode is device-dependent IntentCode ic = getIntentCode(); switch(ic) { @@ -139,10 +157,10 @@ private void setBaseCost() { case NODE_LAGUNA_OUTPUT: // LAG_LAG.{LAG_MUX_ATOM_*_TXOUT,RXD*} (US+) case NODE_LAGUNA_DATA: // LAG_LAG.UBUMP* super long lines for u-turns at the boundary of the device (US+) case NODE_PINFEED: + case INTENT_DEFAULT: // INT.VCC_WIRE assert(length == 0); break; - case NODE_LOCAL: // US and US+ - case INTENT_DEFAULT: + case NODE_LOCAL: // US and US+ assert(length <= 1); break; case NODE_VSINGLE: // Versal-only @@ -215,12 +233,6 @@ private void setBaseCost() { throw new RuntimeException(ic.toString()); } break; - case PINFEED_I: - case PINBOUNCE: - break; - case PINFEED_O: - baseCost = 1f; - break; default: throw new RuntimeException(type.toString()); } @@ -348,11 +360,11 @@ public RouteNodeType getType() { */ public void setType(RouteNodeType type) { assert(this.type == type || - // Support demotion from PINFEED_I to PINBOUNCE since they have the same base cost - (this.type == RouteNodeType.PINFEED_I && type == RouteNodeType.PINBOUNCE) || - // Or promotion from PINBOUNCE to PINFEED_I (by PartialRouter when PINBOUNCE on - // preserved net needs to become a PINFEED_I) - (this.type == RouteNodeType.PINBOUNCE && type == RouteNodeType.PINFEED_I)); + // Support demotion from EXCLUSIVE_SINK to LOCAL since they have the same base cost + (this.type == RouteNodeType.EXCLUSIVE_SINK && type == RouteNodeType.LOCAL) || + // Or promotion from LOCAL to EXCLUSIVE_SINK (by PartialRouter when NODE_PINBOUNCE on + // a newly unpreserved net becomes a sink) + (this.type == RouteNodeType.LOCAL && type == RouteNodeType.EXCLUSIVE_SINK)); this.type = type; } diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index e68ad6d8c..324be57e3 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -23,10 +23,8 @@ package com.xilinx.rapidwright.rwroute; -import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; -import java.util.Collection; import java.util.EnumMap; import java.util.EnumSet; import java.util.HashMap; @@ -37,7 +35,6 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; import com.xilinx.rapidwright.design.Design; import com.xilinx.rapidwright.design.Net; @@ -80,11 +77,6 @@ public class RouteNodeGraph { */ private final CountUpDownLatch asyncPreserveOutstanding; - /** - * Visited rnodes data during connection routing - */ - private final Collection targets; - private long createRnodeTime; public static final short SUPER_LONG_LINE_LENGTH_IN_TILES = 60; @@ -100,19 +92,15 @@ public class RouteNodeGraph { */ protected final Map lagunaI; - /** Map indicating which wire indices within an INT tile should be considered - * accessible only if it is within the same column (same X tile coordinate) as - * the target tile. - */ - protected final Map accessibleWireOnlyIfAboveBelowTarget; - /** Map indicating the wire indices corresponding to the [A-H]MUX output */ protected final Map muxWires; - /** Flag for whether LUT routethrus are to be considered - */ + /** Flag for whether LUT routethrus are to be considered */ protected final boolean lutRoutethru; + /** Map indicating the wire indices that have a local intent code, but is what RWRoute considers to be non-local */ + protected final Map ultraScaleNonLocalWires; + public RouteNodeGraph(Design design, RWRouteConfig config) { this(design, config, new HashMap<>()); } @@ -126,7 +114,6 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map(); preservedMapSize = new AtomicInteger(); asyncPreserveOutstanding = new CountUpDownLatch(); - targets = new ArrayList<>(); createRnodeTime = 0; Device device = design.getDevice(); @@ -142,58 +129,64 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map(TileTypeEnum.class); - BitSet wires = new BitSet(); - Tile intTile = device.getArbitraryTileOfType(TileTypeEnum.INT); - // Device.getArbitraryTileOfType() typically gives you the North-Western-most - // tile (with minimum X, maximum Y). Analyze the tile just below that. - intTile = intTile.getTileXYNeighbor(0, -1); Series series = device.getSeries(); - for (int wireIndex = 0; wireIndex < intTile.getWireCount(); wireIndex++) { - Node baseNode = Node.getNode(intTile, wireIndex); - if (baseNode == null) { - continue; - } - Tile baseTile = baseNode.getTile(); - String wireName = baseNode.getWireName(); - if (wireName.startsWith("BOUNCE_")) { - assert(baseNode.getIntentCode() == IntentCode.NODE_PINBOUNCE); - assert(baseTile.getTileXCoordinate() == intTile.getTileXCoordinate()); - // Uphill from INT_NODE_IMUX_* in tile above/below and INODE_* in above/target or below/target tiles - // Downhill to INT_NODE_IMUX_* and INODE_* to above/below tile - } else if (wireName.startsWith("BYPASS_")) { - assert(baseNode.getIntentCode() == IntentCode.NODE_PINBOUNCE); - assert(baseTile == intTile); - assert(wireIndex == baseNode.getWireIndex()); - // Uphill and downhill are INT_NODE_IMUX_* in the target tile and INODE_* to above/below tiles - } else if (wireName.startsWith("INT_NODE_GLOBAL_")) { - assert(baseNode.getIntentCode() == IntentCode.NODE_LOCAL); - assert(baseTile == intTile); - assert(wireIndex == baseNode.getWireIndex()); - // Downhill to CTRL_* in the target tile, INODE_* to above/below tile, INT_NODE_IMUX_* in target tile - } else if (wireName.startsWith("INT_NODE_IMUX_") && - // Do not block INT_NODE_IMUX node accessibility when LUT routethrus are considered - !lutRoutethru) { - assert(((series == Series.UltraScale || series == Series.UltraScalePlus) && baseNode.getIntentCode() == IntentCode.NODE_LOCAL) || - (series == Series.Versal && baseNode.getIntentCode() == IntentCode.NODE_INODE)); - assert(baseTile == intTile); - assert(wireIndex == baseNode.getWireIndex()); - // Downhill to BOUNCE_* in the above/below/target tile, BYPASS_* in the base tile, IMUX_* in target tile - } else if (wireName.startsWith("INODE_")) { - assert(baseNode.getIntentCode() == IntentCode.NODE_LOCAL); - assert(baseTile.getTileXCoordinate() == intTile.getTileXCoordinate()); - // Uphill from nodes in above/target or below/target tiles - // Downhill to BOUNCE_*/BYPASS_*/IMUX_* in above/target or below/target tiles - } else { - continue; - } + boolean isUltraScale = series == Series.UltraScale; + boolean isUltraScalePlus = series == Series.UltraScalePlus; + if (isUltraScale || isUltraScalePlus) { + ultraScaleNonLocalWires = new EnumMap<>(TileTypeEnum.class); + BitSet wires = new BitSet(); + Tile intTile = device.getArbitraryTileOfType(TileTypeEnum.INT); + // Device.getArbitraryTileOfType() typically gives you the North-Western-most + // tile (with minimum X, maximum Y). Analyze the tile just below that. + intTile = intTile.getTileXYNeighbor(0, -1); + ultraScaleNonLocalWires.put(intTile.getTileTypeEnum(), wires); + for (int wireIndex = 0; wireIndex < intTile.getWireCount(); wireIndex++) { + Node baseNode = Node.getNode(intTile, wireIndex); + if (baseNode == null) { + continue; + } + if (baseNode.getIntentCode() != IntentCode.NODE_LOCAL) { + continue; + } + + Tile baseTile = baseNode.getTile(); + String wireName = baseNode.getWireName(); + if (isUltraScalePlus) { + if (!wireName.startsWith("INT_NODE_SDQ_") && !wireName.startsWith("SDQNODE_")) { + continue; + } + if (baseTile != intTile) { + if (wireName.endsWith("_FT0")) { + assert(baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() - 1); + } else { + assert(wireName.endsWith("_FT1")); + assert(baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() + 1); + } + } + } else { + assert(isUltraScale); - wires.set(baseNode.getWireIndex()); + if (!wireName.startsWith("INT_NODE_SINGLE_DOUBLE_") && !wireName.startsWith("SDND") && + !wireName.startsWith("INT_NODE_QUAD_LONG") && !wireName.startsWith("QLND")) { + continue; + } + if (baseTile != intTile) { + if (wireName.endsWith("_FTN")) { + assert(baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() - 1); + } else { + assert(wireName.endsWith("_FTS")); + assert(baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() + 1); + } + } + } + wires.set(baseNode.getWireIndex()); + } + } else { + ultraScaleNonLocalWires = null; } - accessibleWireOnlyIfAboveBelowTarget.put(intTile.getTileTypeEnum(), wires); if (lutRoutethru) { - assert(design.getSeries() == Series.UltraScale || design.getSeries() == Series.UltraScalePlus); + assert(isUltraScalePlus || isUltraScale); muxWires = new EnumMap<>(TileTypeEnum.class); for (TileTypeEnum tileTypeEnum : Utils.getCLBTileTypes()) { @@ -201,7 +194,7 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map lagunaI) { + public static RouteNodeInfo get(Node node, RouteNodeGraph routingGraph) { Wire[] wires = node.getAllWiresInNode(); Tile baseTile = node.getTile(); TileTypeEnum baseTileType = baseTile.getTileTypeEnum(); @@ -66,7 +65,7 @@ public static RouteNodeInfo get(Node node, Map lagunaI) { endTile = node.getTile(); } - RouteNodeType type = getType(node, endTile, lagunaI); + RouteNodeType type = getType(node, endTile, routingGraph); short endTileXCoordinate = getEndTileXCoordinate(node, type, (short) endTile.getTileXCoordinate()); short endTileYCoordinate = (short) endTile.getTileYCoordinate(); short length = getLength(baseTile, type, endTileXCoordinate, endTileYCoordinate); @@ -93,7 +92,7 @@ private static short getLength(Tile baseTile, RouteNodeType type, short endTileX } break; case INT: - if (type == RouteNodeType.LAGUNA_I) { + if (type == RouteNodeType.LAGUNA_PINFEED) { assert(length == 0); } break; @@ -112,7 +111,7 @@ private static short getEndTileXCoordinate(Node node, RouteNodeType type, short // fanout nodes of the SLL are marked as) unless it is a fanin (LAGUNA_I) // (i.e. do not apply it to the fanout nodes). // Nor apply it to VCC_WIREs since their end tiles are INT tiles. - if ((node.getIntentCode() != IntentCode.NODE_LAGUNA_OUTPUT || type == RouteNodeType.LAGUNA_I) && + if ((node.getIntentCode() != IntentCode.NODE_LAGUNA_OUTPUT || type == RouteNodeType.LAGUNA_PINFEED) && !node.isTiedToVcc()) { assert(baseTile.getTileXCoordinate() == endTileXCoordinate); endTileXCoordinate++; @@ -126,24 +125,38 @@ private static short getEndTileXCoordinate(Node node, RouteNodeType type, short return endTileXCoordinate; } - private static RouteNodeType getType(Node node, Tile endTile, Map lagunaI) { + private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph routingGraph) { // NOTE: IntentCode is device-dependent IntentCode ic = node.getIntentCode(); switch (ic) { + case NODE_LOCAL: { // US/US+ + assert(node.getTile().getTileTypeEnum() == TileTypeEnum.INT); + if (routingGraph != null) { + BitSet bs = routingGraph.ultraScaleNonLocalWires.get(node.getTile().getTileTypeEnum()); + if (!bs.get(node.getWireIndex())) { + return RouteNodeType.LOCAL; + } + break; + } + } + case NODE_PINBOUNCE: - return RouteNodeType.PINBOUNCE; + return RouteNodeType.LOCAL; - case NODE_PINFEED: - BitSet bs = (lagunaI != null) ? lagunaI.get(node.getTile()) : null; - if (bs != null && bs.get(node.getWireIndex())) { - return RouteNodeType.LAGUNA_I; + case NODE_PINFEED: { + if (routingGraph != null && routingGraph.lagunaI != null) { + BitSet bs = routingGraph.lagunaI.get(node.getTile()); + if (bs != null && bs.get(node.getWireIndex())) { + return RouteNodeType.LAGUNA_PINFEED; + } } - break; + return RouteNodeType.LOCAL; + } case NODE_LAGUNA_OUTPUT: // UltraScale+ only assert(node.getTile().getTileTypeEnum() == TileTypeEnum.LAG_LAG); if (node.getWireName().endsWith("_TXOUT")) { - return RouteNodeType.LAGUNA_I; + return RouteNodeType.LAGUNA_PINFEED; } break; @@ -164,12 +177,12 @@ private static RouteNodeType getType(Node node, Tile endTile, Map l return RouteNodeType.SUPER_LONG_LINE; } else if (wireName.endsWith("_TXOUT")) { // This is the inner LAGUNA_I, mark it so it gets a base cost discount - return RouteNodeType.LAGUNA_I; + return RouteNodeType.LAGUNA_PINFEED; } } break; } - return RouteNodeType.WIRE; + return RouteNodeType.NON_LOCAL; } } diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java index d81176409..2510b4701 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java @@ -24,26 +24,11 @@ package com.xilinx.rapidwright.rwroute; -import com.xilinx.rapidwright.design.Net; -import com.xilinx.rapidwright.device.IntentCode; import com.xilinx.rapidwright.device.Node; public enum RouteNodeType { - /** - * Denotes {@link RouteNode} objects that correspond to the output pins of {@link Net} Objects, - * typically the source {@link RouteNode} Objects of {@link Connection} Objects. - */ - PINFEED_O, - /** - * Denotes {@link RouteNode} objects that correspond to input pins of {@link Net} Objects, - * typically the sink {@link RouteNode} Objects of {@link Connection} Objects. - */ - PINFEED_I, - /** - * Denotes {@link RouteNode} objects that are created based on {@link Node} Objects - * that have an {@link IntentCode} of NODE_PINBOUNCE. - */ - PINBOUNCE, + EXCLUSIVE_SOURCE, + EXCLUSIVE_SINK, /** * Denotes {@link RouteNode} objects that correspond to a super long line {@link Node}, @@ -55,12 +40,9 @@ public enum RouteNodeType { * Denotes {@link RouteNode} objects that correspond to {@link Node} objects that enter * a Laguna tile from an INT tile, or those Laguna tile nodes leading to a SUPER_LONG_LINE. */ - LAGUNA_I, + LAGUNA_PINFEED, - /** - * Denotes other wiring {@link RouteNode} Objects - * that are created for routing {@link Connection} Objects. - */ - WIRE + NON_LOCAL, + LOCAL } diff --git a/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java b/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java index 7da5a405f..c51cc6789 100644 --- a/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java +++ b/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java @@ -25,7 +25,6 @@ package com.xilinx.rapidwright.rwroute; import java.util.HashMap; -import java.util.List; import java.util.Map; import com.xilinx.rapidwright.design.Design; @@ -35,7 +34,6 @@ import com.xilinx.rapidwright.design.SitePinInst; import com.xilinx.rapidwright.device.IntentCode; import com.xilinx.rapidwright.device.Node; -import com.xilinx.rapidwright.device.TileTypeEnum; import com.xilinx.rapidwright.timing.TimingManager; import com.xilinx.rapidwright.timing.TimingVertex; import com.xilinx.rapidwright.timing.delayestimator.DelayEstimatorBase; @@ -130,11 +128,11 @@ private NetWrapper createNetWrapper(Net net) { if (sinkINTNode == null) { connection.setDirect(true); } else { - connection.setSinkRnode(routingGraph.getOrCreate(sinkINTNode, RouteNodeType.PINFEED_I)); + connection.setSinkRnode(routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK)); if (sourceINTNode == null) { sourceINTNode = RouterHelper.projectOutputPinToINTNode(source); } - connection.setSourceRnode(routingGraph.getOrCreate(sourceINTNode, RouteNodeType.PINFEED_O)); + connection.setSourceRnode(routingGraph.getOrCreate(sourceINTNode, RouteNodeType.EXCLUSIVE_SOURCE)); connection.setDirect(false); } } diff --git a/test/src/com/xilinx/rapidwright/device/TestNode.java b/test/src/com/xilinx/rapidwright/device/TestNode.java index 2b24b6544..e72e0cd4a 100644 --- a/test/src/com/xilinx/rapidwright/device/TestNode.java +++ b/test/src/com/xilinx/rapidwright/device/TestNode.java @@ -24,6 +24,7 @@ import java.util.ArrayDeque; import java.util.Collection; +import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Queue; @@ -83,45 +84,71 @@ public void testUphillNodeIsInvalid() { @ParameterizedTest @CsvSource({ // UltraScale+ part - "xcvu3p,INT_X37Y220,BOUNCE_", - "xcvu3p,INT_X37Y220,BYPASS_", - "xcvu3p,INT_X37Y220,INT_NODE_GLOBAL_", - "xcvu3p,INT_X37Y220,INT_NODE_IMUX_", - "xcvu3p,INT_X37Y220,INODE_", - // These nodes fanout to NESW nodes in the tile above or below - // "xcvu3p,INT_X37Y220,SDQNODE_", + "xcvu3p,INT_X37Y220,BOUNCE_.*,true", + "xcvu3p,INT_X37Y220,BYPASS_.*,true", + "xcvu3p,INT_X37Y220,INT_NODE_GLOBAL_.*,true", + "xcvu3p,INT_X37Y220,INT_NODE_IMUX_.*,true", + "xcvu3p,INT_X37Y220,INODE_.*,true", + "xcvu3p,INT_X37Y220,INT_INT_SDQ_.*,false", // IntentCode.NODE_SINGLE + "xcvu3p,INT_X37Y220,INT_NODE_SDQ_.*,false", + "xcvu3p,INT_X37Y220,SDQNODE_.*,false", + "xcvu3p,INT_X37Y220,IMUX_.*,true", + "xcvu3p,INT_X37Y220,CTRL_.*,true", + "xcvu3p,INT_X37Y220,(NN|EE|SS|WW)1_.*,false", + "xcvu3p,INT_X37Y220,(NN|EE|SS|WW)2_.*,false", + "xcvu3p,INT_X37Y220,(NN|EE|SS|WW)4_.*,false", + "xcvu3p,INT_X37Y220,(NN|EE|SS|WW)12_.*,false", + "xcvu3p,CLEM_X37Y220,CLE_CLE_M_SITE_0_[A-H](_O|Q|Q2|MUX),false", // UltraScale part - "xcvu065,INT_X38Y220,BOUNCE_", - "xcvu065,INT_X38Y220,BYPASS_", - "xcvu065,INT_X38Y220,INT_NODE_GLOBAL_", - "xcvu065,INT_X38Y220,INT_NODE_IMUX_", - "xcvu065,INT_X38Y220,INODE_", - // "xcvu065,INT_X38Y220,QLND", - // "xcvu065,INT_X38Y220,SDND", + "xcvu065,INT_X38Y220,BOUNCE_.*,true", + "xcvu065,INT_X38Y220,BYPASS_.*,true", + "xcvu065,INT_X38Y220,INT_NODE_GLOBAL_.*,true", + "xcvu065,INT_X38Y220,INT_NODE_IMUX_.*,true", + "xcvu065,INT_X38Y220,INODE_.*,true", + "xcvu065,INT_X38Y220,INT_INT_SINGLE_.*,false", // IntentCode.NODE_SINGLE + "xcvu065,INT_X38Y220,INT_NODE_SINGLE_DOUBLE_.*,false", + "xcvu065,INT_X38Y220,INT_NODE_QUAD_LONG_.*,false", + "xcvu065,INT_X38Y220,IMUX_.*,true", + "xcvu065,INT_X38Y220,CTRL_.*,true", + "xcvu065,INT_X37Y220,(NN|EE|SS|WW)1_.*,false", + "xcvu065,INT_X37Y220,(NN|EE|SS|WW)2_.*,false", + "xcvu065,INT_X37Y220,(NN|EE|SS|WW)4_.*,false", + "xcvu065,INT_X37Y220,(NN|EE|SS|WW)5_.*,false", + "xcvu065,INT_X37Y220,(NN|EE|SS|WW)12_.*,false", + "xcvu065,INT_X37Y220,(NN|EE|SS|WW)16_.*,false", + "xcvu065,INT_X38Y220,QLND.*,false", + "xcvu065,INT_X38Y220,SDND.*,false", + "xcvu065,CLE_M_X38Y220,CLE_CLE_M_SITE_0_[A-H](_O|Q|Q2|MUX),false", }) - public void testNodeReachabilityUltraScale(String partName, String tileName, String wirePrefix) { + public void testNodeReachabilityUltraScale(String partName, String tileName, String wireRegex, boolean local) { Device device = Device.getDevice(partName); Tile baseTile = device.getTile(tileName); Queue queue = new ArrayDeque<>(); + Set intentCodes = EnumSet.noneOf(IntentCode.class); for (String wireName : baseTile.getWireNames()) { - if (!wireName.startsWith(wirePrefix)) { + if (!wireName.matches(wireRegex)) { continue; } - queue.add(Node.getNode(baseTile, wireName)); + Node node = Node.getNode(baseTile, wireName); + queue.add(node); + intentCodes.add(node.getIntentCode()); } System.out.println("Initial queue.size() = " + queue.size()); + System.out.println("Intent codes = " + intentCodes); // Print out the prefixes of nodes that are immediately uphill of these wire prefixes // (i.e. "BOUNCE_E_0_FT1" -> "BOUNCE_") System.out.println("Immediately uphill:"); - queue.stream().map(Node::getAllUphillNodes).flatMap(List::stream).map(Node::getWireName) - .map(s -> s.replaceFirst("((BOUNCE|BYPASS|CTRL|INT_NODE_[^_]+|INODE)_).*", "$1")) + boolean ultraScalePlus = partName.endsWith("p"); + queue.stream().map(Node::getAllUphillNodes).flatMap(List::stream) + .map(n -> n.getWireName() + " (" + n.getIntentCode() + ")") + .map(s -> s.replaceFirst("((BOUNCE|BYPASS|CTRL|INT_NODE_[^_]+|INODE|IMUX|SDQNODE)_)[^\\(]+", "$1")) .map(s -> s.replaceFirst( - // UltraScale+ - (partName.endsWith("p")) ? "((CLE_CLE_[LM]_SITE_0|CLK_LEAF_SITES|EE[124]|INT_INT_SDQ|NN[12]|SS[12]|WW[124])_).*" - // UltraScale - : "((CLE_CLE_[LM]_SITE_0|CLK_BUFCE_LEAF_X16_1_CLK|EE[124]|INT_INT_SINGLE|NN[12]|SS[12]|WW[124])_).*", + // UltraScale+ + ultraScalePlus ? "((CLE_CLE_[LM]_SITE_0|CLK_LEAF_SITES|INT_INT_SDQ|(NN|EE|SS|WW)(1|2|4|12))_)[^\\(]+" + // UltraScale + : "((CLE_CLE_[LM]_SITE_0|CLK_BUFCE_LEAF_X16_1_CLK|EE[124]|INT_INT_SINGLE|(NN|SS)(1|2|4|5|12|16)|(EE|WW)(1|2|4|12)|QLND(NW|SE|SW)|SDND[NS]W)_)[^\\(]+", "$1")) .distinct() .sorted() @@ -129,15 +156,33 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str // Print out the prefixes of nodes that are immediately downhill of these wire prefixes System.out.println("Immediately downhill:"); - queue.stream().map(Node::getAllDownhillNodes).flatMap(List::stream).map(Node::getWireName) - .map(s -> s.replaceFirst("((BOUNCE|BYPASS|CTRL|IMUX|INT_NODE_[^_]+|INODE)_).*", "$1")) + queue.stream().map(Node::getAllDownhillNodes).flatMap(List::stream) + .map(n -> n.getWireName() + " (" + n.getIntentCode() + ")") + .map(s -> s.replaceFirst("((BOUNCE|BYPASS|CTRL|IMUX|INT_NODE_[^_]+|INODE|SDQNODE)_)[^\\(]+", "$1")) + .map(s -> s.replaceFirst( + // UltraScale+ + ultraScalePlus ? "((CLE_CLE_[LM]_SITE_0|INT_INT_SDQ|(NN|EE|SS|WW)(1|2|4|12))_)[^\\(]+" + // UltraScale + : "((CLE_CLE_[LM]_SITE_0|INT_INT_SINGLE|(NN|SS)(1|2|4|5|12|16)|(EE|WW)(1|2|4|12)|QLND(NW|S[EW])|SDND[NS]W)_)[^\\(]+", + "$1")) .distinct() .sorted() .forEachOrdered(s -> System.out.println("\t" + s)); Set visited = new HashSet<>(); + boolean exitsBaseTile = false; while (!queue.isEmpty()) { Node node = queue.poll(); + String wireName = node.getWireName(); + if ((ultraScalePlus && wireName.matches("(INT_NODE_SDQ|SDQNODE)_.*")) || // UltraScale+ + (!ultraScalePlus && wireName.matches("(INT_NODE_(SINGLE_DOUBLE|QUAD_LONG)|QLND(NW|SE|SW)|SDND[NS]W)_.*") || // UltraScale + EnumSet.of(IntentCode.NODE_SINGLE, IntentCode.NODE_DOUBLE, IntentCode.NODE_HQUAD, IntentCode.NODE_VQUAD, IntentCode.NODE_HLONG, IntentCode.NODE_VLONG) + .contains(node.getIntentCode())) + ) { + // Do not descend into SDQNODEs or SDQLs + exitsBaseTile = true; + continue; + } for (Node downhill : node.getAllDownhillNodes()) { if (!visited.add(downhill)) { continue; @@ -145,12 +190,121 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str if (!Utils.isInterConnect(downhill.getTile().getTileTypeEnum())) { continue; } + // Check that they are all in the same column Assertions.assertEquals(baseTile.getTileXCoordinate(), downhill.getTile().getTileXCoordinate()); queue.add(downhill); } } System.out.println("visited.size() = " + visited.size()); + + // Local nodes should never exit the tile + Assertions.assertNotEquals(local, exitsBaseTile); + } + + @ParameterizedTest + @CsvSource({ + "xcvp1002,INT_X38Y220,NODE_PINBOUNCE,true", + "xcvp1002,INT_X38Y220,NODE_INODE,true", + "xcvp1002,INT_X38Y220,NODE_IMUX,true", + "xcvp1002,INT_X38Y220,NODE_SDQNODE,false", + "xcvp1002,INT_X38Y220,NODE_HSINGLE,false", + "xcvp1002,INT_X38Y220,NODE_VSINGLE,false", + "xcvp1002,INT_X38Y220,NODE_HDOUBLE,false", + "xcvp1002,INT_X38Y220,NODE_VDOUBLE,false", + "xcvp1002,INT_X38Y220,NODE_HQUAD,false", + "xcvp1002,INT_X38Y220,NODE_VQUAD,false", + "xcvp1002,INT_X38Y220,NODE_HLONG6,false", + "xcvp1002,INT_X38Y220,NODE_HLONG10,false", + "xcvp1002,INT_X38Y220,NODE_VLONG7,false", + "xcvp1002,INT_X38Y220,NODE_VLONG12,false", + "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_BNODE,true", + "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_CNODE,true", + "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_CTRL,true", + "xcvp1002,CLE_W_CORE_X38Y220,NODE_PINFEED,true", + "xcvp1002,CLE_E_CORE_X38Y220,NODE_CLE_OUTPUT,false", + "xcvp1002,CLE_W_CORE_X38Y220,NODE_CLE_OUTPUT,false", + }) + public void testNodeReachabilityVersal(String partName, String tileName, String intentCodeName, boolean local) { + Device device = Device.getDevice(partName); + Tile baseTile = device.getTile(tileName); + IntentCode baseIntentCode = IntentCode.valueOf(intentCodeName); + Queue queue = new ArrayDeque<>(); + for (int wireIdx = 0; wireIdx < baseTile.getWireCount(); wireIdx++) { + if (baseTile.getWireIntentCode(wireIdx) != baseIntentCode) { + continue; + } + queue.add(Node.getNode(baseTile, wireIdx)); + } + System.out.println("Initial queue.size() = " + queue.size()); + System.out.println("Initial queue = " + queue); + + // Print out the intent code of nodes that are immediately uphill of this intent code + System.out.println("Immediately uphill:"); + queue.stream().map(Node::getAllUphillNodes).flatMap(List::stream).map(Node::getIntentCode) + .distinct() + .sorted() + .forEachOrdered(s -> System.out.println("\t" + s)); + + // Print out the intent code of nodes that are immediately downhill of this intent code + System.out.println("Immediately downhill:"); + queue.stream().map(Node::getAllDownhillNodes).flatMap(List::stream).map(Node::getIntentCode) + .distinct() + .sorted() + .forEachOrdered(s -> System.out.println("\t" + s)); + + TileTypeEnum baseTileTypeEnum = baseTile.getTileTypeEnum(); + Set visited = new HashSet<>(); + boolean exitsBaseTile = false; + while (!queue.isEmpty()) { + Node node = queue.poll(); + if (EnumSet.of(IntentCode.NODE_SDQNODE, IntentCode.NODE_HSINGLE, IntentCode.NODE_VSINGLE, + IntentCode.NODE_HDOUBLE, IntentCode.NODE_VDOUBLE, + IntentCode.NODE_HQUAD, IntentCode.NODE_VQUAD, + IntentCode.NODE_HLONG10, IntentCode.NODE_HLONG6, + IntentCode.NODE_VLONG12, IntentCode.NODE_VLONG7).contains(node.getIntentCode())) { + // Do not descend into SDQNODEs or any SDQLs + exitsBaseTile = true; + continue; + } + for (Node downhill : node.getAllDownhillNodes()) { + if (!visited.add(downhill)) { + continue; + } + if (!Utils.isInterConnect(downhill.getTile().getTileTypeEnum())) { + continue; + } + if (Utils.isCLB(baseTileTypeEnum)) { + if (EnumSet.of(IntentCode.NODE_VLONG7, IntentCode.NODE_VLONG12, IntentCode.NODE_HLONG10, IntentCode.NODE_HLONG6).contains(downhill.getIntentCode())) { + // Ignore long wires that obviously leave the tile + } else { + // All other wires should have the same X coordinate, if not the same Y + Assertions.assertEquals(baseTile.getTileXCoordinate(), downhill.getTile().getTileXCoordinate()); + if (baseTile.getTileYCoordinate() != downhill.getTile().getTileYCoordinate()) { + // Only exception for Y are specific NODE_SDQNODEs with the following wire name + Assertions.assertTrue(downhill.getWireName().matches("OUT_[NEWS]NODE_[EW]_\\d+")); + Assertions.assertEquals(IntentCode.NODE_SDQNODE, downhill.getIntentCode()); + Assertions.assertTrue(1 >= Math.abs(baseTile.getTileYCoordinate() - downhill.getTile().getTileYCoordinate())); + } + } + } + // All INT-to-INT connections should be to the same tile + else if (baseTileTypeEnum == TileTypeEnum.CLE_BC_CORE) { + // Except CLE_BC_CORE tiles which spans two adjacent INT tiles + if (baseTile != downhill.getTile()) { + Assertions.assertTrue(1 >= Math.abs(baseTile.getTileXCoordinate() - downhill.getTile().getTileXCoordinate())); + Assertions.assertEquals(TileTypeEnum.INT, downhill.getTile().getTileTypeEnum()); + } + } else { + Assertions.assertEquals(baseTile, downhill.getTile()); + } + queue.add(downhill); + } + } + System.out.println("visited.size() = " + visited.size()); + + // Local nodes should never exit the tile + Assertions.assertNotEquals(local, exitsBaseTile); } @ParameterizedTest From b4922eb53938feddb5189617c6359c1c057ae9ca Mon Sep 17 00:00:00 2001 From: Chris Lavin Date: Wed, 6 Nov 2024 14:12:04 -0700 Subject: [PATCH 23/71] TileGroup and DeviceBrowser Improvements (#1094) * Adds Versal DSP types to pblock range set Signed-off-by: Chris Lavin * Adds TileGroup object, threaded device browser Signed-off-by: Chris Lavin * Apply suggestions from code review Co-authored-by: eddieh-xlnx Signed-off-by: Chris Lavin * Changed to double click, avoid duplicate populating. Signed-off-by: Chris Lavin --------- Signed-off-by: Chris Lavin Co-authored-by: eddieh-xlnx --- .../rapidwright/design/blocks/PBlock.java | 3 + .../xilinx/rapidwright/design/tools/Edge.java | 43 +++++ .../rapidwright/design/tools/TileGroup.java | 106 +++++++++++ .../device/browser/DeviceBrowser.java | 168 +++++++++++++++++- .../device/browser/DeviceBrowserScene.java | 59 +++++- .../device/browser/ThreadedDeviceBrowser.java | 61 +++++++ .../gui/NumberedHighlightedTile.java | 30 ++-- .../design/tools/TestTileGroup.java | 64 +++++++ 8 files changed, 512 insertions(+), 22 deletions(-) create mode 100644 src/com/xilinx/rapidwright/design/tools/Edge.java create mode 100644 src/com/xilinx/rapidwright/design/tools/TileGroup.java create mode 100644 src/com/xilinx/rapidwright/device/browser/ThreadedDeviceBrowser.java create mode 100644 test/src/com/xilinx/rapidwright/design/tools/TestTileGroup.java diff --git a/src/com/xilinx/rapidwright/design/blocks/PBlock.java b/src/com/xilinx/rapidwright/design/blocks/PBlock.java index 4b248d205..0bf236dc9 100644 --- a/src/com/xilinx/rapidwright/design/blocks/PBlock.java +++ b/src/com/xilinx/rapidwright/design/blocks/PBlock.java @@ -67,6 +67,9 @@ public class PBlock extends ArrayList { pblockTypes.add(SiteTypeEnum.SLICEM); pblockTypes.add(SiteTypeEnum.DSP48E1); pblockTypes.add(SiteTypeEnum.DSP48E2); + pblockTypes.add(SiteTypeEnum.DSP58_PRIMARY); + pblockTypes.add(SiteTypeEnum.DSP58); + pblockTypes.add(SiteTypeEnum.DSPFP); pblockTypes.add(SiteTypeEnum.RAMB180); pblockTypes.add(SiteTypeEnum.RAMB181); pblockTypes.add(SiteTypeEnum.RAMB18E1); diff --git a/src/com/xilinx/rapidwright/design/tools/Edge.java b/src/com/xilinx/rapidwright/design/tools/Edge.java new file mode 100644 index 000000000..07ce82a45 --- /dev/null +++ b/src/com/xilinx/rapidwright/design/tools/Edge.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024, 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.design.tools; + +/** + * Describes the edge types of rectangles when composed of tiles. + */ +public enum Edge { + NORTH, + EAST, + SOUTH, + WEST, + NORTH_EAST, + SOUTH_EAST, + SOUTH_WEST, + NORTH_WEST, + INTERNAL, + EXTERNAL; + + public boolean isEdgeCrossing() { + return this != INTERNAL && this != EXTERNAL; + } +} diff --git a/src/com/xilinx/rapidwright/design/tools/TileGroup.java b/src/com/xilinx/rapidwright/design/tools/TileGroup.java new file mode 100644 index 000000000..9891b4f1a --- /dev/null +++ b/src/com/xilinx/rapidwright/design/tools/TileGroup.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2024, 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.design.tools; + +import java.util.HashMap; +import java.util.Map; + +import com.xilinx.rapidwright.device.ClockRegion; +import com.xilinx.rapidwright.device.Device; +import com.xilinx.rapidwright.device.Tile; + +/** + * Simple class to capture a rectangular group of tiles defined by the upper + * left and lower right corner tiles. + */ +public class TileGroup { + + private Tile upperLeft; + + private Tile lowerRight; + + private int northRow; + + private int southRow; + + private int westColumn; + + private int eastColumn; + + public TileGroup(Tile upperLeft, Tile lowerRight) { + this.upperLeft = upperLeft; + this.lowerRight = lowerRight; + northRow = upperLeft.getRow(); + southRow = lowerRight.getRow(); + westColumn = upperLeft.getColumn(); + eastColumn = lowerRight.getColumn(); + } + + public TileGroup(ClockRegion cr) { + this(cr.getUpperLeft(), cr.getLowerRight()); + } + + public Map getRegionTiles() { + Map tiles = new HashMap<>(); + Device device = upperLeft.getDevice(); + for (int row = northRow; row <= southRow; row++) { + for (int col = westColumn; col <= eastColumn; col++) { + Tile tile = device.getTile(row, col); + tiles.put(tile, getEdgeOfTile(tile)); + } + } + return tiles; + } + + public Edge getEdgeOfTile(Tile tile) { + if (!tileInRegion(tile)) { + return Edge.EXTERNAL; + } + int row = tile.getRow(); + int col = tile.getColumn(); + + if (row == northRow) { + return col == eastColumn ? Edge.NORTH_EAST : Edge.NORTH; + } else if (row == southRow) { + return col == westColumn ? Edge.SOUTH_WEST : Edge.SOUTH; + } else if (col == westColumn) { + return row == northRow ? Edge.NORTH_WEST : Edge.WEST; + } else if (col == eastColumn) { + return row == southRow ? Edge.SOUTH_EAST : Edge.EAST; + } + + return Edge.INTERNAL; + } + + public boolean tileInRegion(Tile tile) { + int row = tile.getRow(); + int col = tile.getColumn(); + return northRow <= row && row <= southRow && westColumn <= col && col <= eastColumn; + + } + + public String toString() { + return "[" + upperLeft + " (" + upperLeft.getColumn() + ", " + upperLeft.getRow() + ")" + ":" + + lowerRight + " (" + lowerRight.getColumn() + ", " + lowerRight.getRow() + ")" + "]"; + } +} diff --git a/src/com/xilinx/rapidwright/device/browser/DeviceBrowser.java b/src/com/xilinx/rapidwright/device/browser/DeviceBrowser.java index 72dd84898..c8ffed53d 100644 --- a/src/com/xilinx/rapidwright/device/browser/DeviceBrowser.java +++ b/src/com/xilinx/rapidwright/device/browser/DeviceBrowser.java @@ -24,23 +24,29 @@ package com.xilinx.rapidwright.device.browser; import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import com.trolltech.qt.core.QEvent; import com.trolltech.qt.core.QModelIndex; import com.trolltech.qt.core.Qt.DockWidgetArea; import com.trolltech.qt.core.Qt.ItemDataRole; import com.trolltech.qt.core.Qt.SortOrder; import com.trolltech.qt.gui.QApplication; import com.trolltech.qt.gui.QDockWidget; +import com.trolltech.qt.gui.QDockWidget.DockWidgetFeature; import com.trolltech.qt.gui.QLabel; import com.trolltech.qt.gui.QMainWindow; import com.trolltech.qt.gui.QStatusBar; import com.trolltech.qt.gui.QTreeWidget; import com.trolltech.qt.gui.QTreeWidgetItem; import com.trolltech.qt.gui.QWidget; -import com.trolltech.qt.gui.QDockWidget.DockWidgetFeature; +import com.xilinx.rapidwright.design.tools.TileGroup; import com.xilinx.rapidwright.device.Device; +import com.xilinx.rapidwright.device.Node; import com.xilinx.rapidwright.device.Site; import com.xilinx.rapidwright.device.Tile; import com.xilinx.rapidwright.device.Wire; @@ -71,16 +77,25 @@ public class DeviceBrowser extends QMainWindow{ private String currPart; /** This is the tree of parts to select */ private QTreeWidget treeWidget; + /** This is the tree of nodes to select */ + private QTreeWidget nodeTreeWidget; /** This is the list of primitive sites in the current tile selected */ private QTreeWidget primitiveList; /** This is the list of wires in the current tile selected */ private QTreeWidget wireList; + + private Map nodeMap; + private Set expandedItems; + /** This is the current tile that has been selected */ private Tile currTile = null; protected boolean hideTiles = false; protected boolean drawPrimitives = true; + + protected static final String UPHILL_NODES = "Uphill Nodes"; + protected static final String DOWNHILL_NODES = "Downhill Nodes"; /** * Main method setting up the Qt environment for the program to run. * @param args @@ -146,8 +161,8 @@ public DeviceBrowser(QWidget parent, String defaultPart) { statusBar.addWidget(statusLabel); setStatusBar(statusBar); - // Set the opening default window size to 1024x768 pixels - resize(1024, 768); + // Set the opening default window size to 1280x1024 pixels + resize(1280, 1024); } public DeviceBrowser(QWidget parent) { @@ -182,6 +197,16 @@ private void initializeSideBar() { dockWidget2.setFeatures(DockWidgetFeature.DockWidgetMovable); addDockWidget(DockWidgetArea.LeftDockWidgetArea, dockWidget2); + // Create the node list window + nodeTreeWidget = new QTreeWidget(); + nodeTreeWidget.setColumnCount(1); + nodeTreeWidget.setHeaderLabel("Nodes"); + QDockWidget nodeWidget = new QDockWidget(tr("Node List"), this); + nodeWidget.setWidget(nodeTreeWidget); + nodeWidget.setFeatures(DockWidgetFeature.DockWidgetMovable); + addDockWidget(DockWidgetArea.LeftDockWidgetArea, nodeWidget); + nodeTreeWidget.itemClicked.connect(this, "nodeClicked(QTreeWidgetItem, Integer)"); + // Create the wire list window wireList = new QTreeWidget(); wireList.setColumnCount(2); @@ -214,6 +239,21 @@ public void wireDoubleClicked(QModelIndex index) { } } + /** + * Expands items in the node tree to add children nodes under uphill and + * downhill. + * + * @param index + */ + public void nodeClicked(QTreeWidgetItem item, Integer value) { + String currNodeName = item.text(value); + if (!expandedItems.contains(currNodeName) && !currNodeName.equals(DOWNHILL_NODES) + && !currNodeName.equals(UPHILL_NODES)) { + QTreeWidgetItem parent = nodeMap.get(item.text(value)); + updateNodeItem(currTile.getDevice().getNode(currNodeName), parent); + } + } + /** * This method gets called each time a user double clicks on a tile. */ @@ -221,6 +261,7 @@ protected void updateTile(Tile tile) { currTile = tile; updatePrimitiveList(); updateWireList(); + updateNodeTreeWidget(); } /** @@ -255,6 +296,43 @@ protected void updateWireList() { wireList.sortByColumn(0, SortOrder.AscendingOrder); } + protected void updateNodeTreeWidget() { + nodeTreeWidget.clear(); + nodeMap = new HashMap<>(); + expandedItems = new HashSet<>(); + + if (currTile == null || currTile.getWireNames() == null) + return; + Device d = currTile.getDevice(); + for (int i = 0; i < currTile.getWireCount(); i++) { + Node n = d.getNode(currTile.toString() + "/" + currTile.getWireName(i)); + if (n == null || n.isInvalidNode()) + continue; + + QTreeWidgetItem treeItem = new QTreeWidgetItem(nodeTreeWidget); + treeItem.setText(0, n.toString()); + updateNodeItem(n, treeItem); + } + } + + private void updateNodeItem(Node n, QTreeWidgetItem parent) { + QTreeWidgetItem uphillItem = new QTreeWidgetItem(parent); + expandedItems.add(parent.text(0)); + uphillItem.setText(0, UPHILL_NODES); + for (Node up : n.getAllUphillNodes()) { + QTreeWidgetItem upNodeItem = new QTreeWidgetItem(uphillItem); + upNodeItem.setText(0, up.toString()); + nodeMap.put(upNodeItem.text(0), upNodeItem); + } + QTreeWidgetItem downhillItem = new QTreeWidgetItem(parent); + downhillItem.setText(0, DOWNHILL_NODES); + for (Node down : n.getAllDownhillNodes()) { + QTreeWidgetItem downNodeItem = new QTreeWidgetItem(downhillItem); + downNodeItem.setText(0, down.toString()); + nodeMap.put(downNodeItem.text(0), downNodeItem); + } + } + /** * This method loads a new device based on the part name selected in the * treeWidget. @@ -265,14 +343,18 @@ protected void showPart(QModelIndex qmIndex) { if ( data != null) { if (currPart.equals(data)) return; - currPart = (String) data; - device = Device.getDevice(currPart); - scene.setDevice(device); - scene.initializeScene(hideTiles, drawPrimitives); - statusLabel.setText("Loaded: "+currPart.toUpperCase()); + setPart((String) data); } } + private void setPart(String partName) { + currPart = partName; + device = Device.getDevice(currPart); + scene.setDevice(device); + scene.initializeScene(hideTiles, drawPrimitives); + statusLabel.setText("Loaded: " + currPart.toUpperCase()); + } + /** * This method updates the status bar each time the mouse moves from a * different tile. @@ -282,4 +364,74 @@ protected void updateStatus(String text, Tile tile) { //currTile = tile; //System.out.println("currTile=" + tile); } + + public Device getDevice() { + return device; + } + + public DeviceBrowserScene getScene() { + return scene; + } + + /** + * Triggers an event on the scene to clear any highlighted tiles + */ + public void clearHighlightedTiles() { + QEvent event = new QEvent(QEvent.Type.resolve(DeviceBrowserScene.CLEAR_HIGHLIGHTED_TILES)); + QApplication.postEvent(scene, event); + } + + /** + * Populates the scene with the tile group and triggers a highlight event on the + * scene object to highlight the perimeter tiles of the tile groups + * + * @param tileGroup The tile group to highlight + */ + public void highlightTileGroup(TileGroup tileGroup) { + List tgs = new ArrayList<>(); + tgs.add(tileGroup); + highlightTileGroups(tgs); + } + + /** + * Populates the scene with the tile groups and triggers a highlight event on + * the scene object to highlight the perimeter tiles of the tile groups. + * + * @param tileGroups The tile groups to highlight + */ + public void highlightTileGroups(List tileGroups) { + scene.tileGroups = tileGroups; + QEvent event = new QEvent(QEvent.Type.resolve(DeviceBrowserScene.HIGHLIGHT_TILE_GROUPS)); + QApplication.postEvent(scene, event); + } + + /** Static reference to a threaded instance */ + private static ThreadedDeviceBrowser threadedBrowser; + + /** + * Creates a new DeviceBrowser window in a separate thread so that it can be + * called interactively from an interpreter. + * + * @param partName The device or part name to load + * @return The DeviceBrowser window object + * @throws InterruptedException + */ + public static DeviceBrowser createWindow(String partName) throws InterruptedException { + if (threadedBrowser != null) { + System.err.println("ERROR: Only a single instance of the DeviceBrowser is currently supported"); + return null; + } + threadedBrowser = new ThreadedDeviceBrowser(new String[] { partName }); + threadedBrowser.start(); + // Since start() returns immediately, we need to wait until the constructor has + // finished populating class member variables before continuting + while (threadedBrowser.getDeviceBrowser() == null) { + Thread.sleep(10); + } + return threadedBrowser.getDeviceBrowser(); + } + + public static void removeThreadedInstance() { + threadedBrowser = null; + } } diff --git a/src/com/xilinx/rapidwright/device/browser/DeviceBrowserScene.java b/src/com/xilinx/rapidwright/device/browser/DeviceBrowserScene.java index 73dd73b19..48d656288 100644 --- a/src/com/xilinx/rapidwright/device/browser/DeviceBrowserScene.java +++ b/src/com/xilinx/rapidwright/device/browser/DeviceBrowserScene.java @@ -28,8 +28,11 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import java.util.Queue; +import com.trolltech.qt.core.QEvent; import com.trolltech.qt.core.Qt.MouseButton; import com.trolltech.qt.core.Qt.PenStyle; import com.trolltech.qt.gui.QAction; @@ -39,12 +42,14 @@ import com.trolltech.qt.gui.QGraphicsSceneMouseEvent; import com.trolltech.qt.gui.QMenu; import com.trolltech.qt.gui.QPen; -import com.xilinx.rapidwright.router.RouteNode; +import com.xilinx.rapidwright.design.tools.Edge; +import com.xilinx.rapidwright.design.tools.TileGroup; import com.xilinx.rapidwright.device.Device; import com.xilinx.rapidwright.device.Tile; import com.xilinx.rapidwright.device.Wire; import com.xilinx.rapidwright.gui.NumberedHighlightedTile; import com.xilinx.rapidwright.gui.TileScene; +import com.xilinx.rapidwright.router.RouteNode; /** * This class was written specifically for the DeviceBrowser class. It @@ -64,12 +69,18 @@ public class DeviceBrowserScene extends TileScene{ /** */ private ArrayList currentTiles = new ArrayList(); + // User Defined Qt Events + public static final int CLEAR_HIGHLIGHTED_TILES = 1001; + public static final int HIGHLIGHT_TILE_GROUPS = 1002; + // End Events public DeviceBrowserScene(Device device, boolean hideTiles, boolean drawPrimitives, DeviceBrowser browser) { super(device, hideTiles, drawPrimitives); currLines = new ArrayList(); wirePen = new QPen(QColor.yellow, 0.25, PenStyle.SolidLine); this.browser = browser; + QEvent.registerEventType(CLEAR_HIGHLIGHTED_TILES); + QEvent.registerEventType(HIGHLIGHT_TILE_GROUPS); } public void drawWire(Tile src, Tile dst) { @@ -181,6 +192,15 @@ private void menuReachability5() { } private void menuReachabilityClear() { + clearHighlightedTiles(); + } + + + public void addHighlightedTile(NumberedHighlightedTile tile) { + currentTiles.add(tile); + } + + public void clearHighlightedTiles() { for (NumberedHighlightedTile rect : currentTiles) { rect.remove(); } @@ -230,4 +250,41 @@ public void mouseReleaseEvent(QGraphicsSceneMouseEvent event) { super.mouseReleaseEvent(event); } + + public List tileGroups; + + public void highlightTileGroups() { + for (TileGroup tg : tileGroups) { + highlightTileGroup(tg); + } + } + + public void highlightTileGroup(TileGroup tg) { + QBrush brush = new QBrush(QColor.red); + Map tileMap = tg.getRegionTiles(); + for (Entry e : tileMap.entrySet()) { + if (e.getValue() == Edge.INTERNAL) + continue; + NumberedHighlightedTile highTile = new NumberedHighlightedTile(e.getKey(), this, null); + highTile.setBrush(brush); + addHighlightedTile(highTile); + } + } + + @Override + public boolean event(QEvent event) { + boolean result = true; + + switch(event.type().value()) { + case CLEAR_HIGHLIGHTED_TILES: + clearHighlightedTiles(); + break; + case HIGHLIGHT_TILE_GROUPS: + highlightTileGroups(); + break; + default: + result = super.event(event); + } + return result; + } } diff --git a/src/com/xilinx/rapidwright/device/browser/ThreadedDeviceBrowser.java b/src/com/xilinx/rapidwright/device/browser/ThreadedDeviceBrowser.java new file mode 100644 index 000000000..9d67fcc21 --- /dev/null +++ b/src/com/xilinx/rapidwright/device/browser/ThreadedDeviceBrowser.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024, 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.device.browser; + +import com.trolltech.qt.gui.QApplication; + +/** + * Helper class to enable {@link DeviceBrowser} to be threaded and non-blocking + * when using an interpreter. + */ +public class ThreadedDeviceBrowser extends Thread { + + private DeviceBrowser deviceBrowser; + + private String[] args; + + public ThreadedDeviceBrowser(String[] args) { + this.args = args; + } + + @Override + public void run() { + QApplication.setGraphicsSystem("raster"); + QApplication.initialize(args); + + String defaultPart = null; + if (args.length > 0) { + defaultPart = args[0]; + } + + deviceBrowser = new DeviceBrowser(null, defaultPart); + + deviceBrowser.show(); + QApplication.exec(); + DeviceBrowser.removeThreadedInstance(); + } + + public DeviceBrowser getDeviceBrowser() { + return deviceBrowser; + } +} diff --git a/src/com/xilinx/rapidwright/gui/NumberedHighlightedTile.java b/src/com/xilinx/rapidwright/gui/NumberedHighlightedTile.java index d3e08e3d6..5e117a044 100644 --- a/src/com/xilinx/rapidwright/gui/NumberedHighlightedTile.java +++ b/src/com/xilinx/rapidwright/gui/NumberedHighlightedTile.java @@ -41,30 +41,34 @@ public class NumberedHighlightedTile extends QGraphicsRectItem{ protected static QFont font8 = new QFont("Arial", 8); - public NumberedHighlightedTile(Tile t, TileScene scene, int number) { + public NumberedHighlightedTile(Tile t, TileScene scene, Integer number) { super(0, 0, scene.tileSize - 2, scene.tileSize - 2); this.scene = scene; - this.text = new QGraphicsTextItem(Integer.toString(number)); int x = scene.getDrawnTileX(t) * scene.tileSize; int y = scene.getDrawnTileY(t) * scene.tileSize; - text.setPos(x-4, y); - if (number < 100) { - text.setFont(font8); - } else if (number < 1000) { - text.setFont(font6); - } else { - text.setFont(font4); - } this.moveBy(x, y); this.scene.addItem(this); - this.scene.addItem(text); - this.text.setZValue(this.zValue() + 1); + if (number != null) { + this.text = new QGraphicsTextItem(Integer.toString(number)); + text.setPos(x - 4, y); + if (number < 100) { + text.setFont(font8); + } else if (number < 1000) { + text.setFont(font6); + } else { + text.setFont(font4); + } + this.scene.addItem(text); + this.text.setZValue(this.zValue() + 1); + } } public void remove() { - scene.removeItem(text); + if (text != null) { + scene.removeItem(text); + } scene.removeItem(this); } } diff --git a/test/src/com/xilinx/rapidwright/design/tools/TestTileGroup.java b/test/src/com/xilinx/rapidwright/design/tools/TestTileGroup.java new file mode 100644 index 000000000..6d50139d7 --- /dev/null +++ b/test/src/com/xilinx/rapidwright/design/tools/TestTileGroup.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024, 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.design.tools; + +import java.util.Map; +import java.util.Map.Entry; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.xilinx.rapidwright.device.ClockRegion; +import com.xilinx.rapidwright.device.Device; +import com.xilinx.rapidwright.device.Tile; + +public class TestTileGroup { + + @Test + public void testTileGroup() { + Device d = Device.getDevice("xcvc1902"); + + for (ClockRegion[] crs : d.getClockRegions()) { + for (ClockRegion cr : crs) { + if (cr.getUpperLeft() == null || cr.getUpperRight() == null) { + continue; + } + TileGroup tg = new TileGroup(cr.getUpperLeft(), cr.getLowerRight()); + Map tileMap = tg.getRegionTiles(); + for (Entry e : tileMap.entrySet()) { + Assertions.assertEquals(cr, e.getKey().getClockRegion()); + Assertions.assertTrue(e.getValue() != Edge.EXTERNAL); + } + + for (Tile tile : d.getAllTiles()) { + Edge edge = tg.getEdgeOfTile(tile); + if (tile.getClockRegion() == cr) { + Assertions.assertNotEquals(Edge.EXTERNAL, edge); + } else { + Assertions.assertEquals(Edge.EXTERNAL, edge); + } + } + } + } + } +} From 7274b33c50841e0c18c2e617e63313a9e75b1e26 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 6 Nov 2024 23:22:27 -0800 Subject: [PATCH 24/71] More explanatory approach; no difference Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/RouteNodeGraph.java | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index c1879a52c..0c665dfa3 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -588,19 +588,35 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { if (isVersal) { if (childTile.getTileYCoordinate() == sinkTile.getTileYCoordinate()) { + // Same row as our sink tile + boolean childInInt = childTile.getTileTypeEnum() == TileTypeEnum.INT; boolean sinkInInt = sinkTile.getTileTypeEnum() == TileTypeEnum.INT; - if (!childInInt && sinkInInt) { - // Allow CLE CNODE/BNODEs that reach into the sink INT tile + + if (!sinkInInt) { + // Sink is a NODE_{CTRL,INTF}_CTRL + + if (!childInInt) { + // Same row, but not the same exact CLE_BC_CORE tile, as our sink + assert(childTile != sinkTile); + return false; + } + + // Allow use of LOCALs inside the two INT tiles that border this non-INT sink tile + assert(childInInt); + return Math.abs(childTile.getTileXCoordinate() - sinkTile.getTileXCoordinate()) <= 1; + } + + if (!childInInt) { + // Allow CNODE/BNODEs that reach into the sink INT tile assert(EnumSet.of(IntentCode.NODE_CLE_BNODE, IntentCode.NODE_CLE_CNODE, IntentCode.NODE_INTF_BNODE, IntentCode.NODE_INTF_CNODE) .contains(childRnode.getIntentCode())); return childRnode.getEndTileXCoordinate() == sinkTile.getTileXCoordinate(); } - if (childInInt && !sinkInInt) { - // Allow use of LOCALs inside the INT tile that (by way of being at most one X coordinate away) services the CLE_BC_CORE - return Math.abs(childRnode.getEndTileXCoordinate() - sinkTile.getTileXCoordinate()) <= 1; - } + // Do not use LOCALs in any other INT tile but our sink's + assert(sinkInInt && childInInt); + assert(childTile != sinkTile); } return false; From 14955fe703336f668fab15a6329d545edad82778 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 7 Nov 2024 10:20:26 -0800 Subject: [PATCH 25/71] Improvement? Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/RouteNodeGraph.java | 114 ++++++++++++------ 1 file changed, 80 insertions(+), 34 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 0c665dfa3..67edcdf48 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -578,50 +578,96 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { return true; } - // (b) in the sink tile Tile childTile = childRnode.getTile(); RouteNode sinkRnode = connection.getSinkRnode(); Tile sinkTile = sinkRnode.getTile(); - if (childTile == sinkTile) { - return true; - } - if (isVersal) { - if (childTile.getTileYCoordinate() == sinkTile.getTileYCoordinate()) { - // Same row as our sink tile - - boolean childInInt = childTile.getTileTypeEnum() == TileTypeEnum.INT; - boolean sinkInInt = sinkTile.getTileTypeEnum() == TileTypeEnum.INT; - - if (!sinkInInt) { - // Sink is a NODE_{CTRL,INTF}_CTRL - - if (!childInInt) { - // Same row, but not the same exact CLE_BC_CORE tile, as our sink - assert(childTile != sinkTile); + IntentCode childIntentCode = childRnode.getIntentCode(); + switch (childIntentCode) { + case NODE_INODE: + // Block access to all INODEs outside the sink tile, since NODE_INODE -> NODE_IMUX -> NODE_PINFEED (or NODE_INODE _> NODE_PINBOUNCE) + if (childRnode.getTile() != sinkTile) { return false; } - - // Allow use of LOCALs inside the two INT tiles that border this non-INT sink tile - assert(childInInt); - return Math.abs(childTile.getTileXCoordinate() - sinkTile.getTileXCoordinate()) <= 1; - } - - if (!childInInt) { - // Allow CNODE/BNODEs that reach into the sink INT tile - assert(EnumSet.of(IntentCode.NODE_CLE_BNODE, IntentCode.NODE_CLE_CNODE, IntentCode.NODE_INTF_BNODE, IntentCode.NODE_INTF_CNODE) - .contains(childRnode.getIntentCode())); - return childRnode.getEndTileXCoordinate() == sinkTile.getTileXCoordinate(); - } - - // Do not use LOCALs in any other INT tile but our sink's - assert(sinkInInt && childInInt); - assert(childTile != sinkTile); + assert(sinkRnode.getIntentCode() == IntentCode.NODE_IMUX || sinkRnode.getIntentCode() == IntentCode.NODE_PINBOUNCE); + break; + case NODE_CLE_CNODE: + // Block access to all CNODEs outside the sink tile, since NODE_CLE_CNODE -> NODE_CLE_CTRL + if (childRnode.getTile() != sinkTile) { + return false; + } + assert(sinkRnode.getIntentCode() == IntentCode.NODE_CLE_CTRL); + break; + case NODE_INTF_CNODE: + // Block access to all CNODEs outside the sink tile, since NODE_INTF_CNODE -> NODE_INTF_CTRL + if (childRnode.getTile() != sinkTile) { + return false; + } + assert(sinkRnode.getIntentCode() == IntentCode.NODE_INTF_CTRL); + break; + case NODE_PINBOUNCE: + // BOUNCEs are only accessible through INODEs, so transitively this node must be in the sink tile too + assert(childRnode.getTile() == sinkTile); + assert(sinkRnode.getIntentCode() == IntentCode.NODE_IMUX || sinkRnode.getIntentCode() == IntentCode.NODE_PINBOUNCE); + break; + case NODE_CLE_BNODE: + case NODE_INTF_BNODE: + IntentCode sinkIntentCode = sinkRnode.getIntentCode(); + // For CTRL sinks, only allow BNODEs in the sink tile + if (sinkIntentCode == IntentCode.NODE_CLE_CTRL || sinkIntentCode == IntentCode.NODE_INTF_CTRL) { + return childTile == sinkTile; + } + // For other sinks, only allow if BNODE reaches into the sink tile + assert(sinkIntentCode == IntentCode.NODE_IMUX || sinkIntentCode == IntentCode.NODE_PINBOUNCE); + return childTile.getTileYCoordinate() == sinkTile.getTileYCoordinate() && + childRnode.getEndTileXCoordinate() == sinkTile.getTileXCoordinate(); + default: + throw new RuntimeException("ERROR: Unhandled IntentCode: " + childIntentCode); } + return true; + } - return false; + // (b) in the sink tile + if (childTile == sinkTile) { + return true; } + // if (isVersal) { + // if (childTile.getTileYCoordinate() == sinkTile.getTileYCoordinate()) { + // // Same row as our sink tile + // + // boolean childInInt = childTile.getTileTypeEnum() == TileTypeEnum.INT; + // boolean sinkInInt = sinkTile.getTileTypeEnum() == TileTypeEnum.INT; + // + // if (!sinkInInt) { + // // Sink is a NODE_{CTRL,INTF}_CTRL + // + // if (!childInInt) { + // // Same row, but not the same exact CLE_BC_CORE tile, as our sink + // assert(childTile != sinkTile); + // return false; + // } + // + // // Allow use of LOCALs inside the two INT tiles that border this non-INT sink tile + // assert(childInInt); + // return Math.abs(childTile.getTileXCoordinate() - sinkTile.getTileXCoordinate()) <= 1; + // } + // + // if (!childInInt) { + // // Allow CNODE/BNODEs that reach into the sink INT tile + // assert(EnumSet.of(IntentCode.NODE_CLE_BNODE, IntentCode.NODE_CLE_CNODE, IntentCode.NODE_INTF_BNODE, IntentCode.NODE_INTF_CNODE) + // .contains(childRnode.getIntentCode())); + // return childRnode.getEndTileXCoordinate() == sinkTile.getTileXCoordinate(); + // } + // + // // Do not use LOCALs in any other INT tile but our sink's + // assert(sinkInInt && childInInt); + // assert(childTile != sinkTile); + // } + // + // return false; + // } + // (c) connection crosses SLR and this is a Laguna column int childX = childTile.getTileXCoordinate(); if (connection.isCrossSLR() && nextLagunaColumn[childX] == childX) { From 56afd4b21958a3d129070f54d45a62f98999b6bb Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 7 Nov 2024 10:23:43 -0800 Subject: [PATCH 26/71] Cleanup Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/RouteNodeGraph.java | 74 +++---------------- 1 file changed, 11 insertions(+), 63 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 67edcdf48..890ec4ef9 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -578,96 +578,44 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { return true; } + // (b) in the sink tile Tile childTile = childRnode.getTile(); RouteNode sinkRnode = connection.getSinkRnode(); Tile sinkTile = sinkRnode.getTile(); + if (childTile == sinkTile) { + return true; + } + if (isVersal) { IntentCode childIntentCode = childRnode.getIntentCode(); switch (childIntentCode) { case NODE_INODE: // Block access to all INODEs outside the sink tile, since NODE_INODE -> NODE_IMUX -> NODE_PINFEED (or NODE_INODE _> NODE_PINBOUNCE) - if (childRnode.getTile() != sinkTile) { - return false; - } - assert(sinkRnode.getIntentCode() == IntentCode.NODE_IMUX || sinkRnode.getIntentCode() == IntentCode.NODE_PINBOUNCE); - break; + return false; case NODE_CLE_CNODE: // Block access to all CNODEs outside the sink tile, since NODE_CLE_CNODE -> NODE_CLE_CTRL - if (childRnode.getTile() != sinkTile) { - return false; - } - assert(sinkRnode.getIntentCode() == IntentCode.NODE_CLE_CTRL); - break; + return false; case NODE_INTF_CNODE: // Block access to all CNODEs outside the sink tile, since NODE_INTF_CNODE -> NODE_INTF_CTRL - if (childRnode.getTile() != sinkTile) { - return false; - } - assert(sinkRnode.getIntentCode() == IntentCode.NODE_INTF_CTRL); - break; + return false; case NODE_PINBOUNCE: // BOUNCEs are only accessible through INODEs, so transitively this node must be in the sink tile too - assert(childRnode.getTile() == sinkTile); - assert(sinkRnode.getIntentCode() == IntentCode.NODE_IMUX || sinkRnode.getIntentCode() == IntentCode.NODE_PINBOUNCE); - break; + return false; case NODE_CLE_BNODE: case NODE_INTF_BNODE: IntentCode sinkIntentCode = sinkRnode.getIntentCode(); // For CTRL sinks, only allow BNODEs in the sink tile if (sinkIntentCode == IntentCode.NODE_CLE_CTRL || sinkIntentCode == IntentCode.NODE_INTF_CTRL) { - return childTile == sinkTile; + return false; } // For other sinks, only allow if BNODE reaches into the sink tile assert(sinkIntentCode == IntentCode.NODE_IMUX || sinkIntentCode == IntentCode.NODE_PINBOUNCE); return childTile.getTileYCoordinate() == sinkTile.getTileYCoordinate() && childRnode.getEndTileXCoordinate() == sinkTile.getTileXCoordinate(); - default: - throw new RuntimeException("ERROR: Unhandled IntentCode: " + childIntentCode); } - return true; + throw new RuntimeException("ERROR: Unhandled IntentCode: " + childIntentCode); } - // (b) in the sink tile - if (childTile == sinkTile) { - return true; - } - - // if (isVersal) { - // if (childTile.getTileYCoordinate() == sinkTile.getTileYCoordinate()) { - // // Same row as our sink tile - // - // boolean childInInt = childTile.getTileTypeEnum() == TileTypeEnum.INT; - // boolean sinkInInt = sinkTile.getTileTypeEnum() == TileTypeEnum.INT; - // - // if (!sinkInInt) { - // // Sink is a NODE_{CTRL,INTF}_CTRL - // - // if (!childInInt) { - // // Same row, but not the same exact CLE_BC_CORE tile, as our sink - // assert(childTile != sinkTile); - // return false; - // } - // - // // Allow use of LOCALs inside the two INT tiles that border this non-INT sink tile - // assert(childInInt); - // return Math.abs(childTile.getTileXCoordinate() - sinkTile.getTileXCoordinate()) <= 1; - // } - // - // if (!childInInt) { - // // Allow CNODE/BNODEs that reach into the sink INT tile - // assert(EnumSet.of(IntentCode.NODE_CLE_BNODE, IntentCode.NODE_CLE_CNODE, IntentCode.NODE_INTF_BNODE, IntentCode.NODE_INTF_CNODE) - // .contains(childRnode.getIntentCode())); - // return childRnode.getEndTileXCoordinate() == sinkTile.getTileXCoordinate(); - // } - // - // // Do not use LOCALs in any other INT tile but our sink's - // assert(sinkInInt && childInInt); - // assert(childTile != sinkTile); - // } - // - // return false; - // } - // (c) connection crosses SLR and this is a Laguna column int childX = childTile.getTileXCoordinate(); if (connection.isCrossSLR() && nextLagunaColumn[childX] == childX) { From cac787ed3147f183b7cbfce2dab5691fcc339a5d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 7 Nov 2024 11:58:42 -0800 Subject: [PATCH 27/71] Update comments Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/RouteNodeGraph.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 890ec4ef9..70f9bea65 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -590,7 +590,7 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { IntentCode childIntentCode = childRnode.getIntentCode(); switch (childIntentCode) { case NODE_INODE: - // Block access to all INODEs outside the sink tile, since NODE_INODE -> NODE_IMUX -> NODE_PINFEED (or NODE_INODE _> NODE_PINBOUNCE) + // Block access to all INODEs outside the sink tile, since NODE_INODE -> NODE_IMUX -> NODE_PINFEED (or NODE_INODE -> NODE_PINBOUNCE) return false; case NODE_CLE_CNODE: // Block access to all CNODEs outside the sink tile, since NODE_CLE_CNODE -> NODE_CLE_CTRL @@ -604,7 +604,7 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { case NODE_CLE_BNODE: case NODE_INTF_BNODE: IntentCode sinkIntentCode = sinkRnode.getIntentCode(); - // For CTRL sinks, only allow BNODEs in the sink tile + // For CTRL sinks, block all BNODEs outside the sink tile if (sinkIntentCode == IntentCode.NODE_CLE_CTRL || sinkIntentCode == IntentCode.NODE_INTF_CTRL) { return false; } @@ -612,6 +612,17 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { assert(sinkIntentCode == IntentCode.NODE_IMUX || sinkIntentCode == IntentCode.NODE_PINBOUNCE); return childTile.getTileYCoordinate() == sinkTile.getTileYCoordinate() && childRnode.getEndTileXCoordinate() == sinkTile.getTileXCoordinate(); + case NODE_IMUX: + // IMUXes that are not EXCLUSIVE_SINKs will have been isExcluded() from the graph unless LUT routethrus are enabled + assert(lutRoutethru); + return true; + case NODE_PINFEED: + // Expected to be projected away + break; + case NODE_CLE_CTRL: + case NODE_INTF_CTRL: + // CTRL pins that are not EXCLUSIVE_SINKs will have been isExcluded() from the graph + break; } throw new RuntimeException("ERROR: Unhandled IntentCode: " + childIntentCode); } From ef4227c5f85f9518c63a3f52fd33a8f250e1ca44 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 7 Nov 2024 12:26:08 -0800 Subject: [PATCH 28/71] Add NODE_INTF_{CNODE,BNODE} Signed-off-by: Eddie Hung --- .../src/com/xilinx/rapidwright/device/TestNode.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test/src/com/xilinx/rapidwright/device/TestNode.java b/test/src/com/xilinx/rapidwright/device/TestNode.java index e72e0cd4a..22f99789b 100644 --- a/test/src/com/xilinx/rapidwright/device/TestNode.java +++ b/test/src/com/xilinx/rapidwright/device/TestNode.java @@ -224,6 +224,8 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str "xcvp1002,CLE_W_CORE_X38Y220,NODE_PINFEED,true", "xcvp1002,CLE_E_CORE_X38Y220,NODE_CLE_OUTPUT,false", "xcvp1002,CLE_W_CORE_X38Y220,NODE_CLE_OUTPUT,false", + "xcvp1002,INTF_ROCF_TR_TILE_X39Y153,NODE_INTF_CNODE,true", + "xcvp1002,INTF_ROCF_TR_TILE_X39Y153,NODE_INTF_BNODE,true", }) public void testNodeReachabilityVersal(String partName, String tileName, String intentCodeName, boolean local) { Device device = Device.getDevice(partName); @@ -289,7 +291,16 @@ public void testNodeReachabilityVersal(String partName, String tileName, String } } // All INT-to-INT connections should be to the same tile - else if (baseTileTypeEnum == TileTypeEnum.CLE_BC_CORE) { + else if (EnumSet.of(TileTypeEnum.CLE_BC_CORE, + TileTypeEnum.INTF_LOCF_TL_TILE, + TileTypeEnum.INTF_LOCF_TR_TILE, + TileTypeEnum.INTF_LOCF_BL_TILE, + TileTypeEnum.INTF_LOCF_BR_TILE, + TileTypeEnum.INTF_ROCF_TL_TILE, + TileTypeEnum.INTF_ROCF_TR_TILE, + TileTypeEnum.INTF_ROCF_BL_TILE, + TileTypeEnum.INTF_ROCF_BR_TILE) + .contains(baseTileTypeEnum)) { // Except CLE_BC_CORE tiles which spans two adjacent INT tiles if (baseTile != downhill.getTile()) { Assertions.assertTrue(1 >= Math.abs(baseTile.getTileXCoordinate() - downhill.getTile().getTileXCoordinate())); From b81febd7c529e958927d7d9604fb0a86a54dd16f Mon Sep 17 00:00:00 2001 From: eddieh-xlnx Date: Tue, 12 Nov 2024 08:28:59 -0800 Subject: [PATCH 29/71] [Utils] isClocking() to include TileTypeEnum.CMT_L (#1100) * Add failing testcase Signed-off-by: Eddie Hung * [Utils] isClocking() to include TileTypeEnum.CMT_L Signed-off-by: Eddie Hung * Bump year Signed-off-by: Eddie Hung * Fix broken projectInputPinToINTNode too Signed-off-by: Eddie Hung --------- Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RouterHelper.java | 8 ++++++-- src/com/xilinx/rapidwright/util/Utils.java | 3 ++- .../com/xilinx/rapidwright/rwroute/TestRouterHelper.java | 2 ++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouterHelper.java b/src/com/xilinx/rapidwright/rwroute/RouterHelper.java index 3bb7f660d..3c21704df 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouterHelper.java +++ b/src/com/xilinx/rapidwright/rwroute/RouterHelper.java @@ -180,9 +180,13 @@ public static Node projectOutputPinToINTNode(SitePinInst output) { */ public static Node projectInputPinToINTNode(SitePinInst input) { Node sink = input.getConnectedNode(); - if (sink.getTile().getTileTypeEnum() == TileTypeEnum.INT) { + TileTypeEnum sinkTileType = sink.getTile().getTileTypeEnum(); + if (sinkTileType == TileTypeEnum.INT) { return sink; } + // Only block clocking tiles if source is not in a clock tile + final boolean blockClocking = !Utils.isClocking(sinkTileType); + int watchdog = 40; // Starting from the SPI's connected node, perform an uphill breadth-first search @@ -198,7 +202,7 @@ public static Node projectInputPinToINTNode(SitePinInst input) { EnumSet.of(IntentCode.NODE_CLE_CTRL, IntentCode.NODE_INTF_CTRL).contains(uphill.getIntentCode())) { return uphill; } - if (Utils.isClocking(uphillTileType)) { + if (uphillTileType != sinkTileType && Utils.isClocking(uphillTileType)) { continue; } queue.add(uphill); diff --git a/src/com/xilinx/rapidwright/util/Utils.java b/src/com/xilinx/rapidwright/util/Utils.java index aa7d534cb..8a1950898 100644 --- a/src/com/xilinx/rapidwright/util/Utils.java +++ b/src/com/xilinx/rapidwright/util/Utils.java @@ -1,7 +1,7 @@ /* * Original work: Copyright (c) 2010-2011 Brigham Young University * Modified work: Copyright (c) 2017-2022, Xilinx, Inc. - * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. + * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. * All rights reserved. * * Author: Chris Lavin, Xilinx Research Labs. @@ -350,6 +350,7 @@ public static boolean isIOB(SiteTypeEnum s) { clocking = EnumSet.of( TileTypeEnum.RCLK_CLEM_CLKBUF_L, + TileTypeEnum.CMT_L, // Versal TileTypeEnum.CLK_REBUF_BUFGS_HSR_CORE, TileTypeEnum.CLK_PLL_AND_PHY, diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestRouterHelper.java b/test/src/com/xilinx/rapidwright/rwroute/TestRouterHelper.java index 6d96f12d2..41efaf567 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestRouterHelper.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestRouterHelper.java @@ -59,6 +59,7 @@ public class TestRouterHelper { "xcvu3p,SLICE_X0Y0,A_O,CLEL_R_X0Y0/CLE_CLE_L_SITE_0_A_O", "xcvu3p,GTYE4_CHANNEL_X0Y12,TXOUTCLK_INT,null", "xcvu3p,IOB_X1Y95,I,INT_INTF_L_IO_X72Y109/LOGIC_OUTS_R23", + "xcvu3p,IOB_X1Y80,I,INT_INTF_L_IO_X72Y92/LOGIC_OUTS_R22", "xcvu3p,MMCM_X0Y0,LOCKED,INT_INTF_L_IO_X36Y54/LOGIC_OUTS_R0", "xcvp1002,MMCM_X2Y0,LOCKED,BLI_CLE_BOT_CORE_X27Y0/LOGIC_OUTS_D23" }) @@ -72,6 +73,7 @@ public void testProjectOutputPinToINTNode(String partName, String siteName, Stri @ParameterizedTest @CsvSource({ "xcvu3p,MMCM_X0Y0,PSEN,INT_X36Y56/IMUX_W0", + "xcvu3p,BUFGCE_X0Y58,CLK_IN,INT_X36Y151/IMUX_W34", "xcvp1002,MMCM_X2Y0,PSEN,INT_X27Y0/IMUX_B_W24" }) public void testProjectInputPinToINTNode(String partName, String siteName, String pinName, String nodeAsString) { From cd631ac34bb9c58af446637d1cf606030d2b5c16 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 7 Nov 2024 15:15:16 -0800 Subject: [PATCH 30/71] [TestNode] Expand testNodeReachabilityUltraScale Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/device/TestNode.java | 65 +++++++++++++------ 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/test/src/com/xilinx/rapidwright/device/TestNode.java b/test/src/com/xilinx/rapidwright/device/TestNode.java index e72e0cd4a..18cbb524f 100644 --- a/test/src/com/xilinx/rapidwright/device/TestNode.java +++ b/test/src/com/xilinx/rapidwright/device/TestNode.java @@ -84,16 +84,23 @@ public void testUphillNodeIsInvalid() { @ParameterizedTest @CsvSource({ // UltraScale+ part - "xcvu3p,INT_X37Y220,BOUNCE_.*,true", - "xcvu3p,INT_X37Y220,BYPASS_.*,true", + "xcvu3p,INT_X37Y220,BOUNCE_E_.*,true", + "xcvu3p,INT_X37Y220,BOUNCE_W_.*,true", + "xcvu3p,INT_X37Y220,BYPASS_E.*,true", + "xcvu3p,INT_X37Y220,BYPASS_W.*,true", "xcvu3p,INT_X37Y220,INT_NODE_GLOBAL_.*,true", - "xcvu3p,INT_X37Y220,INT_NODE_IMUX_.*,true", - "xcvu3p,INT_X37Y220,INODE_.*,true", + "xcvu3p,INT_X37Y220,INT_NODE_IMUX_([0-9]|1[0-9]|2[0-9]|3[01])_.*,true", + "xcvu3p,INT_X37Y220,INT_NODE_IMUX_(3[2-9]|4[0-9]|5[0-9]|6[0-3])_.*,true", + "xcvu3p,INT_X37Y220,INODE_E_.*,true", + "xcvu3p,INT_X37Y220,INODE_W_.*,true", "xcvu3p,INT_X37Y220,INT_INT_SDQ_.*,false", // IntentCode.NODE_SINGLE "xcvu3p,INT_X37Y220,INT_NODE_SDQ_.*,false", - "xcvu3p,INT_X37Y220,SDQNODE_.*,false", - "xcvu3p,INT_X37Y220,IMUX_.*,true", - "xcvu3p,INT_X37Y220,CTRL_.*,true", + "xcvu3p,INT_X37Y220,SDQNODE_E_.*,false", + "xcvu3p,INT_X37Y220,SDQNODE_W_.*,false", + "xcvu3p,INT_X37Y220,IMUX_E.*,true", + "xcvu3p,INT_X37Y220,IMUX_W.*,true", + "xcvu3p,INT_X37Y220,CTRL_E.*,true", + "xcvu3p,INT_X37Y220,CTRL_W.*,true", "xcvu3p,INT_X37Y220,(NN|EE|SS|WW)1_.*,false", "xcvu3p,INT_X37Y220,(NN|EE|SS|WW)2_.*,false", "xcvu3p,INT_X37Y220,(NN|EE|SS|WW)4_.*,false", @@ -101,16 +108,22 @@ public void testUphillNodeIsInvalid() { "xcvu3p,CLEM_X37Y220,CLE_CLE_M_SITE_0_[A-H](_O|Q|Q2|MUX),false", // UltraScale part - "xcvu065,INT_X38Y220,BOUNCE_.*,true", - "xcvu065,INT_X38Y220,BYPASS_.*,true", + "xcvu065,INT_X38Y220,BOUNCE_E_.*,true", + "xcvu065,INT_X38Y220,BOUNCE_W_.*,true", + "xcvu065,INT_X38Y220,BYPASS_E.*,true", + "xcvu065,INT_X38Y220,BYPASS_W.*,true", "xcvu065,INT_X38Y220,INT_NODE_GLOBAL_.*,true", - "xcvu065,INT_X38Y220,INT_NODE_IMUX_.*,true", - "xcvu065,INT_X38Y220,INODE_.*,true", + "xcvu065,INT_X38Y220,INT_NODE_IMUX_([0-9]|1[0-9]|2[0-9]|3[01]|6[4-9]|7[0-9]|8[0-9]|9[0-5])_.*,true", + "xcvu065,INT_X38Y220,INT_NODE_IMUX_(3[2-9]|4[0-9]|5[0-9]|6[0-3]|9[6-9]|10[0-9]|11[0-9]|12[0-7])_.*,true", + "xcvu065,INT_X38Y220,INODE_[12]_E_.*,true", + "xcvu065,INT_X38Y220,INODE_[12]_W_.*,true", "xcvu065,INT_X38Y220,INT_INT_SINGLE_.*,false", // IntentCode.NODE_SINGLE "xcvu065,INT_X38Y220,INT_NODE_SINGLE_DOUBLE_.*,false", "xcvu065,INT_X38Y220,INT_NODE_QUAD_LONG_.*,false", - "xcvu065,INT_X38Y220,IMUX_.*,true", - "xcvu065,INT_X38Y220,CTRL_.*,true", + "xcvu065,INT_X38Y220,IMUX_E.*,true", + "xcvu065,INT_X38Y220,IMUX_W.*,true", + "xcvu065,INT_X38Y220,CTRL_E.*,true", + "xcvu065,INT_X38Y220,CTRL_W.*,true", "xcvu065,INT_X37Y220,(NN|EE|SS|WW)1_.*,false", "xcvu065,INT_X37Y220,(NN|EE|SS|WW)2_.*,false", "xcvu065,INT_X37Y220,(NN|EE|SS|WW)4_.*,false", @@ -143,13 +156,18 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str boolean ultraScalePlus = partName.endsWith("p"); queue.stream().map(Node::getAllUphillNodes).flatMap(List::stream) .map(n -> n.getWireName() + " (" + n.getIntentCode() + ")") - .map(s -> s.replaceFirst("((BOUNCE|BYPASS|CTRL|INT_NODE_[^_]+|INODE|IMUX|SDQNODE)_)[^\\(]+", "$1")) + .map(s -> s.replaceFirst("^((BOUNCE|BYPASS|CTRL|INODE(_[12])?|IMUX|SDQNODE)_([EW]_?)?)[^ ]+", "$1")) + .map(s -> s.replaceFirst("(INT_NODE_(GLOBAL|SDQ|SINGLE_DOUBLE|QUAD_LONG)_)[^ ]+", "$1")) + .map(s -> ultraScalePlus ? s.replaceFirst("(INT_NODE_IMUX_)([0-9]|1[0-9]|2[0-9]|3[01])_INT_OUT[01]?", "$1<0-31>") + : s.replaceFirst("(INT_NODE_IMUX_)([0-9]|1[0-9]|2[0-9]|3[01]|6[4-9]|7[0-9]|8[0-9]|9[0-5])_INT_OUT", "$1<0-31,64-95>")) + .map(s -> ultraScalePlus ? s.replaceFirst("(INT_NODE_IMUX_)(3[2-9]|4[0-9]|5[0-9]|6[0-3])_INT_OUT[01]?", "$1<32-63>") + : s.replaceFirst("(INT_NODE_IMUX_)(3[2-9]|4[0-9]|5[0-9]|6[0-3]|9[6-9]|10[0-9]|11[0-9]|12[0-7])_INT_OUT", "$1<32-63,96-127>")) .map(s -> s.replaceFirst( // UltraScale+ - ultraScalePlus ? "((CLE_CLE_[LM]_SITE_0|CLK_LEAF_SITES|INT_INT_SDQ|(NN|EE|SS|WW)(1|2|4|12))_)[^\\(]+" + ultraScalePlus ? "((CLE_CLE_[LM]_SITE_0|CLK_LEAF_SITES|INT_INT_SDQ|(NN|EE|SS|WW)(1|2|4|12)(_[EW])?)_)[^\\(]+" // UltraScale - : "((CLE_CLE_[LM]_SITE_0|CLK_BUFCE_LEAF_X16_1_CLK|EE[124]|INT_INT_SINGLE|(NN|SS)(1|2|4|5|12|16)|(EE|WW)(1|2|4|12)|QLND(NW|SE|SW)|SDND[NS]W)_)[^\\(]+", - "$1")) + : "((CLE_CLE_[LM]_SITE_0|CLK_BUFCE_LEAF_X16_1_CLK|EE[124]|INT_INT_SINGLE|(NN|SS)(1|2|4|5|12|16)(_[EW])?|(EE|WW)(1|2|4|12)|QLND(NW|SE|SW)|SDND[NS]W)_)[^\\(]+", + "$1 ")) .distinct() .sorted() .forEachOrdered(s -> System.out.println("\t" + s)); @@ -158,13 +176,18 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str System.out.println("Immediately downhill:"); queue.stream().map(Node::getAllDownhillNodes).flatMap(List::stream) .map(n -> n.getWireName() + " (" + n.getIntentCode() + ")") - .map(s -> s.replaceFirst("((BOUNCE|BYPASS|CTRL|IMUX|INT_NODE_[^_]+|INODE|SDQNODE)_)[^\\(]+", "$1")) + .map(s -> s.replaceFirst("^((BOUNCE|BYPASS|CTRL|INODE(_[12])?|IMUX|SDQNODE)_([EW]_?)?)[^ ]+", "$1")) + .map(s -> s.replaceFirst("(INT_NODE_(GLOBAL|SDQ|SINGLE_DOUBLE|QUAD_LONG)_)[^ ]+", "$1")) + .map(s -> ultraScalePlus ? s.replaceFirst("(INT_NODE_IMUX_)([0-9]|1[0-9]|2[0-9]|3[01])_INT_OUT[01]?", "$1<0-31>") + : s.replaceFirst("(INT_NODE_IMUX_)([0-9]|1[0-9]|2[0-9]|3[01]|6[4-9]|7[0-9]|8[0-9]|9[0-5])_INT_OUT", "$1<0-31,64-95>")) + .map(s -> ultraScalePlus ? s.replaceFirst("(INT_NODE_IMUX_)(3[2-9]|4[0-9]|5[0-9]|6[0-3])_INT_OUT[01]?", "$1<32-63>") + : s.replaceFirst("(INT_NODE_IMUX_)(3[2-9]|4[0-9]|5[0-9]|6[0-3]|9[6-9]|10[0-9]|11[0-9]|12[0-7])_INT_OUT", "$1<32-63,96-127>")) .map(s -> s.replaceFirst( // UltraScale+ - ultraScalePlus ? "((CLE_CLE_[LM]_SITE_0|INT_INT_SDQ|(NN|EE|SS|WW)(1|2|4|12))_)[^\\(]+" + ultraScalePlus ? "((CLE_CLE_[LM]_SITE_0|INT_INT_SDQ|(NN|EE|SS|WW)(1|2|4|12)(_[EW])?)_)[^\\(]+" // UltraScale - : "((CLE_CLE_[LM]_SITE_0|INT_INT_SINGLE|(NN|SS)(1|2|4|5|12|16)|(EE|WW)(1|2|4|12)|QLND(NW|S[EW])|SDND[NS]W)_)[^\\(]+", - "$1")) + : "((CLE_CLE_[LM]_SITE_0|INT_INT_SINGLE|(NN|SS)(1|2|4|5|12|16)|(EE|WW)(1|2|4|12)(_[EW])?|QLND(NW|S[EW])|SDND[NS]W)_)[^\\(]+", + "$1 ")) .distinct() .sorted() .forEachOrdered(s -> System.out.println("\t" + s)); From 038aa805ece27059f409efbe4cff8e2e2ac2321d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 7 Nov 2024 15:15:39 -0800 Subject: [PATCH 31/71] Expand testNodeReachabilityVersal too Signed-off-by: Eddie Hung --- .../src/com/xilinx/rapidwright/device/TestNode.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test/src/com/xilinx/rapidwright/device/TestNode.java b/test/src/com/xilinx/rapidwright/device/TestNode.java index 18cbb524f..2b0d6bef1 100644 --- a/test/src/com/xilinx/rapidwright/device/TestNode.java +++ b/test/src/com/xilinx/rapidwright/device/TestNode.java @@ -247,6 +247,8 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str "xcvp1002,CLE_W_CORE_X38Y220,NODE_PINFEED,true", "xcvp1002,CLE_E_CORE_X38Y220,NODE_CLE_OUTPUT,false", "xcvp1002,CLE_W_CORE_X38Y220,NODE_CLE_OUTPUT,false", + "xcvp1002,INTF_ROCF_TR_TILE_X39Y153,NODE_INTF_CNODE,true", + "xcvp1002,INTF_ROCF_TR_TILE_X39Y153,NODE_INTF_BNODE,true", }) public void testNodeReachabilityVersal(String partName, String tileName, String intentCodeName, boolean local) { Device device = Device.getDevice(partName); @@ -312,7 +314,16 @@ public void testNodeReachabilityVersal(String partName, String tileName, String } } // All INT-to-INT connections should be to the same tile - else if (baseTileTypeEnum == TileTypeEnum.CLE_BC_CORE) { + else if (EnumSet.of(TileTypeEnum.CLE_BC_CORE, + TileTypeEnum.INTF_LOCF_TL_TILE, + TileTypeEnum.INTF_LOCF_TR_TILE, + TileTypeEnum.INTF_LOCF_BL_TILE, + TileTypeEnum.INTF_LOCF_BR_TILE, + TileTypeEnum.INTF_ROCF_TL_TILE, + TileTypeEnum.INTF_ROCF_TR_TILE, + TileTypeEnum.INTF_ROCF_BL_TILE, + TileTypeEnum.INTF_ROCF_BR_TILE) + .contains(baseTileTypeEnum)) { // Except CLE_BC_CORE tiles which spans two adjacent INT tiles if (baseTile != downhill.getTile()) { Assertions.assertTrue(1 >= Math.abs(baseTile.getTileXCoordinate() - downhill.getTile().getTileXCoordinate())); From 77fa308ddcb35bdf77214bc3a6f63b6577ce3a89 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 7 Nov 2024 16:15:35 -0800 Subject: [PATCH 32/71] UltraScale+: Sub-divide LOCALs into _EAST/_WEST and stick to sink's side Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/Connection.java | 4 +- .../rapidwright/rwroute/PartialRouter.java | 4 +- .../xilinx/rapidwright/rwroute/RWRoute.java | 30 ++++- .../xilinx/rapidwright/rwroute/RouteNode.java | 13 +- .../rapidwright/rwroute/RouteNodeGraph.java | 112 ++++++++++++------ .../rapidwright/rwroute/RouteNodeInfo.java | 33 ++++-- .../rapidwright/rwroute/RouteNodeType.java | 15 ++- .../rwroute/TimingAndWirelengthReport.java | 13 +- 8 files changed, 164 insertions(+), 60 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/Connection.java b/src/com/xilinx/rapidwright/rwroute/Connection.java index 6c08342dc..95a7f87e0 100644 --- a/src/com/xilinx/rapidwright/rwroute/Connection.java +++ b/src/com/xilinx/rapidwright/rwroute/Connection.java @@ -305,7 +305,7 @@ public void addAltSinkRnode(RouteNode sinkRnode) { } else { assert(!altSinkRnodes.contains(sinkRnode)); } - assert(sinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK || + assert(sinkRnode.getType().isExclusiveSink() || // Can be a WIRE if node is not exclusive a sink sinkRnode.getType() == RouteNodeType.NON_LOCAL); altSinkRnodes.add(sinkRnode); @@ -487,7 +487,7 @@ public void setAllTargets(RWRoute.ConnectionState state) { // where the same physical pin services more than one logical pin if (rnode.countConnectionsOfUser(netWrapper) == 0 || // Except if it is not an EXCLUSIVE_SINK - rnode.getType() != RouteNodeType.EXCLUSIVE_SINK) { + rnode.getType().isExclusiveSink()) { assert(rnode.getIntentCode() != IntentCode.NODE_PINBOUNCE); rnode.markTarget(state); } diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index 871637153..90435b794 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -256,7 +256,7 @@ protected void determineRoutingTargets() { preservedNet = routingGraph.getPreservedNet(sinkRnode); if (preservedNet != null && preservedNet != net) { unpreserveNets.add(preservedNet); - assert(sinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK); + assert(sinkRnode.getType().isExclusiveSink()); } } @@ -599,7 +599,7 @@ protected void unpreserveNet(Net net) { RouteNode sourceRnode = connection.getSourceRnode(); RouteNode sinkRnode = connection.getSinkRnode(); assert(sourceRnode.getType() == RouteNodeType.EXCLUSIVE_SOURCE); - assert(sinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK); + assert(sinkRnode.getType().isExclusiveSink()); // Even though this connection is not expected to have any routing yet, // perform a rip up anyway in order to release any exclusive sinks diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 4d2f363d5..0a38dd27e 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -59,6 +59,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.BitSet; import java.util.Collection; import java.util.Collections; import java.util.EnumMap; @@ -600,8 +601,16 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { } indirectConnections.add(connection); - RouteNode sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK); - sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK); + BitSet[] eastWestWires = routingGraph.eastWestWires.get(sinkINTNode.getTile().getTileTypeEnum()); + RouteNode sinkRnode; + if (eastWestWires[0].get(sinkINTNode.getWireIndex())) { + sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_EAST); + sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK_EAST); + } else { + assert(eastWestWires[1].get(sinkINTNode.getWireIndex())); + sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_WEST); + sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK_WEST); + } connection.setSinkRnode(sinkRnode); // Where appropriate, allow all 6 LUT pins to be swapped to begin with @@ -650,8 +659,14 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { if (routingGraph.isPreserved(node)) { continue; } - RouteNode altSinkRnode = routingGraph.getOrCreate(node, RouteNodeType.EXCLUSIVE_SINK); - assert(altSinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK); + RouteNode altSinkRnode; + if (eastWestWires[0].get(sinkINTNode.getWireIndex())) { + altSinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_EAST); + } else { + assert(eastWestWires[1].get(sinkINTNode.getWireIndex())); + altSinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_WEST); + } + assert(altSinkRnode.getType().isExclusiveSink()); connection.addAltSinkRnode(altSinkRnode); } @@ -1798,6 +1813,8 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { } switch (childRNode.getType()) { case LOCAL: + case LOCAL_EAST: + case LOCAL_WEST: if (!routingGraph.isAccessible(childRNode, connection)) { continue; } @@ -1818,7 +1835,8 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { continue; } break; - case EXCLUSIVE_SINK: + case EXCLUSIVE_SINK_EAST: + case EXCLUSIVE_SINK_WEST: if (!isAccessibleSink(childRNode, connection)) { continue; } @@ -1863,7 +1881,7 @@ protected boolean isAccessibleSink(RouteNode child, Connection connection) { } protected boolean isAccessibleSink(RouteNode child, Connection connection, boolean assertOnOveruse) { - assert(child.getType() == RouteNodeType.EXCLUSIVE_SINK); + assert(child.getType().isExclusiveSink()); assert(!assertOnOveruse || !child.isOverUsed()); if (child.isTarget()) { diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index c70a18000..d993496aa 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -93,7 +93,7 @@ public class RouteNode extends Node implements Comparable { protected RouteNode(RouteNodeGraph routingGraph, Node node, RouteNodeType type) { super(node); - RouteNodeInfo nodeInfo = RouteNodeInfo.get(this, routingGraph); + RouteNodeInfo nodeInfo = RouteNodeInfo.get(node, routingGraph); this.type = (type == null) ? nodeInfo.type : type; endTileXCoordinate = nodeInfo.endTileXCoordinate; endTileYCoordinate = nodeInfo.endTileYCoordinate; @@ -123,11 +123,16 @@ private void setBaseCost(Series series) { assert(length == 0 || (length <= 3 && series == Series.Versal)); break; - case EXCLUSIVE_SINK: + case EXCLUSIVE_SINK_EAST: + case EXCLUSIVE_SINK_WEST: assert(length == 0 || (length == 1 && (series == Series.UltraScalePlus || series == Series.UltraScale) && getIntentCode() == IntentCode.NODE_PINBOUNCE)); break; case LOCAL: + assert(length == 0); + break; + case LOCAL_EAST: + case LOCAL_WEST: assert(length == 0 || (length == 1 && ( ((series == Series.UltraScalePlus || series == Series.UltraScale) && getIntentCode() == IntentCode.NODE_PINBOUNCE) || @@ -361,10 +366,10 @@ public RouteNodeType getType() { public void setType(RouteNodeType type) { assert(this.type == type || // Support demotion from EXCLUSIVE_SINK to LOCAL since they have the same base cost - (this.type == RouteNodeType.EXCLUSIVE_SINK && type == RouteNodeType.LOCAL) || + (this.type.isExclusiveSink() && type == RouteNodeType.LOCAL) || // Or promotion from LOCAL to EXCLUSIVE_SINK (by PartialRouter when NODE_PINBOUNCE on // a newly unpreserved net becomes a sink) - (this.type == RouteNodeType.LOCAL && type == RouteNodeType.EXCLUSIVE_SINK)); + (this.type == RouteNodeType.LOCAL && type.isExclusiveSink())); this.type = type; } diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 324be57e3..289c99f51 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -35,6 +35,8 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import com.xilinx.rapidwright.design.Design; import com.xilinx.rapidwright.design.Net; @@ -101,6 +103,8 @@ public class RouteNodeGraph { /** Map indicating the wire indices that have a local intent code, but is what RWRoute considers to be non-local */ protected final Map ultraScaleNonLocalWires; + protected final Map eastWestWires; + public RouteNodeGraph(Design design, RWRouteConfig config) { this(design, config, new HashMap<>()); } @@ -133,6 +137,8 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map(TileTypeEnum.class); BitSet wires = new BitSet(); Tile intTile = device.getArbitraryTileOfType(TileTypeEnum.INT); @@ -140,49 +146,80 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map(TileTypeEnum.class); + BitSet eastWires = new BitSet(); + BitSet westWires = new BitSet(); + eastWestWires.put(intTile.getTileTypeEnum(), new BitSet[]{eastWires, westWires}); + for (int wireIndex = 0; wireIndex < intTile.getWireCount(); wireIndex++) { Node baseNode = Node.getNode(intTile, wireIndex); if (baseNode == null) { continue; } - if (baseNode.getIntentCode() != IntentCode.NODE_LOCAL) { - continue; - } - Tile baseTile = baseNode.getTile(); - String wireName = baseNode.getWireName(); - if (isUltraScalePlus) { - if (!wireName.startsWith("INT_NODE_SDQ_") && !wireName.startsWith("SDQNODE_")) { + String baseWireName = baseNode.getWireName(); + IntentCode baseIntentCode = baseNode.getIntentCode(); + if (baseIntentCode == IntentCode.NODE_LOCAL) { + Tile baseTile = baseNode.getTile(); + assert(baseTile.getTileTypeEnum() == intTile.getTileTypeEnum()); + if (isUltraScalePlus) { + if (baseWireName.startsWith("INT_NODE_SDQ_") || baseWireName.startsWith("SDQNODE_")) { + if (baseTile != intTile) { + if (baseWireName.endsWith("_FT0")) { + assert(baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() - 1); + } else { + assert(baseWireName.endsWith("_FT1")); + assert(baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() + 1); + } + } + wires.set(baseNode.getWireIndex()); + continue; + } + } else { + assert(isUltraScale); + + if (baseWireName.startsWith("INT_NODE_SINGLE_DOUBLE_") || baseWireName.startsWith("SDND") || + baseWireName.startsWith("INT_NODE_QUAD_LONG") || baseWireName.startsWith("QLND")) { + if (baseTile != intTile) { + if (baseWireName.endsWith("_FTN")) { + assert (baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() - 1); + } else { + assert (baseWireName.endsWith("_FTS")); + assert (baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() + 1); + } + } + } + wires.set(baseNode.getWireIndex()); continue; } - if (baseTile != intTile) { - if (wireName.endsWith("_FT0")) { - assert(baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() - 1); + } else if (baseIntentCode != IntentCode.NODE_PINFEED && baseIntentCode != IntentCode.NODE_PINBOUNCE) { + continue; + } + + Matcher m = eastWestPattern.matcher(baseWireName); + if (m.matches()) { + if (m.group(4) != null) { + if (m.group(4).equals("E")) { + eastWires.set(baseNode.getWireIndex()); } else { - assert(wireName.endsWith("_FT1")); - assert(baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() + 1); + assert(m.group(4).equals("W")); + westWires.set(baseNode.getWireIndex()); } - } - } else { - assert(isUltraScale); - - if (!wireName.startsWith("INT_NODE_SINGLE_DOUBLE_") && !wireName.startsWith("SDND") && - !wireName.startsWith("INT_NODE_QUAD_LONG") && !wireName.startsWith("QLND")) { - continue; - } - if (baseTile != intTile) { - if (wireName.endsWith("_FTN")) { - assert(baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() - 1); + } else if (m.group(5) != null) { + int i = Integer.valueOf(m.group(5)); + if (i < 32) { + eastWires.set(baseNode.getWireIndex()); } else { - assert(wireName.endsWith("_FTS")); - assert(baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() + 1); + assert(i < 64); + westWires.set(baseNode.getWireIndex()); } } } - wires.set(baseNode.getWireIndex()); } } else { ultraScaleNonLocalWires = null; + eastWestWires = null; } if (lutRoutethru) { @@ -429,7 +466,7 @@ protected boolean isExcluded(RouteNode parent, Node child) { // PINFEEDs can lead to a site pin, or into a Laguna tile RouteNode childRnode = getNode(child); if (childRnode != null) { - assert(childRnode.getType() == RouteNodeType.EXCLUSIVE_SINK || + assert(childRnode.getType().isExclusiveSink() || childRnode.getType() == RouteNodeType.LAGUNA_PINFEED || (lutRoutethru && childRnode.getType() == RouteNodeType.LOCAL)); } else if (!lutRoutethru) { @@ -557,25 +594,34 @@ public int averageChildren() { public boolean isAccessible(RouteNode childRnode, Connection connection) { // Only consider LOCAL nodes when: // (a) considering LUT routethrus - if (childRnode.getType() != RouteNodeType.LOCAL || lutRoutethru) { + if (!childRnode.getType().isLocal() || lutRoutethru) { return true; } - // (b) in the sink tile + // (b) on the same side as the sink + RouteNodeType type = childRnode.getType(); + RouteNode sinkRnode = connection.getSinkRnode(); + RouteNodeType sinkType = sinkRnode.getType(); + assert(sinkType.isExclusiveSink()); + if ((type == RouteNodeType.LOCAL_EAST && sinkType != RouteNodeType.EXCLUSIVE_SINK_EAST) || + (type == RouteNodeType.LOCAL_WEST && sinkType != RouteNodeType.EXCLUSIVE_SINK_WEST)) { + return false; + } + + // (c) in the sink tile Tile childTile = childRnode.getTile(); - Tile sinkTile = connection.getSinkRnode().getTile(); + Tile sinkTile = sinkRnode.getTile(); if (childTile == sinkTile) { return true; } - // (c) connection crosses SLR and this is a Laguna column + // (d) connection crosses SLR and this is a Laguna column int childX = childTile.getTileXCoordinate(); if (connection.isCrossSLR() && nextLagunaColumn[childX] == childX) { - return true; } - // (d) when in X as the sink tile, but Y +/- 1 + // (e) when in X as the sink tile, but Y +/- 1 return childX == sinkTile.getTileXCoordinate() && Math.abs(childTile.getTileYCoordinate() - sinkTile.getTileYCoordinate()) <= 1; } diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java index 8a64cbeab..2573f0493 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java @@ -128,40 +128,53 @@ private static short getEndTileXCoordinate(Node node, RouteNodeType type, short private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph routingGraph) { // NOTE: IntentCode is device-dependent IntentCode ic = node.getIntentCode(); + TileTypeEnum tileTypeEnum = node.getTile().getTileTypeEnum(); switch (ic) { case NODE_LOCAL: { // US/US+ - assert(node.getTile().getTileTypeEnum() == TileTypeEnum.INT); + assert(tileTypeEnum == TileTypeEnum.INT); if (routingGraph != null) { - BitSet bs = routingGraph.ultraScaleNonLocalWires.get(node.getTile().getTileTypeEnum()); + BitSet bs = routingGraph.ultraScaleNonLocalWires.get(tileTypeEnum); if (!bs.get(node.getWireIndex())) { + BitSet[] eastWestWires = routingGraph.eastWestWires.get(tileTypeEnum); + if (eastWestWires[0].get(node.getWireIndex())) { + return RouteNodeType.LOCAL_EAST; + } else if (eastWestWires[1].get(node.getWireIndex())) { + return RouteNodeType.LOCAL_WEST; + } return RouteNodeType.LOCAL; } break; } } - case NODE_PINBOUNCE: - return RouteNodeType.LOCAL; - - case NODE_PINFEED: { + case NODE_PINFEED: if (routingGraph != null && routingGraph.lagunaI != null) { BitSet bs = routingGraph.lagunaI.get(node.getTile()); if (bs != null && bs.get(node.getWireIndex())) { return RouteNodeType.LAGUNA_PINFEED; } } + // Fall through + case NODE_PINBOUNCE: + if (routingGraph != null) { + BitSet[] eastWestWires = routingGraph.eastWestWires.get(tileTypeEnum); + if (eastWestWires[0].get(node.getWireIndex())) { + return RouteNodeType.LOCAL_EAST; + } + assert (eastWestWires[1].get(node.getWireIndex())); + return RouteNodeType.LOCAL_WEST; + } return RouteNodeType.LOCAL; - } case NODE_LAGUNA_OUTPUT: // UltraScale+ only - assert(node.getTile().getTileTypeEnum() == TileTypeEnum.LAG_LAG); + assert(tileTypeEnum == TileTypeEnum.LAG_LAG); if (node.getWireName().endsWith("_TXOUT")) { return RouteNodeType.LAGUNA_PINFEED; } break; case NODE_LAGUNA_DATA: // UltraScale+ only - assert(node.getTile().getTileTypeEnum() == TileTypeEnum.LAG_LAG); + assert(tileTypeEnum == TileTypeEnum.LAG_LAG); if (node.getTile() != endTile) { return RouteNodeType.SUPER_LONG_LINE; } @@ -170,7 +183,7 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou break; case INTENT_DEFAULT: - if (node.getTile().getTileTypeEnum() == TileTypeEnum.LAGUNA_TILE) { // UltraScale only + if (tileTypeEnum == TileTypeEnum.LAGUNA_TILE) { // UltraScale only String wireName = node.getWireName(); if (wireName.startsWith("UBUMP")) { assert(node.getTile() != endTile); diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java index 2510b4701..e974e281e 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java @@ -28,7 +28,8 @@ public enum RouteNodeType { EXCLUSIVE_SOURCE, - EXCLUSIVE_SINK, + EXCLUSIVE_SINK_EAST, + EXCLUSIVE_SINK_WEST, /** * Denotes {@link RouteNode} objects that correspond to a super long line {@link Node}, @@ -44,5 +45,15 @@ public enum RouteNodeType { NON_LOCAL, - LOCAL + LOCAL, + LOCAL_EAST, + LOCAL_WEST; + + public boolean isExclusiveSink() { + return this == EXCLUSIVE_SINK_EAST || this == EXCLUSIVE_SINK_WEST; + } + + public boolean isLocal() { + return this == LOCAL || this == LOCAL_EAST || this == LOCAL_WEST; + } } diff --git a/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java b/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java index c51cc6789..3b7b94361 100644 --- a/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java +++ b/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java @@ -24,6 +24,7 @@ package com.xilinx.rapidwright.rwroute; +import java.util.BitSet; import java.util.HashMap; import java.util.Map; @@ -128,7 +129,17 @@ private NetWrapper createNetWrapper(Net net) { if (sinkINTNode == null) { connection.setDirect(true); } else { - connection.setSinkRnode(routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK)); + BitSet[] eastWestWires = routingGraph.eastWestWires.get(sinkINTNode.getTile().getTileTypeEnum()); + RouteNode sinkRnode; + if (eastWestWires[0].get(sinkINTNode.getWireIndex())) { + sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_EAST); + sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK_EAST); + } else { + assert(eastWestWires[1].get(sinkINTNode.getWireIndex())); + sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_WEST); + sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK_WEST); + } + connection.setSinkRnode(sinkRnode); if (sourceINTNode == null) { sourceINTNode = RouterHelper.projectOutputPinToINTNode(source); } From 6229dbe3e3d92f869bff17741d3ba5d050446af8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 7 Nov 2024 16:30:53 -0800 Subject: [PATCH 33/71] Re-add EXCLUSIVE_SINK (non-sided) for CTRL sinks Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RWRoute.java | 7 +++++-- src/com/xilinx/rapidwright/rwroute/RouteNode.java | 3 +++ .../xilinx/rapidwright/rwroute/RouteNodeGraph.java | 6 ++++-- .../xilinx/rapidwright/rwroute/RouteNodeInfo.java | 5 +++-- .../xilinx/rapidwright/rwroute/RouteNodeType.java | 3 ++- .../rwroute/TimingAndWirelengthReport.java | 12 +----------- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 0a38dd27e..ba112f090 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -606,10 +606,12 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { if (eastWestWires[0].get(sinkINTNode.getWireIndex())) { sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_EAST); sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK_EAST); - } else { - assert(eastWestWires[1].get(sinkINTNode.getWireIndex())); + } else if (eastWestWires[1].get(sinkINTNode.getWireIndex())) { sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_WEST); sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK_WEST); + } else { + sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK); + sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK); } connection.setSinkRnode(sinkRnode); @@ -1835,6 +1837,7 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { continue; } break; + case EXCLUSIVE_SINK: case EXCLUSIVE_SINK_EAST: case EXCLUSIVE_SINK_WEST: if (!isAccessibleSink(childRNode, connection)) { diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index d993496aa..56df8a046 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -123,6 +123,9 @@ private void setBaseCost(Series series) { assert(length == 0 || (length <= 3 && series == Series.Versal)); break; + case EXCLUSIVE_SINK: + assert(length == 0); + break; case EXCLUSIVE_SINK_EAST: case EXCLUSIVE_SINK_WEST: assert(length == 0 || diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 289c99f51..01b55831c 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -137,7 +137,7 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map(TileTypeEnum.class); BitSet wires = new BitSet(); @@ -604,7 +604,9 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { RouteNodeType sinkType = sinkRnode.getType(); assert(sinkType.isExclusiveSink()); if ((type == RouteNodeType.LOCAL_EAST && sinkType != RouteNodeType.EXCLUSIVE_SINK_EAST) || - (type == RouteNodeType.LOCAL_WEST && sinkType != RouteNodeType.EXCLUSIVE_SINK_WEST)) { + (type == RouteNodeType.LOCAL_WEST && sinkType != RouteNodeType.EXCLUSIVE_SINK_WEST) || + // Sinks without a side (e.g. CTRL) can only be approached from LOCAL nodes also without a side + (sinkType == RouteNodeType.EXCLUSIVE_SINK && type != RouteNodeType.LOCAL)) { return false; } diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java index 2573f0493..ffd11765e 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java @@ -160,9 +160,10 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou BitSet[] eastWestWires = routingGraph.eastWestWires.get(tileTypeEnum); if (eastWestWires[0].get(node.getWireIndex())) { return RouteNodeType.LOCAL_EAST; + } else if (eastWestWires[1].get(node.getWireIndex())) { + return RouteNodeType.LOCAL_WEST; } - assert (eastWestWires[1].get(node.getWireIndex())); - return RouteNodeType.LOCAL_WEST; + assert(node.getWireName().startsWith("CTRL_")); } return RouteNodeType.LOCAL; diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java index e974e281e..0c024bb0b 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java @@ -28,6 +28,7 @@ public enum RouteNodeType { EXCLUSIVE_SOURCE, + EXCLUSIVE_SINK, EXCLUSIVE_SINK_EAST, EXCLUSIVE_SINK_WEST, @@ -50,7 +51,7 @@ public enum RouteNodeType { LOCAL_WEST; public boolean isExclusiveSink() { - return this == EXCLUSIVE_SINK_EAST || this == EXCLUSIVE_SINK_WEST; + return this == EXCLUSIVE_SINK || this == EXCLUSIVE_SINK_EAST || this == EXCLUSIVE_SINK_WEST; } public boolean isLocal() { diff --git a/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java b/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java index 3b7b94361..0ff666a2f 100644 --- a/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java +++ b/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java @@ -129,17 +129,7 @@ private NetWrapper createNetWrapper(Net net) { if (sinkINTNode == null) { connection.setDirect(true); } else { - BitSet[] eastWestWires = routingGraph.eastWestWires.get(sinkINTNode.getTile().getTileTypeEnum()); - RouteNode sinkRnode; - if (eastWestWires[0].get(sinkINTNode.getWireIndex())) { - sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_EAST); - sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK_EAST); - } else { - assert(eastWestWires[1].get(sinkINTNode.getWireIndex())); - sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_WEST); - sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK_WEST); - } - connection.setSinkRnode(sinkRnode); + connection.setSinkRnode(routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK)); if (sourceINTNode == null) { sourceINTNode = RouterHelper.projectOutputPinToINTNode(source); } From 74fdf59e608fbffa91187ec3d841b332fb6456fe Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 7 Nov 2024 16:40:15 -0800 Subject: [PATCH 34/71] Support UltraScale Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 01b55831c..2275eb334 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -208,13 +208,15 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map= 64 && i < 96))) { eastWires.set(baseNode.getWireIndex()); } else { - assert(i < 64); + assert(i < 64 || (isUltraScale && (i >= 96 && i < 128))); westWires.set(baseNode.getWireIndex()); } } + } else { + assert(baseWireName.matches("CTRL_[EW](_B)?\\d+|INT_NODE_GLOBAL_\\d+_INT_OUT[01]?")); } } } else { From a1dca3737ac739bc44c62f656760d2f1679df48c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 7 Nov 2024 16:40:27 -0800 Subject: [PATCH 35/71] Print Signed-off-by: Eddie Hung --- test/src/com/xilinx/rapidwright/device/TestNode.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/src/com/xilinx/rapidwright/device/TestNode.java b/test/src/com/xilinx/rapidwright/device/TestNode.java index 2b0d6bef1..8075a6cf7 100644 --- a/test/src/com/xilinx/rapidwright/device/TestNode.java +++ b/test/src/com/xilinx/rapidwright/device/TestNode.java @@ -148,6 +148,7 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str intentCodes.add(node.getIntentCode()); } System.out.println("Initial queue.size() = " + queue.size()); + System.out.println("Initial queue = " + queue); System.out.println("Intent codes = " + intentCodes); // Print out the prefixes of nodes that are immediately uphill of these wire prefixes From 977b0689aa0a726c4add8ffaf9017f3ead3f598a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 7 Nov 2024 17:16:08 -0800 Subject: [PATCH 36/71] Expand testNodeReachabilityVersal Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/device/TestNode.java | 101 ++++++++++++------ 1 file changed, 67 insertions(+), 34 deletions(-) diff --git a/test/src/com/xilinx/rapidwright/device/TestNode.java b/test/src/com/xilinx/rapidwright/device/TestNode.java index 8075a6cf7..175172258 100644 --- a/test/src/com/xilinx/rapidwright/device/TestNode.java +++ b/test/src/com/xilinx/rapidwright/device/TestNode.java @@ -159,9 +159,9 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str .map(n -> n.getWireName() + " (" + n.getIntentCode() + ")") .map(s -> s.replaceFirst("^((BOUNCE|BYPASS|CTRL|INODE(_[12])?|IMUX|SDQNODE)_([EW]_?)?)[^ ]+", "$1")) .map(s -> s.replaceFirst("(INT_NODE_(GLOBAL|SDQ|SINGLE_DOUBLE|QUAD_LONG)_)[^ ]+", "$1")) - .map(s -> ultraScalePlus ? s.replaceFirst("(INT_NODE_IMUX_)([0-9]|1[0-9]|2[0-9]|3[01])_INT_OUT[01]?", "$1<0-31>") + .map(s -> ultraScalePlus ? s.replaceFirst("(INT_NODE_IMUX_)([0-9]|1[0-9]|2[0-9]|3[01])_INT_OUT[01]", "$1<0-31>") : s.replaceFirst("(INT_NODE_IMUX_)([0-9]|1[0-9]|2[0-9]|3[01]|6[4-9]|7[0-9]|8[0-9]|9[0-5])_INT_OUT", "$1<0-31,64-95>")) - .map(s -> ultraScalePlus ? s.replaceFirst("(INT_NODE_IMUX_)(3[2-9]|4[0-9]|5[0-9]|6[0-3])_INT_OUT[01]?", "$1<32-63>") + .map(s -> ultraScalePlus ? s.replaceFirst("(INT_NODE_IMUX_)(3[2-9]|4[0-9]|5[0-9]|6[0-3])_INT_OUT[01]", "$1<32-63>") : s.replaceFirst("(INT_NODE_IMUX_)(3[2-9]|4[0-9]|5[0-9]|6[0-3]|9[6-9]|10[0-9]|11[0-9]|12[0-7])_INT_OUT", "$1<32-63,96-127>")) .map(s -> s.replaceFirst( // UltraScale+ @@ -179,16 +179,16 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str .map(n -> n.getWireName() + " (" + n.getIntentCode() + ")") .map(s -> s.replaceFirst("^((BOUNCE|BYPASS|CTRL|INODE(_[12])?|IMUX|SDQNODE)_([EW]_?)?)[^ ]+", "$1")) .map(s -> s.replaceFirst("(INT_NODE_(GLOBAL|SDQ|SINGLE_DOUBLE|QUAD_LONG)_)[^ ]+", "$1")) - .map(s -> ultraScalePlus ? s.replaceFirst("(INT_NODE_IMUX_)([0-9]|1[0-9]|2[0-9]|3[01])_INT_OUT[01]?", "$1<0-31>") + .map(s -> ultraScalePlus ? s.replaceFirst("(INT_NODE_IMUX_)([0-9]|1[0-9]|2[0-9]|3[01])_INT_OUT[01]", "$1<0-31>") : s.replaceFirst("(INT_NODE_IMUX_)([0-9]|1[0-9]|2[0-9]|3[01]|6[4-9]|7[0-9]|8[0-9]|9[0-5])_INT_OUT", "$1<0-31,64-95>")) - .map(s -> ultraScalePlus ? s.replaceFirst("(INT_NODE_IMUX_)(3[2-9]|4[0-9]|5[0-9]|6[0-3])_INT_OUT[01]?", "$1<32-63>") + .map(s -> ultraScalePlus ? s.replaceFirst("(INT_NODE_IMUX_)(3[2-9]|4[0-9]|5[0-9]|6[0-3])_INT_OUT[01]", "$1<32-63>") : s.replaceFirst("(INT_NODE_IMUX_)(3[2-9]|4[0-9]|5[0-9]|6[0-3]|9[6-9]|10[0-9]|11[0-9]|12[0-7])_INT_OUT", "$1<32-63,96-127>")) .map(s -> s.replaceFirst( // UltraScale+ ultraScalePlus ? "((CLE_CLE_[LM]_SITE_0|INT_INT_SDQ|(NN|EE|SS|WW)(1|2|4|12)(_[EW])?)_)[^\\(]+" // UltraScale - : "((CLE_CLE_[LM]_SITE_0|INT_INT_SINGLE|(NN|SS)(1|2|4|5|12|16)|(EE|WW)(1|2|4|12)(_[EW])?|QLND(NW|S[EW])|SDND[NS]W)_)[^\\(]+", - "$1 ")) + : "((CLE_CLE_[LM]_SITE_0|INT_INT_SINGLE|(NN|SS)(1|2|4|5|12|16)|(EE|WW)(1|2|4|12)(_[EW])?|QLND(NW|S[EW])|SDND[NS]W)_)[^ ]+", + "$1")) .distinct() .sorted() .forEachOrdered(s -> System.out.println("\t" + s)); @@ -228,30 +228,36 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str @ParameterizedTest @CsvSource({ - "xcvp1002,INT_X38Y220,NODE_PINBOUNCE,true", - "xcvp1002,INT_X38Y220,NODE_INODE,true", - "xcvp1002,INT_X38Y220,NODE_IMUX,true", - "xcvp1002,INT_X38Y220,NODE_SDQNODE,false", - "xcvp1002,INT_X38Y220,NODE_HSINGLE,false", - "xcvp1002,INT_X38Y220,NODE_VSINGLE,false", - "xcvp1002,INT_X38Y220,NODE_HDOUBLE,false", - "xcvp1002,INT_X38Y220,NODE_VDOUBLE,false", - "xcvp1002,INT_X38Y220,NODE_HQUAD,false", - "xcvp1002,INT_X38Y220,NODE_VQUAD,false", - "xcvp1002,INT_X38Y220,NODE_HLONG6,false", - "xcvp1002,INT_X38Y220,NODE_HLONG10,false", - "xcvp1002,INT_X38Y220,NODE_VLONG7,false", - "xcvp1002,INT_X38Y220,NODE_VLONG12,false", - "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_BNODE,true", - "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_CNODE,true", - "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_CTRL,true", - "xcvp1002,CLE_W_CORE_X38Y220,NODE_PINFEED,true", - "xcvp1002,CLE_E_CORE_X38Y220,NODE_CLE_OUTPUT,false", - "xcvp1002,CLE_W_CORE_X38Y220,NODE_CLE_OUTPUT,false", - "xcvp1002,INTF_ROCF_TR_TILE_X39Y153,NODE_INTF_CNODE,true", - "xcvp1002,INTF_ROCF_TR_TILE_X39Y153,NODE_INTF_BNODE,true", + "xcvp1002,INT_X38Y220,NODE_PINBOUNCE,BOUNCE_E.*,true", + "xcvp1002,INT_X38Y220,NODE_PINBOUNCE,BOUNCE_W.*,true", + "xcvp1002,INT_X38Y220,NODE_INODE,INT_NODE_IMUX_ATOM_([0-9]|1[0-9]|2[0-9]|3[01]|6[4-9]|7[0-9]|8[0-9]|9[0-5])_.*,true", + "xcvp1002,INT_X38Y220,NODE_INODE,INT_NODE_IMUX_ATOM_(3[2-9]|4[0-9]|5[0-9]|6[0-3]|9[6-9]|10[0-9]|11[0-9]|12[0-7])_.*,true", + "xcvp1002,INT_X38Y220,NODE_IMUX,IMUX_B_E.*,true", + "xcvp1002,INT_X38Y220,NODE_IMUX,IMUX_B_W.*,true", + "xcvp1002,INT_X38Y220,NODE_SDQNODE,,false", + "xcvp1002,INT_X38Y220,NODE_HSINGLE,,false", + "xcvp1002,INT_X38Y220,NODE_VSINGLE,,false", + "xcvp1002,INT_X38Y220,NODE_HDOUBLE,,false", + "xcvp1002,INT_X38Y220,NODE_VDOUBLE,,false", + "xcvp1002,INT_X38Y220,NODE_HQUAD,,false", + "xcvp1002,INT_X38Y220,NODE_VQUAD,,false", + "xcvp1002,INT_X38Y220,NODE_HLONG6,,false", + "xcvp1002,INT_X38Y220,NODE_HLONG10,,false", + "xcvp1002,INT_X38Y220,NODE_VLONG7,,false", + "xcvp1002,INT_X38Y220,NODE_VLONG12,,false", + "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_BNODE,BNODE_OUTS_E.*,true", + "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_BNODE,BNODE_OUTS_W.*,true", + "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_CNODE,CNODE_OUTS_E.*,true", + "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_CNODE,CNODE_OUTS_W.*,true", + "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_CTRL,CTRL_L_B.*,true", + "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_CTRL,CTRL_R_B.*,true", + "xcvp1002,CLE_W_CORE_X38Y220,NODE_PINFEED,,true", + "xcvp1002,CLE_E_CORE_X38Y220,NODE_CLE_OUTPUT,,false", + "xcvp1002,CLE_W_CORE_X38Y220,NODE_CLE_OUTPUT,,false", + "xcvp1002,INTF_ROCF_TR_TILE_X39Y153,NODE_INTF_CNODE,,true", + "xcvp1002,INTF_ROCF_TR_TILE_X39Y153,NODE_INTF_BNODE,,true", }) - public void testNodeReachabilityVersal(String partName, String tileName, String intentCodeName, boolean local) { + public void testNodeReachabilityVersal(String partName, String tileName, String intentCodeName, String wireNameRegex, boolean local) { Device device = Device.getDevice(partName); Tile baseTile = device.getTile(tileName); IntentCode baseIntentCode = IntentCode.valueOf(intentCodeName); @@ -260,21 +266,48 @@ public void testNodeReachabilityVersal(String partName, String tileName, String if (baseTile.getWireIntentCode(wireIdx) != baseIntentCode) { continue; } - queue.add(Node.getNode(baseTile, wireIdx)); + + Node node = Node.getNode(baseTile, wireIdx); + if (wireNameRegex != null && !node.getWireName().matches(wireNameRegex)) { + continue; + } + queue.add(node); } System.out.println("Initial queue.size() = " + queue.size()); System.out.println("Initial queue = " + queue); - // Print out the intent code of nodes that are immediately uphill of this intent code + // Print out the prefixes of nodes that are immediately uphill of these wire prefixes + // (i.e. "BOUNCE_E_0_FT1" -> "BOUNCE_") System.out.println("Immediately uphill:"); - queue.stream().map(Node::getAllUphillNodes).flatMap(List::stream).map(Node::getIntentCode) + boolean ultraScalePlus = partName.endsWith("p"); + queue.stream().map(Node::getAllUphillNodes).flatMap(List::stream) + .map(n -> n.getWireName() + " (" + n.getIntentCode() + ")") + .map(s -> s.replaceFirst("^((BOUNCE|IMUX_B)_[EW])[^ ]+", "$1")) + .map(s -> s.replaceFirst("^(CTRL_[LR]_)B\\d+", "$1")) + .map(s -> s.replaceFirst("(INT_NODE_SDQ_|INT_SDQ_RED_ATOM_)[^ ]+", "$1")) + .map(s -> s.replaceFirst("(INT_NODE_IMUX_ATOM_)([0-9]|1[0-9]|2[0-9]|3[01]|6[4-9]|7[0-9]|8[0-9]|9[0-5])_INT_OUT[01]", "$1<0-31,64-95>")) + .map(s -> s.replaceFirst("(INT_NODE_IMUX_ATOM_)(3[2-9]|4[0-9]|5[0-9]|6[0-3]|9[6-9]|10[0-9]|11[0-9]|12[0-7])_INT_OUT[01]", "$1<32-63,96-127>")) + .map(s -> s.replaceFirst("([BC]NODE_OUTS_[EW])\\d+", "$1")) + .map(s -> s.replaceFirst("((CLE_SLICE[LM]_TOP_[01]|OUT_[NESW]NODE|(NN|EE|SS|WW)(1|2|4|6|7|10|12)(_[EW])?)_)[^ ]+", "$1")) + .map(s -> s.replaceFirst("(CLK_LEAF_SITES_)\\d+_O", "$1")) + .map(s -> s.replaceFirst("(VCC_WIRE)\\d+", "$1")) .distinct() .sorted() .forEachOrdered(s -> System.out.println("\t" + s)); - // Print out the intent code of nodes that are immediately downhill of this intent code + // Print out the prefixes of nodes that are immediately downhill of these wire prefixes System.out.println("Immediately downhill:"); - queue.stream().map(Node::getAllDownhillNodes).flatMap(List::stream).map(Node::getIntentCode) + queue.stream().map(Node::getAllDownhillNodes).flatMap(List::stream) + .map(n -> n.getWireName() + " (" + n.getIntentCode() + ")") + .map(s -> s.replaceFirst("^((BOUNCE|IMUX_B)_[EW])[^ ]+", "$1")) + .map(s -> s.replaceFirst("^(CTRL_[LR]_)B\\d+", "$1")) + .map(s -> s.replaceFirst("(INT_NODE_SDQ_|INT_SDQ_RED_ATOM_)[^ ]+", "$1")) + .map(s -> s.replaceFirst("(INT_NODE_IMUX_ATOM_)([0-9]|1[0-9]|2[0-9]|3[01]|6[4-9]|7[0-9]|8[0-9]|9[0-5])_INT_OUT[01]", "$1<0-31,64-95>")) + .map(s -> s.replaceFirst("(INT_NODE_IMUX_ATOM_)(3[2-9]|4[0-9]|5[0-9]|6[0-3]|9[6-9]|10[0-9]|11[0-9]|12[0-7])_INT_OUT[01]", "$1<32-63,96-127>")) + .map(s -> s.replaceFirst("([BC]NODE_OUTS_[EW])\\d+", "$1")) + .map(s -> s.replaceFirst("((CLE_SLICE[LM]_TOP_[01]|OUT_[NESW]NODE|(NN|EE|SS|WW)(1|2|4|6|7|10|12)(_[EW])?)_)[^ ]+", "$1")) + .map(s -> s.replaceFirst("(IF_INT_BNODE_OUTS)\\d+", "$1")) + .map(s -> s.replaceFirst("(INTF_IRI_QUADRANT_(GREEN|RED))_\\d+_[^ ]+", "$1")) .distinct() .sorted() .forEachOrdered(s -> System.out.println("\t" + s)); From 967890dc25721678ef77559e5789dc7ab40b4a5e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 7 Nov 2024 17:20:50 -0800 Subject: [PATCH 37/71] Do not error out for Versal Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/RouteNodeGraph.java | 162 ++++++++++-------- .../rapidwright/rwroute/RouteNodeInfo.java | 7 +- 2 files changed, 92 insertions(+), 77 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 2275eb334..5adf3ad36 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -101,7 +101,7 @@ public class RouteNodeGraph { protected final boolean lutRoutethru; /** Map indicating the wire indices that have a local intent code, but is what RWRoute considers to be non-local */ - protected final Map ultraScaleNonLocalWires; + protected final Map ultraScalesNonLocalWires; protected final Map eastWestWires; @@ -136,92 +136,104 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map(TileTypeEnum.class); + BitSet eastWires = new BitSet(); + BitSet westWires = new BitSet(); + eastWestWires.put(intTile.getTileTypeEnum(), new BitSet[]{eastWires, westWires}); + + BitSet wires = new BitSet(); if (isUltraScale || isUltraScalePlus) { - Pattern eastWestPattern = Pattern.compile("(((BOUNCE|BYPASS|IMUX|INODE)_([EW]))|INT_NODE_IMUX_(\\d+)_).*"); - - ultraScaleNonLocalWires = new EnumMap<>(TileTypeEnum.class); - BitSet wires = new BitSet(); - Tile intTile = device.getArbitraryTileOfType(TileTypeEnum.INT); - // Device.getArbitraryTileOfType() typically gives you the North-Western-most - // tile (with minimum X, maximum Y). Analyze the tile just below that. - intTile = intTile.getTileXYNeighbor(0, -1); - ultraScaleNonLocalWires.put(intTile.getTileTypeEnum(), wires); - - eastWestWires = new EnumMap<>(TileTypeEnum.class); - BitSet eastWires = new BitSet(); - BitSet westWires = new BitSet(); - eastWestWires.put(intTile.getTileTypeEnum(), new BitSet[]{eastWires, westWires}); - - for (int wireIndex = 0; wireIndex < intTile.getWireCount(); wireIndex++) { - Node baseNode = Node.getNode(intTile, wireIndex); - if (baseNode == null) { - continue; - } + ultraScalesNonLocalWires = new EnumMap<>(TileTypeEnum.class); + ultraScalesNonLocalWires.put(intTile.getTileTypeEnum(), wires); + eastWestPattern = Pattern.compile("(((BOUNCE|BYPASS|IMUX|INODE)_([EW]))|INT_NODE_IMUX_(\\d+)_).*"); + } else { + assert(series == Series.Versal); + ultraScalesNonLocalWires = null; - String baseWireName = baseNode.getWireName(); - IntentCode baseIntentCode = baseNode.getIntentCode(); - if (baseIntentCode == IntentCode.NODE_LOCAL) { - Tile baseTile = baseNode.getTile(); - assert(baseTile.getTileTypeEnum() == intTile.getTileTypeEnum()); - if (isUltraScalePlus) { - if (baseWireName.startsWith("INT_NODE_SDQ_") || baseWireName.startsWith("SDQNODE_")) { - if (baseTile != intTile) { - if (baseWireName.endsWith("_FT0")) { - assert(baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() - 1); - } else { - assert(baseWireName.endsWith("_FT1")); - assert(baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() + 1); - } - } - wires.set(baseNode.getWireIndex()); - continue; - } - } else { - assert(isUltraScale); - - if (baseWireName.startsWith("INT_NODE_SINGLE_DOUBLE_") || baseWireName.startsWith("SDND") || - baseWireName.startsWith("INT_NODE_QUAD_LONG") || baseWireName.startsWith("QLND")) { - if (baseTile != intTile) { - if (baseWireName.endsWith("_FTN")) { - assert (baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() - 1); - } else { - assert (baseWireName.endsWith("_FTS")); - assert (baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() + 1); - } + // FIXME: + eastWestPattern = null; + eastWestWires.put(TileTypeEnum.CLE_BC_CORE, new BitSet[]{eastWires, westWires}); + } + + for (int wireIndex = 0; wireIndex < intTile.getWireCount(); wireIndex++) { + Node baseNode = Node.getNode(intTile, wireIndex); + if (baseNode == null) { + continue; + } + + String baseWireName = baseNode.getWireName(); + IntentCode baseIntentCode = baseNode.getIntentCode(); + if (baseIntentCode == IntentCode.NODE_LOCAL) { + Tile baseTile = baseNode.getTile(); + assert(baseTile.getTileTypeEnum() == intTile.getTileTypeEnum()); + if (isUltraScalePlus) { + if (baseWireName.startsWith("INT_NODE_SDQ_") || baseWireName.startsWith("SDQNODE_")) { + if (baseTile != intTile) { + if (baseWireName.endsWith("_FT0")) { + assert(baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() - 1); + } else { + assert(baseWireName.endsWith("_FT1")); + assert(baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() + 1); } } wires.set(baseNode.getWireIndex()); continue; } - } else if (baseIntentCode != IntentCode.NODE_PINFEED && baseIntentCode != IntentCode.NODE_PINBOUNCE) { + } else if (isUltraScale) { + if (baseWireName.startsWith("INT_NODE_SINGLE_DOUBLE_") || baseWireName.startsWith("SDND") || + baseWireName.startsWith("INT_NODE_QUAD_LONG") || baseWireName.startsWith("QLND")) { + if (baseTile != intTile) { + if (baseWireName.endsWith("_FTN")) { + assert (baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() - 1); + } else { + assert (baseWireName.endsWith("_FTS")); + assert (baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() + 1); + } + } + } + wires.set(baseNode.getWireIndex()); continue; } + } else if (baseIntentCode != IntentCode.NODE_PINFEED && baseIntentCode != IntentCode.NODE_PINBOUNCE) { + continue; + } - Matcher m = eastWestPattern.matcher(baseWireName); - if (m.matches()) { - if (m.group(4) != null) { - if (m.group(4).equals("E")) { - eastWires.set(baseNode.getWireIndex()); - } else { - assert(m.group(4).equals("W")); - westWires.set(baseNode.getWireIndex()); - } - } else if (m.group(5) != null) { - int i = Integer.valueOf(m.group(5)); - if (i < 32 || (isUltraScale && (i >= 64 && i < 96))) { - eastWires.set(baseNode.getWireIndex()); - } else { - assert(i < 64 || (isUltraScale && (i >= 96 && i < 128))); - westWires.set(baseNode.getWireIndex()); - } + if (eastWestPattern == null) { + // FIXME: + assert(series == Series.Versal); + continue; + } + + Matcher m = eastWestPattern.matcher(baseWireName); + if (m.matches()) { + if (m.group(4) != null) { + if (m.group(4).equals("E")) { + eastWires.set(baseNode.getWireIndex()); + } else { + assert(m.group(4).equals("W")); + westWires.set(baseNode.getWireIndex()); + } + } else if (m.group(5) != null) { + int i = Integer.valueOf(m.group(5)); + if (i < 32 || (isUltraScale && (i >= 64 && i < 96))) { + eastWires.set(baseNode.getWireIndex()); + } else { + assert(i < 64 || (isUltraScale && (i >= 96 && i < 128))); + westWires.set(baseNode.getWireIndex()); } - } else { - assert(baseWireName.matches("CTRL_[EW](_B)?\\d+|INT_NODE_GLOBAL_\\d+_INT_OUT[01]?")); } + } else { + assert(baseWireName.matches("CTRL_[EW](_B)?\\d+|INT_NODE_GLOBAL_\\d+_INT_OUT[01]?") + // FIXME: + || series == Series.Versal); } - } else { - ultraScaleNonLocalWires = null; - eastWestWires = null; } if (lutRoutethru) { @@ -233,7 +245,7 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map Date: Thu, 7 Nov 2024 18:33:44 -0800 Subject: [PATCH 38/71] Fix failing assertions Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RouteNode.java | 2 -- src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index 56df8a046..8f8f78d12 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -124,8 +124,6 @@ private void setBaseCost(Series series) { (length <= 3 && series == Series.Versal)); break; case EXCLUSIVE_SINK: - assert(length == 0); - break; case EXCLUSIVE_SINK_EAST: case EXCLUSIVE_SINK_WEST: assert(length == 0 || diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 5adf3ad36..2ba58dbe2 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -482,7 +482,7 @@ protected boolean isExcluded(RouteNode parent, Node child) { if (childRnode != null) { assert(childRnode.getType().isExclusiveSink() || childRnode.getType() == RouteNodeType.LAGUNA_PINFEED || - (lutRoutethru && childRnode.getType() == RouteNodeType.LOCAL)); + (lutRoutethru && childRnode.getType().isLocal())); } else if (!lutRoutethru) { // child does not already exist in our routing graph, meaning it's not a used site pin // in our design, but it could be a LAGUNA_I From 95bba953317fb90a8ddc29f4772605c6772b6ce7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 7 Nov 2024 18:35:07 -0800 Subject: [PATCH 39/71] Remove unused import Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java b/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java index 0ff666a2f..c51cc6789 100644 --- a/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java +++ b/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java @@ -24,7 +24,6 @@ package com.xilinx.rapidwright.rwroute; -import java.util.BitSet; import java.util.HashMap; import java.util.Map; From 3a25ead24a7d733af9114d61e799cd40ba5242a1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 7 Nov 2024 19:28:17 -0800 Subject: [PATCH 40/71] Fix another typo Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RWRoute.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index ba112f090..9fa089202 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -620,6 +620,8 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { int numberOfSwappablePins = (lutPinSwapping && sink.isLUTInputPin()) ? LUTTools.MAX_LUT_SIZE : 0; if (numberOfSwappablePins > 0) { + assert(sinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK_EAST || sinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK_WEST); + for (Cell cell : DesignTools.getConnectedCells(sink)) { BEL bel = cell.getBEL(); assert(bel.isLUT()); @@ -661,13 +663,7 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { if (routingGraph.isPreserved(node)) { continue; } - RouteNode altSinkRnode; - if (eastWestWires[0].get(sinkINTNode.getWireIndex())) { - altSinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_EAST); - } else { - assert(eastWestWires[1].get(sinkINTNode.getWireIndex())); - altSinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_WEST); - } + RouteNode altSinkRnode = routingGraph.getOrCreate(node, sinkRnode.getType()); assert(altSinkRnode.getType().isExclusiveSink()); connection.addAltSinkRnode(altSinkRnode); } From 0d60f48d373746aaadfd4e354c27e28d28e2e9b5 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 7 Nov 2024 20:13:16 -0800 Subject: [PATCH 41/71] Fix SLR crossings Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/RouteNodeGraph.java | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 2ba58dbe2..312eb276f 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -612,9 +612,18 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { return true; } - // (b) on the same side as the sink - RouteNodeType type = childRnode.getType(); + // (b) needs to cross an SLR and this is a Laguna column + Tile childTile = childRnode.getTile(); RouteNode sinkRnode = connection.getSinkRnode(); + int childX = childTile.getTileXCoordinate(); + if (connection.isCrossSLR() && + childRnode.getSLRIndex(this) != sinkRnode.getSLRIndex(this) && + nextLagunaColumn[childX] == childX) { + return true; + } + + // (c) on the same side as the sink + RouteNodeType type = childRnode.getType(); RouteNodeType sinkType = sinkRnode.getType(); assert(sinkType.isExclusiveSink()); if ((type == RouteNodeType.LOCAL_EAST && sinkType != RouteNodeType.EXCLUSIVE_SINK_EAST) || @@ -624,20 +633,13 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { return false; } - // (c) in the sink tile - Tile childTile = childRnode.getTile(); + // (d) in the sink tile Tile sinkTile = sinkRnode.getTile(); if (childTile == sinkTile) { return true; } - // (d) connection crosses SLR and this is a Laguna column - int childX = childTile.getTileXCoordinate(); - if (connection.isCrossSLR() && nextLagunaColumn[childX] == childX) { - return true; - } - - // (e) when in X as the sink tile, but Y +/- 1 + // (e) when in same X as the sink tile, but Y +/- 1 return childX == sinkTile.getTileXCoordinate() && Math.abs(childTile.getTileYCoordinate() - sinkTile.getTileYCoordinate()) <= 1; } From d4e0ea573da63c5af2fb2c72174020afe92631a9 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 7 Nov 2024 20:18:34 -0800 Subject: [PATCH 42/71] More Versal fixes Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RWRoute.java | 7 ++++--- .../xilinx/rapidwright/rwroute/RouteNodeGraph.java | 11 ++++++----- src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 9fa089202..ed4541deb 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -601,12 +601,13 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { } indirectConnections.add(connection); - BitSet[] eastWestWires = routingGraph.eastWestWires.get(sinkINTNode.getTile().getTileTypeEnum()); + BitSet[] eastWestWires = (routingGraph.eastWestWires == null) ? null : + routingGraph.eastWestWires.get(sinkINTNode.getTile().getTileTypeEnum()); RouteNode sinkRnode; - if (eastWestWires[0].get(sinkINTNode.getWireIndex())) { + if (eastWestWires != null && eastWestWires[0].get(sinkINTNode.getWireIndex())) { sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_EAST); sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK_EAST); - } else if (eastWestWires[1].get(sinkINTNode.getWireIndex())) { + } else if (eastWestWires != null && eastWestWires[1].get(sinkINTNode.getWireIndex())) { sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_WEST); sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK_WEST); } else { diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 312eb276f..8b0ca7eab 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -104,6 +104,7 @@ public class RouteNodeGraph { protected final Map ultraScalesNonLocalWires; protected final Map eastWestWires; + protected static final BitSet EMPTY_BITSET = new BitSet(0); public RouteNodeGraph(Design design, RWRouteConfig config) { this(design, config, new HashMap<>()); @@ -143,23 +144,23 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map(TileTypeEnum.class); + BitSet wires = new BitSet(); BitSet eastWires = new BitSet(); BitSet westWires = new BitSet(); - eastWestWires.put(intTile.getTileTypeEnum(), new BitSet[]{eastWires, westWires}); - - BitSet wires = new BitSet(); if (isUltraScale || isUltraScalePlus) { ultraScalesNonLocalWires = new EnumMap<>(TileTypeEnum.class); ultraScalesNonLocalWires.put(intTile.getTileTypeEnum(), wires); eastWestPattern = Pattern.compile("(((BOUNCE|BYPASS|IMUX|INODE)_([EW]))|INT_NODE_IMUX_(\\d+)_).*"); + + eastWestWires = new EnumMap<>(TileTypeEnum.class); + eastWestWires.put(intTile.getTileTypeEnum(), new BitSet[]{eastWires, westWires}); } else { assert(series == Series.Versal); ultraScalesNonLocalWires = null; // FIXME: eastWestPattern = null; - eastWestWires.put(TileTypeEnum.CLE_BC_CORE, new BitSet[]{eastWires, westWires}); + eastWestWires = null; } for (int wireIndex = 0; wireIndex < intTile.getWireCount(); wireIndex++) { diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java index 10d9335b1..2387dd745 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java @@ -157,7 +157,7 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou } // Fall through case NODE_PINBOUNCE: - if (routingGraph != null) { + if (routingGraph != null && routingGraph.eastWestWires != null) { BitSet[] eastWestWires = routingGraph.eastWestWires.get(tileTypeEnum); if (eastWestWires[0].get(node.getWireIndex())) { return RouteNodeType.LOCAL_EAST; From 07935a45533e6aac93d867cd30467bc8c585eb9a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 7 Nov 2024 20:43:22 -0800 Subject: [PATCH 43/71] Update testSLRCrossingNonTimingDriven golden values Signed-off-by: Eddie Hung --- test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java index 071468658..97bb28c56 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java @@ -401,7 +401,7 @@ void testSingleConnectionHelper(String partName, // One SLR crossing // (Too) Close "SLICE_X9Y299,SLICE_X9Y300,500", // On Laguna column - "SLICE_X9Y300,SLICE_X9Y299,400", + "SLICE_X9Y300,SLICE_X9Y299,500", "SLICE_X0Y299,SLICE_X0Y300,200", // Far from Laguna column "SLICE_X0Y300,SLICE_X0Y299,200", "SLICE_X53Y299,SLICE_X53Y300,200", // Equidistant from two Laguna columns @@ -422,7 +422,7 @@ void testSingleConnectionHelper(String partName, "SLICE_X0Y430,SLICE_X12Y240,200", // Two SLR crossings - "SLICE_X162Y299,SLICE_X162Y599,200", + "SLICE_X162Y299,SLICE_X162Y599,600", "SLICE_X162Y599,SLICE_X162Y299,100", // Three SLR crossings From bb9db76c150b1dfc832e69cfe6c193980eb39799 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 7 Nov 2024 20:44:01 -0800 Subject: [PATCH 44/71] Tidy up and comments Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/RouteNodeGraph.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 8b0ca7eab..587ed6c3c 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -94,17 +94,21 @@ public class RouteNodeGraph { */ protected final Map lagunaI; - /** Map indicating the wire indices corresponding to the [A-H]MUX output */ - protected final Map muxWires; + /** Map indicating (for UltraScale/UltraScale+ only) the wire indices corresponding to the [A-H]MUX output + * to be blocked during LUT routethrus + */ + protected final Map ultraScalesMuxWiresToBlockWhenLutRoutethru; /** Flag for whether LUT routethrus are to be considered */ protected final boolean lutRoutethru; - /** Map indicating the wire indices that have a local intent code, but is what RWRoute considers to be non-local */ + /** Map indicating (for UltraScale/UltraScale+ only) the wire indices that have a local intent code, + * but is what RWRoute will consider to be non-local, e.g. INT_NODE_SDQ_* + */ protected final Map ultraScalesNonLocalWires; + /** Map indicating the wire indices corresponding to the east/west side of interconnect tiles */ protected final Map eastWestWires; - protected static final BitSet EMPTY_BITSET = new BitSet(0); public RouteNodeGraph(Design design, RWRouteConfig config) { this(design, config, new HashMap<>()); @@ -240,7 +244,7 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map(TileTypeEnum.class); + ultraScalesMuxWiresToBlockWhenLutRoutethru = new EnumMap<>(TileTypeEnum.class); for (TileTypeEnum tileTypeEnum : Utils.getCLBTileTypes()) { Tile clbTile = device.getArbitraryTileOfType(tileTypeEnum); if (clbTile == null) { @@ -258,10 +262,10 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map [A-H]MUX routethrus since Vivado does not support the LUT // being fractured to support more than one routethru net From 9e7d383d0159606e6cb9cc2c13c1702d87956ef7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 7 Nov 2024 21:55:09 -0800 Subject: [PATCH 45/71] Add a few more testcases Signed-off-by: Eddie Hung --- test/src/com/xilinx/rapidwright/rwroute/TestRouterHelper.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestRouterHelper.java b/test/src/com/xilinx/rapidwright/rwroute/TestRouterHelper.java index 41efaf567..9aa04840e 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestRouterHelper.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestRouterHelper.java @@ -60,6 +60,9 @@ public class TestRouterHelper { "xcvu3p,GTYE4_CHANNEL_X0Y12,TXOUTCLK_INT,null", "xcvu3p,IOB_X1Y95,I,INT_INTF_L_IO_X72Y109/LOGIC_OUTS_R23", "xcvu3p,IOB_X1Y80,I,INT_INTF_L_IO_X72Y92/LOGIC_OUTS_R22", + "xcvu3p,IOB_X1Y179,I,INT_INTF_L_CMT_X72Y208/LOGIC_OUTS_R18", + "xcvu3p,IOB_X1Y75,I,INT_INTF_L_CMT_X72Y88/LOGIC_OUTS_R18", + "xcvu3p,IOB_X1Y184,I,INT_INTF_L_IO_X72Y212/LOGIC_OUTS_R22", "xcvu3p,MMCM_X0Y0,LOCKED,INT_INTF_L_IO_X36Y54/LOGIC_OUTS_R0", "xcvp1002,MMCM_X2Y0,LOCKED,BLI_CLE_BOT_CORE_X27Y0/LOGIC_OUTS_D23" }) From 4f43cf54c37f84833c0cd7945465cf4d02dca5e8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 8 Nov 2024 10:06:28 -0800 Subject: [PATCH 46/71] [RWRoute] Non-verbose mode to print out nodes popped Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RWRoute.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index ed4541deb..26a652024 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -2160,7 +2160,9 @@ protected void printRoutingStatistics() { printFormattedString("Num iterations:", routeIteration); printFormattedString("Connections routed:", connectionsRouted.get()); printFormattedString("Nodes pushed:", nodesPushed.get()); - printFormattedString("Nodes popped:", nodesPopped.get()); + } + printFormattedString("Nodes popped:", nodesPopped.get()); + if (config.isVerbose()) { System.out.printf("------------------------------------------------------------------------------\n"); } From 7890b5a38c4896bf746e4821967721618aedaad4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 8 Nov 2024 11:06:28 -0800 Subject: [PATCH 47/71] Update comments/asserts Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RWRoute.java | 5 ++++- src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 26a652024..56e7b8b48 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1820,7 +1820,7 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { break; case NON_LOCAL: // LOCALs cannot connect to NON_LOCALs except via a LUT routethru - assert(rnode.getType() != RouteNodeType.LOCAL || + assert(!rnode.getType().isLocal() || routingGraph.lutRoutethru && rnode.getIntentCode() == IntentCode.NODE_PINFEED || // FIXME: design.getSeries() == Series.Versal); @@ -1837,6 +1837,9 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { case EXCLUSIVE_SINK: case EXCLUSIVE_SINK_EAST: case EXCLUSIVE_SINK_WEST: + assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK_EAST || rnode.getType() == RouteNodeType.LOCAL_EAST); + assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK_WEST || rnode.getType() == RouteNodeType.LOCAL_WEST); + assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK || rnode.getType() == RouteNodeType.LOCAL); if (!isAccessibleSink(childRNode, connection)) { continue; } diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 587ed6c3c..646414cc1 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -633,7 +633,7 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { assert(sinkType.isExclusiveSink()); if ((type == RouteNodeType.LOCAL_EAST && sinkType != RouteNodeType.EXCLUSIVE_SINK_EAST) || (type == RouteNodeType.LOCAL_WEST && sinkType != RouteNodeType.EXCLUSIVE_SINK_WEST) || - // Sinks without a side (e.g. CTRL) can only be approached from LOCAL nodes also without a side + // Sinks without a side (e.g. CTRL) must only be approached from LOCAL nodes also without a side (sinkType == RouteNodeType.EXCLUSIVE_SINK && type != RouteNodeType.LOCAL)) { return false; } From 15b74531ea38367c9e8c3118609c1cdf4ad26f17 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 8 Nov 2024 11:52:07 -0800 Subject: [PATCH 48/71] Clean up RouteNodeGraph.isAccessible() Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/RouteNodeGraph.java | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 646414cc1..9e2c0844f 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -629,17 +629,35 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { // (c) on the same side as the sink RouteNodeType type = childRnode.getType(); - RouteNodeType sinkType = sinkRnode.getType(); - assert(sinkType.isExclusiveSink()); - if ((type == RouteNodeType.LOCAL_EAST && sinkType != RouteNodeType.EXCLUSIVE_SINK_EAST) || - (type == RouteNodeType.LOCAL_WEST && sinkType != RouteNodeType.EXCLUSIVE_SINK_WEST) || - // Sinks without a side (e.g. CTRL) must only be approached from LOCAL nodes also without a side - (sinkType == RouteNodeType.EXCLUSIVE_SINK && type != RouteNodeType.LOCAL)) { - return false; + Tile sinkTile = sinkRnode.getTile(); + switch (sinkRnode.getType()) { + case EXCLUSIVE_SINK_EAST: + if (type == RouteNodeType.LOCAL_WEST) { + // West wires can never reach an east sink + return false; + } + break; + case EXCLUSIVE_SINK_WEST: + if (type == RouteNodeType.LOCAL_EAST) { + // East wires can never reach a west sink + return false; + } + break; + case EXCLUSIVE_SINK: + // Only both-sided wires (e.g. INT_NODE_GLOBAL_*) can reach a both-sided sink (CTRL_*) + if (type != RouteNodeType.LOCAL) { + return false; + } + if (design.getSeries() == Series.UltraScale || design.getSeries() == Series.UltraScalePlus) { + // This must be a CTRL sink; these can only be accessed from the sink tile rather than Y +/- 1 below + return childTile == sinkTile; + } + break; + default: + throw new RuntimeException("ERROR: Unexpected sink type " + sinkRnode.getType()); } // (d) in the sink tile - Tile sinkTile = sinkRnode.getTile(); if (childTile == sinkTile) { return true; } From b61a199bbc5d899c8aac5a1a651e06e1c03a3d82 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 8 Nov 2024 12:17:40 -0800 Subject: [PATCH 49/71] Fixes for UltraScale Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/RouteNodeGraph.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 9e2c0844f..ece65969e 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -154,7 +154,7 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map(TileTypeEnum.class); ultraScalesNonLocalWires.put(intTile.getTileTypeEnum(), wires); - eastWestPattern = Pattern.compile("(((BOUNCE|BYPASS|IMUX|INODE)_([EW]))|INT_NODE_IMUX_(\\d+)_).*"); + eastWestPattern = Pattern.compile("(((BOUNCE|BYPASS|IMUX|INODE(_[12])?)_([EW]))|INT_NODE_IMUX_(\\d+)_).*"); eastWestWires = new EnumMap<>(TileTypeEnum.class); eastWestWires.put(intTile.getTileTypeEnum(), new BitSet[]{eastWires, westWires}); @@ -202,9 +202,9 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map= 64 && i < 96))) { eastWires.set(baseNode.getWireIndex()); } else { @@ -235,7 +235,7 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map Date: Fri, 8 Nov 2024 12:22:26 -0800 Subject: [PATCH 50/71] Skip another assert for Versal Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RWRoute.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 56e7b8b48..9c0b26ea8 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1839,7 +1839,9 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { case EXCLUSIVE_SINK_WEST: assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK_EAST || rnode.getType() == RouteNodeType.LOCAL_EAST); assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK_WEST || rnode.getType() == RouteNodeType.LOCAL_WEST); - assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK || rnode.getType() == RouteNodeType.LOCAL); + assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK || rnode.getType() == RouteNodeType.LOCAL || + // FIXME: + design.getSeries() == Series.Versal); if (!isAccessibleSink(childRNode, connection)) { continue; } From b07f2dbbdf72aab5c3c706bf903024e690ac951a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 12 Nov 2024 08:53:05 -0800 Subject: [PATCH 51/71] Fix Versal assertion Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RouteNode.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index 42bd6e5b6..7261b2607 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -131,7 +131,8 @@ private void setBaseCost(Series series) { (length == 1 && (series == Series.UltraScalePlus || series == Series.UltraScale) && getIntentCode() == IntentCode.NODE_PINBOUNCE)); break; case LOCAL: - assert(length == 0); + assert(length == 0 || + (series == Series.Versal && EnumSet.of(IntentCode.NODE_CLE_BNODE, IntentCode.NODE_CLE_CNODE).contains(getIntentCode()))); break; case LOCAL_EAST: case LOCAL_WEST: From 90e8d802e26fb484cd529e51c7f3bcfb0b7a5b0a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 12 Nov 2024 09:32:04 -0800 Subject: [PATCH 52/71] Fix assertion Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RWRoute.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 21ee7fc54..e89d4472a 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1820,7 +1820,7 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { break; case NON_LOCAL: // LOCALs cannot connect to NON_LOCALs except via a LUT routethru - assert(rnode.getType() != RouteNodeType.LOCAL || + assert(!rnode.getType().isLocal() || routingGraph.lutRoutethru && rnode.getIntentCode() == IntentCode.NODE_PINFEED); if (!routingGraph.isAccessible(childRNode, connection)) { From a3af7dcae51ed2c92e6440a21977931b71631683 Mon Sep 17 00:00:00 2001 From: eddieh-xlnx Date: Tue, 12 Nov 2024 11:12:02 -0800 Subject: [PATCH 53/71] [RWRoute] Further divide LOCAL nodes into EAST/WEST for UltraScale(+) (#1098) * [TestNode] Expand testNodeReachabilityUltraScale Signed-off-by: Eddie Hung * Expand testNodeReachabilityVersal too Signed-off-by: Eddie Hung * UltraScale+: Sub-divide LOCALs into _EAST/_WEST and stick to sink's side Signed-off-by: Eddie Hung * Re-add EXCLUSIVE_SINK (non-sided) for CTRL sinks Signed-off-by: Eddie Hung * Support UltraScale Signed-off-by: Eddie Hung * Print Signed-off-by: Eddie Hung * Expand testNodeReachabilityVersal Signed-off-by: Eddie Hung * Do not error out for Versal Signed-off-by: Eddie Hung * Fix failing assertions Signed-off-by: Eddie Hung * Remove unused import Signed-off-by: Eddie Hung * Fix another typo Signed-off-by: Eddie Hung * Fix SLR crossings Signed-off-by: Eddie Hung * More Versal fixes Signed-off-by: Eddie Hung * Update testSLRCrossingNonTimingDriven golden values Signed-off-by: Eddie Hung * Tidy up and comments Signed-off-by: Eddie Hung * Add a few more testcases Signed-off-by: Eddie Hung * [RWRoute] Non-verbose mode to print out nodes popped Signed-off-by: Eddie Hung * Update comments/asserts Signed-off-by: Eddie Hung * Clean up RouteNodeGraph.isAccessible() Signed-off-by: Eddie Hung * Fixes for UltraScale Signed-off-by: Eddie Hung * Skip another assert for Versal Signed-off-by: Eddie Hung * Another assertion Signed-off-by: Eddie Hung --------- Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/Connection.java | 4 +- .../rapidwright/rwroute/PartialRouter.java | 4 +- .../xilinx/rapidwright/rwroute/RWRoute.java | 42 +++- .../xilinx/rapidwright/rwroute/RouteNode.java | 12 +- .../rapidwright/rwroute/RouteNodeGraph.java | 201 +++++++++++++----- .../rapidwright/rwroute/RouteNodeInfo.java | 37 +++- .../rapidwright/rwroute/RouteNodeType.java | 14 +- .../xilinx/rapidwright/device/TestNode.java | 162 ++++++++++---- .../rapidwright/rwroute/TestRWRoute.java | 4 +- .../rapidwright/rwroute/TestRouterHelper.java | 3 + 10 files changed, 352 insertions(+), 131 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/Connection.java b/src/com/xilinx/rapidwright/rwroute/Connection.java index 6c08342dc..95a7f87e0 100644 --- a/src/com/xilinx/rapidwright/rwroute/Connection.java +++ b/src/com/xilinx/rapidwright/rwroute/Connection.java @@ -305,7 +305,7 @@ public void addAltSinkRnode(RouteNode sinkRnode) { } else { assert(!altSinkRnodes.contains(sinkRnode)); } - assert(sinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK || + assert(sinkRnode.getType().isExclusiveSink() || // Can be a WIRE if node is not exclusive a sink sinkRnode.getType() == RouteNodeType.NON_LOCAL); altSinkRnodes.add(sinkRnode); @@ -487,7 +487,7 @@ public void setAllTargets(RWRoute.ConnectionState state) { // where the same physical pin services more than one logical pin if (rnode.countConnectionsOfUser(netWrapper) == 0 || // Except if it is not an EXCLUSIVE_SINK - rnode.getType() != RouteNodeType.EXCLUSIVE_SINK) { + rnode.getType().isExclusiveSink()) { assert(rnode.getIntentCode() != IntentCode.NODE_PINBOUNCE); rnode.markTarget(state); } diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index 871637153..90435b794 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -256,7 +256,7 @@ protected void determineRoutingTargets() { preservedNet = routingGraph.getPreservedNet(sinkRnode); if (preservedNet != null && preservedNet != net) { unpreserveNets.add(preservedNet); - assert(sinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK); + assert(sinkRnode.getType().isExclusiveSink()); } } @@ -599,7 +599,7 @@ protected void unpreserveNet(Net net) { RouteNode sourceRnode = connection.getSourceRnode(); RouteNode sinkRnode = connection.getSinkRnode(); assert(sourceRnode.getType() == RouteNodeType.EXCLUSIVE_SOURCE); - assert(sinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK); + assert(sinkRnode.getType().isExclusiveSink()); // Even though this connection is not expected to have any routing yet, // perform a rip up anyway in order to release any exclusive sinks diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 4d2f363d5..e7c3723d5 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -59,6 +59,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.BitSet; import java.util.Collection; import java.util.Collections; import java.util.EnumMap; @@ -600,8 +601,19 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { } indirectConnections.add(connection); - RouteNode sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK); - sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK); + BitSet[] eastWestWires = (routingGraph.eastWestWires == null) ? null : + routingGraph.eastWestWires.get(sinkINTNode.getTile().getTileTypeEnum()); + RouteNode sinkRnode; + if (eastWestWires != null && eastWestWires[0].get(sinkINTNode.getWireIndex())) { + sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_EAST); + sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK_EAST); + } else if (eastWestWires != null && eastWestWires[1].get(sinkINTNode.getWireIndex())) { + sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_WEST); + sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK_WEST); + } else { + sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK); + sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK); + } connection.setSinkRnode(sinkRnode); // Where appropriate, allow all 6 LUT pins to be swapped to begin with @@ -609,6 +621,8 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { int numberOfSwappablePins = (lutPinSwapping && sink.isLUTInputPin()) ? LUTTools.MAX_LUT_SIZE : 0; if (numberOfSwappablePins > 0) { + assert(sinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK_EAST || sinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK_WEST); + for (Cell cell : DesignTools.getConnectedCells(sink)) { BEL bel = cell.getBEL(); assert(bel.isLUT()); @@ -650,8 +664,8 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { if (routingGraph.isPreserved(node)) { continue; } - RouteNode altSinkRnode = routingGraph.getOrCreate(node, RouteNodeType.EXCLUSIVE_SINK); - assert(altSinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK); + RouteNode altSinkRnode = routingGraph.getOrCreate(node, sinkRnode.getType()); + assert(altSinkRnode.getType().isExclusiveSink()); connection.addAltSinkRnode(altSinkRnode); } @@ -1798,13 +1812,18 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { } switch (childRNode.getType()) { case LOCAL: + case LOCAL_EAST: + case LOCAL_WEST: if (!routingGraph.isAccessible(childRNode, connection)) { continue; } + // Verify invariant that east/west wires stay east/west + assert(rnode.getType() != RouteNodeType.LOCAL_EAST || childRNode.getType() == RouteNodeType.LOCAL_EAST); + assert(rnode.getType() != RouteNodeType.LOCAL_WEST || childRNode.getType() == RouteNodeType.LOCAL_WEST); break; case NON_LOCAL: // LOCALs cannot connect to NON_LOCALs except via a LUT routethru - assert(rnode.getType() != RouteNodeType.LOCAL || + assert(!rnode.getType().isLocal() || routingGraph.lutRoutethru && rnode.getIntentCode() == IntentCode.NODE_PINFEED || // FIXME: design.getSeries() == Series.Versal); @@ -1819,6 +1838,13 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { } break; case EXCLUSIVE_SINK: + case EXCLUSIVE_SINK_EAST: + case EXCLUSIVE_SINK_WEST: + assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK_EAST || rnode.getType() == RouteNodeType.LOCAL_EAST); + assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK_WEST || rnode.getType() == RouteNodeType.LOCAL_WEST); + assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK || rnode.getType() == RouteNodeType.LOCAL || + // FIXME: + design.getSeries() == Series.Versal); if (!isAccessibleSink(childRNode, connection)) { continue; } @@ -1863,7 +1889,7 @@ protected boolean isAccessibleSink(RouteNode child, Connection connection) { } protected boolean isAccessibleSink(RouteNode child, Connection connection, boolean assertOnOveruse) { - assert(child.getType() == RouteNodeType.EXCLUSIVE_SINK); + assert(child.getType().isExclusiveSink()); assert(!assertOnOveruse || !child.isOverUsed()); if (child.isTarget()) { @@ -2142,7 +2168,9 @@ protected void printRoutingStatistics() { printFormattedString("Num iterations:", routeIteration); printFormattedString("Connections routed:", connectionsRouted.get()); printFormattedString("Nodes pushed:", nodesPushed.get()); - printFormattedString("Nodes popped:", nodesPopped.get()); + } + printFormattedString("Nodes popped:", nodesPopped.get()); + if (config.isVerbose()) { System.out.printf("------------------------------------------------------------------------------\n"); } diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index c70a18000..8f8f78d12 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -93,7 +93,7 @@ public class RouteNode extends Node implements Comparable { protected RouteNode(RouteNodeGraph routingGraph, Node node, RouteNodeType type) { super(node); - RouteNodeInfo nodeInfo = RouteNodeInfo.get(this, routingGraph); + RouteNodeInfo nodeInfo = RouteNodeInfo.get(node, routingGraph); this.type = (type == null) ? nodeInfo.type : type; endTileXCoordinate = nodeInfo.endTileXCoordinate; endTileYCoordinate = nodeInfo.endTileYCoordinate; @@ -124,10 +124,16 @@ private void setBaseCost(Series series) { (length <= 3 && series == Series.Versal)); break; case EXCLUSIVE_SINK: + case EXCLUSIVE_SINK_EAST: + case EXCLUSIVE_SINK_WEST: assert(length == 0 || (length == 1 && (series == Series.UltraScalePlus || series == Series.UltraScale) && getIntentCode() == IntentCode.NODE_PINBOUNCE)); break; case LOCAL: + assert(length == 0); + break; + case LOCAL_EAST: + case LOCAL_WEST: assert(length == 0 || (length == 1 && ( ((series == Series.UltraScalePlus || series == Series.UltraScale) && getIntentCode() == IntentCode.NODE_PINBOUNCE) || @@ -361,10 +367,10 @@ public RouteNodeType getType() { public void setType(RouteNodeType type) { assert(this.type == type || // Support demotion from EXCLUSIVE_SINK to LOCAL since they have the same base cost - (this.type == RouteNodeType.EXCLUSIVE_SINK && type == RouteNodeType.LOCAL) || + (this.type.isExclusiveSink() && type == RouteNodeType.LOCAL) || // Or promotion from LOCAL to EXCLUSIVE_SINK (by PartialRouter when NODE_PINBOUNCE on // a newly unpreserved net becomes a sink) - (this.type == RouteNodeType.LOCAL && type == RouteNodeType.EXCLUSIVE_SINK)); + (this.type == RouteNodeType.LOCAL && type.isExclusiveSink())); this.type = type; } diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 324be57e3..ece65969e 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -35,6 +35,8 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import com.xilinx.rapidwright.design.Design; import com.xilinx.rapidwright.design.Net; @@ -92,14 +94,21 @@ public class RouteNodeGraph { */ protected final Map lagunaI; - /** Map indicating the wire indices corresponding to the [A-H]MUX output */ - protected final Map muxWires; + /** Map indicating (for UltraScale/UltraScale+ only) the wire indices corresponding to the [A-H]MUX output + * to be blocked during LUT routethrus + */ + protected final Map ultraScalesMuxWiresToBlockWhenLutRoutethru; /** Flag for whether LUT routethrus are to be considered */ protected final boolean lutRoutethru; - /** Map indicating the wire indices that have a local intent code, but is what RWRoute considers to be non-local */ - protected final Map ultraScaleNonLocalWires; + /** Map indicating (for UltraScale/UltraScale+ only) the wire indices that have a local intent code, + * but is what RWRoute will consider to be non-local, e.g. INT_NODE_SDQ_* + */ + protected final Map ultraScalesNonLocalWires; + + /** Map indicating the wire indices corresponding to the east/west side of interconnect tiles */ + protected final Map eastWestWires; public RouteNodeGraph(Design design, RWRouteConfig config) { this(design, config, new HashMap<>()); @@ -132,69 +141,116 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map(TileTypeEnum.class); - BitSet wires = new BitSet(); - Tile intTile = device.getArbitraryTileOfType(TileTypeEnum.INT); - // Device.getArbitraryTileOfType() typically gives you the North-Western-most - // tile (with minimum X, maximum Y). Analyze the tile just below that. - intTile = intTile.getTileXYNeighbor(0, -1); - ultraScaleNonLocalWires.put(intTile.getTileTypeEnum(), wires); - for (int wireIndex = 0; wireIndex < intTile.getWireCount(); wireIndex++) { - Node baseNode = Node.getNode(intTile, wireIndex); - if (baseNode == null) { - continue; - } - if (baseNode.getIntentCode() != IntentCode.NODE_LOCAL) { - continue; - } + ultraScalesNonLocalWires = new EnumMap<>(TileTypeEnum.class); + ultraScalesNonLocalWires.put(intTile.getTileTypeEnum(), wires); + eastWestPattern = Pattern.compile("(((BOUNCE|BYPASS|IMUX|INODE(_[12])?)_([EW]))|INT_NODE_IMUX_(\\d+)_).*"); + eastWestWires = new EnumMap<>(TileTypeEnum.class); + eastWestWires.put(intTile.getTileTypeEnum(), new BitSet[]{eastWires, westWires}); + } else { + assert(series == Series.Versal); + ultraScalesNonLocalWires = null; + + // FIXME: + eastWestPattern = null; + eastWestWires = null; + } + + for (int wireIndex = 0; wireIndex < intTile.getWireCount(); wireIndex++) { + Node baseNode = Node.getNode(intTile, wireIndex); + if (baseNode == null) { + continue; + } + + String baseWireName = baseNode.getWireName(); + IntentCode baseIntentCode = baseNode.getIntentCode(); + if (baseIntentCode == IntentCode.NODE_LOCAL) { Tile baseTile = baseNode.getTile(); - String wireName = baseNode.getWireName(); + assert(baseTile.getTileTypeEnum() == intTile.getTileTypeEnum()); if (isUltraScalePlus) { - if (!wireName.startsWith("INT_NODE_SDQ_") && !wireName.startsWith("SDQNODE_")) { + if (baseWireName.startsWith("INT_NODE_SDQ_") || baseWireName.startsWith("SDQNODE_")) { + if (baseTile != intTile) { + if (baseWireName.endsWith("_FT0")) { + assert(baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() - 1); + } else { + assert(baseWireName.endsWith("_FT1")); + assert(baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() + 1); + } + } + wires.set(baseNode.getWireIndex()); continue; } - if (baseTile != intTile) { - if (wireName.endsWith("_FT0")) { - assert(baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() - 1); - } else { - assert(wireName.endsWith("_FT1")); - assert(baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() + 1); + } else if (isUltraScale) { + if (baseWireName.startsWith("INT_NODE_SINGLE_DOUBLE_") || baseWireName.startsWith("SDND") || + baseWireName.startsWith("INT_NODE_QUAD_LONG") || baseWireName.startsWith("QLND")) { + if (baseTile != intTile) { + if (baseWireName.endsWith("_FTN")) { + assert (baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() - 1); + } else { + assert (baseWireName.endsWith("_FTS")); + assert (baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() + 1); + } } + wires.set(baseNode.getWireIndex()); + continue; } - } else { - assert(isUltraScale); + } + } else if (baseIntentCode != IntentCode.NODE_PINFEED && baseIntentCode != IntentCode.NODE_PINBOUNCE) { + continue; + } - if (!wireName.startsWith("INT_NODE_SINGLE_DOUBLE_") && !wireName.startsWith("SDND") && - !wireName.startsWith("INT_NODE_QUAD_LONG") && !wireName.startsWith("QLND")) { - continue; + if (eastWestPattern == null) { + // FIXME: + assert(series == Series.Versal); + continue; + } + + Matcher m = eastWestPattern.matcher(baseWireName); + if (m.matches()) { + if (m.group(5) != null) { + if (m.group(5).equals("E")) { + eastWires.set(baseNode.getWireIndex()); + } else { + assert(m.group(5).equals("W")); + westWires.set(baseNode.getWireIndex()); } - if (baseTile != intTile) { - if (wireName.endsWith("_FTN")) { - assert(baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() - 1); - } else { - assert(wireName.endsWith("_FTS")); - assert(baseTile.getTileYCoordinate() == intTile.getTileYCoordinate() + 1); - } + } else if (m.group(6) != null) { + int i = Integer.valueOf(m.group(6)); + if (i < 32 || (isUltraScale && (i >= 64 && i < 96))) { + eastWires.set(baseNode.getWireIndex()); + } else { + assert(i < 64 || (isUltraScale && (i >= 96 && i < 128))); + westWires.set(baseNode.getWireIndex()); } } - wires.set(baseNode.getWireIndex()); + } else { + assert(baseWireName.matches("CTRL_[EW](_B)?\\d+|INT_NODE_GLOBAL_\\d+(_INT)?_OUT[01]?") + // FIXME: + || series == Series.Versal); } - } else { - ultraScaleNonLocalWires = null; } if (lutRoutethru) { assert(isUltraScalePlus || isUltraScale); - muxWires = new EnumMap<>(TileTypeEnum.class); + ultraScalesMuxWiresToBlockWhenLutRoutethru = new EnumMap<>(TileTypeEnum.class); for (TileTypeEnum tileTypeEnum : Utils.getCLBTileTypes()) { Tile clbTile = device.getArbitraryTileOfType(tileTypeEnum); if (clbTile == null) { continue; } - BitSet wires = new BitSet(); + wires = new BitSet(); for (int wireIndex = 0; wireIndex < clbTile.getWireCount(); wireIndex++) { String wireName = clbTile.getWireName(wireIndex); if (wireName.endsWith("MUX")) { @@ -206,10 +262,10 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map [A-H]MUX routethrus since Vivado does not support the LUT // being fractured to support more than one routethru net diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java index 8a64cbeab..2387dd745 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java @@ -24,6 +24,7 @@ import com.xilinx.rapidwright.device.IntentCode; import com.xilinx.rapidwright.device.Node; +import com.xilinx.rapidwright.device.Series; import com.xilinx.rapidwright.device.Tile; import com.xilinx.rapidwright.device.TileTypeEnum; import com.xilinx.rapidwright.device.Wire; @@ -128,40 +129,56 @@ private static short getEndTileXCoordinate(Node node, RouteNodeType type, short private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph routingGraph) { // NOTE: IntentCode is device-dependent IntentCode ic = node.getIntentCode(); + TileTypeEnum tileTypeEnum = node.getTile().getTileTypeEnum(); switch (ic) { case NODE_LOCAL: { // US/US+ - assert(node.getTile().getTileTypeEnum() == TileTypeEnum.INT); + assert(tileTypeEnum == TileTypeEnum.INT); if (routingGraph != null) { - BitSet bs = routingGraph.ultraScaleNonLocalWires.get(node.getTile().getTileTypeEnum()); + BitSet bs = routingGraph.ultraScalesNonLocalWires.get(tileTypeEnum); if (!bs.get(node.getWireIndex())) { + BitSet[] eastWestWires = routingGraph.eastWestWires.get(tileTypeEnum); + if (eastWestWires[0].get(node.getWireIndex())) { + return RouteNodeType.LOCAL_EAST; + } else if (eastWestWires[1].get(node.getWireIndex())) { + return RouteNodeType.LOCAL_WEST; + } return RouteNodeType.LOCAL; } break; } } - case NODE_PINBOUNCE: - return RouteNodeType.LOCAL; - - case NODE_PINFEED: { + case NODE_PINFEED: if (routingGraph != null && routingGraph.lagunaI != null) { BitSet bs = routingGraph.lagunaI.get(node.getTile()); if (bs != null && bs.get(node.getWireIndex())) { return RouteNodeType.LAGUNA_PINFEED; } } + // Fall through + case NODE_PINBOUNCE: + if (routingGraph != null && routingGraph.eastWestWires != null) { + BitSet[] eastWestWires = routingGraph.eastWestWires.get(tileTypeEnum); + if (eastWestWires[0].get(node.getWireIndex())) { + return RouteNodeType.LOCAL_EAST; + } else if (eastWestWires[1].get(node.getWireIndex())) { + return RouteNodeType.LOCAL_WEST; + } + assert(node.getWireName().startsWith("CTRL_") || + // FIXME: + routingGraph.design.getSeries() == Series.Versal); + } return RouteNodeType.LOCAL; - } case NODE_LAGUNA_OUTPUT: // UltraScale+ only - assert(node.getTile().getTileTypeEnum() == TileTypeEnum.LAG_LAG); + assert(tileTypeEnum == TileTypeEnum.LAG_LAG); if (node.getWireName().endsWith("_TXOUT")) { return RouteNodeType.LAGUNA_PINFEED; } break; case NODE_LAGUNA_DATA: // UltraScale+ only - assert(node.getTile().getTileTypeEnum() == TileTypeEnum.LAG_LAG); + assert(tileTypeEnum == TileTypeEnum.LAG_LAG); if (node.getTile() != endTile) { return RouteNodeType.SUPER_LONG_LINE; } @@ -170,7 +187,7 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou break; case INTENT_DEFAULT: - if (node.getTile().getTileTypeEnum() == TileTypeEnum.LAGUNA_TILE) { // UltraScale only + if (tileTypeEnum == TileTypeEnum.LAGUNA_TILE) { // UltraScale only String wireName = node.getWireName(); if (wireName.startsWith("UBUMP")) { assert(node.getTile() != endTile); diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java index 2510b4701..0c024bb0b 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java @@ -29,6 +29,8 @@ public enum RouteNodeType { EXCLUSIVE_SOURCE, EXCLUSIVE_SINK, + EXCLUSIVE_SINK_EAST, + EXCLUSIVE_SINK_WEST, /** * Denotes {@link RouteNode} objects that correspond to a super long line {@link Node}, @@ -44,5 +46,15 @@ public enum RouteNodeType { NON_LOCAL, - LOCAL + LOCAL, + LOCAL_EAST, + LOCAL_WEST; + + public boolean isExclusiveSink() { + return this == EXCLUSIVE_SINK || this == EXCLUSIVE_SINK_EAST || this == EXCLUSIVE_SINK_WEST; + } + + public boolean isLocal() { + return this == LOCAL || this == LOCAL_EAST || this == LOCAL_WEST; + } } diff --git a/test/src/com/xilinx/rapidwright/device/TestNode.java b/test/src/com/xilinx/rapidwright/device/TestNode.java index e72e0cd4a..175172258 100644 --- a/test/src/com/xilinx/rapidwright/device/TestNode.java +++ b/test/src/com/xilinx/rapidwright/device/TestNode.java @@ -84,16 +84,23 @@ public void testUphillNodeIsInvalid() { @ParameterizedTest @CsvSource({ // UltraScale+ part - "xcvu3p,INT_X37Y220,BOUNCE_.*,true", - "xcvu3p,INT_X37Y220,BYPASS_.*,true", + "xcvu3p,INT_X37Y220,BOUNCE_E_.*,true", + "xcvu3p,INT_X37Y220,BOUNCE_W_.*,true", + "xcvu3p,INT_X37Y220,BYPASS_E.*,true", + "xcvu3p,INT_X37Y220,BYPASS_W.*,true", "xcvu3p,INT_X37Y220,INT_NODE_GLOBAL_.*,true", - "xcvu3p,INT_X37Y220,INT_NODE_IMUX_.*,true", - "xcvu3p,INT_X37Y220,INODE_.*,true", + "xcvu3p,INT_X37Y220,INT_NODE_IMUX_([0-9]|1[0-9]|2[0-9]|3[01])_.*,true", + "xcvu3p,INT_X37Y220,INT_NODE_IMUX_(3[2-9]|4[0-9]|5[0-9]|6[0-3])_.*,true", + "xcvu3p,INT_X37Y220,INODE_E_.*,true", + "xcvu3p,INT_X37Y220,INODE_W_.*,true", "xcvu3p,INT_X37Y220,INT_INT_SDQ_.*,false", // IntentCode.NODE_SINGLE "xcvu3p,INT_X37Y220,INT_NODE_SDQ_.*,false", - "xcvu3p,INT_X37Y220,SDQNODE_.*,false", - "xcvu3p,INT_X37Y220,IMUX_.*,true", - "xcvu3p,INT_X37Y220,CTRL_.*,true", + "xcvu3p,INT_X37Y220,SDQNODE_E_.*,false", + "xcvu3p,INT_X37Y220,SDQNODE_W_.*,false", + "xcvu3p,INT_X37Y220,IMUX_E.*,true", + "xcvu3p,INT_X37Y220,IMUX_W.*,true", + "xcvu3p,INT_X37Y220,CTRL_E.*,true", + "xcvu3p,INT_X37Y220,CTRL_W.*,true", "xcvu3p,INT_X37Y220,(NN|EE|SS|WW)1_.*,false", "xcvu3p,INT_X37Y220,(NN|EE|SS|WW)2_.*,false", "xcvu3p,INT_X37Y220,(NN|EE|SS|WW)4_.*,false", @@ -101,16 +108,22 @@ public void testUphillNodeIsInvalid() { "xcvu3p,CLEM_X37Y220,CLE_CLE_M_SITE_0_[A-H](_O|Q|Q2|MUX),false", // UltraScale part - "xcvu065,INT_X38Y220,BOUNCE_.*,true", - "xcvu065,INT_X38Y220,BYPASS_.*,true", + "xcvu065,INT_X38Y220,BOUNCE_E_.*,true", + "xcvu065,INT_X38Y220,BOUNCE_W_.*,true", + "xcvu065,INT_X38Y220,BYPASS_E.*,true", + "xcvu065,INT_X38Y220,BYPASS_W.*,true", "xcvu065,INT_X38Y220,INT_NODE_GLOBAL_.*,true", - "xcvu065,INT_X38Y220,INT_NODE_IMUX_.*,true", - "xcvu065,INT_X38Y220,INODE_.*,true", + "xcvu065,INT_X38Y220,INT_NODE_IMUX_([0-9]|1[0-9]|2[0-9]|3[01]|6[4-9]|7[0-9]|8[0-9]|9[0-5])_.*,true", + "xcvu065,INT_X38Y220,INT_NODE_IMUX_(3[2-9]|4[0-9]|5[0-9]|6[0-3]|9[6-9]|10[0-9]|11[0-9]|12[0-7])_.*,true", + "xcvu065,INT_X38Y220,INODE_[12]_E_.*,true", + "xcvu065,INT_X38Y220,INODE_[12]_W_.*,true", "xcvu065,INT_X38Y220,INT_INT_SINGLE_.*,false", // IntentCode.NODE_SINGLE "xcvu065,INT_X38Y220,INT_NODE_SINGLE_DOUBLE_.*,false", "xcvu065,INT_X38Y220,INT_NODE_QUAD_LONG_.*,false", - "xcvu065,INT_X38Y220,IMUX_.*,true", - "xcvu065,INT_X38Y220,CTRL_.*,true", + "xcvu065,INT_X38Y220,IMUX_E.*,true", + "xcvu065,INT_X38Y220,IMUX_W.*,true", + "xcvu065,INT_X38Y220,CTRL_E.*,true", + "xcvu065,INT_X38Y220,CTRL_W.*,true", "xcvu065,INT_X37Y220,(NN|EE|SS|WW)1_.*,false", "xcvu065,INT_X37Y220,(NN|EE|SS|WW)2_.*,false", "xcvu065,INT_X37Y220,(NN|EE|SS|WW)4_.*,false", @@ -135,6 +148,7 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str intentCodes.add(node.getIntentCode()); } System.out.println("Initial queue.size() = " + queue.size()); + System.out.println("Initial queue = " + queue); System.out.println("Intent codes = " + intentCodes); // Print out the prefixes of nodes that are immediately uphill of these wire prefixes @@ -143,13 +157,18 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str boolean ultraScalePlus = partName.endsWith("p"); queue.stream().map(Node::getAllUphillNodes).flatMap(List::stream) .map(n -> n.getWireName() + " (" + n.getIntentCode() + ")") - .map(s -> s.replaceFirst("((BOUNCE|BYPASS|CTRL|INT_NODE_[^_]+|INODE|IMUX|SDQNODE)_)[^\\(]+", "$1")) + .map(s -> s.replaceFirst("^((BOUNCE|BYPASS|CTRL|INODE(_[12])?|IMUX|SDQNODE)_([EW]_?)?)[^ ]+", "$1")) + .map(s -> s.replaceFirst("(INT_NODE_(GLOBAL|SDQ|SINGLE_DOUBLE|QUAD_LONG)_)[^ ]+", "$1")) + .map(s -> ultraScalePlus ? s.replaceFirst("(INT_NODE_IMUX_)([0-9]|1[0-9]|2[0-9]|3[01])_INT_OUT[01]", "$1<0-31>") + : s.replaceFirst("(INT_NODE_IMUX_)([0-9]|1[0-9]|2[0-9]|3[01]|6[4-9]|7[0-9]|8[0-9]|9[0-5])_INT_OUT", "$1<0-31,64-95>")) + .map(s -> ultraScalePlus ? s.replaceFirst("(INT_NODE_IMUX_)(3[2-9]|4[0-9]|5[0-9]|6[0-3])_INT_OUT[01]", "$1<32-63>") + : s.replaceFirst("(INT_NODE_IMUX_)(3[2-9]|4[0-9]|5[0-9]|6[0-3]|9[6-9]|10[0-9]|11[0-9]|12[0-7])_INT_OUT", "$1<32-63,96-127>")) .map(s -> s.replaceFirst( // UltraScale+ - ultraScalePlus ? "((CLE_CLE_[LM]_SITE_0|CLK_LEAF_SITES|INT_INT_SDQ|(NN|EE|SS|WW)(1|2|4|12))_)[^\\(]+" + ultraScalePlus ? "((CLE_CLE_[LM]_SITE_0|CLK_LEAF_SITES|INT_INT_SDQ|(NN|EE|SS|WW)(1|2|4|12)(_[EW])?)_)[^\\(]+" // UltraScale - : "((CLE_CLE_[LM]_SITE_0|CLK_BUFCE_LEAF_X16_1_CLK|EE[124]|INT_INT_SINGLE|(NN|SS)(1|2|4|5|12|16)|(EE|WW)(1|2|4|12)|QLND(NW|SE|SW)|SDND[NS]W)_)[^\\(]+", - "$1")) + : "((CLE_CLE_[LM]_SITE_0|CLK_BUFCE_LEAF_X16_1_CLK|EE[124]|INT_INT_SINGLE|(NN|SS)(1|2|4|5|12|16)(_[EW])?|(EE|WW)(1|2|4|12)|QLND(NW|SE|SW)|SDND[NS]W)_)[^\\(]+", + "$1 ")) .distinct() .sorted() .forEachOrdered(s -> System.out.println("\t" + s)); @@ -158,12 +177,17 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str System.out.println("Immediately downhill:"); queue.stream().map(Node::getAllDownhillNodes).flatMap(List::stream) .map(n -> n.getWireName() + " (" + n.getIntentCode() + ")") - .map(s -> s.replaceFirst("((BOUNCE|BYPASS|CTRL|IMUX|INT_NODE_[^_]+|INODE|SDQNODE)_)[^\\(]+", "$1")) + .map(s -> s.replaceFirst("^((BOUNCE|BYPASS|CTRL|INODE(_[12])?|IMUX|SDQNODE)_([EW]_?)?)[^ ]+", "$1")) + .map(s -> s.replaceFirst("(INT_NODE_(GLOBAL|SDQ|SINGLE_DOUBLE|QUAD_LONG)_)[^ ]+", "$1")) + .map(s -> ultraScalePlus ? s.replaceFirst("(INT_NODE_IMUX_)([0-9]|1[0-9]|2[0-9]|3[01])_INT_OUT[01]", "$1<0-31>") + : s.replaceFirst("(INT_NODE_IMUX_)([0-9]|1[0-9]|2[0-9]|3[01]|6[4-9]|7[0-9]|8[0-9]|9[0-5])_INT_OUT", "$1<0-31,64-95>")) + .map(s -> ultraScalePlus ? s.replaceFirst("(INT_NODE_IMUX_)(3[2-9]|4[0-9]|5[0-9]|6[0-3])_INT_OUT[01]", "$1<32-63>") + : s.replaceFirst("(INT_NODE_IMUX_)(3[2-9]|4[0-9]|5[0-9]|6[0-3]|9[6-9]|10[0-9]|11[0-9]|12[0-7])_INT_OUT", "$1<32-63,96-127>")) .map(s -> s.replaceFirst( // UltraScale+ - ultraScalePlus ? "((CLE_CLE_[LM]_SITE_0|INT_INT_SDQ|(NN|EE|SS|WW)(1|2|4|12))_)[^\\(]+" + ultraScalePlus ? "((CLE_CLE_[LM]_SITE_0|INT_INT_SDQ|(NN|EE|SS|WW)(1|2|4|12)(_[EW])?)_)[^\\(]+" // UltraScale - : "((CLE_CLE_[LM]_SITE_0|INT_INT_SINGLE|(NN|SS)(1|2|4|5|12|16)|(EE|WW)(1|2|4|12)|QLND(NW|S[EW])|SDND[NS]W)_)[^\\(]+", + : "((CLE_CLE_[LM]_SITE_0|INT_INT_SINGLE|(NN|SS)(1|2|4|5|12|16)|(EE|WW)(1|2|4|12)(_[EW])?|QLND(NW|S[EW])|SDND[NS]W)_)[^ ]+", "$1")) .distinct() .sorted() @@ -204,28 +228,36 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str @ParameterizedTest @CsvSource({ - "xcvp1002,INT_X38Y220,NODE_PINBOUNCE,true", - "xcvp1002,INT_X38Y220,NODE_INODE,true", - "xcvp1002,INT_X38Y220,NODE_IMUX,true", - "xcvp1002,INT_X38Y220,NODE_SDQNODE,false", - "xcvp1002,INT_X38Y220,NODE_HSINGLE,false", - "xcvp1002,INT_X38Y220,NODE_VSINGLE,false", - "xcvp1002,INT_X38Y220,NODE_HDOUBLE,false", - "xcvp1002,INT_X38Y220,NODE_VDOUBLE,false", - "xcvp1002,INT_X38Y220,NODE_HQUAD,false", - "xcvp1002,INT_X38Y220,NODE_VQUAD,false", - "xcvp1002,INT_X38Y220,NODE_HLONG6,false", - "xcvp1002,INT_X38Y220,NODE_HLONG10,false", - "xcvp1002,INT_X38Y220,NODE_VLONG7,false", - "xcvp1002,INT_X38Y220,NODE_VLONG12,false", - "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_BNODE,true", - "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_CNODE,true", - "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_CTRL,true", - "xcvp1002,CLE_W_CORE_X38Y220,NODE_PINFEED,true", - "xcvp1002,CLE_E_CORE_X38Y220,NODE_CLE_OUTPUT,false", - "xcvp1002,CLE_W_CORE_X38Y220,NODE_CLE_OUTPUT,false", + "xcvp1002,INT_X38Y220,NODE_PINBOUNCE,BOUNCE_E.*,true", + "xcvp1002,INT_X38Y220,NODE_PINBOUNCE,BOUNCE_W.*,true", + "xcvp1002,INT_X38Y220,NODE_INODE,INT_NODE_IMUX_ATOM_([0-9]|1[0-9]|2[0-9]|3[01]|6[4-9]|7[0-9]|8[0-9]|9[0-5])_.*,true", + "xcvp1002,INT_X38Y220,NODE_INODE,INT_NODE_IMUX_ATOM_(3[2-9]|4[0-9]|5[0-9]|6[0-3]|9[6-9]|10[0-9]|11[0-9]|12[0-7])_.*,true", + "xcvp1002,INT_X38Y220,NODE_IMUX,IMUX_B_E.*,true", + "xcvp1002,INT_X38Y220,NODE_IMUX,IMUX_B_W.*,true", + "xcvp1002,INT_X38Y220,NODE_SDQNODE,,false", + "xcvp1002,INT_X38Y220,NODE_HSINGLE,,false", + "xcvp1002,INT_X38Y220,NODE_VSINGLE,,false", + "xcvp1002,INT_X38Y220,NODE_HDOUBLE,,false", + "xcvp1002,INT_X38Y220,NODE_VDOUBLE,,false", + "xcvp1002,INT_X38Y220,NODE_HQUAD,,false", + "xcvp1002,INT_X38Y220,NODE_VQUAD,,false", + "xcvp1002,INT_X38Y220,NODE_HLONG6,,false", + "xcvp1002,INT_X38Y220,NODE_HLONG10,,false", + "xcvp1002,INT_X38Y220,NODE_VLONG7,,false", + "xcvp1002,INT_X38Y220,NODE_VLONG12,,false", + "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_BNODE,BNODE_OUTS_E.*,true", + "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_BNODE,BNODE_OUTS_W.*,true", + "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_CNODE,CNODE_OUTS_E.*,true", + "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_CNODE,CNODE_OUTS_W.*,true", + "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_CTRL,CTRL_L_B.*,true", + "xcvp1002,CLE_BC_CORE_X37Y220,NODE_CLE_CTRL,CTRL_R_B.*,true", + "xcvp1002,CLE_W_CORE_X38Y220,NODE_PINFEED,,true", + "xcvp1002,CLE_E_CORE_X38Y220,NODE_CLE_OUTPUT,,false", + "xcvp1002,CLE_W_CORE_X38Y220,NODE_CLE_OUTPUT,,false", + "xcvp1002,INTF_ROCF_TR_TILE_X39Y153,NODE_INTF_CNODE,,true", + "xcvp1002,INTF_ROCF_TR_TILE_X39Y153,NODE_INTF_BNODE,,true", }) - public void testNodeReachabilityVersal(String partName, String tileName, String intentCodeName, boolean local) { + public void testNodeReachabilityVersal(String partName, String tileName, String intentCodeName, String wireNameRegex, boolean local) { Device device = Device.getDevice(partName); Tile baseTile = device.getTile(tileName); IntentCode baseIntentCode = IntentCode.valueOf(intentCodeName); @@ -234,21 +266,48 @@ public void testNodeReachabilityVersal(String partName, String tileName, String if (baseTile.getWireIntentCode(wireIdx) != baseIntentCode) { continue; } - queue.add(Node.getNode(baseTile, wireIdx)); + + Node node = Node.getNode(baseTile, wireIdx); + if (wireNameRegex != null && !node.getWireName().matches(wireNameRegex)) { + continue; + } + queue.add(node); } System.out.println("Initial queue.size() = " + queue.size()); System.out.println("Initial queue = " + queue); - // Print out the intent code of nodes that are immediately uphill of this intent code + // Print out the prefixes of nodes that are immediately uphill of these wire prefixes + // (i.e. "BOUNCE_E_0_FT1" -> "BOUNCE_") System.out.println("Immediately uphill:"); - queue.stream().map(Node::getAllUphillNodes).flatMap(List::stream).map(Node::getIntentCode) + boolean ultraScalePlus = partName.endsWith("p"); + queue.stream().map(Node::getAllUphillNodes).flatMap(List::stream) + .map(n -> n.getWireName() + " (" + n.getIntentCode() + ")") + .map(s -> s.replaceFirst("^((BOUNCE|IMUX_B)_[EW])[^ ]+", "$1")) + .map(s -> s.replaceFirst("^(CTRL_[LR]_)B\\d+", "$1")) + .map(s -> s.replaceFirst("(INT_NODE_SDQ_|INT_SDQ_RED_ATOM_)[^ ]+", "$1")) + .map(s -> s.replaceFirst("(INT_NODE_IMUX_ATOM_)([0-9]|1[0-9]|2[0-9]|3[01]|6[4-9]|7[0-9]|8[0-9]|9[0-5])_INT_OUT[01]", "$1<0-31,64-95>")) + .map(s -> s.replaceFirst("(INT_NODE_IMUX_ATOM_)(3[2-9]|4[0-9]|5[0-9]|6[0-3]|9[6-9]|10[0-9]|11[0-9]|12[0-7])_INT_OUT[01]", "$1<32-63,96-127>")) + .map(s -> s.replaceFirst("([BC]NODE_OUTS_[EW])\\d+", "$1")) + .map(s -> s.replaceFirst("((CLE_SLICE[LM]_TOP_[01]|OUT_[NESW]NODE|(NN|EE|SS|WW)(1|2|4|6|7|10|12)(_[EW])?)_)[^ ]+", "$1")) + .map(s -> s.replaceFirst("(CLK_LEAF_SITES_)\\d+_O", "$1")) + .map(s -> s.replaceFirst("(VCC_WIRE)\\d+", "$1")) .distinct() .sorted() .forEachOrdered(s -> System.out.println("\t" + s)); - // Print out the intent code of nodes that are immediately downhill of this intent code + // Print out the prefixes of nodes that are immediately downhill of these wire prefixes System.out.println("Immediately downhill:"); - queue.stream().map(Node::getAllDownhillNodes).flatMap(List::stream).map(Node::getIntentCode) + queue.stream().map(Node::getAllDownhillNodes).flatMap(List::stream) + .map(n -> n.getWireName() + " (" + n.getIntentCode() + ")") + .map(s -> s.replaceFirst("^((BOUNCE|IMUX_B)_[EW])[^ ]+", "$1")) + .map(s -> s.replaceFirst("^(CTRL_[LR]_)B\\d+", "$1")) + .map(s -> s.replaceFirst("(INT_NODE_SDQ_|INT_SDQ_RED_ATOM_)[^ ]+", "$1")) + .map(s -> s.replaceFirst("(INT_NODE_IMUX_ATOM_)([0-9]|1[0-9]|2[0-9]|3[01]|6[4-9]|7[0-9]|8[0-9]|9[0-5])_INT_OUT[01]", "$1<0-31,64-95>")) + .map(s -> s.replaceFirst("(INT_NODE_IMUX_ATOM_)(3[2-9]|4[0-9]|5[0-9]|6[0-3]|9[6-9]|10[0-9]|11[0-9]|12[0-7])_INT_OUT[01]", "$1<32-63,96-127>")) + .map(s -> s.replaceFirst("([BC]NODE_OUTS_[EW])\\d+", "$1")) + .map(s -> s.replaceFirst("((CLE_SLICE[LM]_TOP_[01]|OUT_[NESW]NODE|(NN|EE|SS|WW)(1|2|4|6|7|10|12)(_[EW])?)_)[^ ]+", "$1")) + .map(s -> s.replaceFirst("(IF_INT_BNODE_OUTS)\\d+", "$1")) + .map(s -> s.replaceFirst("(INTF_IRI_QUADRANT_(GREEN|RED))_\\d+_[^ ]+", "$1")) .distinct() .sorted() .forEachOrdered(s -> System.out.println("\t" + s)); @@ -289,7 +348,16 @@ public void testNodeReachabilityVersal(String partName, String tileName, String } } // All INT-to-INT connections should be to the same tile - else if (baseTileTypeEnum == TileTypeEnum.CLE_BC_CORE) { + else if (EnumSet.of(TileTypeEnum.CLE_BC_CORE, + TileTypeEnum.INTF_LOCF_TL_TILE, + TileTypeEnum.INTF_LOCF_TR_TILE, + TileTypeEnum.INTF_LOCF_BL_TILE, + TileTypeEnum.INTF_LOCF_BR_TILE, + TileTypeEnum.INTF_ROCF_TL_TILE, + TileTypeEnum.INTF_ROCF_TR_TILE, + TileTypeEnum.INTF_ROCF_BL_TILE, + TileTypeEnum.INTF_ROCF_BR_TILE) + .contains(baseTileTypeEnum)) { // Except CLE_BC_CORE tiles which spans two adjacent INT tiles if (baseTile != downhill.getTile()) { Assertions.assertTrue(1 >= Math.abs(baseTile.getTileXCoordinate() - downhill.getTile().getTileXCoordinate())); diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java index 071468658..97bb28c56 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java @@ -401,7 +401,7 @@ void testSingleConnectionHelper(String partName, // One SLR crossing // (Too) Close "SLICE_X9Y299,SLICE_X9Y300,500", // On Laguna column - "SLICE_X9Y300,SLICE_X9Y299,400", + "SLICE_X9Y300,SLICE_X9Y299,500", "SLICE_X0Y299,SLICE_X0Y300,200", // Far from Laguna column "SLICE_X0Y300,SLICE_X0Y299,200", "SLICE_X53Y299,SLICE_X53Y300,200", // Equidistant from two Laguna columns @@ -422,7 +422,7 @@ void testSingleConnectionHelper(String partName, "SLICE_X0Y430,SLICE_X12Y240,200", // Two SLR crossings - "SLICE_X162Y299,SLICE_X162Y599,200", + "SLICE_X162Y299,SLICE_X162Y599,600", "SLICE_X162Y599,SLICE_X162Y299,100", // Three SLR crossings diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestRouterHelper.java b/test/src/com/xilinx/rapidwright/rwroute/TestRouterHelper.java index 41efaf567..9aa04840e 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestRouterHelper.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestRouterHelper.java @@ -60,6 +60,9 @@ public class TestRouterHelper { "xcvu3p,GTYE4_CHANNEL_X0Y12,TXOUTCLK_INT,null", "xcvu3p,IOB_X1Y95,I,INT_INTF_L_IO_X72Y109/LOGIC_OUTS_R23", "xcvu3p,IOB_X1Y80,I,INT_INTF_L_IO_X72Y92/LOGIC_OUTS_R22", + "xcvu3p,IOB_X1Y179,I,INT_INTF_L_CMT_X72Y208/LOGIC_OUTS_R18", + "xcvu3p,IOB_X1Y75,I,INT_INTF_L_CMT_X72Y88/LOGIC_OUTS_R18", + "xcvu3p,IOB_X1Y184,I,INT_INTF_L_IO_X72Y212/LOGIC_OUTS_R22", "xcvu3p,MMCM_X0Y0,LOCKED,INT_INTF_L_IO_X36Y54/LOGIC_OUTS_R0", "xcvp1002,MMCM_X2Y0,LOCKED,BLI_CLE_BOT_CORE_X27Y0/LOGIC_OUTS_D23" }) From bdf791f6e7d18616ef6d826131a24e438eaf0709 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 12 Nov 2024 13:39:44 -0800 Subject: [PATCH 54/71] Expand test Signed-off-by: Eddie Hung --- test/src/com/xilinx/rapidwright/device/TestNode.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/src/com/xilinx/rapidwright/device/TestNode.java b/test/src/com/xilinx/rapidwright/device/TestNode.java index 175172258..eacef5bd4 100644 --- a/test/src/com/xilinx/rapidwright/device/TestNode.java +++ b/test/src/com/xilinx/rapidwright/device/TestNode.java @@ -228,8 +228,10 @@ public void testNodeReachabilityUltraScale(String partName, String tileName, Str @ParameterizedTest @CsvSource({ - "xcvp1002,INT_X38Y220,NODE_PINBOUNCE,BOUNCE_E.*,true", - "xcvp1002,INT_X38Y220,NODE_PINBOUNCE,BOUNCE_W.*,true", + "xcvp1002,INT_X38Y220,NODE_PINBOUNCE,BOUNCE_E([0-9]|1[0-5]),true", + "xcvp1002,INT_X38Y220,NODE_PINBOUNCE,BOUNCE_E(1[6-9]|2[0-9]|3[01]),true", + "xcvp1002,INT_X38Y220,NODE_PINBOUNCE,BOUNCE_W([0-9]|1[0-5]),true", + "xcvp1002,INT_X38Y220,NODE_PINBOUNCE,BOUNCE_W(1[6-9]|2[0-9]|3[01]),true", "xcvp1002,INT_X38Y220,NODE_INODE,INT_NODE_IMUX_ATOM_([0-9]|1[0-9]|2[0-9]|3[01]|6[4-9]|7[0-9]|8[0-9]|9[0-5])_.*,true", "xcvp1002,INT_X38Y220,NODE_INODE,INT_NODE_IMUX_ATOM_(3[2-9]|4[0-9]|5[0-9]|6[0-3]|9[6-9]|10[0-9]|11[0-9]|12[0-7])_.*,true", "xcvp1002,INT_X38Y220,NODE_IMUX,IMUX_B_E.*,true", From c1e82749681caa0e8844a6cc15f96c15d0296fd4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 12 Nov 2024 13:41:36 -0800 Subject: [PATCH 55/71] Apply #1098 to Versal too Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/rwroute/RWRoute.java | 9 +- .../rapidwright/rwroute/RouteNodeGraph.java | 239 ++++++++++-------- .../rapidwright/rwroute/RouteNodeInfo.java | 9 +- 3 files changed, 140 insertions(+), 117 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index e89d4472a..044e2d70f 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1817,6 +1817,12 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { if (!routingGraph.isAccessible(childRNode, connection)) { continue; } + assert(rnode.getType() != RouteNodeType.LOCAL_EAST || childRNode.getType() == RouteNodeType.LOCAL_EAST + // FIXME: + || childRNode.getTile().getName().matches("INTF_[LR]OCF_[TB]R_TILE_.*")); + assert(rnode.getType() != RouteNodeType.LOCAL_WEST || childRNode.getType() == RouteNodeType.LOCAL_WEST + // FIXME: + || childRNode.getTile().getName().matches("INTF_[LR]OCF_[TB]L_TILE_.*")); break; case NON_LOCAL: // LOCALs cannot connect to NON_LOCALs except via a LUT routethru @@ -1838,8 +1844,7 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK_EAST || rnode.getType() == RouteNodeType.LOCAL_EAST); assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK_WEST || rnode.getType() == RouteNodeType.LOCAL_WEST); assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK || rnode.getType() == RouteNodeType.LOCAL || - // FIXME: - design.getSeries() == Series.Versal); + (routingGraph.isVersal && rnode.getIntentCode() == IntentCode.NODE_CLE_BNODE)); if (!isAccessibleSink(childRNode, connection)) { continue; } diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 8fbb0046b..9cc826d18 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -145,30 +145,33 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map(TileTypeEnum.class); BitSet wires = new BitSet(); - BitSet eastWires = new BitSet(); - BitSet westWires = new BitSet(); if (isUltraScale || isUltraScalePlus) { + intTile = device.getArbitraryTileOfType(TileTypeEnum.INT); + // Device.getArbitraryTileOfType() typically gives you the North-Western-most + // tile (with minimum X, maximum Y). Analyze the tile just below that. + intTile = intTile.getTileXYNeighbor(0, -1); + ultraScalesNonLocalWires = new EnumMap<>(TileTypeEnum.class); ultraScalesNonLocalWires.put(intTile.getTileTypeEnum(), wires); - eastWestPattern = Pattern.compile("(((BOUNCE|BYPASS|IMUX|INODE(_[12])?)_([EW]))|INT_NODE_IMUX_(\\d+)_).*"); - eastWestWires = new EnumMap<>(TileTypeEnum.class); - eastWestWires.put(intTile.getTileTypeEnum(), new BitSet[]{eastWires, westWires}); + eastWestPattern = Pattern.compile("(((BOUNCE|BYPASS|IMUX|INODE(_[12])?)_(?[EW]))|INT_NODE_IMUX_(?\\d+)_).*"); } else { - assert(series == Series.Versal); + assert(isVersal); + + // Find an INT tile adjacent to a CLE_BC_CORE tile since Versal devices may contain AIEs on their northern edge + Tile bcCoreTile = device.getArbitraryTileOfType(TileTypeEnum.CLE_BC_CORE); + // Device.getArbitraryTileOfType() typically gives you the North-Western-most + // tile (with minimum X, maximum Y). Analyze the tile just below that. + intTile = bcCoreTile.getTileNeighbor(2, 0); + assert(intTile.getTileTypeEnum() == TileTypeEnum.INT); + ultraScalesNonLocalWires = null; - // FIXME: - eastWestPattern = null; - eastWestWires = null; + eastWestPattern = Pattern.compile("(((BOUNCE|IMUX_B|BNODE_OUTS)_(?[EW])(?\\d+))|INT_NODE_IMUX_ATOM_(?\\d+)_).*"); } for (int wireIndex = 0; wireIndex < intTile.getWireCount(); wireIndex++) { @@ -179,69 +182,86 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map new BitSet[]{new BitSet(), new BitSet()}); + BitSet eastWires = eastWestWires[0]; + BitSet westWires = eastWestWires[1]; + String ew = m.group("eastwest"); + String inode; + if (ew != null) { + assert(ew.equals("E") || ew.equals("W")); + if (baseIntentCode == IntentCode.NODE_CLE_BNODE) { + ew = ew.equals("E") ? "W" : "E"; } - } else if (m.group(6) != null) { - int i = Integer.valueOf(m.group(6)); - if (i < 32 || (isUltraScale && (i >= 64 && i < 96))) { + // Integer bounce = isVersal && baseIntentCode == IntentCode.NODE_PINBOUNCE ? Integer.valueOf(m.group("bounce")) : null; + if (ew.equals("E") /*&& (bounce == null || bounce < 16)*/) { eastWires.set(baseNode.getWireIndex()); - } else { - assert(i < 64 || (isUltraScale && (i >= 96 && i < 128))); + } else if (ew.equals("W") /*&& (bounce == null || bounce < 16)*/) { westWires.set(baseNode.getWireIndex()); + } else { + // assert(!isVersal || baseIntentCode == IntentCode.NODE_IMUX || (bounce >= 16 && bounce < 32)); + } + } else { + if ((inode = m.group("inode")) != null) { + int i = Integer.valueOf(inode); + if (i < 32 || ((isUltraScale || isVersal) && i >= 64 && i < 96)) { + eastWires.set(baseNode.getWireIndex()); + } else { + assert(i < 64 || (isUltraScale || isVersal && i >= 96 && i < 128)); + westWires.set(baseNode.getWireIndex()); + } } } } else { - assert(baseWireName.matches("CTRL_[EW](_B)?\\d+|INT_NODE_GLOBAL_\\d+(_INT)?_OUT[01]?") - // FIXME: - || series == Series.Versal); + assert((isUltraScale || isUltraScalePlus) && baseWireName.matches("CTRL_[EW](_B)?\\d+|INT_NODE_GLOBAL_\\d+(_INT)?_OUT[01]?")); } } @@ -644,54 +664,9 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { return true; } - Tile sinkTile = sinkRnode.getTile(); - if (isVersal) { - if (childTile == sinkTile) { - return true; - } - - IntentCode childIntentCode = childRnode.getIntentCode(); - switch (childIntentCode) { - case NODE_INODE: - // Block access to all INODEs outside the sink tile, since NODE_INODE -> NODE_IMUX -> NODE_PINFEED (or NODE_INODE -> NODE_PINBOUNCE) - return false; - case NODE_CLE_CNODE: - // Block access to all CNODEs outside the sink tile, since NODE_CLE_CNODE -> NODE_CLE_CTRL - return false; - case NODE_INTF_CNODE: - // Block access to all CNODEs outside the sink tile, since NODE_INTF_CNODE -> NODE_INTF_CTRL - return false; - case NODE_PINBOUNCE: - // BOUNCEs are only accessible through INODEs, so transitively this node must be in the sink tile too - return false; - case NODE_CLE_BNODE: - case NODE_INTF_BNODE: - IntentCode sinkIntentCode = sinkRnode.getIntentCode(); - // For CTRL sinks, block all BNODEs outside the sink tile - if (sinkIntentCode == IntentCode.NODE_CLE_CTRL || sinkIntentCode == IntentCode.NODE_INTF_CTRL) { - return false; - } - // For other sinks, only allow if BNODE reaches into the sink tile - assert(sinkIntentCode == IntentCode.NODE_IMUX || sinkIntentCode == IntentCode.NODE_PINBOUNCE); - return childTile.getTileYCoordinate() == sinkTile.getTileYCoordinate() && - childRnode.getEndTileXCoordinate() == sinkTile.getTileXCoordinate(); - case NODE_IMUX: - // IMUXes that are not EXCLUSIVE_SINKs will have been isExcluded() from the graph unless LUT routethrus are enabled - assert(lutRoutethru); - return true; - case NODE_PINFEED: - // Expected to be projected away - break; - case NODE_CLE_CTRL: - case NODE_INTF_CTRL: - // CTRL pins that are not EXCLUSIVE_SINKs will have been isExcluded() from the graph - break; - } - throw new RuntimeException("ERROR: Unhandled IntentCode: " + childIntentCode); - } - // (c) on the same side as the sink RouteNodeType type = childRnode.getType(); + Tile sinkTile = sinkRnode.getTile(); switch (sinkRnode.getType()) { case EXCLUSIVE_SINK_EAST: if (type == RouteNodeType.LOCAL_WEST) { @@ -710,11 +685,15 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { if (type != RouteNodeType.LOCAL) { return false; } - if (design.getSeries() == Series.UltraScale || design.getSeries() == Series.UltraScalePlus) { - // This must be a CTRL sink; these can only be accessed from the sink tile rather than Y +/- 1 below - return childTile == sinkTile; + // This must be a CTRL sink; these can only be accessed from the sink tile (rather than Y +/- 1 below) + if (isVersal) { + assert(sinkRnode.getIntentCode() == IntentCode.NODE_CLE_CTRL || + sinkRnode.getIntentCode() == IntentCode.NODE_INTF_CTRL); + } else { + assert(design.getSeries() == Series.UltraScale || design.getSeries() == Series.UltraScalePlus); + assert(sinkRnode.getWireName().startsWith("CTRL_")); } - break; + return childTile == sinkTile; default: throw new RuntimeException("ERROR: Unexpected sink type " + sinkRnode.getType()); } @@ -724,6 +703,46 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { return true; } + if (isVersal) { + IntentCode childIntentCode = childRnode.getIntentCode(); + switch (childIntentCode) { + case NODE_INODE: + // Block access to all INODEs outside the sink tile, since NODE_INODE -> NODE_IMUX -> NODE_PINFEED (or NODE_INODE -> NODE_PINBOUNCE) + return false; + case NODE_CLE_CNODE: + case NODE_INTF_CNODE: { + // CNODEs must only be used for CTRL sinks; must not be the case if we've reached here + // FIXME + IntentCode sinkIntentCode = sinkRnode.getIntentCode(); + assert(sinkIntentCode != IntentCode.NODE_CLE_CTRL && sinkIntentCode != IntentCode.NODE_INTF_CTRL); + return false; + } + case NODE_CLE_BNODE: + case NODE_INTF_BNODE: { + // Sinks at this point must only, only allow if BNODE reaches into the sink tile + IntentCode sinkIntentCode = sinkRnode.getIntentCode(); + assert(sinkIntentCode == IntentCode.NODE_IMUX || sinkIntentCode == IntentCode.NODE_PINBOUNCE); + return childTile.getTileYCoordinate() == sinkTile.getTileYCoordinate() && + childRnode.getEndTileXCoordinate() == sinkTile.getTileXCoordinate(); + } + case NODE_PINBOUNCE: + // BOUNCEs are only accessible through INODEs, so transitively this intent code is unreachable + break; + case NODE_IMUX: + // IMUXes that are not our target EXCLUSIVE_SINK will have been isExcluded() from the graph unless LUT routethrus are enabled + assert(lutRoutethru); + break; + case NODE_PINFEED: + // Expected to be projected away + break; + case NODE_CLE_CTRL: + case NODE_INTF_CTRL: + // CTRL pins that are not our target EXCLUSIVE_SINK will have been isExcluded() from the graph + break; + } + throw new RuntimeException("ERROR: Unhandled IntentCode: " + childIntentCode); + } + // (e) when in same X as the sink tile, but Y +/- 1 return childX == sinkTile.getTileXCoordinate() && Math.abs(childTile.getTileYCoordinate() - sinkTile.getTileYCoordinate()) <= 1; diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java index 10bf8f874..571f7470c 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java @@ -157,6 +157,9 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou } // Fall through case NODE_PINBOUNCE: + case NODE_INODE: // INT.INT_NODE_IMUX_ATOM_*_INT_OUT[01] (Versal only) + case NODE_IMUX: // INT.IMUX_B_[EW]* (Versal only) + case NODE_CLE_BNODE: // CLE_BC_CORE*.BNODE_OUTS_[EW]* (Versal only) if (routingGraph != null && routingGraph.eastWestWires != null) { BitSet[] eastWestWires = routingGraph.eastWestWires.get(tileTypeEnum); if (eastWestWires[0].get(node.getWireIndex())) { @@ -165,17 +168,13 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou return RouteNodeType.LOCAL_WEST; } assert(node.getWireName().startsWith("CTRL_") || - // FIXME: - routingGraph.design.getSeries() == Series.Versal); + (routingGraph.isVersal && ic == IntentCode.NODE_PINBOUNCE && node.getWireName().matches("BOUNCE_[EW](1[6-9]|2[0-9]|3[01])"))); } return RouteNodeType.LOCAL; // Versal only - case NODE_INODE: // INT.INT_NODE_IMUX_ATOM_*_INT_OUT[01] - case NODE_IMUX: // INT.IMUX_B_[EW]* case NODE_CLE_CTRL: // CLE_BC_CORE*.CTRL_[LR]_B* case NODE_INTF_CTRL: // INTF_[LR]OCF_[TB][LR]_TILE.INTF_IRI* - case NODE_CLE_BNODE: // CLE_BC_CORE*.BNODE_OUTS_[EW]* case NODE_CLE_CNODE: // CLE_BC_CORE*.CNODE_OUTS_[EW]* case NODE_INTF_BNODE: // INTF_[LR]OCF_[TB][LR]_TILE.IF_INT_BNODE_OUTS* case NODE_INTF_CNODE: // INTF_[LR]OCF_[TB][LR]_TILE.IF_INT_CNODE_OUTS* From 50287fedd6e0d924d378b7498758b21ca52509dc Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 12 Nov 2024 16:24:08 -0800 Subject: [PATCH 56/71] Assign CNODEs to be LOCAL_{EAST,WEST} (opposite to name) Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/rwroute/RWRoute.java | 3 +- .../rapidwright/rwroute/RouteNodeGraph.java | 46 +++++++++++-------- .../rapidwright/rwroute/RouteNodeInfo.java | 6 +-- 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 044e2d70f..11742bf4f 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1844,7 +1844,8 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK_EAST || rnode.getType() == RouteNodeType.LOCAL_EAST); assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK_WEST || rnode.getType() == RouteNodeType.LOCAL_WEST); assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK || rnode.getType() == RouteNodeType.LOCAL || - (routingGraph.isVersal && rnode.getIntentCode() == IntentCode.NODE_CLE_BNODE)); + // [BC]NODEs are LOCAL_{EAST,WEST} since they connect to INODEs, but also service CTRL sinks + (routingGraph.isVersal && (rnode.getIntentCode() == IntentCode.NODE_CLE_BNODE || rnode.getIntentCode() == IntentCode.NODE_CLE_CNODE))); if (!isAccessibleSink(childRNode, connection)) { continue; } diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 9cc826d18..1c00f2a5c 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -171,7 +171,7 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map[EW])(?\\d+))|INT_NODE_IMUX_ATOM_(?\\d+)_).*"); + eastWestPattern = Pattern.compile("(((BOUNCE|IMUX_B|[BC]NODE_OUTS)_(?[EW]))|INT_NODE_IMUX_ATOM_(?\\d+)_).*"); } for (int wireIndex = 0; wireIndex < intTile.getWireCount(); wireIndex++) { @@ -223,7 +223,7 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map= 16 && bounce < 32)); + assert(ew.equals("W")); + westWires.set(baseNode.getWireIndex()); } } else { if ((inode = m.group("inode")) != null) { @@ -681,19 +679,24 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { } break; case EXCLUSIVE_SINK: - // Only both-sided wires (e.g. INT_NODE_GLOBAL_*) can reach a both-sided sink (CTRL_*) - if (type != RouteNodeType.LOCAL) { + // This must be a CTRL sink; these can only be accessed from LOCAL nodes in the sink tile (rather than Y +/- 1 below) + if (childTile != sinkTile) { return false; } - // This must be a CTRL sink; these can only be accessed from the sink tile (rather than Y +/- 1 below) if (isVersal) { - assert(sinkRnode.getIntentCode() == IntentCode.NODE_CLE_CTRL || - sinkRnode.getIntentCode() == IntentCode.NODE_INTF_CTRL); + assert((sinkRnode.getIntentCode() == IntentCode.NODE_CLE_CTRL && type != RouteNodeType.LOCAL) || + (sinkRnode.getIntentCode() == IntentCode.NODE_INTF_CTRL && type == RouteNodeType.LOCAL)); } else { assert(design.getSeries() == Series.UltraScale || design.getSeries() == Series.UltraScalePlus); assert(sinkRnode.getWireName().startsWith("CTRL_")); + + // Only both-sided wires (e.g. INT_NODE_GLOBAL_*) can reach a both-sided sink (CTRL_*) + if (type != RouteNodeType.LOCAL) { + return false; + } } - return childTile == sinkTile; + assert(childTile == sinkTile); + break; default: throw new RuntimeException("ERROR: Unexpected sink type " + sinkRnode.getType()); } @@ -711,15 +714,20 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { return false; case NODE_CLE_CNODE: case NODE_INTF_CNODE: { - // CNODEs must only be used for CTRL sinks; must not be the case if we've reached here - // FIXME IntentCode sinkIntentCode = sinkRnode.getIntentCode(); - assert(sinkIntentCode != IntentCode.NODE_CLE_CTRL && sinkIntentCode != IntentCode.NODE_INTF_CTRL); + assert(sinkIntentCode == IntentCode.NODE_IMUX || sinkIntentCode == IntentCode.NODE_PINBOUNCE); + + // Experimentally, found this to lead to runtime increases + // // Only allow CNODEs that reach into the sink tile + // return childTile.getTileYCoordinate() == sinkTile.getTileYCoordinate() && + // childRnode.getEndTileXCoordinate() == sinkTile.getTileXCoordinate(); + + // Do not allow CNODEs when not targeting a CTRL pin return false; } case NODE_CLE_BNODE: case NODE_INTF_BNODE: { - // Sinks at this point must only, only allow if BNODE reaches into the sink tile + // Only allow BNODEs that reach into the sink tile IntentCode sinkIntentCode = sinkRnode.getIntentCode(); assert(sinkIntentCode == IntentCode.NODE_IMUX || sinkIntentCode == IntentCode.NODE_PINBOUNCE); return childTile.getTileYCoordinate() == sinkTile.getTileYCoordinate() && diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java index 571f7470c..9f92d1d6e 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java @@ -159,6 +159,7 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou case NODE_PINBOUNCE: case NODE_INODE: // INT.INT_NODE_IMUX_ATOM_*_INT_OUT[01] (Versal only) case NODE_IMUX: // INT.IMUX_B_[EW]* (Versal only) + case NODE_CLE_CNODE: // CLE_BC_CORE*.CNODE_OUTS_[EW]* (Versal only) case NODE_CLE_BNODE: // CLE_BC_CORE*.BNODE_OUTS_[EW]* (Versal only) if (routingGraph != null && routingGraph.eastWestWires != null) { BitSet[] eastWestWires = routingGraph.eastWestWires.get(tileTypeEnum); @@ -167,15 +168,14 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou } else if (eastWestWires[1].get(node.getWireIndex())) { return RouteNodeType.LOCAL_WEST; } - assert(node.getWireName().startsWith("CTRL_") || - (routingGraph.isVersal && ic == IntentCode.NODE_PINBOUNCE && node.getWireName().matches("BOUNCE_[EW](1[6-9]|2[0-9]|3[01])"))); + assert((!routingGraph.isVersal && node.getWireName().startsWith("CTRL_") || + routingGraph.isVersal && ic == IntentCode.NODE_CLE_CNODE)); } return RouteNodeType.LOCAL; // Versal only case NODE_CLE_CTRL: // CLE_BC_CORE*.CTRL_[LR]_B* case NODE_INTF_CTRL: // INTF_[LR]OCF_[TB][LR]_TILE.INTF_IRI* - case NODE_CLE_CNODE: // CLE_BC_CORE*.CNODE_OUTS_[EW]* case NODE_INTF_BNODE: // INTF_[LR]OCF_[TB][LR]_TILE.IF_INT_BNODE_OUTS* case NODE_INTF_CNODE: // INTF_[LR]OCF_[TB][LR]_TILE.IF_INT_CNODE_OUTS* return RouteNodeType.LOCAL; From f4df0525dbbc71f63414ab1e087ee82637bf474d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 12 Nov 2024 16:51:45 -0800 Subject: [PATCH 57/71] Fix merge Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RouteNode.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index 9729b9e13..42bd6e5b6 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -134,11 +134,6 @@ private void setBaseCost(Series series) { assert(length == 0); break; case LOCAL_EAST: - case LOCAL_WEST: - assert(length == 0 || - (series == Series.Versal && EnumSet.of(IntentCode.NODE_CLE_BNODE, IntentCode.NODE_CLE_CNODE).contains(getIntentCode()))); - break; - case LOCAL_EAST: case LOCAL_WEST: assert(length == 0 || (length == 1 && ( From 003a051b284a169f13751b761362b642e15433a0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 12 Nov 2024 17:08:23 -0800 Subject: [PATCH 58/71] Resolve FIXMEs Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/rwroute/RWRoute.java | 8 +--- .../rapidwright/rwroute/RouteNodeGraph.java | 38 ++++++++++++++++++- .../rapidwright/rwroute/RouteNodeInfo.java | 14 +++---- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 11742bf4f..98967952d 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1817,12 +1817,8 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { if (!routingGraph.isAccessible(childRNode, connection)) { continue; } - assert(rnode.getType() != RouteNodeType.LOCAL_EAST || childRNode.getType() == RouteNodeType.LOCAL_EAST - // FIXME: - || childRNode.getTile().getName().matches("INTF_[LR]OCF_[TB]R_TILE_.*")); - assert(rnode.getType() != RouteNodeType.LOCAL_WEST || childRNode.getType() == RouteNodeType.LOCAL_WEST - // FIXME: - || childRNode.getTile().getName().matches("INTF_[LR]OCF_[TB]L_TILE_.*")); + assert(rnode.getType() != RouteNodeType.LOCAL_EAST || childRNode.getType() == RouteNodeType.LOCAL_EAST); + assert(rnode.getType() != RouteNodeType.LOCAL_WEST || childRNode.getType() == RouteNodeType.LOCAL_WEST); break; case NON_LOCAL: // LOCALs cannot connect to NON_LOCALs except via a LUT routethru diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 1c00f2a5c..9afeb80ae 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -263,6 +263,38 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map new BitSet[]{new BitSet(), new BitSet()}); + BitSet eastWires = eastWestWires[0]; + BitSet westWires = eastWestWires[1]; + for (int wireIndex = 0; wireIndex < intfTile.getWireCount(); wireIndex++) { + IntentCode baseIntentCode = intfTile.getWireIntentCode(wireIndex); + if (baseIntentCode != IntentCode.NODE_INTF_BNODE) { + continue; + } + + if (EnumSet.of(TileTypeEnum.INTF_LOCF_TR_TILE, + TileTypeEnum.INTF_LOCF_BR_TILE, + TileTypeEnum.INTF_ROCF_TR_TILE, + TileTypeEnum.INTF_ROCF_BR_TILE).contains(tte)) { + eastWires.set(wireIndex); + } else { + westWires.set(wireIndex); + } + } + } + } + if (lutRoutethru) { assert(isUltraScalePlus || isUltraScale); @@ -684,8 +716,12 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { return false; } if (isVersal) { + // CLE_CTRL can be reached by NODE_CLE_[BC]NODE which have type LOCAL_{EAST,WEST} assert((sinkRnode.getIntentCode() == IntentCode.NODE_CLE_CTRL && type != RouteNodeType.LOCAL) || - (sinkRnode.getIntentCode() == IntentCode.NODE_INTF_CTRL && type == RouteNodeType.LOCAL)); + // INTF_CTRL can be reached by NODE_INTF_BNODE which have type LOCAL_{EAST,WEST}, + // but also NODE_INTF_CNODE which are currently LOCAL + (sinkRnode.getIntentCode() == IntentCode.NODE_INTF_CTRL && (type != RouteNodeType.LOCAL || + childRnode.getIntentCode() == IntentCode.NODE_INTF_CNODE))); } else { assert(design.getSeries() == Series.UltraScale || design.getSeries() == Series.UltraScalePlus); assert(sinkRnode.getWireName().startsWith("CTRL_")); diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java index 9f92d1d6e..7ef02b910 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java @@ -24,7 +24,6 @@ import com.xilinx.rapidwright.device.IntentCode; import com.xilinx.rapidwright.device.Node; -import com.xilinx.rapidwright.device.Series; import com.xilinx.rapidwright.device.Tile; import com.xilinx.rapidwright.device.TileTypeEnum; import com.xilinx.rapidwright.device.Wire; @@ -157,10 +156,11 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou } // Fall through case NODE_PINBOUNCE: - case NODE_INODE: // INT.INT_NODE_IMUX_ATOM_*_INT_OUT[01] (Versal only) - case NODE_IMUX: // INT.IMUX_B_[EW]* (Versal only) - case NODE_CLE_CNODE: // CLE_BC_CORE*.CNODE_OUTS_[EW]* (Versal only) - case NODE_CLE_BNODE: // CLE_BC_CORE*.BNODE_OUTS_[EW]* (Versal only) + case NODE_INODE: // INT.INT_NODE_IMUX_ATOM_*_INT_OUT[01] (Versal only) + case NODE_IMUX: // INT.IMUX_B_[EW]* (Versal only) + case NODE_CLE_CNODE: // CLE_BC_CORE*.CNODE_OUTS_[EW]* (Versal only) + case NODE_CLE_BNODE: // CLE_BC_CORE*.BNODE_OUTS_[EW]* (Versal only) + case NODE_INTF_BNODE: // INTF_[LR]OCF_[TB][LR]_TILE.IF_INT_BNODE_OUTS* (Versal only) if (routingGraph != null && routingGraph.eastWestWires != null) { BitSet[] eastWestWires = routingGraph.eastWestWires.get(tileTypeEnum); if (eastWestWires[0].get(node.getWireIndex())) { @@ -168,15 +168,13 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou } else if (eastWestWires[1].get(node.getWireIndex())) { return RouteNodeType.LOCAL_WEST; } - assert((!routingGraph.isVersal && node.getWireName().startsWith("CTRL_") || - routingGraph.isVersal && ic == IntentCode.NODE_CLE_CNODE)); + assert(!routingGraph.isVersal && node.getWireName().startsWith("CTRL_")); } return RouteNodeType.LOCAL; // Versal only case NODE_CLE_CTRL: // CLE_BC_CORE*.CTRL_[LR]_B* case NODE_INTF_CTRL: // INTF_[LR]OCF_[TB][LR]_TILE.INTF_IRI* - case NODE_INTF_BNODE: // INTF_[LR]OCF_[TB][LR]_TILE.IF_INT_BNODE_OUTS* case NODE_INTF_CNODE: // INTF_[LR]OCF_[TB][LR]_TILE.IF_INT_CNODE_OUTS* return RouteNodeType.LOCAL; From c057226b9cf6a85d12269f1a726454a6fa5f3f1f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 12 Nov 2024 19:05:43 -0800 Subject: [PATCH 59/71] Restore comment Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RWRoute.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 98967952d..2b1a89158 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1817,6 +1817,7 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { if (!routingGraph.isAccessible(childRNode, connection)) { continue; } + // Verify invariant that east/west wires stay east/west assert(rnode.getType() != RouteNodeType.LOCAL_EAST || childRNode.getType() == RouteNodeType.LOCAL_EAST); assert(rnode.getType() != RouteNodeType.LOCAL_WEST || childRNode.getType() == RouteNodeType.LOCAL_WEST); break; From 353775cd3c769c736c125d4652f67ed46705b625 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 12 Nov 2024 19:07:46 -0800 Subject: [PATCH 60/71] Fix continue Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 9afeb80ae..9222dbfac 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -215,9 +215,8 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map Date: Tue, 12 Nov 2024 20:28:19 -0800 Subject: [PATCH 61/71] On Versal, make all NODE_PINFEEDs RouteNodeType.LOCAL Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java index 7ef02b910..2b799e975 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java @@ -148,7 +148,10 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou } case NODE_PINFEED: - if (routingGraph != null && routingGraph.lagunaI != null) { + if (routingGraph == null || routingGraph.isVersal) { + return RouteNodeType.LOCAL; + } + if (routingGraph.lagunaI != null) { BitSet bs = routingGraph.lagunaI.get(node.getTile()); if (bs != null && bs.get(node.getWireIndex())) { return RouteNodeType.LAGUNA_PINFEED; From 76bc5ccba71acc4d3103fa5ab0f9bca20d909a11 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 12 Nov 2024 20:54:48 -0800 Subject: [PATCH 62/71] Handle NODE_INTF_CNODE too Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RWRoute.java | 4 +++- src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java | 9 +++------ src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 2b1a89158..498174b87 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -1842,7 +1842,9 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK_WEST || rnode.getType() == RouteNodeType.LOCAL_WEST); assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK || rnode.getType() == RouteNodeType.LOCAL || // [BC]NODEs are LOCAL_{EAST,WEST} since they connect to INODEs, but also service CTRL sinks - (routingGraph.isVersal && (rnode.getIntentCode() == IntentCode.NODE_CLE_BNODE || rnode.getIntentCode() == IntentCode.NODE_CLE_CNODE))); + (routingGraph.isVersal && EnumSet.of(IntentCode.NODE_CLE_BNODE, IntentCode.NODE_CLE_CNODE, + IntentCode.NODE_INTF_BNODE, IntentCode.NODE_INTF_CNODE) + .contains(rnode.getIntentCode()))); if (!isAccessibleSink(childRNode, connection)) { continue; } diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 9222dbfac..d4ebcff6c 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -278,7 +278,7 @@ protected RouteNodeGraph(Design design, RWRouteConfig config, Map Date: Tue, 12 Nov 2024 21:02:15 -0800 Subject: [PATCH 63/71] Add comment Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index d4ebcff6c..a2dbe4988 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -749,12 +749,13 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { IntentCode sinkIntentCode = sinkRnode.getIntentCode(); assert(sinkIntentCode == IntentCode.NODE_IMUX || sinkIntentCode == IntentCode.NODE_PINBOUNCE); - // Experimentally, found this to lead to runtime increases + // Experimentally found that considering the following led to runtime increases // // Only allow CNODEs that reach into the sink tile // return childTile.getTileYCoordinate() == sinkTile.getTileYCoordinate() && // childRnode.getEndTileXCoordinate() == sinkTile.getTileXCoordinate(); - // Do not allow CNODEs when not targeting a CTRL pin + // Do not allow CNODEs when not targeting a CTRL sink + // Note: NODE_{CLE,INTF}_CNODE (x24) -> NODE_INODE arcs (128/328 PIPs, 128/154 nodes) will be ignored return false; } case NODE_CLE_BNODE: From e87750371934443d5a6a1012ec64462a62db6aff Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 12 Nov 2024 23:00:32 -0800 Subject: [PATCH 64/71] Simplify if Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java index e04cb4150..76e180715 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java @@ -165,7 +165,7 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou case NODE_CLE_BNODE: // CLE_BC_CORE*.BNODE_OUTS_[EW]* (Versal only) case NODE_INTF_BNODE: // INTF_[LR]OCF_[TB][LR]_TILE.IF_INT_BNODE_OUTS* (Versal only) case NODE_INTF_CNODE: // INTF_[LR]OCF_[TB][LR]_TILE.IF_INT_CNODE_OUTS* (Versal only) - if (routingGraph != null && routingGraph.eastWestWires != null) { + if (routingGraph != null) { BitSet[] eastWestWires = routingGraph.eastWestWires.get(tileTypeEnum); if (eastWestWires[0].get(node.getWireIndex())) { return RouteNodeType.LOCAL_EAST; From ce90eb706a3ed61b6da18699a588a39dbd596f66 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 13 Nov 2024 11:03:39 -0800 Subject: [PATCH 65/71] Introduce LOCAL_RESERVED Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/rwroute/RWRoute.java | 36 +++++++++++++++++-- .../xilinx/rapidwright/rwroute/RouteNode.java | 1 + .../rapidwright/rwroute/RouteNodeGraph.java | 30 ++++++++-------- .../rapidwright/rwroute/RouteNodeType.java | 6 ++-- 4 files changed, 54 insertions(+), 19 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 498174b87..288dd485e 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -325,6 +325,32 @@ protected void determineRoutingTargets() { // Wait for all outstanding RouteNodeGraph.preserveAsync() calls to complete routingGraph.awaitPreserve(); + + // On Versal only, reserve all uphills of NODE_(CLE|INTF)_CTRL sinks since + // their [BC]NODEs can also be used to reach NODE_INODEs --- not applying this + // heuristic can lead to avoidable congestion + if (routingGraph.isVersal) { + for (Connection connection : indirectConnections) { + RouteNode sinkRnode = connection.getSinkRnode(); + if (sinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK) { + for (Node uphill : sinkRnode.getAllUphillNodes()) { + if (uphill.isTiedToVcc()) { + continue; + } + Net preservedNet = routingGraph.getPreservedNet(uphill); + if (preservedNet != null && preservedNet != connection.getNetWrapper().getNet()) { + continue; + } + assert((sinkRnode.getIntentCode() == IntentCode.NODE_CLE_CTRL && + (uphill.getIntentCode() == IntentCode.NODE_CLE_CNODE || uphill.getIntentCode() == IntentCode.NODE_CLE_BNODE)) || + (sinkRnode.getIntentCode() == IntentCode.NODE_INTF_CTRL && + (uphill.getIntentCode() == IntentCode.NODE_INTF_CNODE || uphill.getIntentCode() == IntentCode.NODE_INTF_BNODE))); + RouteNode rnode = routingGraph.getOrCreate(uphill, RouteNodeType.LOCAL_RESERVED); + rnode.setType(RouteNodeType.LOCAL_RESERVED); + } + } + } + } } private void categorizeNets() { @@ -1811,15 +1837,19 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { continue; } switch (childRNode.getType()) { + case LOCAL_RESERVED: case LOCAL: case LOCAL_EAST: case LOCAL_WEST: if (!routingGraph.isAccessible(childRNode, connection)) { continue; } - // Verify invariant that east/west wires stay east/west - assert(rnode.getType() != RouteNodeType.LOCAL_EAST || childRNode.getType() == RouteNodeType.LOCAL_EAST); - assert(rnode.getType() != RouteNodeType.LOCAL_WEST || childRNode.getType() == RouteNodeType.LOCAL_WEST); + // Verify invariant that east/west wires stay east/west ... + assert(rnode.getType() != RouteNodeType.LOCAL_EAST || childRNode.getType() == RouteNodeType.LOCAL_EAST || + // ... unless it's an exclusive sink using a LOCAL_RESERVED node + (childRNode.getType() == RouteNodeType.LOCAL_RESERVED && connection.getSinkRnode().getType() == RouteNodeType.EXCLUSIVE_SINK)); + assert(rnode.getType() != RouteNodeType.LOCAL_WEST || childRNode.getType() == RouteNodeType.LOCAL_WEST || + (childRNode.getType() == RouteNodeType.LOCAL_RESERVED && connection.getSinkRnode().getType() == RouteNodeType.EXCLUSIVE_SINK)); break; case NON_LOCAL: // LOCALs cannot connect to NON_LOCALs except via a LUT routethru diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index 42bd6e5b6..19f50701c 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -135,6 +135,7 @@ private void setBaseCost(Series series) { break; case LOCAL_EAST: case LOCAL_WEST: + case LOCAL_RESERVED: assert(length == 0 || (length == 1 && ( ((series == Series.UltraScalePlus || series == Series.UltraScale) && getIntentCode() == IntentCode.NODE_PINBOUNCE) || diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index a2dbe4988..21b95e29a 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -679,7 +679,8 @@ public int averageChildren() { public boolean isAccessible(RouteNode childRnode, Connection connection) { // Only consider LOCAL nodes when: // (a) considering LUT routethrus - if (!childRnode.getType().isLocal() || lutRoutethru) { + RouteNodeType type = childRnode.getType(); + if (!type.isLocal() || lutRoutethru) { return true; } @@ -694,17 +695,16 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { } // (c) on the same side as the sink - RouteNodeType type = childRnode.getType(); Tile sinkTile = sinkRnode.getTile(); switch (sinkRnode.getType()) { case EXCLUSIVE_SINK_EAST: - if (type == RouteNodeType.LOCAL_WEST) { + if (type == RouteNodeType.LOCAL_WEST || type == RouteNodeType.LOCAL_RESERVED) { // West wires can never reach an east sink return false; } break; case EXCLUSIVE_SINK_WEST: - if (type == RouteNodeType.LOCAL_EAST) { + if (type == RouteNodeType.LOCAL_EAST || type == RouteNodeType.LOCAL_RESERVED) { // East wires can never reach a west sink return false; } @@ -715,9 +715,12 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { return false; } if (isVersal) { - // NODE_(CLE|INTF)_CTRL can be reached by NODE_(CLE|INTF)_[BC]NODE which have type LOCAL_(EAST|WEST) - assert((sinkRnode.getIntentCode() == IntentCode.NODE_CLE_CTRL && type != RouteNodeType.LOCAL) || - (sinkRnode.getIntentCode() == IntentCode.NODE_INTF_CTRL && type != RouteNodeType.LOCAL)); + assert(sinkRnode.getIntentCode() == IntentCode.NODE_CLE_CTRL || sinkRnode.getIntentCode() == IntentCode.NODE_INTF_CTRL); + + // NODE_(CLE|INTF)_CTRL can only be reached by LOCAL_RESERVED nodes + if (type != RouteNodeType.LOCAL_RESERVED) { + return false; + } } else { assert(design.getSeries() == Series.UltraScale || design.getSeries() == Series.UltraScalePlus); assert(sinkRnode.getWireName().startsWith("CTRL_")); @@ -749,14 +752,13 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { IntentCode sinkIntentCode = sinkRnode.getIntentCode(); assert(sinkIntentCode == IntentCode.NODE_IMUX || sinkIntentCode == IntentCode.NODE_PINBOUNCE); - // Experimentally found that considering the following led to runtime increases - // // Only allow CNODEs that reach into the sink tile - // return childTile.getTileYCoordinate() == sinkTile.getTileYCoordinate() && - // childRnode.getEndTileXCoordinate() == sinkTile.getTileXCoordinate(); + // Only allow CNODEs that reach into the sink tile + return childTile.getTileYCoordinate() == sinkTile.getTileYCoordinate() && + childRnode.getEndTileXCoordinate() == sinkTile.getTileXCoordinate(); - // Do not allow CNODEs when not targeting a CTRL sink - // Note: NODE_{CLE,INTF}_CNODE (x24) -> NODE_INODE arcs (128/328 PIPs, 128/154 nodes) will be ignored - return false; + // // Do not allow CNODEs when not targeting a CTRL sink + // // Note: NODE_{CLE,INTF}_CNODE (x24) -> NODE_INODE arcs (128/328 PIPs, 128/154 nodes) will be ignored + // return false; } case NODE_CLE_BNODE: case NODE_INTF_BNODE: { diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java index 0c024bb0b..eba37caf9 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java @@ -48,13 +48,15 @@ public enum RouteNodeType { LOCAL, LOCAL_EAST, - LOCAL_WEST; + LOCAL_WEST, + + LOCAL_RESERVED; public boolean isExclusiveSink() { return this == EXCLUSIVE_SINK || this == EXCLUSIVE_SINK_EAST || this == EXCLUSIVE_SINK_WEST; } public boolean isLocal() { - return this == LOCAL || this == LOCAL_EAST || this == LOCAL_WEST; + return this == LOCAL || this == LOCAL_EAST || this == LOCAL_WEST || this == LOCAL_RESERVED; } } From 1c2b47101992ca8c47e7c1c76b16b647b174e86d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 13 Nov 2024 12:08:25 -0800 Subject: [PATCH 66/71] Allow INODE and PINBOUNCE either side of CTRL sink to be used Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/rwroute/RouteNode.java | 5 +- .../rapidwright/rwroute/RouteNodeGraph.java | 58 +++++++++++-------- 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index 19f50701c..a5a7501d3 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -359,7 +359,10 @@ public void setType(RouteNodeType type) { (this.type.isExclusiveSink() && type == RouteNodeType.LOCAL) || // Or promotion from LOCAL to EXCLUSIVE_SINK (by PartialRouter when NODE_PINBOUNCE on // a newly unpreserved net becomes a sink) - (this.type == RouteNodeType.LOCAL && type.isExclusiveSink())); + (this.type == RouteNodeType.LOCAL && type.isExclusiveSink()) || + // Or promotion for any LOCAL to a LOCAL_RESERVED (by determineRoutingTargets() + // for uphills of CTRL sinks) + (this.type.isLocal() && type == RouteNodeType.LOCAL_RESERVED)); this.type = type; } diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 21b95e29a..e9aa46710 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -710,21 +710,39 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { } break; case EXCLUSIVE_SINK: - // This must be a CTRL sink; these can only be accessed from LOCAL nodes in the sink tile (rather than Y +/- 1 below) - if (childTile != sinkTile) { - return false; - } + // This must be a CTRL sink that can be accessed from both east/west sides + if (isVersal) { assert(sinkRnode.getIntentCode() == IntentCode.NODE_CLE_CTRL || sinkRnode.getIntentCode() == IntentCode.NODE_INTF_CTRL); - // NODE_(CLE|INTF)_CTRL can only be reached by LOCAL_RESERVED nodes - if (type != RouteNodeType.LOCAL_RESERVED) { - return false; + if (childTile == sinkTile) { + // CTRL sinks can be accessed directly from LOCAL_RESERVED nodes in the sink CLE_BC_CORE/INTF_* tile ... + if (type != RouteNodeType.LOCAL_RESERVED) { + return false; + } + } else { + // ... or via LOCAL nodes in the two INT tiles either side + if (childTile.getTileYCoordinate() != sinkTile.getTileYCoordinate() || + Math.abs(childTile.getTileXCoordinate() - sinkTile.getTileXCoordinate()) > 1) { + return false; + } + if (childTile.getTileTypeEnum() != TileTypeEnum.INT) { + // e.g. CLE_BC_CORE_X50Y4 and CLE_BC_CORE_1_X50Y4 on xcvc1502 + return false; + } + // Allow use of INODE + PINBOUNCEs in the two INT tiles on either side of sink + assert(childRnode.getIntentCode() == IntentCode.NODE_INODE || childRnode.getIntentCode() == IntentCode.NODE_PINBOUNCE); + return true; } } else { assert(design.getSeries() == Series.UltraScale || design.getSeries() == Series.UltraScalePlus); assert(sinkRnode.getWireName().startsWith("CTRL_")); + // CTRL sinks can only be accessed from LOCAL nodes in the sink tile (rather than Y +/- 1 below) + if (childTile != sinkTile) { + return false; + } + // Only both-sided wires (e.g. INT_NODE_GLOBAL_*) can reach a both-sided sink (CTRL_*) if (type != RouteNodeType.LOCAL) { return false; @@ -742,32 +760,22 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { } if (isVersal) { + assert(sinkRnode.getType() != RouteNodeType.EXCLUSIVE_SINK); + assert(sinkRnode.getIntentCode() == IntentCode.NODE_IMUX || sinkRnode.getIntentCode() == IntentCode.NODE_PINBOUNCE); + IntentCode childIntentCode = childRnode.getIntentCode(); switch (childIntentCode) { case NODE_INODE: // Block access to all INODEs outside the sink tile, since NODE_INODE -> NODE_IMUX -> NODE_PINFEED (or NODE_INODE -> NODE_PINBOUNCE) + assert(childTile != sinkTile); return false; - case NODE_CLE_CNODE: - case NODE_INTF_CNODE: { - IntentCode sinkIntentCode = sinkRnode.getIntentCode(); - assert(sinkIntentCode == IntentCode.NODE_IMUX || sinkIntentCode == IntentCode.NODE_PINBOUNCE); - - // Only allow CNODEs that reach into the sink tile - return childTile.getTileYCoordinate() == sinkTile.getTileYCoordinate() && - childRnode.getEndTileXCoordinate() == sinkTile.getTileXCoordinate(); - - // // Do not allow CNODEs when not targeting a CTRL sink - // // Note: NODE_{CLE,INTF}_CNODE (x24) -> NODE_INODE arcs (128/328 PIPs, 128/154 nodes) will be ignored - // return false; - } case NODE_CLE_BNODE: - case NODE_INTF_BNODE: { - // Only allow BNODEs that reach into the sink tile - IntentCode sinkIntentCode = sinkRnode.getIntentCode(); - assert(sinkIntentCode == IntentCode.NODE_IMUX || sinkIntentCode == IntentCode.NODE_PINBOUNCE); + case NODE_INTF_BNODE: + case NODE_CLE_CNODE: + case NODE_INTF_CNODE: + // Only allow [BC]NODEs that reach into the sink tile return childTile.getTileYCoordinate() == sinkTile.getTileYCoordinate() && childRnode.getEndTileXCoordinate() == sinkTile.getTileXCoordinate(); - } case NODE_PINBOUNCE: // BOUNCEs are only accessible through INODEs, so transitively this intent code is unreachable break; From 541420686c3d9243fcc0c07298e86ac2530c2aac Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 13 Nov 2024 12:18:54 -0800 Subject: [PATCH 67/71] Update comment Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index e9aa46710..0e0a388e9 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -716,7 +716,7 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { assert(sinkRnode.getIntentCode() == IntentCode.NODE_CLE_CTRL || sinkRnode.getIntentCode() == IntentCode.NODE_INTF_CTRL); if (childTile == sinkTile) { - // CTRL sinks can be accessed directly from LOCAL_RESERVED nodes in the sink CLE_BC_CORE/INTF_* tile ... + // CTRL sinks can be only accessed directly from LOCAL_RESERVED nodes in the sink CLE_BC_CORE/INTF_* tile ... if (type != RouteNodeType.LOCAL_RESERVED) { return false; } From 57ed0514e6d16bbe2a22feababd27a5a9a2b8350 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 13 Nov 2024 14:27:06 -0800 Subject: [PATCH 68/71] Clearer names Signed-off-by: Eddie Hung --- .../rapidwright/rwroute/Connection.java | 4 ++-- .../xilinx/rapidwright/rwroute/RWRoute.java | 22 +++++++++---------- .../xilinx/rapidwright/rwroute/RouteNode.java | 10 ++++----- .../rapidwright/rwroute/RouteNodeGraph.java | 12 +++++----- .../rapidwright/rwroute/RouteNodeInfo.java | 8 +++---- .../rapidwright/rwroute/RouteNodeType.java | 12 +++++----- .../rwroute/TimingAndWirelengthReport.java | 2 +- 7 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/Connection.java b/src/com/xilinx/rapidwright/rwroute/Connection.java index 95a7f87e0..1202b46a8 100644 --- a/src/com/xilinx/rapidwright/rwroute/Connection.java +++ b/src/com/xilinx/rapidwright/rwroute/Connection.java @@ -305,7 +305,7 @@ public void addAltSinkRnode(RouteNode sinkRnode) { } else { assert(!altSinkRnodes.contains(sinkRnode)); } - assert(sinkRnode.getType().isExclusiveSink() || + assert(sinkRnode.getType().isAnyExclusiveSink() || // Can be a WIRE if node is not exclusive a sink sinkRnode.getType() == RouteNodeType.NON_LOCAL); altSinkRnodes.add(sinkRnode); @@ -487,7 +487,7 @@ public void setAllTargets(RWRoute.ConnectionState state) { // where the same physical pin services more than one logical pin if (rnode.countConnectionsOfUser(netWrapper) == 0 || // Except if it is not an EXCLUSIVE_SINK - rnode.getType().isExclusiveSink()) { + rnode.getType().isAnyExclusiveSink()) { assert(rnode.getIntentCode() != IntentCode.NODE_PINBOUNCE); rnode.markTarget(state); } diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 288dd485e..64095bd11 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -332,7 +332,7 @@ protected void determineRoutingTargets() { if (routingGraph.isVersal) { for (Connection connection : indirectConnections) { RouteNode sinkRnode = connection.getSinkRnode(); - if (sinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK) { + if (sinkRnode.getType() == RouteNodeType.EXCLUSIVE_SINK_BOTH) { for (Node uphill : sinkRnode.getAllUphillNodes()) { if (uphill.isTiedToVcc()) { continue; @@ -637,8 +637,8 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_WEST); sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK_WEST); } else { - sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK); - sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK); + sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_BOTH); + sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK_BOTH); } connection.setSinkRnode(sinkRnode); @@ -691,7 +691,7 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { continue; } RouteNode altSinkRnode = routingGraph.getOrCreate(node, sinkRnode.getType()); - assert(altSinkRnode.getType().isExclusiveSink()); + assert(altSinkRnode.getType().isAnyExclusiveSink()); connection.addAltSinkRnode(altSinkRnode); } @@ -1838,7 +1838,7 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { } switch (childRNode.getType()) { case LOCAL_RESERVED: - case LOCAL: + case LOCAL_BOTH: case LOCAL_EAST: case LOCAL_WEST: if (!routingGraph.isAccessible(childRNode, connection)) { @@ -1847,13 +1847,13 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { // Verify invariant that east/west wires stay east/west ... assert(rnode.getType() != RouteNodeType.LOCAL_EAST || childRNode.getType() == RouteNodeType.LOCAL_EAST || // ... unless it's an exclusive sink using a LOCAL_RESERVED node - (childRNode.getType() == RouteNodeType.LOCAL_RESERVED && connection.getSinkRnode().getType() == RouteNodeType.EXCLUSIVE_SINK)); + (childRNode.getType() == RouteNodeType.LOCAL_RESERVED && connection.getSinkRnode().getType() == RouteNodeType.EXCLUSIVE_SINK_BOTH)); assert(rnode.getType() != RouteNodeType.LOCAL_WEST || childRNode.getType() == RouteNodeType.LOCAL_WEST || - (childRNode.getType() == RouteNodeType.LOCAL_RESERVED && connection.getSinkRnode().getType() == RouteNodeType.EXCLUSIVE_SINK)); + (childRNode.getType() == RouteNodeType.LOCAL_RESERVED && connection.getSinkRnode().getType() == RouteNodeType.EXCLUSIVE_SINK_BOTH)); break; case NON_LOCAL: // LOCALs cannot connect to NON_LOCALs except via a LUT routethru - assert(!rnode.getType().isLocal() || + assert(!rnode.getType().isAnyLocal() || routingGraph.lutRoutethru && rnode.getIntentCode() == IntentCode.NODE_PINFEED); if (!routingGraph.isAccessible(childRNode, connection)) { @@ -1865,12 +1865,12 @@ private void exploreAndExpand(ConnectionState state, RouteNode rnode) { continue; } break; - case EXCLUSIVE_SINK: + case EXCLUSIVE_SINK_BOTH: case EXCLUSIVE_SINK_EAST: case EXCLUSIVE_SINK_WEST: assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK_EAST || rnode.getType() == RouteNodeType.LOCAL_EAST); assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK_WEST || rnode.getType() == RouteNodeType.LOCAL_WEST); - assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK || rnode.getType() == RouteNodeType.LOCAL || + assert(childRNode.getType() != RouteNodeType.EXCLUSIVE_SINK_BOTH || rnode.getType() == RouteNodeType.LOCAL_BOTH || // [BC]NODEs are LOCAL_{EAST,WEST} since they connect to INODEs, but also service CTRL sinks (routingGraph.isVersal && EnumSet.of(IntentCode.NODE_CLE_BNODE, IntentCode.NODE_CLE_CNODE, IntentCode.NODE_INTF_BNODE, IntentCode.NODE_INTF_CNODE) @@ -1919,7 +1919,7 @@ protected boolean isAccessibleSink(RouteNode child, Connection connection) { } protected boolean isAccessibleSink(RouteNode child, Connection connection, boolean assertOnOveruse) { - assert(child.getType().isExclusiveSink()); + assert(child.getType().isAnyExclusiveSink()); assert(!assertOnOveruse || !child.isOverUsed()); if (child.isTarget()) { diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index a5a7501d3..c8e35d909 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -124,13 +124,13 @@ private void setBaseCost(Series series) { assert(length == 0 || (length <= 3 && series == Series.Versal)); break; - case EXCLUSIVE_SINK: + case EXCLUSIVE_SINK_BOTH: case EXCLUSIVE_SINK_EAST: case EXCLUSIVE_SINK_WEST: assert(length == 0 || (length == 1 && (series == Series.UltraScalePlus || series == Series.UltraScale) && getIntentCode() == IntentCode.NODE_PINBOUNCE)); break; - case LOCAL: + case LOCAL_BOTH: assert(length == 0); break; case LOCAL_EAST: @@ -356,13 +356,13 @@ public RouteNodeType getType() { public void setType(RouteNodeType type) { assert(this.type == type || // Support demotion from EXCLUSIVE_SINK to LOCAL since they have the same base cost - (this.type.isExclusiveSink() && type == RouteNodeType.LOCAL) || + (this.type.isAnyExclusiveSink() && type == RouteNodeType.LOCAL_BOTH) || // Or promotion from LOCAL to EXCLUSIVE_SINK (by PartialRouter when NODE_PINBOUNCE on // a newly unpreserved net becomes a sink) - (this.type == RouteNodeType.LOCAL && type.isExclusiveSink()) || + (this.type == RouteNodeType.LOCAL_BOTH && type.isAnyExclusiveSink()) || // Or promotion for any LOCAL to a LOCAL_RESERVED (by determineRoutingTargets() // for uphills of CTRL sinks) - (this.type.isLocal() && type == RouteNodeType.LOCAL_RESERVED)); + (this.type.isAnyLocal() && type == RouteNodeType.LOCAL_RESERVED)); this.type = type; } diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java index 0e0a388e9..8b0e45f65 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeGraph.java @@ -550,9 +550,9 @@ protected boolean isExcluded(RouteNode parent, Node child) { // PINFEEDs can lead to a site pin, or into a Laguna tile RouteNode childRnode = getNode(child); if (childRnode != null) { - assert(childRnode.getType().isExclusiveSink() || + assert(childRnode.getType().isAnyExclusiveSink() || childRnode.getType() == RouteNodeType.LAGUNA_PINFEED || - (lutRoutethru && childRnode.getType().isLocal())); + (lutRoutethru && childRnode.getType().isAnyLocal())); } else if (!lutRoutethru) { // child does not already exist in our routing graph, meaning it's not a used site pin // in our design, but it could be a LAGUNA_I @@ -680,7 +680,7 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { // Only consider LOCAL nodes when: // (a) considering LUT routethrus RouteNodeType type = childRnode.getType(); - if (!type.isLocal() || lutRoutethru) { + if (!type.isAnyLocal() || lutRoutethru) { return true; } @@ -709,7 +709,7 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { return false; } break; - case EXCLUSIVE_SINK: + case EXCLUSIVE_SINK_BOTH: // This must be a CTRL sink that can be accessed from both east/west sides if (isVersal) { @@ -744,7 +744,7 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { } // Only both-sided wires (e.g. INT_NODE_GLOBAL_*) can reach a both-sided sink (CTRL_*) - if (type != RouteNodeType.LOCAL) { + if (type != RouteNodeType.LOCAL_BOTH) { return false; } } @@ -760,7 +760,7 @@ public boolean isAccessible(RouteNode childRnode, Connection connection) { } if (isVersal) { - assert(sinkRnode.getType() != RouteNodeType.EXCLUSIVE_SINK); + assert(sinkRnode.getType() != RouteNodeType.EXCLUSIVE_SINK_BOTH); assert(sinkRnode.getIntentCode() == IntentCode.NODE_IMUX || sinkRnode.getIntentCode() == IntentCode.NODE_PINBOUNCE); IntentCode childIntentCode = childRnode.getIntentCode(); diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java index 76e180715..50b223b3c 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeInfo.java @@ -141,7 +141,7 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou } else if (eastWestWires[1].get(node.getWireIndex())) { return RouteNodeType.LOCAL_WEST; } - return RouteNodeType.LOCAL; + return RouteNodeType.LOCAL_BOTH; } break; } @@ -149,7 +149,7 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou case NODE_PINFEED: if (routingGraph == null || routingGraph.isVersal) { - return RouteNodeType.LOCAL; + return RouteNodeType.LOCAL_BOTH; } if (routingGraph.lagunaI != null) { BitSet bs = routingGraph.lagunaI.get(node.getTile()); @@ -174,12 +174,12 @@ private static RouteNodeType getType(Node node, Tile endTile, RouteNodeGraph rou } assert(!routingGraph.isVersal && node.getWireName().startsWith("CTRL_")); } - return RouteNodeType.LOCAL; + return RouteNodeType.LOCAL_BOTH; // Versal only case NODE_CLE_CTRL: // CLE_BC_CORE*.CTRL_[LR]_B* case NODE_INTF_CTRL: // INTF_[LR]OCF_[TB][LR]_TILE.INTF_IRI* - return RouteNodeType.LOCAL; + return RouteNodeType.LOCAL_BOTH; case NODE_LAGUNA_OUTPUT: // UltraScale+ only assert(tileTypeEnum == TileTypeEnum.LAG_LAG); diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java b/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java index eba37caf9..7df6c3bfe 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNodeType.java @@ -28,7 +28,7 @@ public enum RouteNodeType { EXCLUSIVE_SOURCE, - EXCLUSIVE_SINK, + EXCLUSIVE_SINK_BOTH, EXCLUSIVE_SINK_EAST, EXCLUSIVE_SINK_WEST, @@ -46,17 +46,17 @@ public enum RouteNodeType { NON_LOCAL, - LOCAL, + LOCAL_BOTH, LOCAL_EAST, LOCAL_WEST, LOCAL_RESERVED; - public boolean isExclusiveSink() { - return this == EXCLUSIVE_SINK || this == EXCLUSIVE_SINK_EAST || this == EXCLUSIVE_SINK_WEST; + public boolean isAnyExclusiveSink() { + return this == EXCLUSIVE_SINK_BOTH || this == EXCLUSIVE_SINK_EAST || this == EXCLUSIVE_SINK_WEST; } - public boolean isLocal() { - return this == LOCAL || this == LOCAL_EAST || this == LOCAL_WEST || this == LOCAL_RESERVED; + public boolean isAnyLocal() { + return this == LOCAL_BOTH || this == LOCAL_EAST || this == LOCAL_WEST || this == LOCAL_RESERVED; } } diff --git a/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java b/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java index c51cc6789..d57747c92 100644 --- a/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java +++ b/src/com/xilinx/rapidwright/rwroute/TimingAndWirelengthReport.java @@ -128,7 +128,7 @@ private NetWrapper createNetWrapper(Net net) { if (sinkINTNode == null) { connection.setDirect(true); } else { - connection.setSinkRnode(routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK)); + connection.setSinkRnode(routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_BOTH)); if (sourceINTNode == null) { sourceINTNode = RouterHelper.projectOutputPinToINTNode(source); } From 8c0acba90a567670ee12fa9296a3efab400fb494 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 13 Nov 2024 15:31:35 -0800 Subject: [PATCH 69/71] Fix Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/PartialRouter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java index 90435b794..74a5f2d4f 100644 --- a/src/com/xilinx/rapidwright/rwroute/PartialRouter.java +++ b/src/com/xilinx/rapidwright/rwroute/PartialRouter.java @@ -256,7 +256,7 @@ protected void determineRoutingTargets() { preservedNet = routingGraph.getPreservedNet(sinkRnode); if (preservedNet != null && preservedNet != net) { unpreserveNets.add(preservedNet); - assert(sinkRnode.getType().isExclusiveSink()); + assert(sinkRnode.getType().isAnyExclusiveSink()); } } @@ -599,7 +599,7 @@ protected void unpreserveNet(Net net) { RouteNode sourceRnode = connection.getSourceRnode(); RouteNode sinkRnode = connection.getSinkRnode(); assert(sourceRnode.getType() == RouteNodeType.EXCLUSIVE_SOURCE); - assert(sinkRnode.getType().isExclusiveSink()); + assert(sinkRnode.getType().isAnyExclusiveSink()); // Even though this connection is not expected to have any routing yet, // perform a rip up anyway in order to release any exclusive sinks From d1e843a792b8329400b9309d6012bef686a43f90 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 13 Nov 2024 15:57:19 -0800 Subject: [PATCH 70/71] Tidy up Signed-off-by: Eddie Hung --- .../xilinx/rapidwright/rwroute/RWRoute.java | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 64095bd11..b7028f901 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -627,19 +627,16 @@ protected NetWrapper createNetWrapperAndConnections(Net net) { } indirectConnections.add(connection); - BitSet[] eastWestWires = (routingGraph.eastWestWires == null) ? null : - routingGraph.eastWestWires.get(sinkINTNode.getTile().getTileTypeEnum()); - RouteNode sinkRnode; - if (eastWestWires != null && eastWestWires[0].get(sinkINTNode.getWireIndex())) { - sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_EAST); - sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK_EAST); - } else if (eastWestWires != null && eastWestWires[1].get(sinkINTNode.getWireIndex())) { - sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_WEST); - sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK_WEST); - } else { - sinkRnode = routingGraph.getOrCreate(sinkINTNode, RouteNodeType.EXCLUSIVE_SINK_BOTH); - sinkRnode.setType(RouteNodeType.EXCLUSIVE_SINK_BOTH); - } + + RouteNodeInfo rni = RouteNodeInfo.get(sinkINTNode, routingGraph); + assert(rni.type.isAnyLocal()); + RouteNodeType sinkType = rni.type == RouteNodeType.LOCAL_EAST ? RouteNodeType.EXCLUSIVE_SINK_EAST : + rni.type == RouteNodeType.LOCAL_WEST ? RouteNodeType.EXCLUSIVE_SINK_WEST : + rni.type == RouteNodeType.LOCAL_BOTH ? RouteNodeType.EXCLUSIVE_SINK_BOTH : + null; + assert(sinkType != null); + RouteNode sinkRnode = routingGraph.getOrCreate(sinkINTNode, sinkType); + sinkRnode.setType(sinkType); connection.setSinkRnode(sinkRnode); // Where appropriate, allow all 6 LUT pins to be swapped to begin with From f3308126b1a48dbc2faa6eb42f2c3f69fc0b1a5b Mon Sep 17 00:00:00 2001 From: eddieh-xlnx Date: Wed, 13 Nov 2024 20:16:42 -0800 Subject: [PATCH 71/71] [RWRoute] RouteNode.setType() to accept any locals (#1103) Signed-off-by: Eddie Hung --- src/com/xilinx/rapidwright/rwroute/RouteNode.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/xilinx/rapidwright/rwroute/RouteNode.java b/src/com/xilinx/rapidwright/rwroute/RouteNode.java index 8f8f78d12..7a345658a 100644 --- a/src/com/xilinx/rapidwright/rwroute/RouteNode.java +++ b/src/com/xilinx/rapidwright/rwroute/RouteNode.java @@ -367,10 +367,10 @@ public RouteNodeType getType() { public void setType(RouteNodeType type) { assert(this.type == type || // Support demotion from EXCLUSIVE_SINK to LOCAL since they have the same base cost - (this.type.isExclusiveSink() && type == RouteNodeType.LOCAL) || + (this.type.isExclusiveSink() && type.isLocal()) || // Or promotion from LOCAL to EXCLUSIVE_SINK (by PartialRouter when NODE_PINBOUNCE on // a newly unpreserved net becomes a sink) - (this.type == RouteNodeType.LOCAL && type.isExclusiveSink())); + (this.type.isLocal() && type.isExclusiveSink())); this.type = type; }