All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.electric.tool.routing.River Maven / Gradle / Ivy

/* -*- tab-width: 4 -*-
 *
 * Electric(tm) VLSI Design System
 *
 * File: River.java
 * Routing tool: River Routing (busses).
 * Original C Code written by Telle Whitney, Schlumberger Palo Alto Research
 * Translated to Java by Steven M. Rubin, Sun Microsystems.
 *
 * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
 *
 * Electric(tm) is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Electric(tm) is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Electric(tm); see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, Mass 02111-1307, USA.
 */
package com.sun.electric.tool.routing;

import com.sun.electric.database.EditingPreferences;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.sun.electric.database.geometry.Poly;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.network.Netlist;
import com.sun.electric.database.network.Network;
import com.sun.electric.database.prototype.NodeProto;
import com.sun.electric.database.prototype.PortProto;
import com.sun.electric.database.topology.ArcInst;
import com.sun.electric.database.topology.Connection;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.topology.PortInst;
import com.sun.electric.database.variable.EditWindow_;
import com.sun.electric.database.variable.UserInterface;
import com.sun.electric.technology.ArcProto;
import com.sun.electric.technology.Layer;
import com.sun.electric.technology.technologies.Generic;
import com.sun.electric.tool.Job;
import com.sun.electric.tool.JobException;
import com.sun.electric.tool.drc.DRC;
import com.sun.electric.util.math.MutableDouble;
import com.sun.electric.util.math.MutableInteger;

