/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: TrackRouter.java
*
* Copyright (c) 2003, 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.generator.layout;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.Export;
import com.sun.electric.technology.ArcProto;
import com.sun.electric.database.topology.ArcInst;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.topology.PortInst;
import com.sun.electric.tool.Job;
public abstract class TrackRouter {
// ----------------------- private and protected data ------------------------
private double shareableViaDist = 6;
// The list: vias is a list of ViaStacks sorted by their X/Y
// coordinates. ViaStack connections are daisy chained in the order
// that they occur on this list. TrackRouter maintains daisy-chained
// connections to avoid overlapping metal. This was done because I
// initially understood that Electric doesn't report parasitics
// correctly when metal overlaps. This rumor may not be true.
private List<ViaStack> vias = new ArrayList<ViaStack>();
// lastPos is a Cursor into vias that makes insertion more
// efficient. The next point of insertion is often very close to the
// last point of insertion.
private int lastPos = 0;
Cell parent;
PortInst curPort;
ArcProto layer;
double width = 0;
Double center = null;
PortInst prevElbow;
boolean endsExtend;
final TechType tech;
// ------------------ private and protected methods ----------------------
static void error(boolean pred, String msg) {
Job.error(pred, msg);
}
private double getXY(ViaStack via) {
return (this instanceof TrackRouterH)
? via.getCenterX()
: via.getCenterY();
}
private void removeExistingArc(ViaStack prev, ViaStack next) {
if (prev == null || next == null)
return;
PortInst prevPort = prev.getPort1();
PortInst nextPort = next.getPort1();
for (Iterator<ArcInst> it = LayoutLib.getArcInstsOnPortInst(prevPort);
it.hasNext();
) {
ArcInst ai = it.next();
PortInst end0 = ai.getHeadPortInst();
PortInst end1 = ai.getTailPortInst();
if (end0 == nextPort || end1 == nextPort)
ai.kill();
}
}
private void addArc(ViaStack v1, ViaStack v2) {
PortInst p1 = v1.getPort1();
PortInst p2 = v2.getPort1();
ArcInst ai = LayoutLib.newArcInst(layer, width, p1, p2);
ai.setHeadExtended(endsExtend);
ai.setTailExtended(endsExtend);
}
private void addArcs(ViaStack prev, ViaStack via, ViaStack next) {
if (prev != null)
addArc(prev, via);
if (next != null)
addArc(via, next);
}
void insertVia(ViaStack via) {
if (vias.size()==0) {vias.add(via); return;}
double myXY = getXY(via);
while (lastPos>0 && getXY(vias.get(lastPos-1))>myXY)
lastPos--;
while (lastPos < vias.size()
&& getXY( vias.get(lastPos)) < myXY) lastPos++;
vias.add(lastPos, via);
ViaStack prev = lastPos==0 ? null : (ViaStack)vias.get(lastPos-1);
ViaStack next = lastPos==vias.size()-1
? null
: (ViaStack) vias.get(lastPos+1);
removeExistingArc(prev, next);
addArcs(prev, via, next);
}
// Find the closest via port to position. Search the range position
// +/- shareableViaDist. If nothing found then return null.
ViaStack findSharableVia(double position, ArcProto lay) {
if (vias.size() == 0)
return null;
int closest = -1;
double closestDist = Double.MAX_VALUE;
// search backwards
for (int i = lastPos; i >= 0; i--) {
ViaStack v = vias.get(i);
double dist = Math.abs(getXY(v) - position);
if (dist > closestDist) break;
if (dist > shareableViaDist) continue;
PortInst pi = v.getPort2();
if (pi.getPortProto().connectsTo(lay)) {
if (dist<closestDist) {
closest = i;
closestDist = dist;
}
}
}
// search forwards
for (int i = lastPos + 1; i < vias.size(); i++) {
ViaStack v = vias.get(i);
double dist = Math.abs(getXY(v) - position);
if (dist > closestDist) break;
if (dist > shareableViaDist) continue;
PortInst pi = v.getPort2();
if (pi.getPortProto().connectsTo(lay)) {
if (dist<closestDist) {
closest = i;
closestDist = dist;
}
}
}
if (closestDist == Double.MAX_VALUE) return null;
lastPos = closest;
return vias.get(closest);
}
//------------------------------- public methods ----------------------------
// all ports lie on the same routing track
public TrackRouter(ArcProto lay, double wid, TechType tech, Cell parnt) {
parent = parnt;
layer = lay;
width = wid;
endsExtend = true;
this.tech = tech;
}
// ports may be offset from routing track
public TrackRouter(ArcProto lay, double wid, double centerVal,
TechType tech,
Cell parnt) {
parent = parnt;
layer = lay;
width = wid;
center = new Double(centerVal);
endsExtend = true;
this.tech = tech;
}
public void setEndsExtend(boolean b) { endsExtend = b; }
public boolean getEndsExtend() { return endsExtend; }
public void connect(ArrayList<NodeInst> nodeInsts, String portNm) {
ArrayList<PortInst> ports = new ArrayList<PortInst>();
for (int i=0; i<nodeInsts.size(); i++) {
PortInst p = nodeInsts.get(i).findPortInst(portNm);
if (p!=null) ports.add(p);
}
connect(ports);
}
public void connect(NodeInst[] nodeInsts, String portNm) {
ArrayList<NodeInst> a = new ArrayList<NodeInst>();
for (int i=0; i<nodeInsts.length; i++) a.add(nodeInsts[i]);
connect(a, portNm);
}
public void connect(ArrayList<PortInst> ports) {
for (int i=0; i<ports.size(); i++) connect(ports.get(i));
}
public void connect(PortInst[] ports) {
ArrayList<PortInst> p = new ArrayList<PortInst>();
for (int i=0; i<ports.length; i++) p.add(ports[i]);
connect(p);
}
public void connect(PortInst newPort) {connect(newPort, 0);}
public void connect(Export export) {
connect(export.getOriginalPort(), 0);
}
public void connect(PortInst newPort, double viaOffset) {
connect(newPort, viaOffset, 0);
}
// this connect is specialized for TrackRouterH and TrackRouterV
public abstract void connect(PortInst newPort, double viaOffset,
double wireOffset);
/** If you find an existing via within distance d of this connection,
* connect to that via rather than creating a new one. */
public void setShareableViaDist(double d) {shareableViaDist = d;}
}