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.Technology Maven / Gradle / Ivy
/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: Technology.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.EObjectInputStream;
import com.sun.electric.database.EObjectOutputStream;
import com.sun.electric.database.EditingPreferences;
import com.sun.electric.database.Environment;
import com.sun.electric.database.ImmutableArcInst;
import com.sun.electric.database.ImmutableNodeInst;
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.hierarchy.Cell;
import com.sun.electric.database.hierarchy.EDatabase;
import com.sun.electric.database.id.ArcProtoId;
import com.sun.electric.database.id.IdManager;
import com.sun.electric.database.id.LayerId;
import com.sun.electric.database.id.PrimitiveNodeId;
import com.sun.electric.database.id.TechId;
import com.sun.electric.database.prototype.NodeProto;
import com.sun.electric.database.text.Pref;
import com.sun.electric.database.text.Setting;
import com.sun.electric.database.text.Version;
import com.sun.electric.database.topology.ArcInst;
import com.sun.electric.database.topology.Geometric;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.topology.PortInst;
import com.sun.electric.database.variable.TextDescriptor;
import com.sun.electric.database.variable.VarContext;
import com.sun.electric.database.variable.Variable;
import com.sun.electric.technology.technologies.Artwork;
import com.sun.electric.technology.technologies.GEM;
import com.sun.electric.technology.technologies.Generic;
import com.sun.electric.technology.technologies.Schematics;
import com.sun.electric.tool.Job;
import com.sun.electric.tool.ToolSettings;
import com.sun.electric.tool.user.User;
import com.sun.electric.tool.user.UserInterfaceMain;
import com.sun.electric.util.TextUtils;
import com.sun.electric.util.collections.ImmutableArrayList;
import com.sun.electric.util.math.DBMath;
import com.sun.electric.util.math.ECoord;
import com.sun.electric.util.math.Orientation;
import java.awt.Color;
import java.awt.geom.Point2D;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InvalidObjectException;
import java.io.NotSerializableException;
import java.io.PrintWriter;
import java.io.Serializable;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.TreeMap;
import java.util.prefs.Preferences;
/**
* Technology is the base class for all of the specific technologies in Electric.
*
* It is organized into two main areas: nodes and arcs.
* Both nodes and arcs are composed of Layers.
*
* Subclasses of Technology usually start by defining the Layers (such as Metal-1, Metal-2, etc.)
* Then the ArcProto objects are created, built entirely from Layers.
* Next PrimitiveNode objects are created, and they have Layers as well as connectivity to the ArcProtos.
* The Technology concludes with miscellaneous data assignments of technology-wide information.
*
* Here are the nodes in a sample CMOS technology.
* Note that there are two types of transistors and diffusion contacts, one for Well and one for Substrate.
* Each layer that can exist as a wire must have a pin node (in this case, metal, polysilicon, and two flavors of diffusion.
* Note that there are pure-layer nodes at the bottom which allow arbitrary geometry to be constructed.
*
*
* The Schematic technology has some unusual features.
*
*
* Conceptually, a Technology has 3 types of information:
*
Geometry . Each node and arc can be described in terms of polygons on differnt Layers.
* The ArcLayer and NodeLayer subclasses help define those polygons.
* Connectivity . The very structure of the nodes and arcs establisheds a set of rules of connectivity.
* Examples include the list of allowable arc types that may connect to each port, and the use of port "network numbers"
* to identify those that are connected internally.
* Behavior . Behavioral information takes many forms, but they can all find a place here.
* For example, each layer, node, and arc has a "function" that describes its general behavior.
* Some information applies to the technology as a whole, for example SPICE model cards.
* Other examples include Design Rules and technology characteristics.
*
* @author Steven M. Rubin
*/
public class Technology implements Comparable, Serializable {
/** Jelib writes base sizes since this Electric Version */
public static final Version DISK_VERSION_1 = Version.parseVersion("8.05g");
/** Jelib writes oversize over standard primitive since this Electric Version */
public static final Version DISK_VERSION_2 = Version.parseVersion("8.05o");
public static final Technology[] NULL_ARRAY = {};
public static final ImmutableArrayList EMPTY_LIST = new ImmutableArrayList(NULL_ARRAY);
/** key of Variable for saving scalable transistor contact information. */
public static final Variable.Key TRANS_CONTACT = Variable.newKey("MOCMOS_transcontacts");
/** Relative path in Preferences where technology Settings and Preferences are stored */
public static final String TECH_NODE = "technology/technologies";
// strings used in the Component MenuNodeLayer
public static final String SPECIALMENUCELL = "Cell";
public static final String SPECIALMENUMISC = "Misc.";
public static final String SPECIALMENUPURE = "Pure";
public static final String SPECIALMENUSPICE = "Spice";
public static final String SPECIALMENUEXPORT = "Export";
public static final String SPECIALMENUTEXT = "Text";
public static final String SPECIALMENUHIGH = "High";
public static final String SPECIALMENUPORT = "Port";
public static final String SPECIALMENUSEPARATOR = "-";
/**
* Defines a single layer of a ArcProto.
* A ArcProto has a list of these ArcLayer objects, one for
* each layer in a typical ArcInst.
* Each ArcProto is composed of a number of ArcLayer descriptors.
* A descriptor converts a specific ArcInst into a polygon that describe this particular layer.
*/
public static class ArcLayer {
private final Layer layer;
private final Poly.Type style;
private ECoord extend;
/**
* Constructs an ArcLayer
with the specified description.
* @param layer the Layer of this ArcLayer.
* @param arcLayerWidth the width of this ArcLayer in standard ArcInst.
* @param style the Poly.Style of this ArcLayer.
*/
public ArcLayer(Layer layer, double arcLayerWidth, Poly.Type style) {
this(layer, style, 0.5 * arcLayerWidth);
}
/**
* Constructs an ArcLayer
with the specified description.
* @param layer the Layer of this ArcLayer.
* @param style the Poly.Style of this ArcLayer.
* @param lambdaExtend lambda fraction of extend
*/
public ArcLayer(Layer layer, Poly.Type style, double lambdaExtend) {
this.layer = layer;
this.style = style;
extend = ECoord.fromLambdaRoundGrid(lambdaExtend);
if (extend.getGrid() < 0 || extend.getGrid() >= Integer.MAX_VALUE / 8) {
throw new IllegalArgumentException("extend=" + extend);
}
}
/**
* Returns the Layer from the Technology to be used for this ArcLayer.
* @return the Layer from the Technology to be used for this ArcLayer.
*/
public Layer getLayer() {
return layer;
}
/**
* Returns the distance from the center of the standard ArcInst to the outsize of this ArcLayer as ECoord object.
* The distance from the center of arbitrary ArcInst ai to the outsize of its ArcLayer is
* ai.getD().getExtendOverMin() + arcLayer.getGridExtend()
* @return the distance from the outside of the ArcInst to this ArcLayer as ECoord object.
*/
public ECoord getExtend() {
return extend;
}
/**
* Returns the Poly.Style of this ArcLayer.
* @return the Poly.Style of this ArcLayer.
*/
public Poly.Type getStyle() {
return style;
}
void dump(PrintWriter out) {
out.println("\t\tarcLayer layer=" + layer.getName()
+ " style=" + style.name()
+ " extend=" + extend);
}
Xml.ArcLayer makeXml() {
Xml.ArcLayer al = new Xml.ArcLayer();
al.layer = layer.getName();
al.style = style;
al.extend.addLambda(extend.getLambda());
return al;
}
}
/**
* Defines a point in space that is relative to a NodeInst's bounds.
* The TechPoint has two coordinates: X and Y.
* Each of these coordinates is represented by an Edge class (EdgeH for X
* and EdgeV for Y).
* The Edge classes have two numbers: a multiplier and an adder.
* The desired coordinate takes the NodeInst's center, adds in the
* product of the Edge multiplier and the NodeInst's size, and then adds
* in the Edge adder.
*
* Arrays of TechPoint objects can be used to describe the bounds of
* a particular layer in a NodeInst. Typically, four TechPoint objects
* can describe a rectangle. Circles only need two (center and edge).
* The Poly.Style
class defines the possible types of
* geometry.
* @see EdgeH
* @see EdgeV
*/
public static class TechPoint implements Serializable {
private final EdgeH x;
private final EdgeV y;
/**
* Constructs a TechPoint
with the specified description.
* @param x the EdgeH that converts a NodeInst into an X coordinate on that NodeInst.
* @param y the EdgeV that converts a NodeInst into a Y coordinate on that NodeInst.
*/
public TechPoint(EdgeH x, EdgeV y) {
if (x == null || y == null) {
throw new NullPointerException();
}
this.x = x;
this.y = y;
}
/**
* Method to make a 2-long TechPoint array that describes a point at the center of the node.
* @return a new TechPoint array that describes a point at the center of the node.
*/
public static TechPoint[] makeCenterBox() {
return new Technology.TechPoint[]{
new Technology.TechPoint(EdgeH.fromCenter(0), EdgeV.fromCenter(0)),
new Technology.TechPoint(EdgeH.fromCenter(0), EdgeV.fromCenter(0))};
}
/**
* Method to make a 2-long TechPoint array that describes indentation from the center by a specified amount.
* @param amountX the amount to indent from the center the box along X.
* @param amountY the amount to indent from the center the box along Y.
* @return a new TechPoint array that describes this indented box.
*/
public static TechPoint[] makeIndentedFromCenter(double amountX, double amountY) {
return new Technology.TechPoint[]{
new Technology.TechPoint(EdgeH.fromCenter(-amountX), EdgeV.fromCenter(-amountY)),
new Technology.TechPoint(EdgeH.fromCenter(amountX), EdgeV.fromCenter(amountY))};
}
/**
* Returns the EdgeH that converts a NodeInst into an X coordinate on that NodeInst.
* @return the EdgeH that converts a NodeInst into an X coordinate on that NodeInst.
*/
public EdgeH getX() {
return x;
}
/**
* Returns the TechPoint with a new EdgeH
* @param x new EdgeH
* @return the TechPoint with thew new EdgeH
*/
public TechPoint withX(EdgeH x) {
if (x.equals(this.x)) {
return this;
}
return new TechPoint(x, this.y);
}
/**
* Returns the EdgeV that converts a NodeInst into a Y coordinate on that NodeInst.
* @return the EdgeV that converts a NodeInst into a Y coordinate on that NodeInst.
*/
public EdgeV getY() {
return y;
}
/**
* Returns the TechPoint with a new EdgeV
* @param y new EdgeV
* @return the TechPoint with thew new EdgeV
*/
public TechPoint withY(EdgeV y) {
if (y.equals(this.y)) {
return this;
}
return new TechPoint(this.x, y);
}
}
/**
* Defines a single layer of a PrimitiveNode.
* A PrimitiveNode has a list of these NodeLayer objects, one for
* each layer in a typical NodeInst.
* Each PrimitiveNode is composed of a number of NodeLayer descriptors.
* A descriptor converts a specific NodeInst into a polygon that describe this particular layer.
*/
public static class NodeLayer {
private final Layer layer;
private final int portNum;
private final Poly.Type style;
private final int representation;
private final TechPoint[] points;
private String message;
private TextDescriptor descriptor;
private ECoord lWidth;
private ECoord rWidth;
private ECoord extentT;
private ECoord extendB;
private ECoord cutSizeX = ECoord.ZERO;
private ECoord cutSizeY = ECoord.ZERO;
private ECoord cutSep1D = ECoord.ZERO;
private ECoord cutSep2D = ECoord.ZERO;
// the meaning of "representation"
/**
* Indicates that the "points" list defines scalable points.
* Each point here becomes a point on the Poly.
*/
public static final int POINTS = 0;
/**
* Indicates that the "points" list defines a rectangle.
* It contains two diagonally opposite points.
*/
public static final int BOX = 1;
// /**
// * Indicates that the "points" list defines a minimum sized rectangle.
// * It contains two diagonally opposite points, like BOX,
// * and also contains a minimum box size beyond which the polygon will not shrink
// * (again, two diagonally opposite points).
// */
// public static final int MINBOX = 2;
/**
* Indicates that the "points" list defines a rectangle,
* where centers of multi-cut are located
* It contains two diagonally opposite points.
*/
public static final int MULTICUTBOX = 3;
/** key of Variable for overriding cut spacing. */
public static final Variable.Key CUT_SPACING = Variable.newKey("CUT_spacing");
/** key of Variable for overridint cut alignent */
public static final Variable.Key CUT_ALIGNMENT = Variable.newKey("CUT_alignment");
/** key of Variable for overriding metal surround. */
public static final Variable.Key METAL_OFFSETS = Variable.newKey("METAL_offsets");
/** key of Variable for number of tubes in CNFET. */
public static final Variable.Key CARBON_NANOTUBE_COUNT = Variable.newKey("CARBON_NANOTUBE_count");
/** key of Variable for spacing of tubes in CNFET. */
public static final Variable.Key CARBON_NANOTUBE_PITCH = Variable.newKey("CARBON_NANOTUBE_pitch");
/** CUT_ALIGNMENT: cuts centered in the node */
public static final int MULTICUT_CENTERED = 0;
/** CUT_ALIGNMENT: cuts spread to edges of node */
public static final int MULTICUT_SPREAD = 1;
/** CUT_ALIGNMENT: cuts pushed to corner of node */
public static final int MULTICUT_CORNER = 2;
/**
* Constructs a NodeLayer
with the specified description.
* @param layer the Layer
this is on.
* @param portNum a 0-based index of the port (from the actual NodeInst) on this layer.
* A negative value indicates that this layer is not connected to an electrical layer.
* @param style the Poly.Type this NodeLayer will generate (polygon, circle, text, etc.).
* @param representation tells how to interpret "points". It can be POINTS, BOX, or MULTICUTBOX.
* @param points the list of coordinates (stored as TechPoints) associated with this NodeLayer.
*/
public NodeLayer(Layer layer, int portNum, Poly.Type style, int representation, TechPoint[] points) {
this.layer = layer;
this.portNum = portNum;
this.style = style;
this.representation = representation;
this.points = points.clone();
descriptor = TextDescriptor.EMPTY;
this.lWidth = this.rWidth = this.extentT = this.extendB = ECoord.ZERO;
}
/**
* Constructs a NodeLayer
with the specified description.
* This form of the method, with 4 additional parameters at the end,
* is only used for serpentine transistors.
* @param layer the Layer
this is on.
* @param portNum a 0-based index of the port (from the actual NodeInst) on this layer.
* A negative value indicates that this layer is not connected to an electrical layer.
* @param style the Poly.Type this NodeLayer will generate (polygon, circle, text, etc.).
* @param representation tells how to interpret "points". It can be POINTS, BOX, or MULTICUTBIX.
* @param points the list of coordinates (stored as TechPoints) associated with this NodeLayer.
* @param lWidth the left extension of this layer, measured from the centerline .
* The centerline is the path that the serpentine transistor follows (it defines the path of the
* polysilicon). So, for example, if lWidth is 4 and rWidth is 4, it creates a NodeLayer that is 8 wide
* (with 4 to the left and 4 to the right of the centerline).
* Left and Right widths define the size of the Active layers.
* @param rWidth the right extension the right of this layer, measured from the centerline .
* @param extentT the top extension of this layer, measured from the end of the centerline .
* The top and bottom extensions apply to the ends of the centerline, and not to each segment
* along it. They define the extension of the polysilicon. For example, if extendT is 2,
* it indicates that the NodeLayer extends by 2 from the top end of the centerline.
* @param extendB the bottom extension of this layer, measured from the end of the centerline .
*/
public NodeLayer(Layer layer, int portNum, Poly.Type style, int representation, TechPoint[] points,
ECoord lWidth, ECoord rWidth, ECoord extentT, ECoord extendB) {
this.layer = layer;
this.portNum = portNum;
this.style = style;
this.representation = representation;
this.points = points.clone();
descriptor = TextDescriptor.EMPTY;
this.lWidth = lWidth;
this.rWidth = rWidth;
this.extentT = extentT;
this.extendB = extendB;
}
/**
* Constructs a NodeLayer
from given node
* @param node
*/
public NodeLayer(NodeLayer node) {
this.layer = node.getLayerOrPseudoLayer();
this.portNum = node.getPortNum();
this.style = node.getStyle();
this.representation = node.getRepresentation();
this.descriptor = TextDescriptor.EMPTY;
this.points = node.getPoints().clone();
this.lWidth = this.rWidth = this.extentT = this.extendB = ECoord.ZERO;
}
public static NodeLayer makeMulticut(Layer layer, int portNum, Poly.Type style, TechPoint[] techPoints,
double sizeX, double sizeY, double sep1d, double sep2d) {
NodeLayer nl = new NodeLayer(layer, portNum, style, Technology.NodeLayer.MULTICUTBOX, techPoints);
nl.cutSizeX = ECoord.fromLambdaRoundGrid(sizeX);
nl.cutSizeY = ECoord.fromLambdaRoundGrid(sizeY);
nl.cutSep1D = ECoord.fromLambdaRoundGrid(sep1d);
nl.cutSep2D = ECoord.fromLambdaRoundGrid(sep2d);
return nl;
}
public static NodeLayer makeMulticut(Layer layer, int portNum, Poly.Type style, TechPoint[] techPoints,
ECoord sizeX, ECoord sizeY, ECoord sep1d, ECoord sep2d) {
NodeLayer nl = new NodeLayer(layer, portNum, style, Technology.NodeLayer.MULTICUTBOX, techPoints);
nl.cutSizeX = sizeX;
nl.cutSizeY = sizeY;
nl.cutSep1D = sep1d;
nl.cutSep2D = sep2d;
return nl;
}
/**
* Returns the Layer
object associated with this NodeLayer.
* @return the Layer
object associated with this NodeLayer.
*/
public Layer getLayer() {
return layer.getNonPseudoLayer();
}
/**
* Tells whether this NodeLayer is associated with pseudo-layer.
* @return true if this NodeLayer is associated with pseudo-layer.
*/
public boolean isPseudoLayer() {
return layer.isPseudoLayer();
}
/**
* Returns the Layer
or pseudo-layer object associated with this NodeLayer.
* @return the Layer
or pseudo-layer object associated with this NodeLayer.
*/
public Layer getLayerOrPseudoLayer() {
return layer;
}
/**
* Returns the 0-based index of the port associated with this NodeLayer.
* @return the 0-based index of the port associated with this NodeLayer.
*/
public int getPortNum() {
return portNum;
}
/**
* Returns the port associated with this NodeLayer in specified PrimitiveNode.
* @param pn specified PrimitiveNode
* @return the port associated with this NodeLayer.
*/
public PrimitivePort getPort(PrimitiveNode pn) {
return portNum >= 0 ? pn.getPort(portNum) : null;
}
/**
* Returns the Poly.Type this NodeLayer will generate.
* @return the Poly.Type this NodeLayer will generate.
* Examples are polygon, lines, splines, circle, text, etc.
*/
public Poly.Type getStyle() {
return style;
}
/**
* Returns the method of interpreting "points".
* @return the method of interpreting "points".
* It can be POINTS, BOX, MINBOX, or MULTICUTBOX.
*/
public int getRepresentation() {
return representation;
}
public static String getRepresentationName(int rep) {
if (rep == POINTS) {
return "points";
}
if (rep == BOX) {
return "box";
}
// if (rep == MINBOX) return "min-box";
if (rep == MULTICUTBOX) {
return "multi-cut-box";
}
return "?";
}
/**
* Returns the list of coordinates (stored as TechPoints) associated with this NodeLayer.
* @return the list of coordinates (stored as TechPoints) associated with this NodeLayer.
*/
public TechPoint[] getPoints() {
return points;
}
// /**
// * Method to set new points to this NodeLayer
// * @param pts
// */
// public void setPoints(TechPoint [] pts) {points = pts; }
/**
* Returns the left edge coordinate (a scalable EdgeH object) associated with this NodeLayer.
* @return the left edge coordinate associated with this NodeLayer.
* It only makes sense if the representation is BOX or MINBOX.
* The returned coordinate is a scalable EdgeH object.
*/
public EdgeH getLeftEdge() {
return points[0].getX();
}
/**
* Returns the bottom edge coordinate (a scalable EdgeV object) associated with this NodeLayer.
* @return the bottom edge coordinate associated with this NodeLayer.
* It only makes sense if the representation is BOX or MINBOX.
* The returned coordinate is a scalable EdgeV object.
*/
public EdgeV getBottomEdge() {
return points[0].getY();
}
/**
* Returns the right edge coordinate (a scalable EdgeH object) associated with this NodeLayer.
* @return the right edge coordinate associated with this NodeLayer.
* It only makes sense if the representation is BOX or MINBOX.
* The returned coordinate is a scalable EdgeH object.
*/
public EdgeH getRightEdge() {
return points[1].getX();
}
/**
* Returns the top edge coordinate (a scalable EdgeV object) associated with this NodeLayer.
* @return the top edge coordinate associated with this NodeLayer.
* It only makes sense if the representation is BOX or MINBOX.
* The returned coordinate is a scalable EdgeV object.
*/
public EdgeV getTopEdge() {
return points[1].getY();
}
/**
* Returns the text message associated with this list NodeLayer.
* @return the text message associated with this list NodeLayer.
* This only makes sense if the style is one of the TEXT types.
*/
public String getMessage() {
return message;
}
/**
* Sets the text to be drawn by this NodeLayer.
* @param message the text to be drawn by this NodeLayer.
* This only makes sense if the style is one of the TEXT types.
*/
public void setMessage(String message) {
this.message = message;
}
/**
* Returns the text descriptor associated with this list NodeLayer.
* @return the text descriptor associated with this list NodeLayer.
* This only makes sense if the style is one of the TEXT types.
*/
public TextDescriptor getDescriptor() {
return descriptor;
}
/**
* Sets the text descriptor to be drawn by this NodeLayer.
* @param descriptor the text descriptor to be drawn by this NodeLayer.
* This only makes sense if the style is one of the TEXT types.
*/
public void setDescriptor(TextDescriptor descriptor) {
this.descriptor = descriptor;
}
/**
* Returns the left extension of this layer.
* Only makes sense when this is a layer in a serpentine transistor.
* @return the left extension of this layer.
*/
public ECoord getSerpentineLWidth() {
return lWidth;
}
/**
* Sets the left extension of this layer.
* Only makes sense when this is a layer in a serpentine transistor.
* @param lWidth the left extension of this layer.
*/
public void setSerpentineLWidth(double lWidth) {
this.lWidth = ECoord.fromLambdaRoundGrid(lWidth);
}
/**
* Returns the right extension of this layer.
* Only makes sense when this is a layer in a serpentine transistor.
* @return the right extension of this layer.
*/
public ECoord getSerpentineRWidth() {
return rWidth;
}
/**
* Sets the right extension of this layer.
* Only makes sense when this is a layer in a serpentine transistor.
* @param rWidth the right extension of this layer.
*/
public void setSerpentineRWidth(double rWidth) {
this.rWidth = ECoord.fromLambdaRoundGrid(rWidth);
}
/**
* Returns the top extension of this layer.
* Only makes sense when this is a layer in a serpentine transistor.
* @return the top extension of this layer.
*/
public ECoord getSerpentineExtentT() {
return extentT;
}
/**
* Sets the top extension of this layer.
* Only makes sense when this is a layer in a serpentine transistor.
* @param extentT the top extension of this layer.
*/
public void setSerpentineExtentT(double extentT) {
this.extentT = ECoord.fromLambdaRoundGrid(extentT);
}
/**
* Returns the bottom extension of this layer.
* Only makes sense when this is a layer in a serpentine transistor.
* @return the bottom extension of this layer.
*/
public ECoord getSerpentineExtentB() {
return extendB;
}
/**
* Sets the bottom extension of this layer.
* Only makes sense when this is a layer in a serpentine transistor.
* @param extendB the bottom extension of this layer.
*/
public void setSerpentineExtentB(double extendB) {
this.extendB = ECoord.fromLambdaRoundGrid(extendB);
}
public ECoord getMulticutSizeX() {
return cutSizeX;
}
public ECoord getMulticutSizeY() {
return cutSizeY;
}
public ECoord getMulticutSep1D() {
return cutSep1D;
}
public ECoord getMulticutSep2D() {
return cutSep2D;
}
void dump(PrintWriter out, EPoint correction, boolean isSerp) {
out.println("\tlayer=" + getLayerOrPseudoLayer().getName() + " port=" + getPortNum() + " style=" + getStyle().name() + " repr=" + getRepresentation());
if (getMessage() != null) {
TextDescriptor td = getDescriptor();
out.println("\t\tmessage=\"" + getMessage() + "\" td=" + Long.toHexString(td.lowLevelGet()) + " colorIndex=" + td.getColorIndex() + " disp=" + td.isDisplay());
}
if (getMulticutSizeX().signum() != 0 || getMulticutSizeY().signum() != 0 || getMulticutSep1D().signum() != 0 || getMulticutSep2D().signum() != 0) {
out.println("\t\tmultiSizeX=" + getMulticutSizeX() + " multiSizeY=" + getMulticutSizeY() + " multiSep=" + getMulticutSep1D() + " multiSpe2D=" + getMulticutSep2D());
}
if (isSerp) {
out.println("\t\tLWidth=" + getSerpentineLWidth() + " rWidth=" + getSerpentineRWidth() + " bExtend=" + getSerpentineExtentB() + " tExtend=" + getSerpentineExtentT());
}
for (Technology.TechPoint p : getPoints()) {
out.println("\t\tpoint xm=" + p.getX().getMultiplier() + " xa=" + DBMath.round(p.getX().getAdder().getLambda() - p.getX().getMultiplier() * correction.getLambdaX())
+ " ym=" + p.getY().getMultiplier() + " ya=" + DBMath.round(p.getY().getAdder().getLambda() - p.getY().getMultiplier() * correction.getLambdaY()));
}
}
public Xml.NodeLayer makeXml(boolean isSerp, boolean inLayers, boolean inElectricalLayers, Map> additionalAttributes) {
Xml.NodeLayer nld = new Xml.NodeLayer();
nld.layer = getLayer().getNonPseudoLayer().getName();
nld.style = getStyle();
nld.portNum = getPortNum();
nld.inLayers = inLayers;
nld.inElectricalLayers = inElectricalLayers;
nld.representation = getRepresentation();
Technology.TechPoint[] points = getPoints();
if (nld.representation == Technology.NodeLayer.BOX || nld.representation == Technology.NodeLayer.MULTICUTBOX) {
nld.lx.k = points[0].getX().getMultiplier() * 2;
nld.lx.addLambda(DBMath.round(points[0].getX().getAdder().getLambda()));
nld.hx.k = points[1].getX().getMultiplier() * 2;
nld.hx.addLambda(DBMath.round(points[1].getX().getAdder().getLambda()));
nld.ly.k = points[0].getY().getMultiplier() * 2;
nld.ly.addLambda(DBMath.round(points[0].getY().getAdder().getLambda()));
nld.hy.k = points[1].getY().getMultiplier() * 2;
nld.hy.addLambda(DBMath.round(points[1].getY().getAdder().getLambda()));
} else {
for (Technology.TechPoint p : points) {
nld.techPoints.add(p);
}
}
if (nld.representation == Technology.NodeLayer.MULTICUTBOX) {
nld.sizex = getMulticutSizeX().getLambda();
nld.sizey = getMulticutSizeY().getLambda();
nld.sep1d = getMulticutSep1D().getLambda();
nld.sep2d = getMulticutSep2D().getLambda();
}
if (isSerp) {
nld.lWidth = getSerpentineLWidth().getLambda();
nld.rWidth = getSerpentineRWidth().getLambda();
nld.tExtent = getSerpentineExtentT().getLambda();
nld.bExtent = getSerpentineExtentB().getLambda();
}
if (additionalAttributes != null && getMessage() != null) {
LinkedHashMap attrs = new LinkedHashMap();
attrs.put("message", getMessage());
attrs.put("relSize", getDescriptor().getSize().getSize());
additionalAttributes.put(nld, attrs);
}
return nld;
}
}
public Map getParamValues() {
return paramValues;
}
protected Map checkParamValues(Map paramValues) {
LinkedHashMap fixedParamValues = new LinkedHashMap();
for (TechFactory.Param param : techFactory.getTechParams()) {
Object value = paramValues.get(param);
if (value == null || value.getClass() != param.factoryValue.getClass()) {
value = param.factoryValue;
}
fixedParamValues.put(param, value);
}
return Collections.unmodifiableMap(fixedParamValues);
}
public class SizeCorrector {
public final HashMap arcExtends = new HashMap();
public final HashMap nodeExtends = new HashMap();
private SizeCorrector(Version version, boolean isJelib) {
int techVersion = 0;
if (isJelib) {
if (version.compareTo(DISK_VERSION_2) >= 0) {
techVersion = 2;
} else if (version.compareTo(DISK_VERSION_1) >= 0) {
techVersion = 1;
}
}
for (ArcProto ap : arcs.values()) {
ECoord correction = ECoord.ZERO;
switch (techVersion) {
case 0:
correction = ap.getBaseExtend().add(ECoord.fromLambdaRoundGrid(0.5 * ap.getLambdaElibWidthOffset()));
break;
case 1:
correction = ap.getBaseExtend();
break;
}
arcExtends.put(ap.getId(), correction);
}
for (PrimitiveNode pn : nodes.values()) {
EPoint correction = techVersion == 2 ? EPoint.ORIGIN : pn.getSizeCorrector(techVersion);
// switch (techVersion) {
// case 0:
// correction = EPoint.fromGrid(-pn.sizeCorrector.getGridX(), -pn.sizeCorrector.getGridY());
// break;
// case 1:
// SizeOffset so = pn.getProtoSizeOffset();
// double lambdaX = -0.5*(so.getLowXOffset() + so.getHighXOffset()) - pn.sizeCorrector.getLambdaX();
// double lambdaY = -0.5*(so.getLowYOffset() + so.getHighYOffset()) - pn.sizeCorrector.getLambdaY();
// correction = EPoint.fromLambda(lambdaX, lambdaY);
// break;
// }
nodeExtends.put(pn.getId(), correction);
}
}
public boolean isIdentity() {
for (ECoord arcExtend : arcExtends.values()) {
if (arcExtend.signum() != 0) {
return false;
}
}
for (EPoint nodeExtend : nodeExtends.values()) {
if (nodeExtend.getX() != 0 || nodeExtend.getY() != 0) {
return false;
}
}
return true;
}
public long getExtendFromDisk(ArcProto ap, double width) {
return DBMath.lambdaToGrid(0.5 * width) - arcExtends.get(ap.getId()).getGrid();
}
public long getExtendToDisk(ImmutableArcInst a) {
return a.getGridExtendOverMin() + arcExtends.get(a.protoId).getGrid();
}
public long getWidthToDisk(ImmutableArcInst a) {
return 2 * getExtendToDisk(a);
}
public EPoint getSizeFromDisk(PrimitiveNode pn, EPoint size) {
EPoint correction = nodeExtends.get(pn.getId());
return EPoint.fromGrid(size.getGridX() - 2 * correction.getGridX(), size.getGridY() - 2 * correction.getGridY());
}
public EPoint getSizeToDisk(ImmutableNodeInst n) {
EPoint size = n.size;
EPoint correction = nodeExtends.get(n.protoId);
if (!correction.equals(EPoint.ORIGIN)) {
size = EPoint.fromLambda(size.getLambdaX() + 2 * correction.getLambdaX(), size.getLambdaY() + 2 * correction.getLambdaY());
}
return size;
}
}
public SizeCorrector getSizeCorrector(Version version, Map projectSettings, boolean isJelib, boolean keepExtendOverMin) {
return new SizeCorrector(version, isJelib);
}
protected void setArcCorrection(SizeCorrector sc, String arcName, double lambdaBaseWidth) {
ArcProto ap = findArcProto(arcName);
ECoord correction = sc.arcExtends.get(ap.getId());
ECoord baseExtend = ECoord.fromLambdaRoundGrid(0.5 * lambdaBaseWidth);
if (!baseExtend.equals(ap.getBaseExtend())) {
correction = correction.add(baseExtend).subtract(ap.getBaseExtend());
sc.arcExtends.put(ap.getId(), correction);
}
}
protected void setNodeCorrection(SizeCorrector sc, String nodeName, double lambdaBaseWidth, double lambdaBaseHeight) {
PrimitiveNode np = findNodeProto(nodeName);
EPoint correction = sc.nodeExtends.get(np.getId());
int gridWidthExtend = (int) DBMath.lambdaToGrid(0.5 * lambdaBaseWidth);
int gridHeightExtend = (int) DBMath.lambdaToGrid(0.5 * lambdaBaseHeight);
ERectangle baseRectangle = np.getBaseRectangle();
if (gridWidthExtend != baseRectangle.getGridWidth() / 2 || gridHeightExtend != baseRectangle.getGridHeight() / 2) {
correction = EPoint.fromGrid(
correction.getGridX() + gridWidthExtend - baseRectangle.getGridWidth() / 2,
correction.getGridY() + gridHeightExtend - baseRectangle.getGridHeight() / 2);
sc.nodeExtends.put(np.getId(), correction);
}
}
/** technology is not electrical */
private static final int NONELECTRICAL = 01;
/** has no directional arcs */
private static final int NODIRECTIONALARCS = 02;
/** has no negated arcs */
private static final int NONEGATEDARCS = 04;
/** nonstandard technology (cannot be edited) */
private static final int NONSTANDARD = 010;
/** statically allocated (don't deallocate memory) */
private static final int STATICTECHNOLOGY = 020;
/** no primitives in this technology (don't auto-switch to it) */
private static final int NOPRIMTECHNOLOGY = 040;
// /** the current technology in Electric */ private static Technology curTech = null;
// /** the current tlayout echnology in Electric */ private static Technology curLayoutTech = null;
/** Generic technology for this Technology */
final Generic generic;
/** name of this technology */
private final TechId techId;
/** short, readable name of this technology */
private String techShortName;
/** full description of this technology */
private String techDesc;
/** flags for this technology */
private int userBits;
/** true if "scale" is relevant to this technology */
private boolean scaleRelevant;
/** Setting Group for this Technology */
private final Setting.RootGroup rootSettings;
/** Setting Group for this Technology */
private final Setting.Group settings;
/** factory transparent colors for this technology */
private Color[] factoryTransparentColors = {};
/** list of layers in this technology */
private final List layers = new ArrayList();
/** map from layer names to layers in this technology */
private final HashMap layersByName = new HashMap();
/** array of layers by layerId.chronIndex */
private Layer[] layersByChronIndex = {};
/** True when layer allocation is finished. */
private boolean layersAllocationLocked;
/** list of primitive nodes in this technology */
private final LinkedHashMap nodes = new LinkedHashMap();
/** array of nodes by nodeId.chronIndex */
private PrimitiveNode[] nodesByChronIndex = {};
/** Old names of primitive nodes */
protected final HashMap oldNodeNames = new HashMap();
/** count of primitive nodes in this technology */
private int nodeIndex = 0;
/** list of node groups in this technology */
final ArrayList primitiveNodeGroups = new ArrayList();
/** list of arcs in this technology */
private final LinkedHashMap arcs = new LinkedHashMap();
/** array of arcs by arcId.chronIndex */
private ArcProto[] arcsByChronIndex = {};
/** Old names of arcs */
protected final HashMap oldArcNames = new HashMap();
/** Spice header cards, level 1. */
private String[] spiceHeaderLevel1;
/** Spice header cards, level 2. */
private String[] spiceHeaderLevel2;
/** Spice header cards, level 3. */
private String[] spiceHeaderLevel3;
/** factroy resolution for this Technology */
private ECoord factoryResolution = ECoord.ZERO;
/** static list of all Manufacturers in Electric */
protected final List foundries = new ArrayList();
/** default foundry Setting for this Technology */
private final Setting cacheFoundry;
/** default foundry name for this Technology */
protected String paramFoundry;
/** scale for this Technology. */
private Setting cacheScale;
/** number of metals Setting for this Technology. */
private final Setting cacheNumMetalLayers;
/** number of metals for this Technology. */
protected Integer paramNumMetalLayers;
/** Minimum resistance for this Technology. */
private Setting cacheMinResistance;
/** Minimum capacitance for this Technology. */
private Setting cacheMinCapacitance;
/** Gate Length subtraction (in microns) for this Tech*/
private final Setting cacheGateLengthSubtraction;
/** Include gate in Resistance calculation */
private final Setting cacheIncludeGate;
/** Include ground network in parasitics calculation */
private final Setting cacheIncludeGnd;
/** Include ground network in parasitics calculation */
private final Setting cacheMaxSeriesResistance;
// /** Logical effort global fanout preference. */ private final Setting cacheGlobalFanout;
// /** Logical effort convergence (epsilon) preference. */ private final Setting cacheConvergenceEpsilon;
// /** Logical effort maximum iterations preference. */ private final Setting cacheMaxIterations;
/** Logical effort gate capacitance preference. */
private Setting cacheGateCapacitance;
/** Logical effort wire ratio preference. */
private Setting cacheWireRatio;
/** Logical effort diff alpha preference. */
private Setting cacheDiffAlpha;
// /** Logical effort keeper ratio preference. */ private final Setting cacheKeeperRatio;
// /** Default Logical effort global fanout. */ private static double DEFAULT_GLOBALFANOUT = 4.7;
// /** Default Logical effort convergence (epsilon). */ private static double DEFAULT_EPSILON = 0.001;
// /** Default Logical effort maximum iterations. */ private static int DEFAULT_MAXITER = 30;
// /** Default Logical effort keeper ratio. */ private static double DEFAULT_KEEPERRATIO = 0.1;
/** Default Logical effort gate capacitance. */
private static double DEFAULT_GATECAP = Xml.DEFAULT_LE_GATECAP;
/** Default Logical effort wire ratio. */
private static double DEFAULT_WIRERATIO = Xml.DEFAULT_LE_WIRERATIO;
/** Default Logical effort diff alpha. */
private static double DEFAULT_DIFFALPHA = Xml.DEFAULT_LE_DIFFALPHA;
/** indicates n-type objects. */
public static final int N_TYPE = 1;
/** indicates p-type objects. */
public static final int P_TYPE = 0;
/** Factory rules for the technology. */
protected XMLRules factoryRules = null;
/** Cached rules for the technology. */
protected XMLRules cachedRules = null;
/** TechFactory which created this Technology */
protected final TechFactory techFactory;
/** Params of this Technology */
private final Map paramValues;
/** Xml representation of this Technology */
protected Xml.Technology xmlTech;
/** Xml representation of menu palette */
protected Xml.MenuPalette factoryMenuPalette;
/****************************** CONTROL ******************************/
/**
* Constructs a Technology
.
* This should not be called directly, but instead is invoked through each subclass's factory.
*/
protected Technology(Generic generic, TechFactory techFactory) {
this(generic, techFactory, Foundry.Type.NONE, 0);
}
/**
* Constructs a Technology
.
* This should not be called directly, but instead is invoked through each subclass's factory.
*/
protected Technology(Generic generic, TechFactory techFactory, Foundry.Type defaultFoundry, int defaultNumMetals) {
this(generic.getId().idManager, generic, techFactory, Collections.emptyMap(), defaultFoundry, defaultNumMetals);
}
/**
* Constructs a Technology
.
* This should not be called directly, but instead is invoked through each subclass's factory.
*/
protected Technology(Generic generic, TechFactory techFactory, Map techParams, Foundry.Type defaultFoundry, int defaultNumMetals) {
this(generic.getId().idManager, generic, techFactory, techParams, defaultFoundry, defaultNumMetals);
}
/**
* Constructs a Technology
.
* This should not be called directly, but instead is invoked through each subclass's factory.
*/
protected Technology(IdManager idManager, Generic generic, TechFactory techFactory, Map techParams, Foundry.Type defaultFoundry, int defaultNumMetals) {
if (this instanceof Generic) {
assert generic == null;
generic = (Generic) this;
}
this.generic = generic;
this.techId = idManager.newTechId(techFactory.techName);
this.techFactory = techFactory;
assert techParams.size() == techFactory.getTechParams().size();
for (TechFactory.Param param : techFactory.getTechParams()) {
assert techParams.get(param).getClass() == param.factoryValue.getClass();
}
paramValues = checkParamValues(techParams);
//this.scale = 1.0;
this.scaleRelevant = true;
userBits = 0;
rootSettings = new Setting.RootGroup();
settings = rootSettings.node(getTechName());
cacheFoundry = makeStringSetting("SelectedFoundryFor" + getTechName(),
"Technology tab", getTechName() + " foundry", "Foundry", defaultFoundry.getName());
paramFoundry = defaultFoundry.getName();
cacheNumMetalLayers = makeIntSetting(getTechName() + "NumberOfMetalLayers",
"Technology tab", getTechName() + ": Number of Metal Layers", "NumMetalLayers", defaultNumMetals);
paramNumMetalLayers = Integer.valueOf(defaultNumMetals);
cacheMaxSeriesResistance = makeParasiticSetting("MaxSeriesResistance", 10.0);
cacheGateLengthSubtraction = makeParasiticSetting("GateLengthSubtraction", 0.0);
cacheIncludeGate = makeParasiticSetting("Gate Inclusion", false);
cacheIncludeGnd = makeParasiticSetting("Ground Net Inclusion", false);
// cacheGlobalFanout = makeLESetting("GlobalFanout", DEFAULT_GLOBALFANOUT);
// cacheConvergenceEpsilon = makeLESetting("ConvergenceEpsilon", DEFAULT_EPSILON);
// cacheMaxIterations = makeLESetting("MaxIterations", DEFAULT_MAXITER);
// cacheGateCapacitance = makeLESetting("GateCapacitance", DEFAULT_GATECAP);
// cacheWireRatio = makeLESetting("WireRatio", DEFAULT_WIRERATIO);
// cacheDiffAlpha = makeLESetting("DiffAlpha", DEFAULT_DIFFALPHA);
// cacheKeeperRatio = makeLESetting("KeeperRatio", DEFAULT_KEEPERRATIO);
}
protected Object writeReplace() {
return new TechnologyKey(this);
}
private static class TechnologyKey extends EObjectInputStream.Key {
public TechnologyKey() {
}
private TechnologyKey(Technology tech) {
super(tech);
}
@Override
public void writeExternal(EObjectOutputStream out, Technology tech) throws IOException {
TechId techId = tech.getId();
if (techId.idManager != out.getIdManager()) {
throw new NotSerializableException(tech + " from other IdManager");
}
if (out.getDatabase().getTechPool().getTech(techId) != tech) {
throw new NotSerializableException(tech + " not linked");
}
out.writeInt(techId.techIndex);
}
@Override
public Technology readExternal(EObjectInputStream in) throws IOException, ClassNotFoundException {
int techIndex = in.readInt();
TechId techId = in.getIdManager().getTechId(techIndex);
Technology tech = in.getDatabase().getTech(techId);
if (tech == null) {
throw new InvalidObjectException(techId + " not linked");
}
return tech;
}
}
public Technology(Generic generic, TechFactory techFactory, Map techParams, Xml.Technology t) {
this(generic, techFactory, techParams, Foundry.Type.valueOf(t.defaultFoundry), t.defaultNumMetals);
xmlTech = t;
factoryMenuPalette = t.menuPalette;
setTechShortName(t.shortTechName);
setTechDesc(t.description);
setFactoryScale(t.scaleValue, t.scaleRelevant);
setFactoryResolution(t.resolutionValue);
setFactoryParasitics(t.minResistance, t.minCapacitance);
setFactoryLESettings(t.leGateCapacitance, t.leWireRatio, t.leDiffAlpha);
if (!t.transparentLayers.isEmpty()) {
setFactoryTransparentLayers(t.transparentLayers.toArray(new Color[t.transparentLayers.size()]));
}
HashMap layers = new HashMap();
for (Xml.Layer l : t.layers) {
Layer layer = Layer.newInstance(this, l.name, l.desc);
layers.put(l.name, layer);
layer.setFunction(l.function, l.extraFunction);
layer.setFactoryParasitics(l.resistance, l.capacitance, l.edgeCapacitance);
layer.setFactoryCIFLayer(l.cif != null ? l.cif : "");
layer.setFactoryDXFLayer("");
layer.setFactorySkillLayer(l.skill != null ? l.skill : "");
layer.setFactory3DInfo(l.thick3D, l.height3D);
}
HashMap arcs = new HashMap();
for (Xml.ArcProto a : t.arcs) {
if (findArcProto(a.name) != null) {
System.out.println("Error: technology " + getTechName() + " has multiple arcs named " + a.name);
continue;
}
// Check if there is any pin defined to connect to otherwise it should not create the arc!
if (t.findPinNode(a.name) == null) {
System.out.println("Error: no pin found for arc '" + a.name + "'");
}
ArcLayer[] arcLayers = new ArcLayer[a.arcLayers.size()];
for (int i = 0; i < arcLayers.length; i++) {
Xml.ArcLayer al = a.arcLayers.get(i);
arcLayers[i] = new ArcLayer(layers.get(al.layer), al.style, al.extend.value);
}
Double diskOffset1 = a.diskOffset.get(Integer.valueOf(1));
Double diskOffset2 = a.diskOffset.get(Integer.valueOf(2));
long halfElibWidthOffset = 0;
if (diskOffset1 != null && diskOffset2 != null) {
halfElibWidthOffset = DBMath.lambdaToGrid(diskOffset1.doubleValue() - diskOffset2.doubleValue());
}
ArcProto ap;
if (a.curvable) {
ap = new ArcProto.Curvable(this, a.name, DBMath.gridToLambda(halfElibWidthOffset * 2), a.function, arcLayers, arcs.size());
} else {
ap = new ArcProto(this, a.name, DBMath.gridToLambda(halfElibWidthOffset * 2), a.function, arcLayers, arcs.size());
}
addArcProto(ap);
if (a.oldName != null) {
oldArcNames.put(a.oldName, ap);
}
arcs.put(a.name, ap);
if (a.wipable) {
ap.setWipable();
}
if (a.special) {
ap.setSpecialArc();
}
if (a.notUsed) {
ap.setNotUsed(true);
}
if (a.skipSizeInPalette) {
ap.setSkipSizeInPalette();
}
ap.setFactoryExtended(a.extended);
ap.setFactoryFixedAngle(a.fixedAngle);
ap.setFactoryAngleIncrement(a.angleIncrement);
ap.setFactoryAntennaRatio(a.antennaRatio);
// if (a.arcPin != null)
// ap.makeWipablePin(a.arcPin.name, a.arcPin.portName, a.arcPin.elibSize, makeConnections(a.arcPin.portArcs, arcs));
}
setNoNegatedArcs();
for (Xml.PrimitiveNodeGroup ng : t.nodeGroups) {
PrimitiveNodeGroup.makePrimitiveNodes(this, ng, layers, arcs);
}
for (Xml.Layer l : t.layers) {
if (l.pureLayerNode == null) {
continue;
}
Layer layer = layers.get(l.name);
PrimitiveNode pn = layer.makePureLayerNode(l.pureLayerNode.name, l.pureLayerNode.size.value, l.pureLayerNode.style,
l.pureLayerNode.port, makeConnections(l.pureLayerNode.name, l.pureLayerNode.port, l.pureLayerNode.portArcs, arcs));
if (l.pureLayerNode.oldName != null) {
oldNodeNames.put(l.pureLayerNode.oldName, pn);
}
}
for (Xml.SpiceHeader h : t.spiceHeaders) {
String[] spiceLines = h.spiceLines.toArray(new String[h.spiceLines.size()]);
switch (h.level) {
case 1:
setSpiceHeaderLevel1(spiceLines);
break;
case 2:
setSpiceHeaderLevel2(spiceLines);
break;
case 3:
setSpiceHeaderLevel3(spiceLines);
break;
}
}
for (Xml.Foundry f : t.foundries) {
ArrayList gdsLayers = new ArrayList();
for (Layer layer : this.layers) {
String gds = f.layerGds.get(layer.getName());
if (gds == null) {
continue;
}
gdsLayers.add(layer.getName() + " " + gds);
}
Foundry foundry = new Foundry(this, Foundry.Type.valueOf(f.name), f.rules, gdsLayers.toArray(new String[gdsLayers.size()]));
foundries.add(foundry);
}
}
static ArcProto[] makeConnections(String nodeName, String portName, List portArcs, Map arcs) {
ArcProto[] connections = new ArcProto[portArcs.size()];
for (int j = 0; j < connections.length; j++) {
ArcProto ap = arcs.get(portArcs.get(j));
if (ap == null) {
String error = "No such arcProto '" + portArcs.get(j) + "' found for node '" + nodeName
+ "', port '" + portName + "'";
throw new NoSuchElementException(error);
}
connections[j] = ap;
}
return connections;
}
static TechPoint makeTechPoint(Xml.Distance x, Xml.Distance y) {
return new TechPoint(makeEdgeH(x), makeEdgeV(y));
}
static EdgeH makeEdgeH(Xml.Distance x) {
return new EdgeH(x.k * 0.5, x.value);
}
static EdgeV makeEdgeV(Xml.Distance y) {
return new EdgeV(y.k * 0.5, y.value);
}
public boolean isXmlTechAvailable() {
return xmlTech != null;
}
public Xml.Technology getXmlTech() {
return xmlTech != null ? xmlTech.deepClone() : null;
}
public static Environment makeInitialEnvironment() {
Environment env = IdManager.stdIdManager.getInitialEnvironment();
env = env.withToolSettings((Setting.RootGroup) ToolSettings.getToolSettings(""));
Generic generic = Generic.newInstance(IdManager.stdIdManager);
env = env.addTech(generic);
for (TechFactory techFactory : TechFactory.getKnownTechs().values()) {
Map paramValues = paramValuesFromPreferences(techFactory);
Technology tech = techFactory.newInstance(generic, paramValues);
if (tech != null) {
env = env.addTech(tech);
}
}
Setting.SettingChangeBatch changeBatch = new Setting.SettingChangeBatch();
Preferences prefRoot = Pref.getPrefRoot();
for (Setting setting : env.getSettings().keySet()) {
changeBatch.add(setting, setting.getValueFromPreferences(prefRoot));
}
for (Technology t : env.techPool.values()) {
for (Map.Entry e : t.getParamValues().entrySet()) {
TechFactory.Param param = e.getKey();
changeBatch.add(t.getSetting(param), e.getValue());
}
}
env = env.withSettingChanges(changeBatch);
return env;
}
/**
* Loads from Java Preferences values of technology parameters.
* This is called once, at the start of Electric, to initialize the technologies.
* @return values of technology parameters.
*/
public static Map getParamValuesByXmlPath() {
Map paramValuesByXmlPath = new HashMap();
for (TechFactory techFactory : TechFactory.getKnownTechs().values()) {
Map paramValues = Technology.paramValuesFromPreferences(techFactory);
for (Map.Entry e : paramValues.entrySet()) {
paramValuesByXmlPath.put(e.getKey().xmlPath, e.getValue());
}
}
return paramValuesByXmlPath;
}
/**
* This is called once, at the start of Electric, to initialize the technologies.
* Because of Java's "lazy evaluation", the only way to force the technology constructors to fire
* and build a proper list of technologies, is to call each class.
* So, each technology is listed here. If a new technology is created, this must be added to this list.
*/
public static void initPreinstalledTechnologies(EDatabase database, Map paramValuesByXmlPath) {
database.setToolSettings((Setting.RootGroup) ToolSettings.getToolSettings(""));
assert database.getGeneric() == null;
Generic generic = Generic.newInstance(database.getIdManager());
database.addTech(generic);
for (TechFactory techFactory : TechFactory.getKnownTechs().values()) {
Map paramValues = new HashMap();
for (TechFactory.Param techParam : techFactory.getTechParams()) {
Object paramValue = paramValuesByXmlPath.get(techParam.xmlPath);
if (paramValue == null) {
continue;
}
paramValues.put(techParam, paramValue);
}
Technology tech = techFactory.newInstance(generic, paramValues);
if (tech != null) {
database.addTech(tech);
}
}
}
private static Map paramValuesFromPreferences(TechFactory techFactory) {
HashMap paramValues = new HashMap();
for (TechFactory.Param param : techFactory.getTechParams()) {
String prefPath = param.prefPath;
int index = prefPath.lastIndexOf('/');
String prefName = prefPath.substring(index + 1);
prefPath = prefPath.substring(0, index);
Preferences prefNode = Pref.getPrefRoot().node(prefPath);
Object value = null;
Object factoryValue = param.factoryValue;
if (factoryValue instanceof Boolean) {
value = Boolean.valueOf(prefNode.getBoolean(prefName, ((Boolean) factoryValue).booleanValue()));
} else if (factoryValue instanceof Integer) {
value = Integer.valueOf(prefNode.getInt(prefName, ((Integer) factoryValue).intValue()));
} else if (factoryValue instanceof Long) {
value = Long.valueOf(prefNode.getLong(prefName, ((Long) factoryValue).longValue()));
} else if (factoryValue instanceof Double) {
value = Double.valueOf(prefNode.getDouble(prefName, ((Double) factoryValue).doubleValue()));
} else {
value = prefNode.get(prefName, factoryValue.toString());
}
if (value.equals(factoryValue)) {
value = factoryValue;
}
paramValues.put(param, value);
}
return paramValues;
}
/**
* Method to return the MOSIS CMOS technology.
* @return the MOSIS CMOS technology object.
*/
public static Technology getMocmosTechnology() {
return findTechnology("mocmos");
}
/**
* Method to return the TSMC 180 nanometer technology.
* Since the technology is a "plugin" and not distributed universally, it may not exist.
* @return the TSMC180 technology object (null if it does not exist).
*/
public static Technology getTSMC180Technology() {
return findTechnology("tsmc180");
}
/**
* Method to return the CMOS 90 nanometer technology.
* Since the technology is a "plugin" and not distributed universally, it may not exist.
* @return the CMOS90 technology object (null if it does not exist).
*/
public static Technology getCMOS90Technology() {
return findTechnology("cmos90");
}
/**
* Method to initialize a technology.
* Calls the technology's specific "init()" method (if any).
* Also sets up mappings from pseudo-layers to real layers.
*/
public void setup() {
if (cacheMinResistance == null || cacheMinCapacitance == null) {
setFactoryParasitics(10, 0);
}
if (cacheGateCapacitance == null || cacheWireRatio == null || cacheDiffAlpha == null) {
setFactoryLESettings(DEFAULT_GATECAP, DEFAULT_WIRERATIO, DEFAULT_DIFFALPHA);
}
layersAllocationLocked = true;
for (Foundry foundry : foundries) {
foundry.finish();
}
for (Layer layer : layers) {
if (!layer.isPseudoLayer()) {
layer.finish();
}
}
for (ArcProto arcProto : arcs.values()) {
arcProto.finish();
}
rootSettings.lock();
check();
}
/**
* Method to set state of a technology.
*/
public Technology withTechParams(Map paramValues) {
Map newParams = checkParamValues(paramValues);
if (newParams.equals(this.paramValues)) {
return this;
}
return techFactory.newInstance(generic, newParams);
}
protected void setNotUsed(int numPolys) {
int numMetals = getNumMetals();
for (PrimitiveNode pn : nodes.values()) {
boolean isUsed = true;
for (NodeLayer nl : pn.getNodeLayers()) {
isUsed = isUsed && nl.getLayer().getFunction().isUsed(numMetals, numPolys);
}
pn.setNotUsed(!isUsed);
}
for (ArcProto ap : arcs.values()) {
boolean isUsed = true;
for (ArcLayer al : ap.layers) {
isUsed = isUsed && al.getLayer().getFunction().isUsed(numMetals, numPolys);
}
ap.setNotUsed(!isUsed);
}
}
/**
* Returns the current Technology.
* @return the current Technology.
* The current technology is maintained by the system as a default
* in situations where a technology cannot be determined.
*/
public static Technology getCurrent() {
return Job.getUserInterface().getCurrentTechnology();
// if (curTech == null)
// {
// System.out.println("The current technology is null. Check the technology settings.");
// // tries to get the User default
// curTech = findTechnology(User.getDefaultTechnology());
// if (curTech == null)
// {
// System.out.println("User default technology is not loaded. Check the technology settings");
// // tries to get MoCMOS tech
// curTech = getMocmosTechnology();
// if (curTech == null)
// {
// System.out.println("Major error: MoCMOS technology not loaded. Check the technology settings");
// }
// }
// }
// return curTech;
}
// /**
// * Set this to be the current Technology
// * The current technology is maintained by the system as a default
// * in situations where a technology cannot be determined.
// */
// public void setCurrent()
// {
// curTech = this;
// }
//
// /**
// * Returns the total number of Technologies currently in Electric.
// * @return the total number of Technologies currently in Electric.
// */
// public static int getNumTechnologies()
// {
// return technologies.size();
// }
/**
* Find the Technology with a particular name.
* @param name the name of the desired Technology
* @return the Technology with the same name, or null if no
* Technology matches.
*/
public static Technology findTechnology(String name) {
if (name == null) {
return null;
}
// TechId techId = EDatabase.theDatabase.getIdManager().newTechId(name);
// Technology tech = findTechnology(techId);
// if (tech != null) return tech;
for (Iterator it = getTechnologies(); it.hasNext();) {
Technology t = it.next();
if (t.getTechName().equals(name)) // if (t.getTechName().equalsIgnoreCase(name))
{
return t;
}
}
return null;
}
/**
* Find the Technology with a particular TechId.
* @param techId the TechId of the desired Technology
* @return the Technology with the same name, or null if no
* Technology matches.
*/
public static Technology findTechnology(TechId techId) {
return TechPool.getThreadTechPool().getTech(techId);
}
/**
* Get an iterator over all of the Technologies.
* @return an iterator over all of the Technologies.
*/
public static Iterator getTechnologies() {
return TechPool.getThreadTechPool().values().iterator();
}
/**
* Method to convert any old-style variable information to the new options.
* May be overrideen in subclasses.
* @param varName name of variable
* @param value value of variable
* @return map from project preferences to sitting values if variable was converted
*/
public Map convertOldVariable(String varName, Object value) {
return null;
}
/**
* Method to clean libraries with unused primitive nodes.
* May be overridden in technologies. By default it does nothing
* @param ni NodeInst node to analyze
* @param list nodes that will be removed in a remove job.
* @return true if node is not in used
*/
public boolean cleanUnusedNodesInLibrary(NodeInst ni, List list) {
NodeProto np = ni.getProto();
// To remove
if (np instanceof PrimitiveNode && ((PrimitiveNode) np).isNotUsed()) {
if (list != null) {
list.add(ni);
}
return true;
}
return false;
}
public void dump(PrintWriter out, Map settings) {
final String[] techBits = {
"NONELECTRICAL", "NODIRECTIONALARCS", "NONEGATEDARCS",
"NONSTANDARD", "STATICTECHNOLOGY", "NOPRIMTECHNOLOGY"
};
out.println("Technology " + getTechName());
out.println(getClass().toString());
out.println("shortName=" + getTechShortName());
out.println("techDesc=" + getTechDesc());
out.print("Bits: ");
printlnBits(out, techBits, userBits);
out.print("isScaleRelevant=" + isScaleRelevant());
printlnSetting(out, settings, getScaleSetting());
printlnSetting(out, settings, getPrefFoundrySetting());
printlnSetting(out, settings, getNumMetalsSetting());
dumpExtraProjectSettings(out, settings);
printlnSetting(out, settings, getMinResistanceSetting());
printlnSetting(out, settings, getGateLengthSubtractionSetting());
printlnSetting(out, settings, getGateIncludedSetting());
printlnSetting(out, settings, getGroundNetIncludedSetting());
printlnSetting(out, settings, getMaxSeriesResistanceSetting());
printlnSetting(out, settings, getGateCapacitanceSetting());
printlnSetting(out, settings, getWireRatioSetting());
printlnSetting(out, settings, getDiffAlphaSetting());
printlnPref(out, 0, "ResolutionValueFor" + getTechName(), new Double(factoryResolution.getLambda()));
Color[] transparentLayers = getFactoryTransparentLayerColors();
for (int i = 0; i < transparentLayers.length; i++) {
out.println("TRANSPARENT_" + (i + 1) + "=" + Integer.toHexString(transparentLayers[i].getRGB()));
}
for (Layer layer : layers) {
if (layer.isPseudoLayer()) {
continue;
}
layer.dump(out, settings);
}
for (ArcProto ap : arcs.values()) {
ap.dump(out);
}
if (!oldArcNames.isEmpty()) {
out.println("OldArcNames:");
for (Map.Entry e : getOldArcNames().entrySet()) {
out.println("\t" + e.getKey() + " --> " + e.getValue().getFullName());
}
}
for (PrimitiveNode pnp : nodes.values()) {
pnp.dump(out);
}
if (!oldNodeNames.isEmpty()) {
out.println("OldNodeNames:");
for (Map.Entry e : getOldNodeNames().entrySet()) {
out.println("\t" + e.getKey() + " --> " + e.getValue().getFullName());
}
}
for (Foundry foundry : foundries) {
out.println("Foundry " + foundry.getType());
for (Layer layer : layers) {
if (layer.isPseudoLayer()) {
continue;
}
Setting setting = foundry.getGDSLayerSetting(layer);
out.print("\t");
printlnSetting(out, settings, setting);
}
}
printSpiceHeader(out, 1, getSpiceHeaderLevel1());
printSpiceHeader(out, 2, getSpiceHeaderLevel2());
printSpiceHeader(out, 3, getSpiceHeaderLevel3());
Xml.MenuPalette menuPalette = getFactoryMenuPalette();
for (int i = 0; i < menuPalette.menuBoxes.size(); i++) {
List> menuBox = menuPalette.menuBoxes.get(i);
if (menuBox == null || menuBox.isEmpty()) {
continue;
}
out.print(" menu " + (i / menuPalette.numColumns) + " " + (i % menuPalette.numColumns));
for (Object menuItem : menuBox) {
if (menuItem instanceof Xml.ArcProto) {
out.print(" arc " + ((Xml.ArcProto) menuItem).name);
} else if (menuItem instanceof Xml.PrimitiveNode) {
out.print(" node " + ((Xml.PrimitiveNode) menuItem).name);
} else if (menuItem instanceof Xml.MenuNodeInst) {
Xml.MenuNodeInst n = (Xml.MenuNodeInst) menuItem;
boolean display = n.text != null;
out.print(" nodeInst " + n.protoName + ":" + n.function + ":" + Orientation.fromAngle(n.rotation));
if (n.text != null) {
out.print(":" + n.text + ":" + display);
}
} else {
assert menuItem instanceof String;
out.print(" " + menuItem);
}
}
out.println();
}
for (Iterator it = getFoundries(); it.hasNext();) {
Foundry foundry = it.next();
out.println(" ");
for (Iterator lit = getLayers(); lit.hasNext();) {
Layer layer = lit.next();
Setting layerGdsSetting = foundry.getGDSLayerSetting(layer);
String gdsStr = (String) settings.get(layerGdsSetting);
if (gdsStr == null || gdsStr.length() == 0) {
continue;
}
out.println(" ");
}
// for (Map.Entry e: foundry.getGDSLayers(sc).entrySet())
// out.println(" ");
List rules = foundry.getRules();
if (rules != null) {
for (DRCTemplate rule : rules) {
DRCTemplate.exportDRCRule(out, rule);
}
}
out.println(" ");
}
}
protected void dumpExtraProjectSettings(PrintWriter out, Map settings) {
}
protected static void printlnSetting(PrintWriter out, Map settings, Setting setting) {
out.println(setting.getXmlPath() + "=" + settings.get(setting) + "(" + setting.getFactoryValue() + ")");
}
static void printlnPref(PrintWriter out, int indent, String prefName, Object factoryValue) {
while (indent-- > 0) {
out.print("\t");
}
out.println(prefName + "=" + factoryValue);
}
protected static void printlnBits(PrintWriter out, String[] bitNames, int bits) {
for (int i = 0; i < Integer.SIZE; i++) {
if ((bits & (1 << i)) == 0) {
continue;
}
String bitName = i < bitNames.length ? bitNames[i] : null;
if (bitName == null) {
bitName = "BIT" + i;
}
out.print(" " + bitName);
}
out.println();
}
private void printSpiceHeader(PrintWriter out, int level, String[] header) {
if (header == null) {
return;
}
out.println("SpiceHeader " + level);
for (String s : header) {
out.println("\t\"" + s + "\"");
}
}
/**
* Create Xml structure of this Technology
*/
public Xml.Technology makeXml() {
return makeXml(null);
}
/**
* Create Xml structure of this Technology
*/
public Xml.Technology makeXml(Map> additiionalAttributes) {
Xml.Technology t = new Xml.Technology();
t.techName = getTechName();
if (getClass() != Technology.class) {
t.className = getClass().getName();
}
Xml.Version version;
version = new Xml.Version();
version.techVersion = 1;
version.electricVersion = Technology.DISK_VERSION_1;
t.versions.add(version);
version = new Xml.Version();
version.techVersion = 2;
version.electricVersion = Technology.DISK_VERSION_2;
t.versions.add(version);
t.shortTechName = getTechShortName();
t.description = getTechDesc();
int numMetals = ((Integer) getNumMetalsSetting().getFactoryValue()).intValue();
t.minNumMetals = t.maxNumMetals = t.defaultNumMetals = numMetals;
t.scaleValue = getScaleSetting().getDoubleFactoryValue();
t.scaleRelevant = isScaleRelevant();
t.resolutionValue = getFactoryResolution().getLambda();
t.defaultFoundry = (String) getPrefFoundrySetting().getFactoryValue();
t.minResistance = getMinResistanceSetting().getDoubleFactoryValue();
t.minCapacitance = getMinCapacitanceSetting().getDoubleFactoryValue();
t.leGateCapacitance = getGateCapacitanceSetting().getDoubleFactoryValue();
t.leWireRatio = getWireRatioSetting().getDoubleFactoryValue();
t.leDiffAlpha = getDiffAlphaSetting().getDoubleFactoryValue();
t.transparentLayers.addAll(Arrays.asList(getFactoryTransparentLayerColors()));
for (Iterator it = getLayers(); it.hasNext();) {
Layer layer = it.next();
if (layer.isPseudoLayer()) {
continue;
}
t.layers.add(layer.makeXml());
}
// HashSet arcPins = new HashSet();
for (Iterator it = getArcs(); it.hasNext();) {
ArcProto ap = it.next();
t.arcs.add(ap.makeXml());
// if (ap.arcPin != null)
// arcPins.add(ap.arcPin);
}
HashSet groupsDone = new HashSet();
for (Iterator it = getNodes(); it.hasNext();) {
PrimitiveNode pnp = it.next();
if (pnp.getFunction() == PrimitiveNode.Function.NODE) {
continue;
}
PrimitiveNodeGroup group = pnp.getPrimitiveNodeGroup();
if (group != null) {
if (groupsDone.contains(group)) {
continue;
}
t.nodeGroups.add(group.makeXml());
groupsDone.add(group);
} else {
t.nodeGroups.add(pnp.makeXml(additiionalAttributes));
}
}
addSpiceHeader(t, 1, getSpiceHeaderLevel1());
addSpiceHeader(t, 2, getSpiceHeaderLevel2());
addSpiceHeader(t, 3, getSpiceHeaderLevel3());
t.menuPalette = getFactoryMenuPalette();
for (Iterator it = getFoundries(); it.hasNext();) {
Foundry foundry = it.next();
Xml.Foundry f = new Xml.Foundry();
f.name = foundry.toString();
for (Layer layer : layers) {
Setting setting = foundry.getGDSLayerSetting(layer);
String gds = (String) setting.getFactoryValue();
if (gds.length() == 0) {
continue;
}
f.layerGds.put(layer.getName(), gds);
}
// Map gdsMap = foundry.getGDSLayers();
// for (Map.Entry e: gdsMap.entrySet()) {
// String gds = e.getValue();
// if (gds.length() == 0) continue;
// f.layerGds.put(e.getKey().getName(), gds);
// }
List rules = foundry.getRules();
if (rules != null) {
f.rules.addAll(rules);
}
t.foundries.add(f);
}
return t;
}
private static void addSpiceHeader(Xml.Technology t, int level, String[] spiceLines) {
if (spiceLines == null) {
return;
}
Xml.SpiceHeader spiceHeader = new Xml.SpiceHeader();
spiceHeader.level = level;
for (String spiceLine : spiceLines) {
spiceHeader.spiceLines.add(spiceLine);
}
t.spiceHeaders.add(spiceHeader);
}
/****************************** LAYERS ******************************/
/**
* Returns an Iterator on the Layers in this Technology.
* @return an Iterator on the Layers in this Technology.
*/
public Iterator getLayers() {
layersAllocationLocked = true;
return layers.iterator();
}
/**
* Returns the Layer in this technology with a particular Id
* @param layerId the Id of the Layer.
* @return the Layer in this technology with that Id.
*/
public Layer getLayer(LayerId layerId) {
assert layerId.techId == techId;
int chronIndex = layerId.chronIndex;
return chronIndex < layersByChronIndex.length ? layersByChronIndex[chronIndex] : null;
}
/**
* Returns the Layer in this technology with a particular chron index
* @param chronIndex index the Id of the Layer.
* @return the Layer in this technology with that Id.
*/
Layer getLayerByChronIndex(int chronIndex) {
return chronIndex < layersByChronIndex.length ? layersByChronIndex[chronIndex] : null;
}
/**
* Returns a specific Layer number in this Technology.
* @param index the index of the desired Layer.
* @return the indexed Layer in this Technology.
*/
public Layer getLayer(int index) {
return layers.get(index);
}
/**
* Returns the number of Layers in this Technology.
* @return the number of Layers in this Technology.
*/
public int getNumLayers() {
layersAllocationLocked = true;
return layers.size();
}
/**
* Method to find a Layer with a given name.
* @param layerName the name of the desired Layer.
* @return the Layer with that name (null if none found).
*/
public Layer findLayer(String layerName) {
Layer layer = layersByName.get(layerName);
if (layer != null) {
return layer;
}
for (Iterator it = getLayers(); it.hasNext();) {
layer = it.next();
if (layer.getName().equalsIgnoreCase(layerName)) {
return layer;
}
}
for (Iterator it = getLayers(); it.hasNext();) {
layer = it.next().getPseudoLayer();
if (layer == null) {
continue;
}
if (layer.getName().equalsIgnoreCase(layerName)) {
return layer;
}
}
return null;
}
/**
* Method to determine the index in the upper-left triangle array for two layers/nodes.
* The sequence of indices is: rules for single layers, rules for nodes, rules that
* involve more than 1 layers.
* @param index1 the first layer/node index.
* @param index2 the second layer/node index.
* @return the index in the array that corresponds to these two layers/nodes.
*/
public int getRuleIndex(int index1, int index2) {
int numLayers = getNumLayers();
if (index1 > index2) {
int temp = index1;
index1 = index2;
index2 = temp;
}
int pIndex = (index1 + 1) * (index1 / 2) + (index1 & 1) * ((index1 + 1) / 2);
pIndex = index2 + numLayers * index1 - pIndex;
return numLayers + getNumNodes() + pIndex;
}
/**
* Method to retrieve index of the node in the map containing DRC rules
* It must add the total number of layers to guarantee indexes don't collide with
* layer indices.
* The sequence of indices is: rules for single layers, rules for nodes, rules that
* involve more than 1 layers.
* @return the index of this node in its Technology.
*/
public final int getPrimNodeIndexInTech(PrimitiveNode node) {
return getNumLayers() + node.getPrimNodeInddexInTech();
}
/**
* Method to determine index of layer or node involved in the rule
* @param name name of the layer or node
* @return the index of the rule.
*/
public int getRuleNodeIndex(String name) {
// Checking if node is found
// Be careful because iterator might change over time?
int count = 0;
for (Iterator it = getNodes(); it.hasNext(); count++) {
PrimitiveNode pn = it.next();
if (pn.getName().equals(name)) // if (pn.getName().equalsIgnoreCase(name))
{
return (getNumLayers() + count); // it should use get
}
}
return -1;
}
public static Layer getLayerFromOverride(String override, int startPos, char endChr, Technology tech) {
int endPos = override.indexOf(endChr, startPos);
if (endPos < 0) {
return null;
}
String layerName = override.substring(startPos, endPos);
return tech.findLayer(layerName);
}
/**
* Method to find the Layer in this Technology that matches a function description.
* @param fun the layer function to locate.
* @param functionExtras
* @return the Layer that matches this description (null if not found).
*/
public Layer findLayerFromFunction(Layer.Function fun, int functionExtras) {
for (Iterator it = this.getLayers(); it.hasNext();) {
Layer lay = it.next();
Layer.Function lFun = lay.getFunction();
if (lFun == fun) {
// Nothing extra to look for or it really matches
if (functionExtras == -1 || functionExtras == lay.getFunctionExtras()) {
return lay;
}
}
}
return null;
}
/**
* Method to add a new Layer to this Technology.
* This is usually done during initialization.
* @param layer the Layer to be added to this Technology.
*/
public void addLayer(Layer layer) {
if (layersAllocationLocked) {
throw new IllegalStateException("layers allocation is locked");
}
layer.setIndex(layers.size());
layers.add(layer);
Layer oldLayer = layersByName.put(layer.getName(), layer);
assert oldLayer == null;
LayerId layerId = layer.getId();
if (layerId.chronIndex >= layersByChronIndex.length) {
Layer[] newLayersByChronIndex = new Layer[layerId.chronIndex + 1];
System.arraycopy(layersByChronIndex, 0, newLayersByChronIndex, 0, layersByChronIndex.length);
layersByChronIndex = newLayersByChronIndex;
}
assert layersByChronIndex[layerId.chronIndex] == null;
layersByChronIndex[layerId.chronIndex] = layer;
}
/**
* Method to tell whether two layers should be considered equivalent for the purposes of cropping.
* The method is overridden by individual technologies to provide specific answers.
* @param layer1 the first Layer.
* @param layer2 the second Layer.
* @return true if the layers are equivalent.
*/
public boolean sameLayer(Layer layer1, Layer layer2) {
if (layer1 == layer2) {
return true;
}
// Only when the function and the extra bits match. Case of active and active well
if (layer1.getFunction() == layer2.getFunction()
&& layer1.getFunctionExtras() == layer2.getFunctionExtras()) {
return true;
}
if (layer1.getFunction() == Layer.Function.POLY1 && layer2.getFunction() == Layer.Function.GATE) {
return true;
}
if (layer2.getFunction() == Layer.Function.POLY1 && layer1.getFunction() == Layer.Function.GATE) {
return true;
}
return false;
}
/**
* Method to make a sorted list of layers in this Technology.
* The list is sorted by depth (from bottom to top) stored in Function.height.
* @return a sorted list of Layers in this Technology.
*/
public List getLayersSortedByHeight() {
// determine order of overlappable layers in current technology
List layerList = new ArrayList();
for (Iterator it = getLayers(); it.hasNext();) {
layerList.add(it.next());
}
Collections.sort(layerList, LAYERS_BY_HEIGHT);
return (layerList);
}
/**
* Method to make a sorted list of layers in this Technology
* based on their name.
* @return a sorted list of Layers in this Technology.
*/
public List getLayersSortedByName() {
List layerList = new ArrayList();
for (Iterator it = getLayers(); it.hasNext();) {
layerList.add(it.next());
}
Collections.sort(layerList, Layer.layerSortByName);
return (layerList);
}
public static final LayerHeight LAYERS_BY_HEIGHT = new LayerHeight(false);
public static final LayerHeight LAYERS_BY_HEIGHT_LIFT_CONTACTS = new LayerHeight(true);
private static class LayerHeight implements Comparator {
final boolean liftContacts;
private LayerHeight(boolean liftContacts) {
this.liftContacts = liftContacts;
}
public int compare(Layer l1, Layer l2) {
Layer.Function f1 = l1.getFunction();
Layer.Function f2 = l2.getFunction();
if (f1 == null || f2 == null) {
System.out.println();
}
int h1 = f1.getHeight();
int h2 = f2.getHeight();
if (liftContacts) {
if (f1.isContact()) {
h1++;
} else if (f1.isMetal()) {
h1--;
}
if (f2.isContact()) {
h2++;
} else if (f2.isMetal()) {
h2--;
}
}
int cmp = h1 - h2;
if (cmp != 0) {
return cmp;
}
Technology tech1 = l1.getTechnology();
Technology tech2 = l2.getTechnology();
if (tech1 != tech2) {
int techIndex1 = tech1 != null ? tech1.getId().techIndex : -1;
int techIndex2 = tech2 != null ? tech2.getId().techIndex : -1;
return techIndex1 - techIndex2;
}
return l1.getIndex() - l2.getIndex();
}
}
/**
* Dummy method overridden by implementing technologies to define
* the number of metal layers in the technology. Applies to layout
* technologies. Can by changed by user preferences.
* @return the number of metal layers currently specified for the technology
*/
public int getNumMetals() {
return paramNumMetalLayers.intValue();
}
/**
* Returns project preferences to tell the number of metal layers in the MoCMOS technology.
* @return project preferences to tell the number of metal layers in the MoCMOS technology (from 2 to 6).
*/
public Setting getNumMetalsSetting() {
return cacheNumMetalLayers;
}
/****************************** ARCS ******************************/
/**
* Method to create a new ArcProto from the parameters.
* @param protoName the name of this ArcProto.
* It may not have unprintable characters, spaces, or tabs in it.
* @param lambdaWidthOffset width offset in lambda units.
* @param defaultWidth the default width of this ArcProto.
* @param layers the Layers that make up this ArcProto.
* @return the newly created ArcProto.
*/
protected ArcProto newArcProto(String protoName, double lambdaWidthOffset, double defaultWidth, ArcProto.Function function, Technology.ArcLayer... layers) {
// check the arguments
if (findArcProto(protoName) != null) {
System.out.println("Error: technology " + getTechName() + " has multiple arcs named " + protoName);
return null;
}
long gridWidthOffset = DBMath.lambdaToSizeGrid(lambdaWidthOffset);
if (gridWidthOffset < 0 || gridWidthOffset > Integer.MAX_VALUE) {
System.out.println("ArcProto " + getTechName() + ":" + protoName + " has invalid width offset " + lambdaWidthOffset);
return null;
}
if (defaultWidth < DBMath.gridToLambda(gridWidthOffset)) {
System.out.println("ArcProto " + getTechName() + ":" + protoName + " has negative width");
return null;
}
long defaultGridWidth = DBMath.lambdaToSizeGrid(defaultWidth);
assert layers[0].getExtend().getGrid() == (defaultGridWidth - gridWidthOffset) / 2;
ArcProto ap = new ArcProto(this, protoName, DBMath.gridToLambda(gridWidthOffset), function, layers, arcs.size());
addArcProto(ap);
return ap;
}
/**
* Returns the ArcProto in this technology with a particular name.
* @param name the name of the ArcProto.
* @return the ArcProto in this technology with that name.
*/
public ArcProto findArcProto(String name) {
if (name == null) {
return null;
}
return arcs.get(name);
// ArcProto primArc = arcs.get(name);
// if (primArc != null) return primArc;
//
// for (Iterator it = getArcs(); it.hasNext(); )
// {
// ArcProto ap = it.next();
// if (ap.getName().equalsIgnoreCase(name))
// return ap;
// }
// return null;
}
/**
* Returns the ArcProto in this technology with a particular Id
* @param arcProtoId the Id of the ArcProto.
* @return the ArcProto in this technology with that Id.
*/
public ArcProto getArcProto(ArcProtoId arcProtoId) {
assert arcProtoId.techId == techId;
int chronIndex = arcProtoId.chronIndex;
return chronIndex < arcsByChronIndex.length ? arcsByChronIndex[chronIndex] : null;
}
/**
* Returns the ArcProto in this technology with a particular chron index
* @param chronIndex index the Id of the ArcProto.
* @return the ArcProto in this technology with that Id.
*/
ArcProto getArcProtoByChronIndex(int chronIndex) {
return chronIndex < arcsByChronIndex.length ? arcsByChronIndex[chronIndex] : null;
}
/**
* Returns an Iterator on the ArcProto objects in this technology.
* @return an Iterator on the ArcProto objects in this technology.
*/
public Iterator getArcs() {
return arcs.values().iterator();
}
/**
* Retusn a collection of the ArcProto objects in this technology
* @return a collection of the ArcProto objects in this technology
*/
public Collection getArcsCollection() {
return arcs.values();
}
/**
* Returns the number of ArcProto objects in this technology.
* @return the number of ArcProto objects in this technology.
*/
public int getNumArcs() {
return arcs.size();
}
/**
* Method to add a new ArcProto to this Technology.
* This is usually done during initialization.
* @param ap the ArcProto to be added to this Technology.
*/
public void addArcProto(ArcProto ap) {
assert findArcProto(ap.getName()) == null;
assert ap.primArcIndex == arcs.size();
arcs.put(ap.getName(), ap);
ArcProtoId arcProtoId = ap.getId();
if (arcProtoId.chronIndex >= arcsByChronIndex.length) {
ArcProto[] newArcsByChronIndex = new ArcProto[arcProtoId.chronIndex + 1];
System.arraycopy(arcsByChronIndex, 0, newArcsByChronIndex, 0, arcsByChronIndex.length);
arcsByChronIndex = newArcsByChronIndex;
}
arcsByChronIndex[arcProtoId.chronIndex] = ap;
}
/**
* Sets the technology to have no directional arcs.
* Users should never call this method.
* It is set once by the technology during initialization.
* Directional arcs are those with arrows on them, indicating (only graphically) the direction of flow through the arc.
*/
protected void setNoDirectionalArcs() {
userBits |= NODIRECTIONALARCS;
}
/**
* Returns true if this technology does not have directional arcs.
* @return true if this technology does not have directional arcs.
* Directional arcs are those with arrows on them, indicating (only graphically) the direction of flow through the arc.
*/
public boolean isNoDirectionalArcs() {
return (userBits & NODIRECTIONALARCS) != 0;
}
/**
* Sets the technology to have no negated arcs.
* Users should never call this method.
* It is set once by the technology during initialization.
* Negated arcs have bubbles on them to graphically indicated negation.
* Only Schematics and related technologies allow negated arcs.
*/
protected void setNoNegatedArcs() {
userBits |= NONEGATEDARCS;
}
/**
* Returns true if this technology does not have negated arcs.
* @return true if this technology does not have negated arcs.
* Negated arcs have bubbles on them to graphically indicated negation.
* Only Schematics and related technologies allow negated arcs.
*/
public boolean isNoNegatedArcs() {
return (userBits & NONEGATEDARCS) != 0;
}
/**
* Returns the polygons that describe arc "ai".
* @param ai the ArcInst that is being described.
* @return an array of Poly objects that describes this ArcInst graphically.
*/
public Poly[] getShapeOfArc(ArcInst ai) {
return getShapeOfArc(ai, null);
}
/**
* Returns the polygons that describe arc "ai".
* @param ai the ArcInst that is being described.
* @param onlyTheseLayers to filter the only required layers
* @return an array of Poly objects that describes this ArcInst graphically.
*/
public Poly[] getShapeOfArc(ArcInst ai, Layer.Function.Set onlyTheseLayers) {
Poly.Builder polyBuilder = Poly.threadLocalLambdaBuilder();
return polyBuilder.getShapeArray(ai, onlyTheseLayers);
}
/**
* Method to convert old primitive arc names to their proper ArcProtos.
* @param name the unknown arc name, read from an old Library.
* @return the proper ArcProto to use for this name.
*/
public ArcProto convertOldArcName(String name) {
return oldArcNames.get(name);
}
public Map getOldArcNames() {
return new TreeMap(oldArcNames);
}
/****************************** NODES ******************************/
/**
* Method to return a sorted list of nodes in the technology
* @return a list with all nodes sorted
*/
public List getNodesSortedByName() {
TreeMap sortedMap = new TreeMap(TextUtils.STRING_NUMBER_ORDER);
for (Iterator it = getNodes(); it.hasNext();) {
PrimitiveNode pn = it.next();
sortedMap.put(pn.getName(), pn);
}
return new ArrayList(sortedMap.values());
}
/**
* Returns the PrimitiveNode in this technology with a particular name.
* @param name the name of the PrimitiveNode.
* @return the PrimitiveNode in this technology with that name.
*/
public PrimitiveNode findNodeProto(String name) {
if (name == null) {
return null;
}
return nodes.get(name);
// PrimitiveNode primNode = nodes.get(name);
// if (primNode != null) return primNode;
//
// for (Iterator it = getNodes(); it.hasNext(); )
// {
// PrimitiveNode pn = it.next();
// if (pn.getName().equalsIgnoreCase(name))
// return pn;
// }
// return null;
}
/**
* Returns the PrimitiveNode in this technology with a particular Id
* @param primitiveNodeId the Id of the PrimitiveNode.
* @return the PrimitiveNiode in this technology with that Id.
*/
public PrimitiveNode getPrimitiveNode(PrimitiveNodeId primitiveNodeId) {
assert primitiveNodeId.techId == techId;
int chronIndex = primitiveNodeId.chronIndex;
return chronIndex < nodesByChronIndex.length ? nodesByChronIndex[chronIndex] : null;
}
/**
* Returns the PrimitiveNode in this technology with a particular chron index
* @param chronIndex index the Id of the PrimitiveNode.
* @return the PrimitiveNode in this technology with that Id.
*/
PrimitiveNode getPrimitiveNodeByChronIndex(int chronIndex) {
return chronIndex < nodesByChronIndex.length ? nodesByChronIndex[chronIndex] : null;
}
/**
* Returns an Iterator on the PrimitiveNode objects in this technology.
* @return an Iterator on the PrimitiveNode objects in this technology.
*/
public Iterator getNodes() {
return nodes.values().iterator();
}
/**
* Retusn a collection of the PrimitiveNode objects in this technology
* @return a collection of the PrimitiveNode objects in this technology
*/
public Collection getNodesCollection() {
return nodes.values();
}
/**
* Returns the number of PrimitiveNodes objects in this technology.
* @return the number of PrimitiveNodes objects in this technology.
*/
public int getNumNodes() {
return nodes.size();
}
/**
* Method to create a new PrimitiveNode from the parameters.
* @param protoName the name of the PrimitiveNode.
* Primitive names may not contain unprintable characters, spaces, tabs, a colon (:), semicolon (;) or curly braces ({}).
* @param sizeCorrector size corrector for the PrimitiveNode,
* @param width the width of the PrimitiveNode.
* @param height the height of the PrimitiveNode.
* @param baseRectangle the reported/selected part of the PrimitiveNode with standard size.
* @param layers the Layers that comprise the PrimitiveNode.
* @return the newly created PrimitiveNode.
*/
protected PrimitiveNode newPrimitiveNode(String protoName, EPoint sizeCorrector1, EPoint sizeCorrector2,
String minSizeRule, double width, double height,
ERectangle fullRectangle, ERectangle baseRectangle, Technology.NodeLayer[] layers) {
return new PrimitiveNode(protoName, this, sizeCorrector1, sizeCorrector2, minSizeRule, width, height,
fullRectangle, baseRectangle, layers);
}
/**
* Method to add a new PrimitiveNode to this Technology.
* This is usually done during initialization.
* @param np the PrimitiveNode to be added to this Technology.
*/
public void addNodeProto(PrimitiveNode np) {
assert findNodeProto(np.getName()) == null;
np.setPrimNodeIndexInTech(nodeIndex++);
nodes.put(np.getName(), np);
PrimitiveNodeId primitiveNodeId = np.getId();
if (primitiveNodeId.chronIndex >= nodesByChronIndex.length) {
PrimitiveNode[] newNodesByChronIndex = new PrimitiveNode[primitiveNodeId.chronIndex + 1];
System.arraycopy(nodesByChronIndex, 0, newNodesByChronIndex, 0, nodesByChronIndex.length);
nodesByChronIndex = newNodesByChronIndex;
}
nodesByChronIndex[primitiveNodeId.chronIndex] = np;
}
private static final Layer.Function.Set diffLayers = new Layer.Function.Set(Layer.Function.DIFFP, Layer.Function.DIFFN);
/**
* Method to return the size of a resistor-type NodeInst in this Technology.
* @param ni the NodeInst.
* @param context the VarContext in which any vars will be evaluated,
* pass in VarContext.globalContext if no context needed, or set to null
* to avoid evaluation of variables (if any).
* @return the size of the NodeInst.
*/
public PrimitiveNodeSize getResistorSize(NodeInst ni, VarContext context) {
if (ni.isCellInstance()) {
return null;
}
double length = ni.getLambdaBaseXSize();
double width = ni.getLambdaBaseYSize();
// SizeOffset so = ni.getSizeOffset();
// double length = ni.getXSize() - so.getLowXOffset() - so.getHighXOffset();
// double width = ni.getYSize() - so.getLowYOffset() - so.getHighYOffset();
PrimitiveNodeSize size = new PrimitiveNodeSize(new Double(width), new Double(length), false);
return size;
}
/**
* Method to return length of active reqion. This will be used for
* parasitics extraction. Electric layers are used for the calculation
* @param ni the NodeInst.
* @return length of the any active region
*/
public double getTransistorActiveLength(NodeInst ni) {
Poly[] diffList = getShapeOfNode(ni, true, false, diffLayers);
double activeLen = 0;
if (diffList.length > 0) {
// Since electric layers are used, it takes the first active region
Poly poly = diffList[0];
activeLen = poly.getBounds2D().getHeight();
}
return activeLen;
}
/**
* Method to return the size of a transistor NodeInst in this Technology.
* You should most likely be calling NodeInst.getTransistorSize instead of this.
* @param ni the NodeInst.
* @param context the VarContext in which any vars will be evaluated,
* pass in VarContext.globalContext if no context needed, or set to null
* to avoid evaluation of variables (if any).
* @return the size of the NodeInst.
*/
public TransistorSize getTransistorSize(NodeInst ni, VarContext context) {
double width = ni.getLambdaBaseXSize();
double height = ni.getLambdaBaseYSize();
// override if there is serpentine information
Point2D[] trace = ni.getTrace();
if (trace != null) {
width = 0;
for (int i = 1; i < trace.length; i++) {
width += trace[i - 1].distance(trace[i]);
}
height = 2;
double serpentineLength = ni.getSerpentineTransistorLength();
if (serpentineLength > 0) {
height = serpentineLength;
}
//System.out.println("No calculating length for active regions yet");
}
double activeLen = getTransistorActiveLength(ni);
TransistorSize size = new TransistorSize(new Double(width), new Double(height), new Double(activeLen), null, true);
return size;
}
/**
* Method to set the size of a transistor NodeInst in this Technology.
* You should be calling NodeInst.setTransistorSize instead of this.
* @param ni the NodeInst
* @param width the new width (positive values only)
* @param length the new length (positive values only)
*/
private void setPrimitiveNodeSizeLocal(NodeInst ni, double width, double length) {
double oldWidth = ni.getLambdaBaseXSize();
double oldLength = ni.getLambdaBaseYSize();
double dW = width - oldWidth;
double dL = length - oldLength;
ni.resize(dW, dL);
}
/**
* Method to set the size of a transistor NodeInst in this Technology.
* Sense of "width" and "length" are different for resistors and transistors.
* Default function when transistor gate and resistor length are horizontal.
* @param ni the NodeInst
* @param width the new width (positive values only)
* @param length the new length (positive values only)
* @param ep EditingPreferences with default TextDescriptors
*/
public void setPrimitiveNodeSize(NodeInst ni, double width, double length, EditingPreferences ep) {
if (ni.getFunction().isResistor()) {
setPrimitiveNodeSizeLocal(ni, length, width);
} else {
setPrimitiveNodeSizeLocal(ni, width, length);
}
}
/**
* Method to return a gate PortInst for this transistor NodeInst.
* Implementation Note: May want to make this a more general
* method, getPrimitivePort(PortType), if the number of port
* types increases. Note: You should be calling
* NodeInst.getTransistorGatePort() instead of this, most likely.
* @param ni the NodeInst
* @return a PortInst for the gate of the transistor
*/
public PortInst getTransistorGatePort(NodeInst ni) {
return ni.getPortInst(0);
}
/**
* Method to return the other gate PortInst for this transistor NodeInst.
* Only useful for layout transistors that have two gate ports.
* Implementation Note: May want to make this a more general
* method, getPrimitivePort(PortType), if the number of port
* types increases. Note: You should be calling
* NodeInst.getTransistorGatePort() instead of this, most likely.
* @param ni the NodeInst
* @return a PortInst for the alternate gate of the transistor
*/
public PortInst getTransistorAltGatePort(NodeInst ni) {
if (ni.getProto().getTechnology() == Schematics.tech()) {
return ni.getPortInst(0);
}
return ni.getPortInst(2);
}
/**
* Method to return a base PortInst for this transistor NodeInst.
* @param ni the NodeInst
* @return a PortInst for the base of the transistor
*/
public PortInst getTransistorBasePort(NodeInst ni) {
return ni.getPortInst(0);
}
/**
* Method to return a source PortInst for this transistor NodeInst.
* Implementation Note: May want to make this a more general
* method, getPrimitivePort(PortType), if the number of port
* types increases. Note: You should be calling
* NodeInst.getTransistorSourcePort() instead of this, most likely.
* @param ni the NodeInst
* @return a PortInst for the source of the transistor
*/
public PortInst getTransistorSourcePort(NodeInst ni) {
return ni.getPortInst(1);
}
/**
* Method to return a emitter PortInst for this transistor NodeInst.
* @param ni the NodeInst
* @return a PortInst for the emitter of the transistor
*/
public PortInst getTransistorEmitterPort(NodeInst ni) {
return ni.getPortInst(1);
}
/**
* Method to return a drain PortInst for this transistor NodeInst.
* Implementation Note: May want to make this a more general
* method, getPrimitivePort(PortType), if the number of port
* types increases. Note: You should be calling
* NodeInst.getTransistorDrainPort() instead of this, most likely.
* @param ni the NodeInst
* @return a PortInst for the drain of the transistor
*/
public PortInst getTransistorDrainPort(NodeInst ni) {
if (ni.getProto().getTechnology() == Schematics.tech()) {
return ni.getPortInst(2);
}
return ni.getPortInst(3);
}
/**
* Method to return a collector PortInst for this transistor NodeInst.
* @param ni the NodeInst
* @return a PortInst for the collector of the transistor
*/
public PortInst getTransistorCollectorPort(NodeInst ni) {
return ni.getPortInst(2);
}
/**
* Method to return a bias PortInst for this transistor NodeInst.
* Implementation Note: May want to make this a more general
* method, getPrimitivePort(PortType), if the number of port
* types increases. Note: You should be calling
* NodeInst.getTransistorBiasPort() instead of this, most likely.
* @param ni the NodeInst
* @return a PortInst for the bias of the transistor
*/
public PortInst getTransistorBiasPort(NodeInst ni) {
// By default, transistors have no bias port
return null;
}
/**
* Sets the technology to have no primitives.
* Users should never call this method.
* It is set once by the technology during initialization.
* This indicates to the user interface that it should not switch to this technology.
* The FPGA technology has this bit set because it initially contains no primitives,
* and they are only created dynamically.
*/
public void setNoPrimitiveNodes() {
userBits |= NOPRIMTECHNOLOGY;
}
/**
* Returns true if this technology has no primitives.
* @return true if this technology has no primitives.
* This indicates to the user interface that it should not switch to this technology.
* The FPGA technology has this bit set because it initially contains no primitives,
* and they are only created dynamically.
*/
public boolean isNoPrimitiveNodes() {
return (userBits & NOPRIMTECHNOLOGY) != 0;
}
/**
* Method to set default outline information on a NodeInst.
* Very few primitives have default outline information (usually just in the Artwork Technology).
* This method is overridden by the appropriate technology.
* @param ni the NodeInst to load with default outline information.
*/
public void setDefaultOutline(NodeInst ni) {
}
/**
* Method to get the base (highlight) ERectangle associated with a NodeInst
* in this PrimitiveNode.
* Base ERectangle is a highlight rectangle of standard-size NodeInst of
* this PrimtiveNode
* By having this be a method of Technology, it can be overridden by
* individual Technologies that need to make special considerations.
* @param ni the NodeInst to query.
* @return the base ERectangle of this PrimitiveNode.
*/
public ERectangle getNodeInstBaseRectangle(NodeInst ni) {
PrimitiveNode pn = (PrimitiveNode) ni.getProto();
return pn.getBaseRectangle();
}
private static final Technology.NodeLayer[] nullPrimLayers = new Technology.NodeLayer[0];
/**
* Returns the polygons that describe node "ni".
* @param ni the NodeInst that is being described.
* The prototype of this NodeInst must be a PrimitiveNode and not a Cell.
* @return an array of Poly objects that describes this NodeInst graphically.
*/
public Poly[] getShapeOfNode(NodeInst ni) {
return getShapeOfNode(ni, false, false, (Layer.Function.Set) null);
}
// private static PrintWriter out;
//
// public static void startDebug(String fileName) {
// try {
// out = new PrintWriter(fileName);
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
//
// public static void stopDebug() {
// out.close();
// out = null;
// }
/**
* Returns the polygons that describe node "ni".
* @param ni the NodeInst that is being described.
* The prototype of this NodeInst must be a PrimitiveNode and not a Cell.
* @param electrical true to get the "electrical" layers.
* When electrical layers are requested, each layer is tied to a specific port on the node.
* If any piece of geometry covers more than one port,
* it must be split for the purposes of an "electrical" description.
* For example, the MOS transistor has 2 layers: Active and Poly.
* But it has 3 electrical layers: Active, Active, and Poly.
* The active must be split since each half corresponds to a different PrimitivePort on the PrimitiveNode.
* @param reasonable true to get only a minimal set of contact cuts in large contacts.
* The minimal set covers all edge contacts, but ignores the inner cuts in large contacts.
* @param onlyTheseLayers a set of layers to draw (if null, draw all layers).
* @return an array of Poly objects that describes this NodeInst graphically.
*/
public Poly[] getShapeOfNode(NodeInst ni, boolean electrical, boolean reasonable, Layer.Function.Set onlyTheseLayers) {
if (ni.isCellInstance()) {
return null;
}
Poly.Builder polyBuilder = Poly.threadLocalLambdaBuilder();
return polyBuilder.getShapeArray(ni, electrical, reasonable, onlyTheseLayers);
}
/**
* Tells if node can be drawn by simplified algorithm
* Overidden in subclasses
* @param ni node to test
* @param explain if true then print explanation why arc is not easy
* @return true if arc can be drawn by simplified algorithm
*/
public boolean isEasyShape(NodeInst ni, boolean explain) {
return false;
}
/**
* Method to determine if cut case is considered multi cut
* It gets overridden by CMOS90
*/
public boolean isMultiCutInTechnology(MultiCutData mcd) {
if (mcd == null) {
return false;
}
return (mcd.numCuts() > 1);
}
/**
* Method to get a multi-cut structure associated to
* a NodeInst representing a Multiple-cut contact.
* @param ni the NodeInst being tested.
* @return a non-null MultiCutData pointer if it is a Multiple-cut contact
*/
public MultiCutData getMultiCutData(NodeInst ni) {
if (ni.isCellInstance()) {
return null;
}
PrimitiveNode pnp = (PrimitiveNode) ni.getProto();
if (!pnp.isMulticut()) {
return null;
}
return ((new MultiCutData(ni.getD(), ni.getTechPool())));
}
/**
* Method to decide whether a NodeInst is a multi-cut contact.
* The function is done by the Technologies so that it can be subclassed.
* @param ni the NodeInst being tested.
* @return true if it is a Multiple-cut contact.
*/
public boolean isMultiCutCase(NodeInst ni) {
MultiCutData data = getMultiCutData(ni);
if (data == null) {
return false;
}
return (isMultiCutInTechnology(data));
}
/**
* Class MultiCutData determines the locations of cuts in a multi-cut contact node.
*/
public static class MultiCutData {
/** the size of each cut */
private long cutSizeX, cutSizeY;
/** the separation between cuts */
private long cutSep1D;
/** the separation between cuts in 3-neighboring or more cases */
private long cutSep2D;
/** the number of cuts in X and Y */
private int cutsX, cutsY;
/** the total number of cuts */
private int cutsTotal;
/**
* Constructor to initialize for multiple cuts.
*/
private MultiCutData(ImmutableNodeInst niD, NodeLayer cutLayer) {
calculateInternalData(niD, cutLayer);
}
/**
* Constructor to initialize for multiple cuts.
* @param niD the NodeInst with multiple cuts.
*/
public MultiCutData(ImmutableNodeInst niD, TechPool techPool) {
calculateInternalData(niD, techPool.getPrimitiveNode((PrimitiveNodeId) niD.protoId).findMulticut());
}
private void calculateInternalData(ImmutableNodeInst niD, NodeLayer cutLayer) {
EPoint size = niD.size;
assert cutLayer.representation == NodeLayer.MULTICUTBOX;
long gridWidth = size.getGridX();
long gridHeight = size.getGridY();
TechPoint[] techPoints = cutLayer.points;
long lx = techPoints[0].getX().getAdder().getGrid() + (long) (gridWidth * techPoints[0].getX().getMultiplier());
long hx = techPoints[1].getX().getAdder().getGrid() + (long) (gridWidth * techPoints[1].getX().getMultiplier());
long ly = techPoints[0].getY().getAdder().getGrid() + (long) (gridHeight * techPoints[0].getY().getMultiplier());
long hy = techPoints[1].getY().getAdder().getGrid() + (long) (gridHeight * techPoints[1].getY().getMultiplier());
cutSizeX = cutLayer.cutSizeX.getGrid();
cutSizeY = cutLayer.cutSizeY.getGrid();
cutSep1D = cutLayer.cutSep1D.getGrid();
cutSep2D = cutLayer.cutSep2D.getGrid();
if (!niD.isEasyShape()) {
// get the value of the cut spacing
Variable var = niD.getVar(NodeLayer.CUT_SPACING);
if (var != null) {
double spacingD = VarContext.objectToDouble(var.getObject(), -1);
if (spacingD != -1) {
cutSep1D = cutSep2D = DBMath.lambdaToGrid(spacingD);
}
}
}
// determine the actual node size
long cutAreaWidth = hx - lx;
long cutAreaHeight = hy - ly;
// number of cuts depends on the size of cut area
int oneDcutsX = 1 + (int) (cutAreaWidth / (cutSizeX + cutSep1D));
int oneDcutsY = 1 + (int) (cutAreaHeight / (cutSizeY + cutSep1D));
// check if configuration gives 2D cuts
cutsX = oneDcutsX;
cutsY = oneDcutsY;
if (cutsX > 1 && cutsY > 1) {
// recompute number of cuts for 2D spacing
int twoDcutsX = 1 + (int) (cutAreaWidth / (cutSizeX + cutSep2D));
int twoDcutsY = 1 + (int) (cutAreaHeight / (cutSizeY + cutSep2D));
cutsX = twoDcutsX;
cutsY = twoDcutsY;
if (cutsX == 1 || cutsY == 1) {
// 1D separation sees a 2D grid, but 2D separation sees a linear array: use 1D linear settings
if (cutAreaWidth > cutAreaHeight) {
cutsX = oneDcutsX;
} else {
cutsY = oneDcutsY;
}
}
}
if (cutsX <= 0) {
cutsX = 1;
}
if (cutsY <= 0) {
cutsY = 1;
}
cutsTotal = cutsX * cutsY;
}
/**
* Method to return the number of cuts in the contact node.
* @return the number of cuts in the contact node.
*/
public int numCuts() {
return cutsTotal;
}
/**
* Method to return the number of cuts along X axis in the contact node.
* @return the number of cuts in the contact node along X axis.
*/
public int numCutsX() {
return cutsX;
}
/**
* Method to return the number of cuts along Y axis in the contact node.
* @return the number of cuts in the contact node along Y axis.
*/
public int numCutsY() {
return cutsY;
}
}
/**
* Method to convert old primitive node names to their proper NodeProtos.
* @param name the unknown node name, read from an old Library.
* @return the proper PrimitiveNode to use for this name.
*/
public PrimitiveNode convertOldNodeName(String name) {
return oldNodeNames.get(name);
}
public Map getOldNodeNames() {
return new TreeMap(oldNodeNames);
}
/****************************** PORTS ******************************/
/**
* Returns a polygon that describes a particular port on a NodeInst.
* @param ni the NodeInst that has the port of interest.
* The prototype of this NodeInst must be a PrimitiveNode and not a Cell.
* @param pp the PrimitivePort on that NodeInst that is being described.
* @return a Poly object that describes this PrimitivePort graphically.
*/
public Poly getShapeOfPort(NodeInst ni, PrimitivePort pp) {
Poly.Builder polyBuilder = Poly.threadLocalLambdaBuilder();
return polyBuilder.getShape(ni, pp);
}
// /**
// * Returns a polygon that describes a particular port on a NodeInst.
// * @param ni the NodeInst that has the port of interest.
// * The prototype of this NodeInst must be a PrimitiveNode and not a Cell.
// * @param pp the PrimitivePort on that NodeInst that is being described.
// * @param selectPt if not null, it requests a new location on the port,
// * away from existing arcs, and close to this point.
// * This is useful for "area" ports such as the left side of AND and OR gates.
// * @return a Poly object that describes this PrimitivePort graphically.
// */
// public Poly getShapeOfPort(NodeInst ni, PrimitivePort pp, Point2D selectPt) {
// Poly.Builder polyBuilder = Poly.threadLocalLambdaBuilder();
// return polyBuilder.getShape(ni, pp, selectPt);
// }
/**
* Method to convert old primitive port names to their proper PortProtos.
* This method is overridden by those technologies that have any special port name conversion issues.
* By default, there is little to be done, because by the time this
* method is called, normal searches have failed.
* @param portName the unknown port name, read from an old Library.
* @param np the PrimitiveNode on which this port resides.
* @return the proper PrimitivePort to use for this name.
*/
public PrimitivePort convertOldPortName(String portName, PrimitiveNode np) {
// some technologies switched from ports ending in "-bot" to the ending "-bottom"
int len = portName.length() - 4;
if (len > 0 && portName.substring(len).equals("-bot")) {
PrimitivePort pp = (PrimitivePort) np.findPortProto(portName + "tom");
if (pp != null) {
return pp;
}
}
if (np.getNumPorts() == 1) {
return np.getPort(0);
}
return null;
}
/**
* Tells if all ArcProtos can connect to the PrimitivePort
* @param pp PrimitivePort to test
* @return true if all ArcProtos can connect to the PrimitivePort
*/
public boolean isUniversalConnectivityPort(PrimitivePort pp) {
return false;
}
/*********************** PARASITIC SETTINGS ***************************/
private Setting makeParasiticSetting(String what, double factory) {
String techShortName = getTechShortName();
if (techShortName == null) {
techShortName = getTechName();
}
return getProjectSettings().makeDoubleSetting(what + "IN" + getTechName(), TECH_NODE,
what, "Parasitic tab", techShortName + " " + what, factory);
}
private Setting makeParasiticSetting(String what, boolean factory) {
String techShortName = getTechShortName();
if (techShortName == null) {
techShortName = getTechName();
}
return getProjectSettings().makeBooleanSetting(what + "IN" + getTechName(), TECH_NODE,
what, "Parasitic tab", techShortName + " " + what, factory);
}
/**
* Returns the minimum resistance of this Technology.
* Default value is 10.0
* @return the minimum resistance of this Technology.
*/
public double getMinResistance() {
return cacheMinResistance.getDouble();
}
/**
* Returns project preferences to tell the minimum resistance of this Technology.
* @return project preferences to tell the minimum resistance of this Technology.
*/
public Setting getMinResistanceSetting() {
return cacheMinResistance;
}
/**
* Returns the minimum capacitance of this Technology.
* Default value is 0.0
* @return the minimum capacitance of this Technology.
*/
public double getMinCapacitance() {
// 0.0 is the default value
return cacheMinCapacitance.getDouble();
}
/**
* Returns project preferences to tell the minimum capacitance of this Technology.
* @return project preferences to tell the minimum capacitance of this Technology.
*/
public Setting getMinCapacitanceSetting() {
return cacheMinCapacitance;
}
/**
* Get the maximum series resistance for layout extraction
* for this Technology.
* @return the maximum series resistance of extracted layout nets
*/
public double getMaxSeriesResistance() {
return cacheMaxSeriesResistance.getDouble();
}
/**
* Returns project preferences to tell the maximum series resistance for layout extraction
* for this Technology.
* @return project preferences to tell the maximum series resistance for layout extraction
* for this Technology.
*/
public Setting getMaxSeriesResistanceSetting() {
return cacheMaxSeriesResistance;
}
/**
* Returns true if gate is included in resistance calculation. False is the default.
* @return true if gate is included in resistance calculation.
*/
public boolean isGateIncluded() {
// False is the default
return cacheIncludeGate.getBoolean();
}
/**
* Returns project preferences to tell gate inclusion.
* @return project preferences to tell gate inclusion
*/
public Setting getGateIncludedSetting() {
return cacheIncludeGate;
}
/**
* Returns true if ground network is included in parasitics calculation. False is the default.
* @return true if ground network is included.
*/
public boolean isGroundNetIncluded() {
// False is the default
return cacheIncludeGnd.getBoolean();
}
/**
* Returns project preferences to tell ground network inclusion.
* @return project preferences to tell ground network inclusion
*/
public Setting getGroundNetIncludedSetting() {
return cacheIncludeGnd;
}
/**
* Gets the gate length subtraction for this Technology (in microns).
* This is used because there is sometimes a subtracted offset from the layout
* to the drawn length.
* @return the gate length subtraction for this Technology
*/
public double getGateLengthSubtraction() {
return cacheGateLengthSubtraction.getDouble();
}
/**
* Returns project preferences to tell the gate length subtraction for this Technology (in microns)
* This is used because there is sometimes a subtracted offset from the layout
* to the drawn length.
* @return project preferences to tell the subtraction value for a gate length in microns
*/
public Setting getGateLengthSubtractionSetting() {
return cacheGateLengthSubtraction;
}
/**
* Method to set default parasitic values on this Technology.
* These values are not saved in the options.
* @param minResistance the minimum resistance in this Technology.
* @param minCapacitance the minimum capacitance in this Technology.
*/
public void setFactoryParasitics(double minResistance, double minCapacitance) {
cacheMinResistance = makeParasiticSetting("MininumResistance", minResistance);
cacheMinCapacitance = makeParasiticSetting("MininumCapacitance", minCapacitance);
}
/*********************** LOGICAL EFFORT SETTINGS ***************************/
private Setting.Group getLESettingsNode() {
return getProjectSettings().node("LogicalEffort");
}
private Setting makeLESetting(String what, double factory) {
String techShortName = getTechShortName();
if (techShortName == null) {
techShortName = getTechName();
}
return getLESettingsNode().makeDoubleSetting(what + "IN" + getTechName(), TECH_NODE,
what, "Logical Effort tab", techShortName + " " + what, factory);
}
// private Setting makeLESetting(String what, int factory) {
// String techShortName = getTechShortName();
// if (techShortName == null) techShortName = getTechName();
// return Setting.makeIntSetting(what + "IN" + getTechName(), prefs,
// getLESettingsNode(), what,
// "Logical Effort tab", techShortName + " " + what, factory);
// }
// ************************ tech specific? - start *****************************
// /**
// * Method to get the Global Fanout for Logical Effort.
// * The default is DEFAULT_GLOBALFANOUT.
// * @return the Global Fanout for Logical Effort.
// */
// public double getGlobalFanout()
// {
// return cacheGlobalFanout.getDouble();
// }
// /**
// * Method to set the Global Fanout for Logical Effort.
// * @param fo the Global Fanout for Logical Effort.
// */
// public void setGlobalFanout(double fo)
// {
// cacheGlobalFanout.setDouble(fo);
// }
//
// /**
// * Method to get the Convergence Epsilon value for Logical Effort.
// * The default is DEFAULT_EPSILON.
// * @return the Convergence Epsilon value for Logical Effort.
// */
// public double getConvergenceEpsilon()
// {
// return cacheConvergenceEpsilon.getDouble();
// }
// /**
// * Method to set the Convergence Epsilon value for Logical Effort.
// * @param ep the Convergence Epsilon value for Logical Effort.
// */
// public void setConvergenceEpsilon(double ep)
// {
// cacheConvergenceEpsilon.setDouble(ep);
// }
//
// /**
// * Method to get the maximum number of iterations for Logical Effort.
// * The default is DEFAULT_MAXITER.
// * @return the maximum number of iterations for Logical Effort.
// */
// public int getMaxIterations()
// {
// return cacheMaxIterations.getInt();
// }
// /**
// * Method to set the maximum number of iterations for Logical Effort.
// * @param it the maximum number of iterations for Logical Effort.
// */
// public void setMaxIterations(int it)
// {
// cacheMaxIterations.setInt(it);
// }
//
// /**
// * Method to get the keeper size ratio for Logical Effort.
// * The default is DEFAULT_KEEPERRATIO.
// * @return the keeper size ratio for Logical Effort.
// */
// public double getKeeperRatio()
// {
// return cacheKeeperRatio.getDouble();
// }
// /**
// * Method to set the keeper size ratio for Logical Effort.
// * @param kr the keeper size ratio for Logical Effort.
// */
// public void setKeeperRatio(double kr)
// {
// cacheKeeperRatio.setDouble(kr);
// }
// ************************ tech specific? - end *****************************
protected void setFactoryLESettings(double gateCapacitance, double wireRation, double diffAlpha) {
cacheGateCapacitance = makeLESetting("GateCapacitance", gateCapacitance);
cacheWireRatio = makeLESetting("WireRatio", wireRation);
cacheDiffAlpha = makeLESetting("DiffAlpha", diffAlpha);
}
/**
* Method to get the Gate Capacitance for Logical Effort.
* The default is DEFAULT_GATECAP.
* @return the Gate Capacitance for Logical Effort.
*/
public double getGateCapacitance() {
return cacheGateCapacitance.getDouble();
}
/**
* Returns project preferences to tell the Gate Capacitance for Logical Effort.
* @return project preferences to tell the Gate Capacitance for Logical Effort.
*/
public Setting getGateCapacitanceSetting() {
return cacheGateCapacitance;
}
/**
* Method to get the wire capacitance ratio for Logical Effort.
* The default is DEFAULT_WIRERATIO.
* @return the wire capacitance ratio for Logical Effort.
*/
public double getWireRatio() {
return cacheWireRatio.getDouble();
}
/**
* Returns project preferences to tell the wire capacitance ratio for Logical Effort.
* @return project preferences to tell the wire capacitance ratio for Logical Effort.
*/
public Setting getWireRatioSetting() {
return cacheWireRatio;
}
/**
* Method to get the diffusion to gate capacitance ratio for Logical Effort.
* The default is DEFAULT_DIFFALPHA.
* @return the diffusion to gate capacitance ratio for Logical Effort.
*/
public double getDiffAlpha() {
return cacheDiffAlpha.getDouble();
}
/**
* Returns project preferences to tell the diffusion to gate capacitance ratio for Logical Effort.
* @return project preferences to tell the diffusion to gate capacitance ratio for Logical Effort.
*/
public Setting getDiffAlphaSetting() {
return cacheDiffAlpha;
}
// ================================================================
/**
* Method to return the level-1 header cards for SPICE in this Technology.
* The default is [""].
* @return the level-1 header cards for SPICE in this Technology.
*/
public String[] getSpiceHeaderLevel1() {
return spiceHeaderLevel1;
}
/**
* Method to set the level-1 header cards for SPICE in this Technology.
* @param lines the level-1 header cards for SPICE in this Technology.
*/
public void setSpiceHeaderLevel1(String[] lines) {
spiceHeaderLevel1 = lines;
}
/**
* Method to return the level-2 header cards for SPICE in this Technology.
* The default is [""].
* @return the level-2 header cards for SPICE in this Technology.
*/
public String[] getSpiceHeaderLevel2() {
return spiceHeaderLevel2;
}
/**
* Method to set the level-2 header cards for SPICE in this Technology.
* @param lines the level-2 header cards for SPICE in this Technology.
*/
public void setSpiceHeaderLevel2(String[] lines) {
spiceHeaderLevel2 = lines;
}
/**
* Method to return the level-3 header cards for SPICE in this Technology.
* The default is [""].
* @return the level-3 header cards for SPICE in this Technology.
*/
public String[] getSpiceHeaderLevel3() {
return spiceHeaderLevel3;
}
/**
* Method to set the level-3 header cards for SPICE in this Technology.
* @param lines the level-3 header cards for SPICE in this Technology.
*/
public void setSpiceHeaderLevel3(String[] lines) {
spiceHeaderLevel3 = lines;
}
/****************************** MISCELANEOUS ******************************/
/**
* Sets the technology to be "non-electrical".
* Users should never call this method.
* It is set once by the technology during initialization.
* Examples of non-electrical technologies are "Artwork" and "Gem".
*/
protected void setNonElectrical() {
userBits |= NONELECTRICAL;
}
/**
* Returns true if this technology is "non-electrical".
* @return true if this technology is "non-electrical".
* Examples of non-electrical technologies are "Artwork" and "Gem".
*/
public boolean isNonElectrical() {
return (userBits & NONELECTRICAL) != 0;
}
/**
* Sets the technology to be non-standard.
* Users should never call this method.
* It is set once by the technology during initialization.
* A non-standard technology cannot be edited in the technology editor.
* Examples are Schematics and Artwork, which have more complex graphics.
*/
protected void setNonStandard() {
userBits |= NONSTANDARD;
}
/**
* Returns true if this technology is non-standard.
* @return true if this technology is non-standard.
* A non-standard technology cannot be edited in the technology editor.
* Examples are Schematics and Artwork, which have more complex graphics.
*/
public boolean isNonStandard() {
return (userBits & NONSTANDARD) != 0;
}
/**
* Sets the technology to be "static".
* Users should never call this method.
* It is set once by the technology during initialization.
* Static technologies are the core set of technologies in Electric that are
* essential, and cannot be deleted.
* The technology-editor can create others later, and they can be deleted.
*/
protected void setStaticTechnology() {
userBits |= STATICTECHNOLOGY;
}
/**
* Returns true if this technoology is "static" (cannot be deleted).
* @return true if this technoology is "static" (cannot be deleted).
* Static technologies are the core set of technologies in Electric that are
* essential, and cannot be deleted.
* The technology-editor can create others later, and they can be deleted.
*/
public boolean isStaticTechnology() {
return (userBits & STATICTECHNOLOGY) != 0;
}
/**
* Returns the TechId of this technology.
* Each technology has a unique name, such as "mocmos" (MOSIS CMOS).
* @return the TechId of this technology.
*/
public TechId getId() {
return techId;
}
/**
* Returns the name of this technology.
* Each technology has a unique name, such as "mocmos" (MOSIS CMOS).
* @return the name of this technology.
*/
public String getTechName() {
return techId.techName;
}
/**
* Sets the name of this technology.
* Technology names must be unique.
*/
public void setTechName(String techName) {
throw new UnsupportedOperationException(); // Correct implementation must also rename ProjectSettings and Preferences of this Technology
// for(Iterator it = Technology.getTechnologies(); it.hasNext(); )
// {
// Technology tech = it.next();
// if (tech == this) continue;
// if (tech.techName.equalsIgnoreCase(techName))
// {
// System.out.println("Cannot rename " + this + "to '" + techName + "' because that name is used by another technology");
// return;
// }
// }
// if (!jelibSafeName(techName))
// System.out.println("Technology name " + techName + " is not safe to write into JELIB");
// this.techName = techName;
}
/**
* Method checks that string is safe to write into JELIB file without
* conversion.
* @param str the string to check.
* @return true if string is safe to write into JELIB file.
*/
static boolean jelibSafeName(String str) {
return TechId.jelibSafeName(str);
}
/**
* Returns the short name of this technology.
* The short name is user readable ("MOSIS CMOS" instead of "mocmos")
* but is shorter than the "description" which often includes options.
* @return the short name of this technology.
*/
public String getTechShortName() {
return techShortName;
}
/**
* Sets the short name of this technology.
* The short name is user readable ("MOSIS CMOS" instead of "mocmos")
* but is shorter than the "description" which often includes options.
* @param techShortName the short name for this technology.
*/
protected void setTechShortName(String techShortName) {
this.techShortName = techShortName;
}
/**
* Returns the full description of this Technology.
* Full descriptions go beyond the one-word technology name by including such
* information as foundry, nuumber of available layers, and process specifics.
* For example, "Complementary MOS (from MOSIS, Submicron, 2-6 metals [4], double poly)".
* @return the full description of this Technology.
*/
public String getTechDesc() {
return techDesc;
}
/**
* Sets the full description of this Technology.
* Full descriptions go beyond the one-word technology name by including such
* information as foundry, nuumber of available layers, and process specifics.
* For example, "Complementary MOS (from MOSIS, Submicron, 2-6 metals [4], double poly)".
*/
public void setTechDesc(String techDesc) {
this.techDesc = techDesc;
}
/**
* Returns the scale for this Technology.
* The technology's scale is for manufacturing output, which must convert
* the unit-based values in Electric to real-world values (in nanometers).
* @return the scale for this Technology.
*/
public double getScale() {
return cacheScale.getDouble();
}
/**
* Method to obtain the Variable name for scaling this Technology.
* Do not use this for arbitrary use.
* The method exists so that ELIB readers can handle the unusual location
* of scale information in the ELIB files.
* @return the Variable name for scaling this Technology.
*/
public String getScaleVariableName() {
return "ScaleFOR" + getTechName();
}
/**
* Sets the factory scale of this technology.
* The technology's scale is for manufacturing output, which must convert
* the unit-based values in Electric to real-world values (in nanometers).
* @param factory the factory scale between this technology and the real units.
* @param scaleRelevant true if this is a layout technology, and the scale factor has meaning.
*/
protected void setFactoryScale(double factory, boolean scaleRelevant) {
this.scaleRelevant = scaleRelevant;
String techShortName = getTechShortName();
if (techShortName == null) {
techShortName = getTechName();
}
cacheScale = getProjectSettings().makeDoubleSetting(getScaleVariableName(), TECH_NODE,
"Scale", "Scale tab", techShortName + " scale", factory);
cacheScale.setValidOption(isScaleRelevant());
}
/**
* Returns project preferences to tell the scale of this technology.
* The technology's scale is for manufacturing output, which must convert
* the unit-based values in Electric to real-world values (in nanometers).
* @return project preferences to tell the scale between this technology and the real units.
*/
public Setting getScaleSetting() {
return cacheScale;
}
/**
* Method to tell whether scaling is relevant for this Technology.
* Most technolgies produce drawings that are exact images of a final product.
* For these technologies (CMOS, bipolar, etc.) the "scale" from displayed grid
* units to actual dimensions is a relevant factor.
* Other technologies, such as schematics, artwork, and generic,
* are not converted to physical objects, and "scale" is not relevant no meaning for them.
* @return true if scaling is relevant for this Technology.
*/
public boolean isScaleRelevant() {
return scaleRelevant;
}
/**
* Method to set Technology resolution in IO/DRC tools.
* This has to be stored per technology.
* @param factory factory value
*/
protected void setFactoryResolution(double factory) {
factoryResolution = ECoord.fromLambdaRoundSizeGrid(factory);
}
/**
* Method to retrieve the default resolution associated to the technology.
* This is the minimum size unit that can be represented.
* @return the technology's default resolution value.
*/
public ECoord getFactoryResolution() {
return factoryResolution;
}
/**
* Method to get foundry in Tech Palette. Different foundry can define different DRC rules.
* The default is "Generic".
* @return the foundry to use in Tech Palette
*/
public String getPrefFoundry() {
return paramFoundry;
}
/**
* Returns project preferences to tell foundry for DRC rules.
* @return project preferences to tell the foundry for DRC rules.
*/
public Setting getPrefFoundrySetting() {
return cacheFoundry;
}
/**
* Find the Foundry in this technology with a particular name. Protected so sub classes will use it
* @param name the name of the desired Foundry.
* @return the Foundry with the same name, or null if no Foundry matches.
*/
protected Foundry findFoundry(String name) {
if (name == null) {
return null;
}
for (Foundry f : foundries) {
Foundry.Type t = f.getType();
if (t.getName().equalsIgnoreCase(name)) {
return f;
}
}
return null;
}
/**
* Get an iterator over all of the Manufacturers.
* @return an iterator over all of the Manufacturers.
*/
public Iterator getFoundries() {
return foundries.iterator();
}
/**
* Method to create a new on this technology.
* @param mode factory type
* @param fileURL URL of xml file with description of rules
* @param gdsLayers stirngs with definition of gds numbers for layers
*/
protected void newFoundry(Foundry.Type mode, URL fileURL, String... gdsLayers) {
Foundry foundry = new Foundry(this, mode, fileURL, gdsLayers);
foundries.add(foundry);
}
/**
* Method to get the foundry index associated with this technology.
* @return the foundry index associated with this technology.
*/
public Foundry getSelectedFoundry() {
String foundryName = getPrefFoundry();
Foundry f = findFoundry(foundryName);
if (f != null) {
return f;
}
if (foundries.size() > 0) {
f = foundries.get(0);
if (foundryName.length() > 0) {
System.out.println("Foundry '" + foundryName + "' not available in Technology '" + this.getTechName()
+ "'. Setting '" + f.toString() + "' as foundry.");
}
return f;
}
return f;
}
/**
* Method to return the map from Layers of this Technology to their GDS names in current foundry.
* Only Layers with non-empty GDS names are present in the map
* @return the map from Layers to GDS names
*/
public Map getGDSLayers() {
Foundry foundry = getSelectedFoundry();
Map gdsLayers = Collections.emptyMap();
if (foundry != null) {
gdsLayers = foundry.getGDSLayers();
}
return gdsLayers;
}
/**
* Sets the color map for transparent layers in this technology.
* Users should never call this method.
* It is set once by the technology during initialization.
* @param layers is an array of colors, one per transparent layer.
* This is expanded to a map that is 2 to the power "getNumTransparentLayers()".
* Color merging is computed automatically.
*/
protected void setFactoryTransparentLayers(Color[] layers) {
factoryTransparentColors = layers;
}
/**
* Method to return the factory default colors for the transparent layers in this Technology.
* @return the factory default colors for the transparent layers in this Technology.
*/
public Color[] getFactoryTransparentLayerColors() {
return factoryTransparentColors.clone();
}
/**
* Method to return the colors for the transparent layers in this Technology.
* @return the factory for the transparent layers in this Technology.
*/
public Color[] getTransparentLayerColors() {
return UserInterfaceMain.getGraphicsPreferences().getTransparentLayerColors(this);
}
/**
* Returns the number of transparent layers in this technology.
* Informs the display system of the number of overlapping or transparent layers
* in use.
* @return the number of transparent layers in this technology.
* There may be 0 transparent layers in technologies that don't do overlapping,
* such as Schematics.
*/
public int getNumTransparentLayers() {
return UserInterfaceMain.getGraphicsPreferences().getNumTransparentLayers(this);
}
/**
* Sets the color map from transparent layers in this technology.
* @param layers an array of colors, one per transparent layer.
* This is expanded to a map that is 2 to the power "getNumTransparentLayers()".
* Color merging is computed automatically.
*/
public void setColorMapFromLayers(Color[] layers) {
UserInterfaceMain.setGraphicsPreferences(UserInterfaceMain.getGraphicsPreferences().withTransparentLayerColors(this, layers));
}
/**
* Method to get the factory design rules.
* Individual technologies subclass this to create their own rules.
* @return the design rules for this Technology.
* Returns null if there are no design rules in this Technology.
*/
public XMLRules getFactoryDesignRules() {
return makeFactoryDesignRules();
}
/**
* Method to get the factory design rules.
* Individual technologies subclass this to create their own rules.
* @return the design rules for this Technology.
* Returns null if there are no design rules in this Technology.
*/
protected XMLRules makeFactoryDesignRules() {
XMLRules rules = new XMLRules(this);
Foundry foundry = getSelectedFoundry();
List rulesList = foundry.getRules();
boolean pSubstrateProcess = User.isPSubstrateProcessLayoutTechnology();
// load the DRC tables from the explanation table
if (rulesList != null) {
for (DRCTemplate rule : rulesList) {
if (rule.ruleType != DRCTemplate.DRCRuleType.NODSIZ) {
rules.loadDRCRules(this, foundry, rule, pSubstrateProcess);
}
}
for (DRCTemplate rule : rulesList) {
if (rule.ruleType == DRCTemplate.DRCRuleType.NODSIZ) {
rules.loadDRCRules(this, foundry, rule, pSubstrateProcess);
}
}
}
return rules;
}
/**
* Method to compare a Rules set with the "factory" set and construct an override string.
* @param origRules
* @param newRules
* @return a StringBuffer that describes any overrides. Returns "" if there are none.
*/
public static StringBuffer getRuleDifferences(DRCRules origRules, DRCRules newRules) {
return (new StringBuffer(""));
}
/**
* Method to be called from DRC:setRules
* @param newRules
*/
public void setRuleVariables(DRCRules newRules) {
}
/**
* Returns the color map for transparent layers in this technology.
* @return the color map for transparent layers in this technology.
* The number of entries in this map equals 2 to the power "getNumTransparentLayers()".
*/
public Color[] getColorMap() {
return UserInterfaceMain.getGraphicsPreferences().getColorMap(this);
}
/**
* Method to create a full colormap from the transparent colors.
* @param transparentColors the transparent colors.
* @return a full map that combines all of the colors.
* The map is 2^transparentcolors.length in size.
*/
public static Color[] makeColorMap(Color[] transparentColors) {
int numEntries = 1 << transparentColors.length;
Color[] map = new Color[numEntries];
for (int i = 0; i < numEntries; i++) {
int r = 200, g = 200, b = 200;
boolean hasPrevious = false;
for (int j = 0; j < transparentColors.length; j++) {
if ((i & (1 << j)) == 0) {
continue;
}
Color layerColor = transparentColors[j];
if (hasPrevious) {
// get the previous color
double[] lastColor = new double[3];
lastColor[0] = r / 255.0;
lastColor[1] = g / 255.0;
lastColor[2] = b / 255.0;
normalizeColor(lastColor);
// get the current color
double[] curColor = new double[3];
curColor[0] = layerColor.getRed() / 255.0;
curColor[1] = layerColor.getGreen() / 255.0;
curColor[2] = layerColor.getBlue() / 255.0;
normalizeColor(curColor);
// combine them
for (int k = 0; k < 3; k++) {
curColor[k] += lastColor[k];
}
normalizeColor(curColor);
r = (int) (curColor[0] * 255.0);
g = (int) (curColor[1] * 255.0);
b = (int) (curColor[2] * 255.0);
} else {
r = layerColor.getRed();
g = layerColor.getGreen();
b = layerColor.getBlue();
hasPrevious = true;
}
}
map[i] = new Color(r, g, b);
}
return map;
}
/**
* Method to normalize a color stored in a 3-long array.
* @param a the array of 3 doubles that holds the color.
* All values range from 0 to 1.
* The values are adjusted so that they are normalized.
*/
private static void normalizeColor(double[] a) {
double mag = Math.sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
if (mag < 1.0e-11f) {
return;
}
a[0] /= mag;
a[1] /= mag;
a[2] /= mag;
}
/**
* Method to determine whether a new technology with the given name would be legal.
* All technology names must be unique, so the name cannot already be in use.
* @param techName the name of the new technology that will be created.
* @return true if the name is valid.
*/
// private static boolean validTechnology(String techName)
// {
// if (Technology.findTechnology(techName) != null)
// {
// System.out.println("ERROR: Multiple technologies named " + techName);
// return false;
// }
// return true;
// }
/**
* Method to determine the appropriate Technology to use for a Cell.
* @param cell the Cell to examine.
* @return the Technology for that cell.
*/
public static Technology whatTechnology(NodeProto cell) {
Technology tech = whatTechnology(cell, null, 0, 0, null);
return tech;
}
/**
* Method to determine the appropriate technology to use for a cell.
* The contents of the cell can be defined by the lists of NodeInsts and ArcInsts, or
* if they are null, then by the contents of the Cell.
* @param cellOrPrim the Cell to examine.
* @param nodeProtoList the list of prototypes of NodeInsts in the Cell.
* @param startNodeProto the starting point in the "nodeProtoList" array.
* @param endNodeProto the ending point in the "nodeProtoList" array.
* @param arcProtoList the list of prototypes of ArcInsts in the Cell.
* @return the Technology for that cell.
*/
public static Technology whatTechnology(NodeProto cellOrPrim, NodeProto[] nodeProtoList, int startNodeProto, int endNodeProto,
ArcProto[] arcProtoList) {
// primitives know their technology
if (cellOrPrim instanceof PrimitiveNode) {
return (((PrimitiveNode) cellOrPrim).getTechnology());
}
Cell cell = (Cell) cellOrPrim;
// count the number of technologies
int maxTech = 0;
for (Iterator it = Technology.getTechnologies(); it.hasNext();) {
Technology tech = it.next();
if (tech.getId().techIndex > maxTech) {
maxTech = tech.getId().techIndex;
}
}
maxTech++;
// create an array of counts for each technology
int[] useCount = new int[maxTech];
for (int i = 0; i < maxTech; i++) {
useCount[i] = 0;
}
// count technologies of all primitive nodes in the cell
if (nodeProtoList != null) {
// iterate over the NodeProtos in the list
for (int i = startNodeProto; i < endNodeProto; i++) {
NodeProto np = nodeProtoList[i];
if (np == null) {
continue;
}
Technology nodeTech = np.getTechnology();
if (np instanceof Cell) {
Cell subCell = (Cell) np;
if (subCell.isIcon()) {
nodeTech = Schematics.tech();
}
}
if (nodeTech != null) {
useCount[nodeTech.getId().techIndex]++;
}
}
} else {
for (Iterator it = cell.getNodes(); it.hasNext();) {
NodeInst ni = it.next();
NodeProto np = ni.getProto();
Technology nodeTech = np.getTechnology();
if (ni.isCellInstance()) {
Cell subCell = (Cell) np;
if (subCell.isIcon()) {
nodeTech = Schematics.tech();
}
}
if (nodeTech != null) {
useCount[nodeTech.getId().techIndex]++;
}
}
}
// count technologies of all arcs in the cell
if (arcProtoList != null) {
// iterate over the arcprotos in the list
for (ArcProto ap : arcProtoList) {
if (ap == null) {
continue;
}
useCount[ap.getTechnology().getId().techIndex]++;
}
} else {
for (Iterator it = cell.getArcs(); it.hasNext();) {
ArcInst ai = it.next();
ArcProto ap = ai.getProto();
useCount[ap.getTechnology().getId().techIndex]++;
}
}
// find a concensus
int best = 0;
Technology bestTech = null;
int bestLayout = 0;
Technology bestLayoutTech = null;
for (Iterator it = Technology.getTechnologies(); it.hasNext();) {
Technology tech = it.next();
// always ignore the generic technology
if (tech instanceof Generic) {
continue;
}
// find the most popular of ALL technologies
if (useCount[tech.getId().techIndex] > best) {
best = useCount[tech.getId().techIndex];
bestTech = tech;
}
// find the most popular of the layout technologies
if (!tech.isLayout()) {
continue;
}
if (useCount[tech.getId().techIndex] > bestLayout) {
bestLayout = useCount[tech.getId().techIndex];
bestLayoutTech = tech;
}
}
Technology retTech = null;
if (cell.isIcon() || cell.getView().isTextView()) {
// in icons, if there is any artwork, use it
if (useCount[Artwork.tech().getId().techIndex] > 0) {
return (Artwork.tech());
}
// in icons, if there is nothing, presume artwork
if (bestTech == null) {
return (Artwork.tech());
}
// use artwork as a default
retTech = Artwork.tech();
} else if (cell.isSchematic()) {
// in schematic, if there are any schematic components, use it
if (useCount[Schematics.tech().getId().techIndex] > 0) {
return (Schematics.tech());
}
// in schematic, if there is nothing, presume schematic
if (bestTech == null) {
return (Schematics.tech());
}
// use schematic as a default
retTech = Schematics.tech();
} else {
// use the current layout technology as the default
retTech = getCurrent();
if (!retTech.isLayout()) {
retTech = findTechnology(User.getDefaultTechnology());
}
if (retTech == null) {
retTech = getMocmosTechnology();
}
}
// if a layout technology was voted the most, return it
if (bestLayoutTech != null) {
retTech = bestLayoutTech;
} else {
// if any technology was voted the most, return it
if (bestTech != null) {
retTech = bestTech;
} else {
// // if this is an icon, presume the technology of its contents
// cv = contentsview(cell);
// if (cv != NONODEPROTO)
// {
// if (cv->tech == NOTECHNOLOGY)
// cv->tech = whattech(cv);
// retTech = cv->tech;
// } else
// {
// // look at the contents of the sub-cells
// foundicons = FALSE;
// for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
// {
// np = ni->proto;
// if (np == NONODEPROTO) continue;
// if (np->primindex != 0) continue;
//
// // ignore recursive references (showing icon in contents)
// if (isiconof(np, cell)) continue;
//
// // see if the cell has an icon
// if (np->cellview == el_iconview) foundicons = TRUE;
//
// // do not follow into another library
// if (np->lib != cell->lib) continue;
// onp = contentsview(np);
// if (onp != NONODEPROTO) np = onp;
// tech = whattech(np);
// if (tech == gen_tech) continue;
// retTech = tech;
// break;
// }
// if (ni == NONODEINST)
// {
// // could not find instances that give information: were there icons?
// if (foundicons) retTech = sch_tech;
// }
// }
}
}
// give up and report the generic technology
return retTech;
}
/**
* Returns true if this Technology is a layout technology.
* @return true if this Technology is a layout technology.
*/
public boolean isLayout() {
return !(this instanceof Artwork /*|| this instanceof EFIDO*/
|| this instanceof GEM || this instanceof Generic || this instanceof Schematics);
}
/**
* Returns true if this Technology is a schematics technology.
* @return true if this Technology is a schematics technology.
*/
public boolean isSchematics() {
return this instanceof Schematics /*|| this instanceof EFIDO*/ || this instanceof GEM;
}
/**
* Compares Technologies by their names.
* @param that the other Technology.
* @return a comparison between the Technologies.
*/
public int compareTo(Technology that) {
return TextUtils.STRING_NUMBER_ORDER.compare(getTechName(), that.getTechName());
}
/**
* Returns a printable version of this Technology.
* @return a printable version of this Technology.
*/
@Override
public String toString() {
return "Technology " + getTechName();
}
/**
* Method to check invariants in this Technology.
* In "debug" mode, prints warnings.
* @exception AssertionError if invariants are not valid
*/
private void check() {
for (TechFactory.Param param : techFactory.getTechParams()) {
String xmlPath = param.xmlPath;
String xmlPrefix = getProjectSettings().getXmlPath();
assert xmlPath.startsWith(xmlPrefix);
xmlPath = xmlPath.substring(xmlPrefix.length());
Setting setting = getSetting(xmlPath);
assert setting.getXmlPath().equals(param.xmlPath);
assert setting.getPrefPath().equals(param.prefPath);
assert setting.getFactoryValue().equals(param.factoryValue);
}
for (ArcProto ap : arcs.values()) {
ap.check();
}
if (!isNonStandard() && isScaleRelevant() && Job.getDebug()) {
Map layToArcFunction = new HashMap();
for (ArcProto ap : arcs.values()) {
for (int i = 0; i < ap.getNumArcLayers(); i++) {
Layer lay = ap.getLayer(i);
Layer.Function fun = lay.getFunction();
if (fun.isSubstrate()) {
continue;
}
ArcProto.Function aFun = ap.getFunction();
if (aFun.isDiffusion()) {
aFun = ArcProto.Function.DIFF;
}
//if (getTechName().equals("mocmosold"))
// System.out.println("-------> ARC "+ap.getName()+" HAS LAYER " + lay.getName()+" WHICH IS FUNCTION " +aFun);
if (aFun != ArcProto.Function.WELL || !fun.isDiff()) {
layToArcFunction.put(lay, aFun);
}
break;
}
}
for (Iterator it = getLayers(); it.hasNext();) {
Layer lay = it.next();
ArcProto.Function aFun = layToArcFunction.get(lay);
if (aFun != null) {
continue;
}
Layer.Function lFun = lay.getFunction();
if (lFun.isDiff()) {
aFun = ArcProto.Function.DIFF;
} else if (lFun.isPoly()) {
aFun = ArcProto.Function.getPoly(lFun.getLevel());
} else if (lFun.isMetal()) {
aFun = ArcProto.Function.getMetal(lFun.getLevel());
}
if (lFun != null) {
layToArcFunction.put(lay, aFun);
//if (getTechName().equals("mocmosold"))
// System.out.println("-------> LAYER "+lay.getName()+" IS FUNCTION " +aFun);
}
}
// check validity of nodes
boolean foundNTrans = false, foundPTrans = false;
for (PrimitiveNode np : nodes.values()) {
PrimitiveNode.Function fun = np.getFunction();
if (fun.isNTypeTransistor()) {
foundNTrans = true;
}
if (fun.isPTypeTransistor()) {
foundPTrans = true;
}
if (fun.isContact() || fun == PrimitiveNode.Function.CONNECT || fun == PrimitiveNode.Function.WELL) {
// check validity of contact nodes
Set neededArcFunctions = new HashSet();
NodeLayer[] nodeLayers = np.getNodeLayers();
for (int i = 0; i < nodeLayers.length; i++) {
Layer lay = nodeLayers[i].layer;
ArcProto.Function aFun = layToArcFunction.get(lay);
//if (getTechName().equals("mocmosold") && np.getName().equals("Metal-1-Well-Con"))
// System.out.println("-------> "+np.getName()+" HAS LAYER " + lay.getName()+" WHICH IS FUNCTION " +aFun);
if (aFun == ArcProto.Function.WELL) {
continue;
}
if (aFun != null) {
neededArcFunctions.add(aFun);
}
}
Set foundArcFunctions = new HashSet();
for (Iterator it = np.getPrimitivePorts(); it.hasNext();) {
PrimitivePort pp = it.next();
ArcProto[] connections = pp.getConnections();
for (int i = 0; i < connections.length; i++) {
ArcProto ap = connections[i];
ArcProto.Function aFun = ap.getFunction();
if (aFun == ArcProto.Function.WELL) {
continue;
}
if (aFun.isDiffusion()) {
aFun = ArcProto.Function.DIFF;
}
if (ap.getTechnology() != this || neededArcFunctions.contains(aFun)) {
foundArcFunctions.add(aFun);
continue;
}
// well contacts do not have to have Active even if they connect to that layer
if (aFun.isDiffusion() && fun == PrimitiveNode.Function.WELL) {
continue;
}
System.out.println("WARNING: Technology " + getTechName() + ", node " + np.getName()
+ " connects to " + ap.getName() + " but probably should not because that layer is not in the node");
}
}
for (ArcProto.Function aFun : neededArcFunctions) {
if (foundArcFunctions.contains(aFun)) {
continue;
}
// well contacts do not have to connect to Active even if that layer is present
if (aFun.isDiffusion() && fun == PrimitiveNode.Function.WELL) {
continue;
}
// Discard case if at least one poly arc was found in foundArcFunctions.
// This is the case of poly2 contact with extra poly1 as capacitor.
if (aFun.isPoly()) {
boolean found = false;
for (ArcProto.Function f : foundArcFunctions) {
if (!f.isPoly()) {
continue; // discard if it is not a poly function
}
found = f != aFun;
}
if (found) {
continue; // it is a valid poly2 contact
}
}
System.out.println("WARNING: Technology " + getTechName() + ", node " + np.getName()
+ " should connect to " + aFun + " because that layer is in the node");
}
} else if (fun.isCapacitor()) {
if (np.getNumPorts() < 2) {
System.out.println("ERROR: Technology " + getTechName() + ", node " + np.getName()
+ " must have at least two ports if defined as capacitor");
}
} else if (fun.isFET()) {
// check validity of transistors
List traPorts = new ArrayList();
for (Iterator it = np.getPrimitivePorts(); it.hasNext();) {
traPorts.add(it.next());
}
if (traPorts.size() != 4 && traPorts.size() != 5) {
System.out.println("WARNING: Technology " + getTechName() + ", node " + np.getName()
+ " should have 4 or 5 ports but has " + traPorts.size());
} else {
PrimitivePort pLeft = traPorts.get(0);
PrimitivePort dTop = traPorts.get(1);
PrimitivePort pRight = traPorts.get(2);
PrimitivePort dBot = traPorts.get(3);
if (!getTechName().startsWith("tft")) {
if (!connectsToPoly(pLeft)) {
System.out.println("WARNING: Technology " + getTechName() + ", node " + np.getName()
+ ", first port (" + pLeft.getName() + ") should connect to Polysilicon");
}
if (!connectsToActive(dTop)) {
System.out.println("WARNING: Technology " + getTechName() + ", node " + np.getName()
+ ", second port (" + dTop.getName() + ") should connect to Active");
}
if (!connectsToPoly(pRight)) {
System.out.println("WARNING: Technology " + getTechName() + ", node " + np.getName()
+ ", third port (" + pRight.getName() + ") should connect to Polysilicon");
}
if (!connectsToActive(dBot)) {
System.out.println("WARNING: Technology " + getTechName() + ", node " + np.getName()
+ ", fourth port (" + dBot.getName() + ") should connect to Active");
}
}
if (pLeft.getTopology() != pRight.getTopology()) {
System.out.println("WARNING: Technology " + getTechName() + ", node " + np.getName()
+ " should connect its Polysilicon ports");
}
if (dTop.getTopology() == dBot.getTopology()) {
System.out.println("WARNING: Technology " + getTechName() + ", node " + np.getName()
+ " should not connect its Active ports to each other");
}
if (pLeft.getTopology() == dBot.getTopology() || pLeft.getTopology() == dTop.getTopology()) {
System.out.println("WARNING: Technology " + getTechName() + ", node " + np.getName()
+ " should not connect its Active ports to its Polysilicon ports");
}
}
// check port connections for electrical layers
NodeLayer[] eLayers = np.getElectricalLayers();
if (eLayers != null) {
boolean foundPort1 = false, foundPort3 = false;
for (int i = 0; i < eLayers.length; i++) {
if (eLayers[i].getLayer().getFunction().isDiff()) {
int portNum = eLayers[i].getPortNum();
if (portNum < 0) {
continue;
}
if (portNum == 1) {
foundPort1 = true;
} else if (portNum == 3) {
foundPort3 = true;
} else {
System.out.println("WARNING: Technology " + getTechName() + ", node " + np.getName()
+ ", Active layer connected to port " + traPorts.get(portNum).getName());
}
}
}
if (!foundPort1) {
System.out.println("WARNING: Technology " + getTechName() + ", node " + np.getName()
+ ", no Active layer is connected to port " + traPorts.get(1).getName());
}
if (!foundPort3) {
System.out.println("WARNING: Technology " + getTechName() + ", node " + np.getName()
+ ", no Active layer is connected to port" + traPorts.get(3).getName());
}
}
}
}
// make sure there are N and P transistors
if (foundNTrans != foundPTrans) {
// "nmos" technology is known to have just N transistors, "tft" has only P transistors
if (!getTechName().equals("nmos") && !getTechName().equals("tft")) {
String has = foundNTrans ? "N" : "P";
String hasnt = foundNTrans ? "P" : "N";
System.out.println("WARNING: Technology " + getTechName()
+ " has " + has + " transistors but has no " + hasnt + " transistors");
}
}
}
}
private boolean connectsToPoly(PrimitivePort pp) {
ArcProto[] connections = pp.getConnections();
for (int i = 0; i < connections.length; i++) {
if (connections[i].getFunction().isPoly()) {
return true;
}
}
return false;
}
private boolean connectsToActive(PrimitivePort pp) {
ArcProto[] connections = pp.getConnections();
for (int i = 0; i < connections.length; i++) {
if (connections[i].getFunction().isDiffusion()) {
return true;
}
}
return false;
}
///////////////////// Generic methods //////////////////////////////////////////////////////////////
// /**
// * Method to change the design rules for layer "layername" layers so that
// * the layers are at least "width" wide. Affects the default arc width
// * and the default pin size.
// */
// protected void setLayerMinWidth(String layername, String rulename, double width)
// {
// // find the arc and set its default width
// ArcProto ap = findArcProto(layername);
// if (ap == null) return;
//
// boolean hasChanged = false;
//
// if (ap.getDefaultLambdaBaseWidth() != width)
//// if (ap.getDefaultLambdaFullWidth() != width + ap.getLambdaWidthOffset())
// hasChanged = true;
//
// // find the arc's pin and set its size and port offset
// PrimitiveNode np = ap.findPinProto();
// if (np == null) return;
// SizeOffset so = np.getProtoSizeOffset();
// double newWidth = width + so.getLowXOffset() + so.getHighXOffset();
// double newHeight = width + so.getLowYOffset() + so.getHighYOffset();
//
// if (np.getDefHeight() != newHeight || np.getDefWidth() != newWidth)
// hasChanged = true;
//
// PrimitivePort pp = (PrimitivePort)np.getPorts().next();
// EdgeH left = pp.getLeft();
// EdgeH right = pp.getRight();
// EdgeV bottom = pp.getBottom();
// EdgeV top = pp.getTop();
// double indent = newWidth / 2;
//
// if (left.getAdder() != indent || right.getAdder() != -indent ||
// top.getAdder() != -indent || bottom.getAdder() != indent)
// hasChanged = true;
// if (hasChanged)
// {
// // describe the error
// String errorMessage = "User preference of " + width + " overwrites original layer minimum size in layer '"
// + layername + "', primitive '" + np.getName() + ":" + getTechShortName() + "' by rule " + rulename;
// if (Job.LOCALDEBUGFLAG) System.out.println(errorMessage);
// }
// }
//
// protected void setDefNodeSize(PrimitiveNode nty, double wid, double hei)
// {
// double xindent = (nty.getDefWidth() - wid) / 2;
// double yindent = (nty.getDefHeight() - hei) / 2;
// nty.setSizeOffset(new SizeOffset(xindent, xindent, yindent, yindent)); // bug 1040
// }
/**
* Method to set the surround distance of layer "layer" from the via in node "nodename" to "surround".
*/
// protected void setLayerSurroundVia(PrimitiveNode nty, Layer layer, double surround)
// {
// // find the via size
// double [] specialValues = nty.getSpecialValues();
// double viasize = specialValues[0];
// double layersize = viasize + surround*2;
// double indent = (nty.getDefWidth() - layersize) / 2;
//
// Technology.NodeLayer oneLayer = nty.findNodeLayer(layer, false);
// if (oneLayer != null)
// {
// TechPoint [] points = oneLayer.getPoints();
// EdgeH left = points[0].getX();
// EdgeH right = points[1].getX();
// EdgeV bottom = points[0].getY();
// EdgeV top = points[1].getY();
// left.setAdder(indent);
// right.setAdder(-indent);
// top.setAdder(-indent);
// bottom.setAdder(indent);
// }
// }
/********************* FOR Wiring tool **********************/
public List getMetalContactCluster(Layer l1, Layer l2) {
List list = new ArrayList();
Xml.MenuPalette menu = xmlTech.menuPalette;
for (List> objList : menu.menuBoxes) {
for (Object obj : objList) {
if (obj instanceof Xml.MenuNodeInst) {
Xml.MenuNodeInst menuItem = (Xml.MenuNodeInst) obj;
if (!menuItem.function.isContact()) {
continue; // not a contact
}
NodeProto np = findNodeProto(((Xml.MenuNodeInst) obj).protoName);
if (np instanceof PrimitiveNode) {
PrimitiveNode pn = (PrimitiveNode) np;
boolean found1 = false, found2 = false;
for (NodeLayer l : pn.getNodeLayers()) {
if (l.getLayer() == l1) {
found1 = true;
}
if (l.getLayer() == l2) {
found2 = true;
}
if (found1 && found2) {
break; // found both
}
}
// both layers found in this particular node
if (found1 && found2) {
list.add(pn);
}
}
}
}
}
return list;
}
/********************* FOR GUI **********************/
protected void loadFactoryMenuPalette(URL menuURL) {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(menuURL.openConnection().getInputStream()));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
reader.close();
factoryMenuPalette = parseComponentMenuXML(sb.toString());
} catch (IOException e) {
System.out.println("Error parsing XML component menu data");
e.printStackTrace();
}
}
/**
* Parses Xml string with component menu definition for this technology
* @param nodeGroupXML Xml string with component menu definition
*/
public Xml.MenuPalette parseComponentMenuXML(String nodeGroupXML) {
// parse the preference and build a component menu
List xmlNodeGroups = new ArrayList();
List xmlPureLayerNodes = new ArrayList();
HashSet groupsDone = new HashSet();
for (Iterator it = getNodes(); it.hasNext();) {
PrimitiveNode pnp = it.next();
if (pnp.getFunction() == PrimitiveNode.Function.NODE) {
Xml.PrimitiveNode n = new Xml.PrimitiveNode();
n.name = pnp.getName();
n.function = PrimitiveNode.Function.NODE;
xmlPureLayerNodes.add(n);
continue;
}
PrimitiveNodeGroup group = pnp.getPrimitiveNodeGroup();
if (group != null) {
if (groupsDone.contains(group)) {
continue;
}
Xml.PrimitiveNodeGroup ng = new Xml.PrimitiveNodeGroup();
for (PrimitiveNode pn : group.getNodes()) {
Xml.PrimitiveNode n = new Xml.PrimitiveNode();
n.name = pn.getName();
ng.nodes.add(n);
}
xmlNodeGroups.add(ng);
groupsDone.add(group);
} else {
Xml.PrimitiveNodeGroup ng = new Xml.PrimitiveNodeGroup();
ng.isSingleton = true;
Xml.PrimitiveNode n = new Xml.PrimitiveNode();
n.name = pnp.getName();
ng.nodes.add(n);
xmlNodeGroups.add(ng);
}
}
List xmlArcs = new ArrayList();
for (ArcProto ap : arcs.values()) {
Xml.ArcProto xap = new Xml.ArcProto();
xap.name = ap.getName();
xmlArcs.add(xap);
}
return Xml.parseComponentMenuXMLTechEdit(nodeGroupXML, xmlNodeGroups, xmlArcs, xmlPureLayerNodes);
}
/**
* Method to construct a factory default Xml menu palette.
* @return the factory default Xml menu palette.
*/
public Xml.MenuPalette getFactoryMenuPalette() {
if (factoryMenuPalette == null) {
makeDummyFactoryMenuPalette();
}
assert factoryMenuPalette != null;
return factoryMenuPalette;
}
private void makeDummyFactoryMenuPalette() {
// compute palette information automatically
List> things = new ArrayList>();
for (Iterator it = getArcs(); it.hasNext();) {
ArcProto ap = it.next();
if (ap.isNotUsed()) {
continue;
}
Xml.ArcProto xap = new Xml.ArcProto();
xap.name = ap.getName();
List list = Collections.singletonList(xap);
things.add(list);
}
Set groups = new HashSet();
for (Iterator it = getNodes(); it.hasNext();) {
PrimitiveNode np = it.next();
if (np.isNotUsed()) {
continue;
}
if (np.getFunction() == PrimitiveNode.Function.NODE) {
continue;
}
if (np.group != null) {
if (groups.contains(np.group)) {
continue;
}
groups.add(np.group);
List list = new ArrayList();
for (PrimitiveNode gnp : np.group.getNodes()) {
Xml.MenuNodeInst xnp = new Xml.MenuNodeInst();
xnp.protoName = gnp.getName();
xnp.function = gnp.getFunction();
list.add(xnp);
}
things.add(list);
} else {
List list = new ArrayList();
Xml.PrimitiveNode xpn = new Xml.PrimitiveNode();
xpn.name = np.getName();
list.add(xpn);
things.add(list);
}
}
things.add(Collections.singletonList(SPECIALMENUPURE));
things.add(Collections.singletonList(SPECIALMENUMISC));
things.add(Collections.singletonList(SPECIALMENUCELL));
int columns = (things.size() + 13) / 14;
int rows = (things.size() + columns - 1) / columns;
while (things.size() < columns * rows) {
things.add(null);
}
factoryMenuPalette = new Xml.MenuPalette();
factoryMenuPalette.numColumns = columns;
for (int row = 0; row < rows; row++) {
for (int col = 0; col < columns; col++) {
List> list = things.get(col * rows + row);
factoryMenuPalette.menuBoxes.add(list);
}
}
}
/**
* This is the most basic function to determine the widest wire and the parallel distance
* that run along them. Done because old class (MOSRules) doesn't consider the parallel distance as input.
*/
public double[] getSpacingDistances(Poly poly1, Poly poly2) {
double size1 = poly1.getMinSize();
double size2 = poly1.getMinSize();
double length = 0;
double wideS = (size1 > size2) ? size1 : size2;
double[] results = new double[2];
results[0] = wideS;
results[1] = length;
return results;
}
/**
* Method to retrieve cached rules
* @return cached design rules.
*/
public XMLRules getCachedRules() {
return cachedRules;
}
/**
* Method to set cached rules
*/
public void setCachedRules(XMLRules rules) {
cachedRules = rules;
}
/**
* Method to determine if the rule name matches an existing VT Poly rule
* @param theRule
* @return true if it matches
*/
public boolean isValidVTPolyRule(DRCTemplate theRule) {
return false;
}
public Setting makeBooleanSetting(String name, String location, String description, String xmlName, boolean factory) {
return getProjectSettings().makeBooleanSetting(name, TECH_NODE, xmlName, location, description, factory);
}
public Setting makeIntSetting(String name, String location, String description, String xmlName, int factory, String... trueMeaning) {
return getProjectSettings().makeIntSetting(name, TECH_NODE, xmlName, location, description, factory, trueMeaning);
}
public Setting makeDoubleSetting(String name, String location, String description, String xmlName, double factory) {
return getProjectSettings().makeDoubleSetting(name, TECH_NODE, xmlName, location, description, factory);
}
public Setting makeStringSetting(String name, String location, String description, String xmlName, String factory) {
return getProjectSettings().makeStringSetting(name, TECH_NODE, xmlName, location, description, factory);
}
// -------------------------- Project Preferences -------------------------
public Setting.Group getProjectSettings() {
return settings;
}
public Setting.RootGroup getProjectSettingsRoot() {
return rootSettings;
}
public Setting getSetting(String xmlPath) {
return getProjectSettings().getSetting(xmlPath);
}
public Setting getSetting(TechFactory.Param param) {
String xmlPath = param.xmlPath;
if (xmlPath.startsWith(settings.xmlPath)) {
return getSetting(xmlPath.substring(settings.xmlPath.length()));
}
return null;
}
}