/**
 * Class to do river routing.
 * 

* River Routing takes two sets of parallel points (connectors, ports, etc) and routes wires * between them. All wires are routed in a single layer with non intersecting lines. *

 *                       p1        p2         p3      p4
 *                        |        |           |       |  /\ cell_off2
 *                       _|        |           |   ____|  \/
 *                      |          |           |  |
 *                    __|    ______|           |  |
 *                   |      |                  |  |
 *                   |   ___|      ____________|  |
 *                   |  |         | /\ pitch      |
 *                 __|  |      ___| \/____________|
 *  cell_off1 /\  |     |     |    <>|
 *            \/  |     |     |      |
 *               a1    a2    a3     a4
 * 
* Restrictions: *
    *
  • The distance between the ports (p1..pn) and (a1..an) is >= "pitch"
  • *
  • The parameter "width" specifies the width of all wires
    * The parameter "space" specifies the distance between wires
    * pitch = 2*(width/2) + space = space + width
  • *
* The sides: *
 *                        SIDE3
 *       ________________________________________
 *       |  route  |                  |  route  |
 *     S |  right  |                  |  left   | S
 *     I | (last)  |   normal right   | (last)  | I
 *     D |_________|  and left route  |_________| D
 *     E |  route  |     (middle)     |  route  | E
 *     4 |  left   |                  |  right  | 2
 *       | (first) |                  | (first) |
 *       |_________|__________________|_________|
 *                        SIDE1
 * 
*/ public class River { private static final int ROUTEINX = 1; private static final int ROUTEINY = 2; private static final int ILLEGALROUTE = -1; // /** bottom to top -- side 1 to side 3 */ private static final int BOTTOP = 1; // /** side to top -- side 2 or side 4 to side 3 */ private static final int FROMSIDE = 2; // /** bottom to side -- side 1 to side 3 or side 2 */ private static final int TOSIDE = 3; /** list of RDESC objects */ private List rightP, leftP; /** the initial coordinate of the route */ private double fromLine; /** final coordinate of the route */ private double toLine; /** ROUTEINX route in X, ROUTEINY route in Y */ private int routDirection; /** where to start wires on the right */ private double startRight; /** where to start wires on the left */ private double startLeft; /** linked list of possible routing coordinates */ private RCOORD xAxis, yAxis; private double height; private double routBoundLX, routBoundLY, routBoundHX, routBoundHY; private double wireBoundLX, wireBoundLY, wireBoundHX, wireBoundHY; private NodeInst moveCell; private boolean moveCellValid; private final EditingPreferences ep; /** * Class for transformations. */ static class TRANSFORM { private double t11, t12; private double t21, t22; TRANSFORM(double t11, double t12, double t21, double t22) { this.t11 = t11; this.t12 = t12; this.t21 = t21; this.t22 = t22; } } /** X increasing, y2>y1 */ private static final TRANSFORM xfNoRot = new TRANSFORM( 1, 0, 0, 1); /** Y decreasing, x2>x1 */ private static final TRANSFORM xfRot90 = new TRANSFORM( 0, 1, -1, 0); /** X decreasing, y2y1 mirror X, around Y axis */ private static final TRANSFORM xfMirrorX = new TRANSFORM(-1, 0, 0, 1); /** Y increasing, x2>x1 rot90 and mirror X */ private static final TRANSFORM xfRot90MirrorX = new TRANSFORM( 0, 1, 1, 0); /** X increasing, y2 arcsToRoute; protected RiverRouteJob(Cell cell) { super("River Route", Routing.getRoutingTool(), Job.Type.CHANGE, null, null, Job.Priority.USER); this.cell = cell; // make a list of arcs to route arcsToRoute = new ArrayList(); boolean foundSome = false; UserInterface ui = Job.getUserInterface(); EditWindow_ wnd = ui.getCurrentEditWindow_(); if (wnd != null) { Set nets = wnd.getHighlightedNetworks(); if (nets.size() != 0) { Netlist netList = cell.getNetlist(); if (netList == null) { System.out.println("Sorry, a deadlock aborted routing (network information unavailable). Please try again"); return; } // add all highlighted arcs to the list for(Iterator it = cell.getArcs(); it.hasNext(); ) { ArcInst ai = it.next(); Network net = netList.getNetwork(ai, 0); if (nets.contains(net)) arcsToRoute.add(ai); } foundSome = true; } } if (!foundSome) { // add all arcs in the cell to the list for(Iterator it = cell.getArcs(); it.hasNext(); ) { ArcInst ai = it.next(); arcsToRoute.add(ai); } } startJob(); } @Override public boolean doIt() throws JobException { River router = new River(getEditingPreferences()); router.river(cell, arcsToRoute); return true; } @Override public void terminateOK() { // UserInterface ui = Job.getUserInterface(); // EditWindow_ wnd = ui.getCurrentEditWindow_(); // if (wnd != null) // { // wnd.clearHighlighting(); // wnd.finishedHighlighting(); // } } } public River(EditingPreferences ep) { this.ep = ep; } /** * This is the public interface for River Routing when done in batch mode. * @param cell the cell to be River-routed. */ public void river(Cell cell, List arcsToRoute) { // locate wires if (findWires(cell, arcsToRoute)) { // make wires for(RDESC q : rightP) { checkTheCell(q.unroutedWire2.getPortInst(q.unroutedEnd2).getNodeInst()); } for(RDESC q : leftP) { checkTheCell(q.unroutedWire2.getPortInst(q.unroutedEnd2).getNodeInst()); } // if there is motion to be done, do it if (moveCellValid && moveCell != null) { if (moveInstance()) makeTheGeometry(cell); } else makeTheGeometry(cell); } } /*************************************** CODE TO DO RIVER ROUTING ***************************************/ /** * once the route occurs, make some geometry and move some cells around */ private void checkTheCell(NodeInst ni) { if (ni.isCellInstance()) { // the node is nonprimitive if (!moveCellValid) return; if (moveCell == null) // first one moveCell = ni; else if (moveCell != ni) moveCellValid = false; } } private boolean findWires(Cell cell, List arcsToRoute) { initialize(); // reset flags on all arcs in this cell Set arcsSeen = new HashSet(); // make a list of RDESC objects List theList = new ArrayList(); // put all arcs to route into these collections for(ArcInst ai : arcsToRoute) addWire(theList, ai, arcsSeen); // determine bounds of the routes boolean first = true; for(RDESC rdesc : theList) { if (first) { routBoundLX = Math.min(rdesc.from.x, rdesc.to.x); routBoundLY = Math.min(rdesc.from.y, rdesc.to.y); routBoundHX = Math.max(rdesc.from.x, rdesc.to.x); routBoundHY = Math.max(rdesc.from.y, rdesc.to.y); } else { routBoundLX = Math.min(Math.min(routBoundLX, rdesc.from.x), rdesc.to.x); routBoundLY = Math.min(Math.min(routBoundLY, rdesc.from.y), rdesc.to.y); routBoundHX = Math.max(Math.max(routBoundHX, rdesc.from.x), rdesc.to.x); routBoundHY = Math.max(Math.max(routBoundHY, rdesc.from.y), rdesc.to.y); } } // figure out which ArcProto to use Map arcProtoUsage = new HashMap(); for(RDESC rd : theList) { sumUp(rd.unroutedWire1.getPortInst(rd.unroutedEnd1), arcProtoUsage); sumUp(rd.unroutedWire2.getPortInst(rd.unroutedEnd2), arcProtoUsage); } // find the most popular ArcProto ArcProto wantAp = null; int mostUses = -1; int total = 0; for(ArcProto ap : arcProtoUsage.keySet()) { MutableInteger mi = arcProtoUsage.get(ap); if (mi == null) continue; total += mi.intValue(); if (mi.intValue() > mostUses) { mostUses = mi.intValue(); wantAp = ap; } } if (wantAp == null) { System.out.println("River router: Cannot find arc that will connect"); return false; } System.out.println("River routing with " + wantAp.describe() + " arcs"); figureOutRails(total); setWiresToRails(theList); // figure out the worst design rule spacing for this type of arc Layer layer = wantAp.getLayerIterator().next(); MutableDouble mutableDist = new MutableDouble(0); boolean found = DRC.getMaxSurround(layer, Double.MAX_VALUE, mutableDist); double amt = mutableDist.doubleValue(); if (!found) amt = 1; // if (amt < 0) amt = 1; return unsortedRivRot(wantAp, theList, wantAp.getDefaultLambdaBaseWidth(ep), amt, amt, amt); } /** * takes two unsorted list of ports and routes between them * warning - if the width is not even, there will be round off problems */ private boolean unsortedRivRot(ArcProto layerDesc, List lists, double width, double space, double cellOff1, double cellOff2) { for(RDESC rd : lists) { rd.sortVal = (routDirection != ROUTEINX ? rd.from.x : rd.from.y); } Collections.sort(lists, new SortRDESC()); return sortedRivRot(layerDesc, lists, width, space, cellOff1, cellOff2); } private static class SortRDESC implements Comparator { public int compare(RDESC r1, RDESC r2) { if (r1.sortVal == r2.sortVal) return 0; if (r1.sortVal > r2.sortVal) return 1; return -1; } } /** * takes two sorted list of ports and routes between them * warning - if the width is not even, there will be round off problems */ private boolean sortedRivRot(ArcProto layerDesc, List listR, double width, double space, double cellOff1, double cellOff2) { // ports invalid if (!checkPoints(listR, width, space)) return false; structurePoints(listR); // put in left/right if (!checkStructuredPoints(rightP, leftP, cellOff1, width, space)) return false; if (processRight(width, layerDesc, rightP, cellOff1, space, -1)) return false; if (processLeft(width, layerDesc, leftP, cellOff1, space, 1)) return false; Double dHeight = calculateHeightAndProcess(rightP, leftP, width, cellOff2); if (dHeight == null) return false; calculateBB(rightP, leftP); height = dHeight.doubleValue(); return true; } private void calculateBB(List right, List left) { routBoundLX = routBoundLY = Double.MAX_VALUE; routBoundHX = routBoundHY = -Double.MAX_VALUE; for(RDESC rRight : right) { for(RPOINT rvp = rRight.path.pathDesc; rvp != null; rvp = rvp.next) { routBoundLX = Math.min(routBoundLX, rvp.x); routBoundLY = Math.min(routBoundLY, rvp.y); routBoundHX = Math.max(routBoundHX, rvp.x); routBoundHY = Math.max(routBoundHY, rvp.y); } } for(RDESC lLeft : left) { for(RPOINT rvp = lLeft.path.pathDesc; rvp != null; rvp = rvp.next) { routBoundLX = Math.min(routBoundLX, rvp.x); routBoundLY = Math.min(routBoundLY, rvp.y); routBoundHX = Math.max(routBoundHX, rvp.x); routBoundHY = Math.max(routBoundHY, rvp.y); } } } private Double calculateHeightAndProcess(List right, List left, double width, double co2) { double minHeight = 0; double maxHeight = Double.MIN_VALUE; for(RDESC rd : right) { maxHeight = Math.max(maxHeight, rd.path.lastP.second); } for(RDESC rd : left) { maxHeight = Math.max(maxHeight, rd.path.lastP.second); } if (minHeight != 0) maxHeight = Math.max(minHeight, maxHeight+(width/2)+co2); else maxHeight = maxHeight+(width/2)+co2; maxHeight = Math.max(maxHeight, toLine); // make sure its at least where the coordinates are for(RDESC rd : right) { RPOINT lastP = rd.path.lastP; if (lastP.side != RPOINT.SIDE2) { lastP.next = new RPOINT(rd.path, lastP.first, maxHeight, null); } remapPoints(rd.path.pathDesc, xfInverse); } for(RDESC rd : left) { RPOINT lastP = rd.path.lastP; if (lastP.side != RPOINT.SIDE4) { lastP.next = new RPOINT(rd.path, lastP.first, maxHeight, null); } remapPoints(rd.path.pathDesc, xfInverse); } toLine = remapSecond(toLine, xfInverse); fromLine = remapSecond(fromLine, xfInverse); return new Double(remapSecond(maxHeight, xfInverse)); } /** * calculate the height of the channel, and remap the points back into the * original coordinate system */ private void remapPoints(RPOINT rp, TRANSFORM matrix) { for(; rp != null; rp = rp.next) { rp.x = (rp.first*matrix.t11) + (rp.second*matrix.t21); rp.y = (rp.first*matrix.t12) + (rp.second*matrix.t22); } } private double remapSecond(double sec, TRANSFORM matrix) { if (routDirection == ROUTEINY) return sec * matrix.t22; return sec * matrix.t12; } private boolean processLeft(double width, ArcProto ptype, List rout, double co1, double space, double dir) { boolean firstTime = true; RPATH lastP = null; double offset = startRight; for(RDESC rd : rout) { if (rd.from.side != RPOINT.SIDE2) { if (firstTime) { rd.path = makeOrigPath(width, ptype, co1, rd.from, rd.to); if (rd.path == null) return true; firstTime = false; } else rd.path = addPath(lastP, width, ptype, rd.from, rd.to, space, co1, dir); if (rd.path == null) return true; } else { if (firstTime) { rd.path = makeSideOrigPath(width, ptype, offset, rd.from, rd.to); if (rd.path == null) return true; firstTime = false; } else { rd.path = sideAddPath(lastP, width, ptype, rd.from, rd.to, space, offset, dir); if (rd.path == null) return true; } offset += space+width; } lastP = rd.path; } return false; } private boolean processRight(double width, ArcProto ptype, List rout, double co1, double space, int dir) { boolean firstTime = true; RPATH lastP = null; double offset = startLeft; reverse(rout); for(RDESC rd : rout) { if (rd.from.side != RPOINT.SIDE4) { // starting from bottom (side1) if (firstTime) { rd.path = makeOrigPath(width, ptype, co1, rd.from, rd.to); if (rd.path == null) return true; firstTime = false; } else rd.path = addPath(lastP, width, ptype, rd.from, rd.to, space, co1, dir); if (rd.path == null) return true; } else { if (firstTime) { rd.path = makeSideOrigPath(width, ptype, offset, rd.from, rd.to); if (rd.path == null) return true; firstTime = false; } else { rd.path = sideAddPath(lastP, width, ptype, rd.from, rd.to, space, offset, dir); if (rd.path == null) return true; } offset += space+width; } lastP = rd.path; } reverse(rout); // return to normal return false; } private RPATH sideAddPath(RPATH path, double width, ArcProto ptype, RPOINT b, RPOINT t, double space, double offset, double dir) { RPATH rp = new RPATH(width, ptype); rp.pathDesc = new RPOINT(rp, b.first, offset, null); double minFirst = Math.min(b.first, t.first); double maxFirst = Math.max(b.first, t.first); RPOINT lp = path.pathDesc; RPOINT lastP = rp.lastP; double newfirst = lp.first+dir*(space+rp.width); while (lp != null && minFirst <= newfirst && newfirst <= maxFirst) { // if first point then inconsistent second(y) offset if (lp == path.pathDesc) lastP.next = new RPOINT(rp, newfirst, Math.min(lastP.second, offset), null); else lastP.next = new RPOINT(rp, newfirst, Math.max(lp.second+space+rp.width, offset), null); lastP = lastP.next; lp = lp.next; if (lp != null) newfirst = lp.first+dir*(space+rp.width); } lastP.next = new RPOINT(rp, t.first, lastP.second, null); rp.lastP.side = t.side; return(rp); } private RPATH addPath(RPATH path, double width, ArcProto ptype, RPOINT b, RPOINT t, double space, double co1, double dir) { RPATH rp = new RPATH(width, ptype); RPOINT i1 = new RPOINT(rp, b.first, b.second+(rp.width/2)+co1, null); rp.pathDesc = new RPOINT(rp, b.first, b.second, i1); double minFirst = Math.min(b.first, t.first); double maxFirst = Math.max(b.first, t.first); RPOINT lp = path.pathDesc; RPOINT lastP = rp.lastP; double newfirst = lp.first+dir*(space+rp.width); while (lp != null && minFirst <= newfirst && newfirst <= maxFirst) { // if first point then inconsistent second(y) offset if (lp == path.pathDesc) lastP.next = new RPOINT(rp, newfirst, lastP.second, null); else lastP.next = new RPOINT(rp, newfirst, lp.second+space+rp.width, null); lastP = lastP.next; lp = lp.next; if (lp != null) newfirst = lp.first+dir*(space+rp.width); } lastP.next = new RPOINT(rp, t.first, lastP.second, null); rp.lastP.side = t.side; return rp; } private RPATH makeOrigPath(double width, ArcProto ptype, double co1, RPOINT b, RPOINT t) { RPATH rp = new RPATH(width, ptype); RPOINT i1 = new RPOINT(rp, t.first, b.second+(width/2)+co1, null); RPOINT i2 = new RPOINT(rp, b.first, b.second+(width/2)+co1, i1); rp.pathDesc = new RPOINT(rp, b.first, b.second, i2); rp.lastP.side = t.side; return rp; } private RPATH makeSideOrigPath(double width, ArcProto ptype, double startoff, RPOINT b, RPOINT t) { RPATH rp = new RPATH(width, ptype); RPOINT i1 = new RPOINT(rp, t.first, startoff, null); rp.pathDesc = new RPOINT(rp, b.first, startoff, i1); rp.lastP.side = t.side; return rp; } private void reverse(List p) { int total = p.size(); if (total <= 1) return; for(int i=0; i right, List left, double co1, double width, double space) { boolean fromSide1 = false; boolean toSide2 = false; double botOffs2 = 0; // ensure ordering is correct for(RDESC r : right) { switch (r.from.side) { case RPOINT.SIDE1: fromSide1 = true; break; case RPOINT.SIDE4: if (fromSide1) { System.out.println("River router: Improper ordering of bottom right ports"); return false; } break; default: System.out.println("River router: Improper sides for bottom right ports (" + RPOINT.sideName(r.from.side) + ")"); return false; } switch (r.to.side) { case RPOINT.SIDE2: if (!toSide2) botOffs2 = fromLine+co1+(width/2); else botOffs2 += space+width; toSide2 = true; break; case RPOINT.SIDE3: if (toSide2) { System.out.println("River router: Improper ordering of top right ports"); return false; } break; default: System.out.println("River router: Improper sides for top right ports"); return false; } } boolean fromSide2 = false; boolean toSide3 = false; boolean toSide4 = false; double botOffs4 = 0; for(RDESC l : left) { switch (l.from.side) { case RPOINT.SIDE1: if (fromSide2) { System.out.println("River router: Improper Ordering of Bottom Left Ports"); return false; } break; case RPOINT.SIDE2: fromSide2 = true; break; default: System.out.println("River router: Improper sides for Bottom Left Ports"); return false; } switch (l.to.side) { case RPOINT.SIDE3: toSide3 = true; break; case RPOINT.SIDE4: if (!toSide3) { if (!toSide4) botOffs4 = fromLine+co1+(width/2); else botOffs4 += space+width; } else { System.out.println("River router: Improper Ordering of Top Left Ports"); return false; } toSide4 = true; break; default: System.out.println("River router: Improper sides for Top Left Ports"); return false; } } if (botOffs2 == 0) startRight = fromLine+co1+(width/2); else startRight = botOffs2+space+width; if (botOffs4 == 0) startLeft = fromLine+co1+(width/2); else startLeft = botOffs4+space+width; return true; } private void structurePoints(List listr) { rightP = new ArrayList(); leftP = new ArrayList(); for(RDESC rd : listr) { if (rd.to.first >= rd.from.first) rightP.add(rd); else leftP.add(rd); } } private boolean checkPoints(List rdescList, double width, double space) { int numRDesc = rdescList.size(); if (numRDesc == 0) { // need at least one point System.out.println("River router: Not enought points"); return false; } RDESC listLast = rdescList.get(numRDesc-1); if (listLast.from == null || listLast.to == null) { System.out.println("River router: Not the same number of points"); return false; } // decide route orientation RDESC listP = rdescList.get(0); TRANSFORM tMatrix = null; double val1 = 0, val2 = 0; if (routDirection == ROUTEINX) { // route in x direction if (listP.to.x >= listP.from.x) { // x2>x1 if (listLast.from.y >= listP.from.y) tMatrix = xfRot90MirrorX; // Y increasing else tMatrix = xfRot90; // Y decreasing } else { // x2= listP.from.y) tMatrix = xfRot270; // Y increasing else tMatrix = xfMirrorXRot90; // Y decreasing } val1 = fromLine = fromLine * tMatrix.t12; val2 = toLine = toLine * tMatrix.t12; } else if (routDirection == ROUTEINY) { // route in y direction if (listP.to.y >= listP.from.y) { // y2>y1 if (listLast.from.x >= listP.from.x) tMatrix = xfNoRot; // X increasing else tMatrix = xfMirrorX; // X decreasing } else { // y2= listP.from.x) tMatrix = xfMirrorY; // X increasing else tMatrix = xfRot180; // X decreasing } val1 = fromLine = fromLine * tMatrix.t22; val2 = toLine = toLine * tMatrix.t22; } else { System.out.println("River router: Not between two parallel lines"); return false; // not on manhattan parallel lines } // check ordering of coordinates for(int i=0; i lListNext.from.x && lList.to.x < lListNext.to.x) || (lList.from.x < lListNext.from.x && lList.to.x > lListNext.to.x)) { System.out.println("River router: Connections may not cross"); return false; } } else { if ((lList.from.y > lListNext.from.y && lList.to.y < lListNext.to.y) || (lList.from.y < lListNext.from.y && lList.to.y > lListNext.to.y)) { System.out.println("River router: Connections may not cross"); return false; } } } double bound1 = routBoundLX * tMatrix.t11 + routBoundLY * tMatrix.t21; double bound2 = routBoundHX * tMatrix.t11 + routBoundHY * tMatrix.t21; if (bound2 < bound1) { double temp = bound2; bound2 = bound1; bound1 = temp; } RPOINT lastFrom = null; RPOINT lastTo = null; // transform points and clip to boundary for(RDESC lList : rdescList) { lList.from.first = (lList.from.x * tMatrix.t11) + (lList.from.y * tMatrix.t21); lList.from.second = (lList.from.x * tMatrix.t12) + (lList.from.y * tMatrix.t22); lList.to.first = (lList.to.x * tMatrix.t11) + (lList.to.y * tMatrix.t21); lList.to.second = (lList.to.x * tMatrix.t12) + (lList.to.y * tMatrix.t22); if (lList.from.second != val1) clipWire(lList.from, bound1, bound2); if (lList.to.second != val2) clipWire(lList.to, bound1, bound2); if (lastFrom != null && lList.from.side == RPOINT.SIDE1) { double diff1 = Math.abs(lastFrom.first - lList.from.first); if (diff1 < width+space) { System.out.println("River router: Ports not design rule distance apart"); return false; } } if (lastTo != null && lList.to.side == RPOINT.SIDE3) { double diff2 = Math.abs(lastTo.first - lList.to.first); if (diff2 < width+space) { System.out.println("River router: Ports not design rule distance apart"); return false; } } // not far enough apart lastFrom = (lList.from.side == RPOINT.SIDE1) ? lList.from : null; lastTo = (lList.to.side == RPOINT.SIDE3) ? lList.to : null; } // matrix to take route back to original coordinate system xfInverse.t11 = tMatrix.t11; xfInverse.t12 = tMatrix.t21; xfInverse.t21 = tMatrix.t12; xfInverse.t22 = tMatrix.t22; fromLine = val1; toLine = val2; return true; } private void clipWire(RPOINT p, double b1, double b2) { double diff1 = Math.abs(b1 - p.first); double diff2 = Math.abs(b2 - p.first); if (diff1 < diff2) { p.first = b1; p.side = RPOINT.SIDE4; } else { p.first = b2; p.side = RPOINT.SIDE2; } } private void setWiresToRails(List lists) { for(RDESC r : lists) { double fVal = pointVal(r.from, routDirection); double tVal = pointVal(r.to, routDirection); if ((fVal != fromLine && tVal == fromLine) || (tVal != toLine && fVal == toLine)) swapPoints(r); } } private void swapPoints(RDESC r) { if (r.from.side != RPOINT.SIDE1 || r.to.side != RPOINT.SIDE3) System.out.println("River router: Unexpected side designation"); RPOINT tmp = r.from; r.from = r.to; r.to = tmp; r.from.side = RPOINT.SIDE1; r.to.side = RPOINT.SIDE3; ArcInst tmpwire = r.unroutedWire1; int tmpe = r.unroutedEnd1; r.unroutedWire1 = r.unroutedWire2; r.unroutedEnd1 = r.unroutedEnd2; r.unroutedWire2 = tmpwire; r.unroutedEnd2 = tmpe; } private double pointVal(RPOINT rp, int xx) { return xx == ROUTEINX ? rp.x : rp.y; } private void figureOutRails(int total) { RCOORD lX = largest(xAxis); RCOORD lY = largest(yAxis); RCOORD nLX = nextLargest(xAxis, lX); RCOORD nLY = nextLargest(yAxis, lY); // determine the type of route RCOORD from = null; RCOORD to = null; int fxx = ILLEGALROUTE; if (lX != null && nLX != null && lX.total == total && nLX.total == total) { from = lX; to = nLX; fxx = ROUTEINX; } else if (lY != null && nLY != null && lY.total == total && nLY.total == total) { from = lY; to = nLY; fxx = ROUTEINY; } else if (lX != null && lX.total == (2*total)) { from = to = lX; fxx = ROUTEINX; } else if (lY != null && lY.total == (2*total)) { from = to = lY; fxx = ROUTEINY; } if (fxx == ILLEGALROUTE) { if (lX.total >= total) { // lX.total == total --- the other one an unusual case // lX.total > total --- both go to the same line fxx = ROUTEINX; from = lX; to = (lX.total > total ? lX : nLX); } else if (lY.total >= total) { // lY.total == total --- the other one an unusual case // lY.total > total --- both go to the same line fxx = ROUTEINY; from = lY; to = (lY.total > total ? lY : nLY); } else { fxx = (((lY.total+nLY.total)>=(lX.total+nLX.total)) ? ROUTEINY : ROUTEINX); from = (fxx == ROUTEINY ? lY : lX); to = (fxx == ROUTEINY ? nLY : nLX); } } if (to.val < from.val) { RCOORD tmp = from; from = to; to = tmp; } routDirection = fxx; fromLine = from.val; toLine = to.val; } private RCOORD largest(RCOORD cc) { RCOORD largest = cc; for(; cc != null; cc = cc.next) { if (cc.total > largest.total) largest = cc; } return largest; } private RCOORD nextLargest(RCOORD cc, RCOORD largest) { RCOORD nLargest = null; for( ; cc != null; cc = cc.next) { if (nLargest == null && cc != largest) nLargest = cc; else if (nLargest != null && cc != largest && cc.total > nLargest.total) nLargest = cc; } return nLargest; } /** * for every layer (or arcproto) that this PORT allows to connect to it, * increment the flag bits (temp1) IN the prototype thus indicating that * this river route point is allowed to connect to it */ private void sumUp(PortInst pi, Map arcProtoUsage) { ArcProto [] possibleArcs = pi.getPortProto().getBasePort().getConnections(); for(int i=0; i list, ArcInst ai, Set arcsSeen) { if (!isInterestingArc(ai, arcsSeen)) return; arcsSeen.add(ai); ArcInst ae1 = ai; int e1 = 0; for(;;) { NodeInst ni = ae1.getPortInst(e1).getNodeInst(); if (!isUnroutedPin(ni)) break; ArcInst oAi = null; for(Iterator it = ni.getConnections(); it.hasNext(); ) { Connection con = it.next(); oAi = con.getArc(); if (!arcsSeen.contains(oAi)) break; oAi = null; } if (oAi == null) break; arcsSeen.add(oAi); if (oAi.getPortInst(0).getNodeInst() == ni) e1 = 1; else e1 = 0; ae1 = oAi; } ArcInst ae2 = ai; int e2 = 1; for(;;) { NodeInst ni = ae2.getPortInst(e2).getNodeInst(); if (!isUnroutedPin(ni)) break; ArcInst oAi = null; for(Iterator it = ni.getConnections(); it.hasNext(); ) { Connection con = it.next(); oAi = con.getArc(); if (!arcsSeen.contains(oAi)) break; oAi = null; } if (oAi == null) break; arcsSeen.add(oAi); if (oAi.getPortInst(0).getNodeInst() == ni) e2 = 1; else e2 = 0; ae2 = oAi; } PortInst pi1 = ae1.getPortInst(e1); Poly poly1 = pi1.getPoly(); double bx = poly1.getCenterX(); double by = poly1.getCenterY(); PortInst pi2 = ae2.getPortInst(e2); Poly poly2 = pi2.getPoly(); double ex = poly2.getCenterX(); double ey = poly2.getCenterY(); RDESC rd = new RDESC(bx, by, RPOINT.SIDE1, ex, ey, RPOINT.SIDE3, ae1, e1, ae2, e2); list.add(rd); vote(rd.from.x, rd.from.y, rd.to.x, rd.to.y); } private void vote(double ffx, double ffy, double ttx, double tty) { xAxis = tallyVote(xAxis, ffx); yAxis = tallyVote(yAxis, ffy); xAxis = tallyVote(xAxis, ttx); yAxis = tallyVote(yAxis, tty); } /** * Figure out which way to route (x and y) and the top coordinate and * bottom coordinate */ private RCOORD tallyVote(RCOORD cc, double c) { if (cc == null) { cc = new RCOORD(c); cc.total = 1; return cc; } RCOORD ccInit = cc; RCOORD ccLast = null; for( ; (cc != null && cc.total >= 0 && cc.val != c); ccLast = cc, cc = cc.next) ; if (cc == null) { cc = new RCOORD(c); ccLast.next = cc; cc.total = 1; return ccInit; } if (cc.total < 0) { cc.val = c; cc.total = 1; } else cc.total++; return ccInit; } private boolean isInterestingArc(ArcInst ai, Set arcsSeen) { // skip arcs already considered if (arcsSeen.contains(ai)) return false; // only want "unrouted" arc in generic technology if (ai.getProto() != Generic.tech().unrouted_arc) return false; return true; } /** * Method to return true if nodeinst "ni" is an unrouted pin */ private boolean isUnroutedPin(NodeInst ni) { // only want the unrouted pin if (ni.getProto() != Generic.tech().unroutedPinNode && ni.getProto() != Generic.tech().universalPinNode) return false; // found one return true; } /*************************************** CODE TO GENERATE CIRCUITRY ***************************************/ private void makeTheGeometry(Cell cell) { Set arcsToDelete = new HashSet(); Set nodesToDelete = new HashSet(); for(RDESC q : rightP) { makeGeometry(q, cell); markToBeDeleted(q.unroutedWire1, arcsToDelete, nodesToDelete); if (q.unroutedWire1 != q.unroutedWire2) markToBeDeleted(q.unroutedWire2, arcsToDelete, nodesToDelete); } for(RDESC q : leftP) { makeGeometry(q, cell); markToBeDeleted(q.unroutedWire2, arcsToDelete, nodesToDelete); if (q.unroutedWire1 != q.unroutedWire2) markToBeDeleted(q.unroutedWire2, arcsToDelete, nodesToDelete); } killWires(cell, arcsToDelete, nodesToDelete); } private void markToBeDeleted(ArcInst ai, Set arcsToDelete, Set nodesToDelete) { if (!isInterestingArc(ai, arcsToDelete)) return; setFlags(ai, arcsToDelete, nodesToDelete); ArcInst ae = ai; int e = 0; for(;;) { NodeInst ni = ae.getPortInst(e).getNodeInst(); if (!isUnroutedPin(ni)) break; ArcInst oAi = null; for(Iterator it = ni.getConnections(); it.hasNext(); ) { Connection con = it.next(); oAi = con.getArc(); if (!arcsToDelete.contains(oAi)) break; oAi = null; } if (oAi == null) break; setFlags(oAi, arcsToDelete, nodesToDelete); if (oAi.getPortInst(0).getNodeInst() == ae.getPortInst(e).getNodeInst()) e = 1; else e = 0; ae = oAi; } ae = ai; e = 1; for(;;) { NodeInst ni = ae.getPortInst(e).getNodeInst(); if (!isUnroutedPin(ni)) break; ArcInst oAi = null; for(Iterator it = ni.getConnections(); it.hasNext(); ) { Connection con = it.next(); oAi = con.getArc(); if (!arcsToDelete.contains(oAi)) break; oAi = null; } if (oAi == null) break; setFlags(oAi, arcsToDelete, nodesToDelete); if (oAi.getPortInst(0).getNodeInst() == ae.getPortInst(e).getNodeInst()) e = 1; else e = 0; ae = oAi; } } private void setFlags(ArcInst ai, Set arcsToDelete, Set nodesToDelete) { arcsToDelete.add(ai); NodeInst niH = ai.getHeadPortInst().getNodeInst(); if (isUnroutedPin(niH)) nodesToDelete.add(niH); NodeInst niT = ai.getTailPortInst().getNodeInst(); if (isUnroutedPin(niT)) nodesToDelete.add(niT); } private void killWires(Cell cell, Set arcsToDelete, Set nodesToDelete) { for(ArcInst ai : arcsToDelete) { ai.kill(); } for(NodeInst ni : nodesToDelete) { if (isUnroutedPin(ni)) delNodeInst(ni); } } private void delNodeInst(NodeInst ni) { // see if any arcs connect to this node if (ni.hasConnections()) return; // see if this nodeinst is a portinst of the cell if (ni.hasExports()) return; // now erase the nodeinst ni.kill(); } /** * make electric geometry */ private void makeGeometry(RDESC rd, Cell cell) { RPATH path = rd.path; Poly poly1 = rd.unroutedWire1.getPortInst(rd.unroutedEnd1).getPoly(); wireBoundLX = poly1.getCenterX(); wireBoundLY = poly1.getCenterY(); Poly poly2 = rd.unroutedWire2.getPortInst(rd.unroutedEnd2).getPoly(); wireBoundHX = poly2.getCenterX(); wireBoundHY = poly2.getCenterY(); NodeProto defNode = path.pathType.findPinProto(); PortProto defPort = defNode.getPort(0); // there is always only one RPOINT prev = path.pathDesc; NodeInst prevNodeInst = theNode(rd, defNode, prev, cell); PortProto prevPort = thePort(defPort, rd, prev); PortInst prevPi = prevNodeInst.findPortInstFromProto(prevPort); for(RPOINT rp = prev.next; rp != null; rp = rp.next) { if (rp.next != null) { if (prev.x == rp.x && rp.x == rp.next.x) continue; if (prev.y == rp.y && rp.y == rp.next.y) continue; } NodeInst rpNodeInst = theNode(rd, defNode, rp, cell); PortProto rpPort = thePort(defPort, rd, rp); PortInst rpPi = rpNodeInst.findPortInstFromProto(rpPort); ArcInst.makeInstanceBase(path.pathType, ep, path.width, prevPi, rpPi); prev = rp; prevPi = rpPi; } } private NodeInst theNode(RDESC rd, NodeProto dn, RPOINT p, Cell cell) { if (p.x == wireBoundLX && p.y == wireBoundLY) return rd.unroutedWire1.getPortInst(rd.unroutedEnd1).getNodeInst(); if (p.x == wireBoundHX && p.y == wireBoundHY) return rd.unroutedWire2.getPortInst(rd.unroutedEnd2).getNodeInst(); double wid = dn.getDefWidth(ep); double hei = dn.getDefHeight(ep); NodeInst ni = NodeInst.makeInstance(dn, ep, new Point2D.Double(p.x, p.y), wid, hei, cell); return ni; } private PortProto thePort(PortProto dp, RDESC rd, RPOINT p) { if (p.x == wireBoundLX && p.y == wireBoundLY) return rd.unroutedWire1.getPortInst(rd.unroutedEnd1).getPortProto(); if (p.x == wireBoundHX && p.y == wireBoundHY) return rd.unroutedWire2.getPortInst(rd.unroutedEnd2).getPortProto(); return dp; } private boolean moveInstance() { NodeInst ni = moveCell; if (!moveCellValid || ni == null) { System.out.println("River router: Cannot determine cell to move"); return false; } double lx = (routDirection == ROUTEINX ? height + ni.getAnchorCenterX() - toLine : ni.getAnchorCenterX()); double ly = (routDirection == ROUTEINY ? height + ni.getAnchorCenterY() - toLine : ni.getAnchorCenterY()); if (lx == ni.getAnchorCenterX() && ly == ni.getAnchorCenterY()) return true; ni.move(lx - ni.getAnchorCenterX(), ly - ni.getAnchorCenterY()); return true; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy