Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.sun.electric.technology.PrimitiveNodeGroup Maven / Gradle / Ivy
/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: PrimitiveNode.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.technology;
import com.sun.electric.database.geometry.EPoint;
import com.sun.electric.database.geometry.ERectangle;
import com.sun.electric.database.geometry.Poly;
import com.sun.electric.database.prototype.PortCharacteristic;
import com.sun.electric.tool.Job;
import com.sun.electric.util.TextUtils;
import com.sun.electric.util.math.DBMath;
import com.sun.electric.util.math.ECoord;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* A PrimitiveNodeGroup is a group of similar PrimitiveNodes.
* PrimitiveNodes in a group share a list of NodeLayers. Each PrimitiveNode
* may omit some NodeLayers of the list.
*/
public class PrimitiveNodeGroup {
private final Technology tech;
private final Technology.NodeLayer[] nodeLayers;
private final List nodes = new ArrayList();
private final List unmodifiableNodes = Collections.unmodifiableList(nodes);
private Xml.PrimitiveNodeGroup ng;
private final EPoint sizeCorrector1;
private final EPoint sizeCorrector2;
private final String minSizeRule;
private final double defaultWidth;
private final double defaultHeight;
private final EPoint fullSize;
private final ERectangle fullRectangle;
private final ERectangle baseRectangle;
private final EdgeH[] elx;
private final EdgeH[] ehx;
private final EdgeV[] ely;
private final EdgeV[] ehy;
private final ArcProto[][] fullConnections;
public List getNodes() {
return unmodifiableNodes;
}
private PrimitiveNodeGroup(Technology tech, Xml.PrimitiveNodeGroup ng, Map layers, Map arcs) {
this.tech = tech;
this.ng = ng;
EPoint sizeCorrector1 = ng.diskOffset.get(Integer.valueOf(1));
EPoint sizeCorrector2 = ng.diskOffset.get(Integer.valueOf(2));
if (sizeCorrector2 == null) {
sizeCorrector2 = EPoint.ORIGIN;
}
if (sizeCorrector1 == null) {
sizeCorrector1 = sizeCorrector2;
}
this.sizeCorrector1 = sizeCorrector1;
this.sizeCorrector2 = sizeCorrector2;
long lx, hx, ly, hy;
if (ng.nodeSizeRule != null) {
hx = DBMath.lambdaToGrid(0.5 * ng.nodeSizeRule.width);
lx = -hx;
hy = DBMath.lambdaToGrid(0.5 * ng.nodeSizeRule.height);
ly = -hy;
minSizeRule = ng.nodeSizeRule.rule;
} else {
lx = Long.MAX_VALUE;
hx = Long.MIN_VALUE;
ly = Long.MAX_VALUE;
hy = Long.MIN_VALUE;
for (int i = 0; i < ng.nodeLayers.size(); i++) {
Xml.NodeLayer nl = ng.nodeLayers.get(i);
long x, y;
if (nl.representation == Technology.NodeLayer.BOX || nl.representation == Technology.NodeLayer.MULTICUTBOX) {
x = DBMath.lambdaToGrid(nl.lx.value);
lx = Math.min(lx, x);
hx = Math.max(hx, x);
x = DBMath.lambdaToGrid(nl.hx.value);
lx = Math.min(lx, x);
hx = Math.max(hx, x);
y = DBMath.lambdaToGrid(nl.ly.value);
ly = Math.min(ly, y);
hy = Math.max(hy, y);
y = DBMath.lambdaToGrid(nl.hy.value);
ly = Math.min(ly, y);
hy = Math.max(hy, y);
} else if (nl.style == Poly.Type.DISC || nl.style == Poly.Type.CIRCLE) {
Technology.TechPoint c = nl.techPoints.get(0);
Technology.TechPoint r = nl.techPoints.get(1);
long cx = c.getX().getAdder().getGrid();
long cy = c.getY().getAdder().getGrid();
long rx = r.getX().getAdder().getGrid();
long ry = r.getY().getAdder().getGrid();
long radius;
if (cx == rx) {
radius = Math.abs(ry - cy);
} else if (cy == ry) {
radius = Math.abs(rx - cx);
} else {
throw new UnsupportedOperationException();
}
lx = Math.min(lx, cx - radius);
hx = Math.max(hx, cx + radius);
ly = Math.min(ly, cy - radius);
hy = Math.max(hy, cy + radius);
} else if (nl.style == Poly.Type.CIRCLEARC || nl.style == Poly.Type.THICKCIRCLEARC || nl.style.isText()) {
throw new UnsupportedOperationException();
} else {
for (Technology.TechPoint p : nl.techPoints) {
x = p.getX().getAdder().getGrid();
lx = Math.min(lx, x);
hx = Math.max(hx, x);
y = p.getY().getAdder().getGrid();
ly = Math.min(ly, y);
hy = Math.max(hy, y);
}
}
}
minSizeRule = null;
}
fullRectangle = ERectangle.fromGrid(lx, ly, hx - lx, hy - ly);
fullSize = EPoint.fromGrid((hx - lx + 1) / 2, (hy - ly + 1) / 2);
nodeLayers = new Technology.NodeLayer[ng.nodeLayers.size()];
for (int i = 0; i < ng.nodeLayers.size(); i++) {
Xml.NodeLayer nl = ng.nodeLayers.get(i);
Layer layer = layers.get(nl.layer);
Technology.TechPoint[] techPoints;
if (nl.representation == Technology.NodeLayer.BOX || nl.representation == Technology.NodeLayer.MULTICUTBOX) {
techPoints = new Technology.TechPoint[2];
if (!(nl.lx.k <= nl.hx.k && nl.ly.k <= nl.hy.k)) {
throw new IllegalArgumentException("In " + layer);
}
if (Job.getDebug()) {
if (nl.lx.value > nl.hx.value || nl.ly.value > nl.hy.value) {
System.out.println("Negative-size polygon in primitive node " + tech.getTechName() + ":" + ng.nodes.get(0).name
+ ", layer " + layer.getName());
}
}
techPoints[0] = Technology.makeTechPoint(nl.lx, nl.ly);
techPoints[1] = Technology.makeTechPoint(nl.hx, nl.hy);
} else {
techPoints = nl.techPoints.toArray(new Technology.TechPoint[nl.techPoints.size()]);
}
Technology.NodeLayer nodeLayer;
if (ng.shrinkArcs) {
if (layer.getPseudoLayer() == null) {
layer.makePseudo();
}
layer = layer.getPseudoLayer();
}
if (nl.representation == Technology.NodeLayer.MULTICUTBOX) {
nodeLayer = Technology.NodeLayer.makeMulticut(layer, nl.portNum, nl.style, techPoints, nl.sizex, nl.sizey, nl.sep1d, nl.sep2d);
} else if (ng.specialType == PrimitiveNode.SERPTRANS) {
nodeLayer = new Technology.NodeLayer(layer, nl.portNum, nl.style, nl.representation, techPoints,
ECoord.fromLambdaRoundGrid(nl.lWidth),
ECoord.fromLambdaRoundGrid(nl.rWidth),
ECoord.fromLambdaRoundGrid(nl.tExtent),
ECoord.fromLambdaRoundGrid(nl.bExtent));
} else {
nodeLayer = new Technology.NodeLayer(layer, nl.portNum, nl.style, nl.representation, techPoints);
}
nodeLayers[i] = nodeLayer;
}
lx = DBMath.lambdaToGrid(ng.baseLX.value);
hx = DBMath.lambdaToGrid(ng.baseHX.value);
ly = DBMath.lambdaToGrid(ng.baseLY.value);
hy = DBMath.lambdaToGrid(ng.baseHY.value);
baseRectangle = ERectangle.fromGrid(lx, ly, hx - lx, hy - ly);
if (baseRectangle.getWidth() < 0 || baseRectangle.getHeight() < 0) {
throw new IllegalArgumentException("Node " + ng.nodes.get(0).toString() + " has negative base rectangle");
}
defaultWidth = DBMath.round(ng.defaultWidth.value + 2 * fullSize.getLambdaX());
defaultHeight = DBMath.round(ng.defaultHeight.value + 2 * fullSize.getLambdaY());
elx = new EdgeH[ng.ports.size()];
ehx = new EdgeH[ng.ports.size()];
ely = new EdgeV[ng.ports.size()];
ehy = new EdgeV[ng.ports.size()];
fullConnections = new ArcProto[ng.ports.size()][];
for (int i = 0; i < ng.ports.size(); i++) {
Xml.PrimitivePort p = ng.ports.get(i);
if (p.lx.value > p.hx.value || p.lx.k > p.hx.k || p.ly.value > p.hy.value || p.ly.k > p.hy.k) {
double lX = p.lx.value - fullSize.getLambdaX() * p.lx.k;
double hX = p.hx.value - fullSize.getLambdaX() * p.hx.k;
double lY = p.ly.value - fullSize.getLambdaY() * p.ly.k;
double hY = p.hy.value - fullSize.getLambdaY() * p.hy.k;
String explain = " (LX=" + TextUtils.formatDouble(p.lx.k / 2) + "W";
if (lX >= 0) {
explain += "+";
}
explain += TextUtils.formatDouble(lX) + ", HX=" + TextUtils.formatDouble(p.hx.k / 2) + "W";
if (hX >= 0) {
explain += "+";
}
explain += TextUtils.formatDouble(hX) + ", LY=" + TextUtils.formatDouble(p.ly.k / 2) + "H";
if (lY >= 0) {
explain += "+";
}
explain += TextUtils.formatDouble(lY) + ", HY=" + TextUtils.formatDouble(p.hy.k / 2) + "H";
if (hY >= 0) {
explain += "+";
}
explain += TextUtils.formatDouble(hY);
explain += " but size is " + fullSize.getLambdaX() * 2 + "x" + fullSize.getLambdaY() * 2 + ")";
throw new IllegalArgumentException("port " + p.name + " in primitive " + tech.getTechName() + ":" + ng.nodes.get(0).name + " has negative size" + explain);
}
elx[i] = Technology.makeEdgeH(p.lx);
ehx[i] = Technology.makeEdgeH(p.hx);
ely[i] = Technology.makeEdgeV(p.ly);
ehy[i] = Technology.makeEdgeV(p.hy);
fullConnections[i] = Technology.makeConnections(ng.nodes.get(0).name, p.name, p.portArcs, arcs);
}
}
private PrimitiveNode makePrimitiveNode(int nodeIndex) {
Xml.PrimitiveNode n = ng.nodes.get(nodeIndex);
boolean needElectricalLayers = false;
assert nodeLayers.length == ng.nodeLayers.size();
ArrayList visualNodeLayers = new ArrayList();
ArrayList electricalNodeLayers = new ArrayList();
for (int i = 0; i < ng.nodeLayers.size(); i++) {
Xml.NodeLayer nl = ng.nodeLayers.get(i);
Technology.NodeLayer nodeLayer = nodeLayers[i];
if (nl.inNodes != null && !nl.inNodes.get(nodeIndex)) {
continue;
}
if (!(nl.inLayers && nl.inElectricalLayers)) {
needElectricalLayers = true;
}
if (nl.inLayers) {
visualNodeLayers.add(nodeLayer);
}
if (nl.inElectricalLayers) {
electricalNodeLayers.add(nodeLayer);
}
}
PrimitiveNode pnp;
switch (ng.specialType) {
case com.sun.electric.technology.PrimitiveNode.POLYGONAL:
pnp = new PrimitiveNode.Polygonal(n.name, tech, sizeCorrector1, sizeCorrector2, minSizeRule,
defaultWidth, defaultHeight,
fullRectangle, baseRectangle, visualNodeLayers.toArray(new Technology.NodeLayer[visualNodeLayers.size()]));
break;
case com.sun.electric.technology.PrimitiveNode.SERPTRANS:
pnp = new PrimitiveNode.Serpentine(n.name, tech, sizeCorrector1, sizeCorrector2, minSizeRule,
defaultWidth, defaultHeight,
fullRectangle, baseRectangle,
visualNodeLayers.toArray(new Technology.NodeLayer[visualNodeLayers.size()]),
ng.specialValues);
break;
default:
pnp = tech.newPrimitiveNode(n.name, sizeCorrector1, sizeCorrector2, minSizeRule,
defaultWidth, defaultHeight,
fullRectangle, baseRectangle, visualNodeLayers.toArray(new Technology.NodeLayer[visualNodeLayers.size()]));
}
if (pnp == null) // error creating the node. Eg. repeated name
{
return null;
}
if (n.oldName != null) {
tech.oldNodeNames.put(n.oldName, pnp);
}
pnp.setFunction(n.function);
if (needElectricalLayers) {
pnp.setElectricalLayers(electricalNodeLayers.toArray(new Technology.NodeLayer[electricalNodeLayers.size()]));
}
if (ng.shrinkArcs) {
pnp.setArcsWipe();
pnp.setArcsShrink();
}
if (ng.square) {
pnp.setSquare();
}
if (ng.canBeZeroSize) {
pnp.setCanBeZeroSize();
}
if (ng.wipes) {
pnp.setWipeOn1or2();
}
if (ng.lockable) {
pnp.setLockedPrim();
}
if (ng.edgeSelect) {
pnp.setEdgeSelect();
}
if (ng.skipSizeInPalette) {
pnp.setSkipSizeInPalette();
}
if (ng.notUsed) {
pnp.setNotUsed(true);
}
if (n.lowVt) {
pnp.setNodeBit(PrimitiveNode.LOWVTBIT);
}
if (n.highVt) {
pnp.setNodeBit(PrimitiveNode.HIGHVTBIT);
}
if (n.nativeBit) {
pnp.setNodeBit(PrimitiveNode.NATIVEBIT);
}
if (n.od18) {
pnp.setNodeBit(PrimitiveNode.OD18BIT);
}
if (n.od25) {
pnp.setNodeBit(PrimitiveNode.OD25BIT);
}
if (n.od33) {
pnp.setNodeBit(PrimitiveNode.OD33BIT);
}
PrimitivePort[] ports = new PrimitivePort[ng.ports.size()];
for (int i = 0; i < ports.length; i++) {
Xml.PrimitivePort p = ng.ports.get(i);
PrimitivePort pp;
switch (ng.specialType) {
case com.sun.electric.technology.PrimitiveNode.POLYGONAL:
pp = new PrimitivePort.Polygonal(pnp, fullConnections[i], p.name, ports.length == 1,
p.portAngle, p.portRange, p.portTopology,
elx[i], ely[i], ehx[i], ehy[i]);
break;
case com.sun.electric.technology.PrimitiveNode.SERPTRANS:
pp = new PrimitivePort.Serpentine(pnp, fullConnections[i], p.name, ports.length == 1,
p.portAngle, p.portRange, p.portTopology,
elx[i], ely[i], ehx[i], ehy[i]);
break;
default:
pp = PrimitivePort.newInstance(pnp, fullConnections[i], p.name, ports.length == 1,
p.portAngle, p.portRange, p.portTopology, PortCharacteristic.UNKNOWN, false, false,
elx[i], ely[i], ehx[i], ehy[i]);
}
ports[i] = pp;
}
pnp.addPrimitivePorts(ports);
if (n.function == PrimitiveNode.Function.NODE) {
System.out.println("ERROR: Node " + n.name + " must not be a Pure-Layer Node");
assert n.function != PrimitiveNode.Function.NODE;
}
if (ng.spiceTemplate != null) {
pnp.setSpiceTemplate(ng.spiceTemplate);
}
pnp.check();
return pnp;
}
static void makePrimitiveNodes(Technology tech, Xml.PrimitiveNodeGroup ng, Map layers, Map arcs) {
PrimitiveNodeGroup group = new PrimitiveNodeGroup(tech, ng, layers, arcs);
for (int i = 0; i < ng.nodes.size(); i++) {
PrimitiveNode pnp = group.makePrimitiveNode(i);
if (!ng.isSingleton) {
group.nodes.add(pnp);
pnp.group = group;
}
}
if (!ng.isSingleton) {
tech.primitiveNodeGroups.add(group);
}
}
Xml.PrimitiveNodeGroup makeXml() {
return ng;
}
}