Skip to content

Commit

Permalink
[NetTools] Add getNodeTrees() method and NodeTree class (#1089)
Browse files Browse the repository at this point in the history
* [NetTools] Add getRouteTrees() method, and NodeTree class

Signed-off-by: Eddie Hung <[email protected]>

* Add TestNetTools.testGetRouteTrees()

Signed-off-by: Eddie Hung <[email protected]>

* [DesignTools] updatePinIsRouted() to use NetTools.getRouteTrees()

Signed-off-by: Eddie Hung <[email protected]>

* Add javadoc and comments

Signed-off-by: Eddie Hung <[email protected]>

* Skip source pins with no fanout

Signed-off-by: Eddie Hung <[email protected]>

* Rename to NetTools.getNodeTrees()

Signed-off-by: Eddie Hung <[email protected]>

---------

Signed-off-by: Eddie Hung <[email protected]>
  • Loading branch information
eddieh-xlnx authored Oct 31, 2024
1 parent 7d74c70 commit 191a949
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 32 deletions.
42 changes: 10 additions & 32 deletions src/com/xilinx/rapidwright/design/DesignTools.java
Original file line number Diff line number Diff line change
Expand Up @@ -4317,49 +4317,27 @@ public static void updatePinsIsRouted(Net net) {
return;
}

Queue<Node> queue = new ArrayDeque<>();
Map<Node, List<Node>> 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<Node, SitePinInst> 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<NetTools.NodeTree> 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<Node> fanouts = node2fanout.remove(node);
if (fanouts != null) {
queue.addAll(fanouts);
}
queue.addAll(node.fanouts);
}
}

Expand Down
98 changes: 98 additions & 0 deletions src/com/xilinx/rapidwright/design/NetTools.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -46,4 +53,95 @@ public static boolean isGlobalClock(Net net) {

return clkSrcSiteTypeEnums.contains(srcSpi.getSiteTypeEnum());
}

public static class NodeTree extends Node {
public List<NodeTree> 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<NodeTree> getNodeTrees(Net net) {
List<NodeTree> subtrees = new ArrayList<>();
Map<Node, NodeTree> 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;
}
}
84 changes: 84 additions & 0 deletions test/src/com/xilinx/rapidwright/design/TestNetTools.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<NetTools.NodeTree> 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]);
}
}
}

0 comments on commit 191a949

Please sign in to comment.