package com.sun.electric.tool.generator.layout; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import com.sun.electric.database.prototype.PortCharacteristic; import com.sun.electric.database.prototype.PortProto; import com.sun.electric.database.topology.NodeInst; import com.sun.electric.database.topology.PortInst; import com.sun.electric.technology.ArcProto; /** For two Cell instances that abut, connect PortInsts that coincide or * nearly coincide. */ public class AbutRouter { // List of layers, from lowest to highest, that we may // use for routing. private final List<ArcProto> layers; private boolean horizBoundary; private static void prln(String msg) {System.out.println(msg);} private AbutRouter(List<ArcProto> layers) {this.layers=layers;} private double coordParallelToBoundary(PortInst pi) { return horizBoundary ? pi.getCenter().getX() : pi.getCenter().getY(); } private double coordPerpedicularToBoundary(PortInst pi) { return horizBoundary ? pi.getCenter().getY() : pi.getCenter().getX(); } private void sortByCoordParallelToBoundary(List<PortInst> ports) { Collections.sort(ports, new Comparator<PortInst>() { public int compare(PortInst pi1, PortInst pi2) { double delta = coordParallelToBoundary(pi1) - coordParallelToBoundary(pi2); return (int) Math.signum(delta); } } ); } private List<PortInst> findPortsNearBoundary(NodeInst ni, double boundaryXY, double distFromBoundary) { List<PortInst> boundaryPorts = new ArrayList<PortInst>(); for (Iterator<PortInst> piIt=ni.getPortInsts(); piIt.hasNext();) { PortInst pi = piIt.next(); double xy = coordPerpedicularToBoundary(pi); if (Math.abs(xy-boundaryXY)<=distFromBoundary) { boundaryPorts.add(pi); } } sortByCoordParallelToBoundary(boundaryPorts); return boundaryPorts; } private List<PortInst> getAndRemovePortsAtCoord(double xy, List<PortInst> ports) { List<PortInst> portsAtXY = new ArrayList<PortInst>(); while (ports.size()!=0 && coordParallelToBoundary(ports.get(0))==xy) { portsAtXY.add(ports.get(0)); ports.remove(0); } return portsAtXY; } private boolean powerToGroundShort(PortInst pi1, PortInst pi2) { PortCharacteristic ch1 = pi1.getPortProto().getCharacteristic(); PortCharacteristic ch2 = pi2.getPortProto().getCharacteristic(); return (ch1==PortCharacteristic.PWR && ch2==PortCharacteristic.GND) || (ch1==PortCharacteristic.GND && ch2==PortCharacteristic.PWR); } // Return the highest layers that pi can connect to. // Return null if pi can't connect to any of the permitted layers. private ArcProto getHighestLayer(PortInst pi) { PortProto pp = pi.getPortProto(); for (int i=layers.size()-1; i>=0; i--) { ArcProto ap = layers.get(i); if (pp.connectsTo(ap)) return ap; } return null; } private void connectAlignedPorts(List<PortInst> loPorts, List<PortInst> hiPorts) { // N^2 search because we might have more than one layer for (PortInst piB : loPorts) { ArcProto arcB = getHighestLayer(piB); if (arcB==null) continue; for (PortInst piT : hiPorts) { if (piT.getPortProto().connectsTo(arcB)) { if (powerToGroundShort(piB, piT)) { prln("Power and Ground ports overlap: "+piB+" "+piT); continue; } // make a connection double w = LayoutLib.widestWireWidth(piB); // debug //prln("Connecting ports: "+piB+" and "+piT+" using "+arcB+" width "+w); LayoutLib.newArcInst(arcB, w, piB, piT); // only allow each bot port to connect to at most one top port break; } } } } private void abutRouteBotTop(NodeInst bot, NodeInst top, double distFromBoundary) { horizBoundary = true; double botMaxY = bot.findEssentialBounds().getMaxY(); double topMinY = top.findEssentialBounds().getMinY(); abutRoute(bot, top, botMaxY, topMinY, distFromBoundary); } private void abutRoute(NodeInst niLo, NodeInst niHi, double xyLo, double xyHi, double distFromBoundary) { List<PortInst> portsLo = findPortsNearBoundary(niLo, xyLo, distFromBoundary); List<PortInst> portsHi = findPortsNearBoundary(niHi, xyHi, distFromBoundary); while (portsLo.size()!=0 && portsHi.size()!=0) { PortInst firstLo = portsLo.get(0); double loXY = coordParallelToBoundary(firstLo); PortInst firstHi = portsHi.get(0); double hiXY = coordParallelToBoundary(firstHi); if (loXY<hiXY) { portsLo.remove(0); } else if (loXY>hiXY) { portsHi.remove(0); } else { // loXY == hiXY List<PortInst> alignedBotPorts = getAndRemovePortsAtCoord(loXY, portsLo); List<PortInst> alignedTopPorts = getAndRemovePortsAtCoord(loXY, portsHi); connectAlignedPorts(alignedBotPorts, alignedTopPorts); } } } private void abutRouteLeftRight(NodeInst left, NodeInst right, double distFromBoundary) { horizBoundary = false; double leftMaxX = left.findEssentialBounds().getMaxX(); double rightMinX = right.findEssentialBounds().getMinX(); abutRoute(left, right, leftMaxX, rightMinX, distFromBoundary); } /** Connect ports on the top edge of bot that line up exactly * with corresponding ports on the bottom edge of top. Only connect * those ports that attach to metals in layers. * layers must be sorted from lowest to highest */ public static void abutRouteBotTop(NodeInst bot, NodeInst top, double distFromBoundary, List<ArcProto> layers) { AbutRouter ar = new AbutRouter(layers); ar.abutRouteBotTop(bot, top, distFromBoundary); } /** Connect ports on the right edge of left that line up exactly * with corresponding ports on the left edge of right. Only connect * those ports that attach to metals in layers. * layers must be sorted from lowest to highest */ public static void abutRouteLeftRight(NodeInst left, NodeInst right, double distFromBoundary, List<ArcProto> layers) { AbutRouter ar = new AbutRouter(layers); ar.abutRouteLeftRight(left, right, distFromBoundary); } }