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; } }