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