/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: Technology.java
*
* Copyright (c) 2003 Sun Microsystems and Static Free Software
*
* 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.StartupPrefs;
import com.sun.electric.database.EObjectInputStream;
import com.sun.electric.database.EObjectOutputStream;
import com.sun.electric.database.Environment;
import com.sun.electric.database.ImmutableArcInst;
import com.sun.electric.database.ImmutableNodeInst;
import com.sun.electric.database.geometry.DBMath;
import com.sun.electric.database.geometry.EGraphics;
import com.sun.electric.database.geometry.EPoint;
import com.sun.electric.database.geometry.ERectangle;
import com.sun.electric.database.geometry.Orientation;
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.ImmutableArrayList;
import com.sun.electric.database.text.Pref;
import com.sun.electric.database.text.Setting;
import com.sun.electric.database.text.TextUtils;
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.EFIDO;
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 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.
*<P>
* 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.
* <P>
* 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.
* <CENTER><IMG SRC="doc-files/Technology-1.gif"></CENTER>
* <P>
* The Schematic technology has some unusual features.
* <CENTER><IMG SRC="doc-files/Technology-2.gif"></CENTER>
* <P>
* Conceptually, a Technology has 3 types of information:
* <UL><LI><I>Geometry</I>. Each node and arc can be described in terms of polygons on differnt Layers.
* The ArcLayer and NodeLayer subclasses help define those polygons.
* <LI><I>Connectivity</I>. 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.
* <LI><I>Behavior</I>. 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.
* </UL>
* @author Steven M. Rubin
*/
public class Technology implements Comparable<Technology>, Serializable
{
/** Skip wiped pins both in electrical and non-electrical mode */
protected static final boolean ALWAYS_SKIP_WIPED_PINS = false;
// Change in TechSettings takes effect only after restart
public static final boolean IMMUTABLE_TECHS = false/*Config.TWO_JVM*/;
/** 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<Technology> EMPTY_LIST = new ImmutableArrayList<Technology>(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.
*/
protected static class ArcLayer
{
private final Layer layer;
private final Poly.Type style;
private int gridExtend;
/**
* Constructs an <CODE>ArcLayer</CODE> 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 <CODE>ArcLayer</CODE> 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;
long gridExtend = DBMath.lambdaToGrid(lambdaExtend);
if (gridExtend < 0 || gridExtend >= Integer.MAX_VALUE/8)
throw new IllegalArgumentException("gridExtend=" + gridExtend);
this.gridExtend = (int)gridExtend;
}
/**
* 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 in grid units.
* 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 in grid units.
*/
public int getGridExtend() { return gridExtend; }
/**
* Returns the Poly.Style of this ArcLayer.
* @return the Poly.Style of this ArcLayer.
*/
public Poly.Type getStyle() { return style; }
void copyState(ArcLayer that) {
gridExtend = that.gridExtend;
}
void dump(PrintWriter out) {
out.println("\t\tarcLayer layer=" + layer.getName() +
" style=" + style.name() +
" extend=" + DBMath.gridToLambda(gridExtend));
}
Xml.ArcLayer makeXml() {
Xml.ArcLayer al = new Xml.ArcLayer();
al.layer = layer.getName();
al.style = style;
al.extend.addLambda(DBMath.gridToLambda(gridExtend));
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.
* <P>
* 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 <CODE>Poly.Style</CODE> 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 <CODE>TechPoint</CODE> 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)
{
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 a box that fills the node.
* @return a new TechPoint array that describes a box that fills the node.
*/
public static TechPoint [] makeFullBox()
{
return makeIndented(0);
}
/**
* Method to make a 2-long TechPoint array that describes indentation by a specified amount.
* @param amount the amount to indent the box.
* @return a new TechPoint array that describes this indented box.
*/
public static TechPoint [] makeIndented(double amount)
{
return new Technology.TechPoint [] {
new Technology.TechPoint(EdgeH.fromLeft(amount), EdgeV.fromBottom(amount)),
new Technology.TechPoint(EdgeH.fromRight(amount), EdgeV.fromTop(amount))};
}
/**
* Method similat to makeIndented(double amount) where the X and Y specified amounts are different
* @param amountX the amount to indent the box along X.
* @param amountY the amount to indent the box along Y.
* @return a new TechPoint array that describes this indented box.
*/
public static TechPoint [] makeIndented(double amountX, double amountY)
{
return new Technology.TechPoint [] {
new Technology.TechPoint(EdgeH.fromLeft(amountX), EdgeV.fromBottom(amountY)),
new Technology.TechPoint(EdgeH.fromRight(amountX), EdgeV.fromTop(amountY))};
}
/**
* 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 Layer layer;
private int portNum;
private Poly.Type style;
private int representation;
private TechPoint [] points;
private EPoint fixupCorrector;
private String message;
private TextDescriptor descriptor;
private double lWidth, rWidth, extentT, extendB;
private int cutGridSizeX, cutGridSizeY, cutGridSep1D, cutGridSep2D;
// 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 <CODE>NodeLayer</CODE> with the specified description.
* @param layer the <CODE>Layer</CODE> 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 = 0;
}
/**
* Constructs a <CODE>NodeLayer</CODE> 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 <CODE>Layer</CODE> 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 <I>centerline</I>.
* 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 <I>centerline</I>.
* @param extentT the top extension of this layer, measured from the end of the <I>centerline</I>.
* 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 <I>centerline</I>.
*/
public NodeLayer(Layer layer, int portNum, Poly.Type style, int representation, TechPoint [] points,
double lWidth, double rWidth, double extentT, double 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 <CODE>NodeLayer</CODE> 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 = 0;
}
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.cutGridSizeX = (int)DBMath.lambdaToGrid(sizeX);
nl.cutGridSizeY = (int)DBMath.lambdaToGrid(sizeY);
nl.cutGridSep1D = (int)DBMath.lambdaToGrid(sep1d);
nl.cutGridSep2D = (int)DBMath.lambdaToGrid(sep2d);
return nl;
}
public void fixup(EPoint fixupCorrector) {
if (this.fixupCorrector != null) {
assert this.fixupCorrector.equals(fixupCorrector);
return;
}
this.fixupCorrector = fixupCorrector;
for (int i = 0; i < points.length; i++) {
TechPoint p = points[i];
EdgeH x = p.getX();
EdgeV y = p.getY();
x = x.withAdder(x.getAdder() + x.getMultiplier() * fixupCorrector.getLambdaX());
y = y.withAdder(y.getAdder() + y.getMultiplier() * fixupCorrector.getLambdaY());
points[i] = p.withX(x).withY(y);
}
}
/**
* Returns the <CODE>Layer</CODE> object associated with this NodeLayer.
* @return the <CODE>Layer</CODE> 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 <CODE>Layer</CODE> or pseudo-layer object associated with this NodeLayer.
* @return the <CODE>Layer</CODE> 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 double 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 = 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 double 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 = 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 double 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 = 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 double 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 = extendB; }
public double getMulticutSizeX() { return DBMath.gridToLambda(cutGridSizeX); }
public double getMulticutSizeY() { return DBMath.gridToLambda(cutGridSizeY); }
public double getMulticutSep1D() { return DBMath.gridToLambda(cutGridSep1D); }
public double getMulticutSep2D() { return DBMath.gridToLambda(cutGridSep2D); }
public int getGridMulticutSizeX() { return cutGridSizeX; }
public int getGridMulticutSizeY() { return cutGridSizeY; }
public int getGridMulticutSep1D() { return cutGridSep1D; }
public int getGridMulticutSep2D() { return cutGridSep2D; }
void copyState(NodeLayer that) {
assert representation == that.representation;
assert points.length == that.points.length;
System.arraycopy(that.points, 0, points, 0, points.length);
lWidth = that.lWidth;
rWidth = that.rWidth;
extentT = that.extentT;
extendB = that.extendB;
cutGridSizeX = that.cutGridSizeX;
cutGridSizeY = that.cutGridSizeY;
cutGridSep1D = that.cutGridSep1D;
cutGridSep2D = that.cutGridSep2D;
}
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() != 0 || getMulticutSizeY() != 0 || getMulticutSep1D() != 0 || getMulticutSep2D() != 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() - p.getX().getMultiplier()*correction.getLambdaX()) +
" ym=" + p.getY().getMultiplier() + " ya=" + DBMath.round(p.getY().getAdder() - p.getY().getMultiplier()*correction.getLambdaY()));
}
Xml.NodeLayer makeXml(boolean isSerp, boolean inLayers, boolean inElectricalLayers) {
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()));
nld.hx.k = points[1].getX().getMultiplier()*2;
nld.hx.addLambda(DBMath.round(points[1].getX().getAdder()));
nld.ly.k = points[0].getY().getMultiplier()*2;
nld.ly.addLambda(DBMath.round(points[0].getY().getAdder()));
nld.hy.k = points[1].getY().getMultiplier()*2;
nld.hy.addLambda(DBMath.round(points[1].getY().getAdder()));
} else {
for (Technology.TechPoint p: points)
nld.techPoints.add(p);
}
if (nld.representation == Technology.NodeLayer.MULTICUTBOX) {
nld.sizex = DBMath.round(getMulticutSizeX());
nld.sizey = DBMath.round(getMulticutSizeY());
nld.sep1d = DBMath.round(getMulticutSep1D());
nld.sep2d = DBMath.round(getMulticutSep2D());
}
if (isSerp) {
nld.lWidth = DBMath.round(getSerpentineLWidth());
nld.rWidth = DBMath.round(getSerpentineRWidth());
nld.tExtent = DBMath.round(getSerpentineExtentT());
nld.bExtent = DBMath.round(getSerpentineExtentB());
}
return nld;
}
}
public class State {
public final Map<TechFactory.Param,Object> paramValues;
private State(Map<TechFactory.Param,Object> paramValues) {
this.paramValues = paramValues;
}
public Technology getTechnology() { return Technology.this; }
public String getTechDesc() { return getTechnology().getTechDesc(); }
public Technology activate() {
if (!IMMUTABLE_TECHS && currentState != this) {
if (!currentState.paramValues.equals(this.paramValues)) {
Technology newTech = techFactory.newInstance(generic, paramValues);
copyState(newTech);
}
currentState = this;
cachedRules = factoryRules = null;
}
return getTechnology();
}
}
protected State newState(Map<TechFactory.Param,Object> paramValues) {
LinkedHashMap<TechFactory.Param,Object> fixedParamValues = new LinkedHashMap<TechFactory.Param,Object>();
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 new State(Collections.unmodifiableMap(fixedParamValues));
}
public class SizeCorrector {
public final HashMap<ArcProtoId,Integer> arcExtends = new HashMap<ArcProtoId,Integer>();
public final HashMap<PrimitiveNodeId,EPoint> nodeExtends = new HashMap<PrimitiveNodeId,EPoint>();
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()) {
int correction = 0;
switch (techVersion) {
case 0:
correction = ap.getGridBaseExtend() + (int)DBMath.lambdaToGrid(0.5*ap.getLambdaElibWidthOffset());
break;
case 1:
correction = ap.getGridBaseExtend();
break;
}
arcExtends.put(ap.getId(), Integer.valueOf(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 (Integer arcExtend: arcExtends.values()) {
if (arcExtend.intValue() != 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()).longValue();
}
public long getExtendToDisk(ImmutableArcInst a) {
return a.getGridExtendOverMin() + arcExtends.get(a.protoId).intValue();
}
public long getWidthToDisk(ImmutableArcInst a) {
return 2*getExtendToDisk(a);
}
public EPoint getSizeFromDisk(PrimitiveNode pn, double width, double height) {
EPoint correction = nodeExtends.get(pn.getId());
return EPoint.fromLambda(width - 2*correction.getLambdaX(), height - 2*correction.getLambdaY());
}
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<Setting,Object> projectSettings, boolean isJelib, boolean keepExtendOverMin) {
return new SizeCorrector(version, isJelib);
}
protected void setArcCorrection(SizeCorrector sc, String arcName, double lambdaBaseWidth) {
ArcProto ap = findArcProto(arcName);
Integer correction = sc.arcExtends.get(ap.getId());
int gridBaseExtend = (int)DBMath.lambdaToGrid(0.5*lambdaBaseWidth);
if (gridBaseExtend != ap.getGridBaseExtend()) {
correction = Integer.valueOf(correction.intValue() + gridBaseExtend - ap.getGridBaseExtend());
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<Layer> layers = new ArrayList<Layer>();
/** map from layer names to layers in this technology */private final HashMap<String,Layer> layersByName = new HashMap<String,Layer>();
/** 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<String,PrimitiveNode> nodes = new LinkedHashMap<String,PrimitiveNode>();
/** array of nodes by nodeId.chronIndex */ private PrimitiveNode[] nodesByChronIndex = {};
/** Old names of primitive nodes */ protected final HashMap<String,PrimitiveNode> oldNodeNames = new HashMap<String,PrimitiveNode>();
/** count of primitive nodes in this technology */ private int nodeIndex = 0;
/** list of node groups in this technology */ final ArrayList<PrimitiveNodeGroup> primitiveNodeGroups = new ArrayList<PrimitiveNodeGroup>();
/** list of arcs in this technology */ private final LinkedHashMap<String,ArcProto> arcs = new LinkedHashMap<String,ArcProto>();
/** array of arcs by arcId.chronIndex */ private ArcProto[] arcsByChronIndex = {};
/** Old names of arcs */ protected final HashMap<String,ArcProto> oldArcNames = new HashMap<String,ArcProto>();
/** 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 double factoryResolution;
/** static list of all Manufacturers in Electric */ protected final List<Foundry> foundries = new ArrayList<Foundry>();
/** 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 State currentState;
/** Xml representation of this Technology */ protected Xml.Technology xmlTech;
/** Xml representation of menu palette */ protected Xml.MenuPalette factoryMenuPalette;
/****************************** CONTROL ******************************/
/**
* Constructs a <CODE>Technology</CODE>.
* 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 <CODE>Technology</CODE>.
* 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.<TechFactory.Param,Object>emptyMap(), defaultFoundry, defaultNumMetals);
}
/**
* Constructs a <CODE>Technology</CODE>.
* This should not be called directly, but instead is invoked through each subclass's factory.
*/
protected Technology(Generic generic, TechFactory techFactory, Map<TechFactory.Param,Object> techParams, Foundry.Type defaultFoundry, int defaultNumMetals) {
this(generic.getId().idManager, generic, techFactory, techParams, defaultFoundry, defaultNumMetals);
}
/**
* Constructs a <CODE>Technology</CODE>.
* This should not be called directly, but instead is invoked through each subclass's factory.
*/
protected Technology(IdManager idManager, Generic generic, TechFactory techFactory, Map<TechFactory.Param,Object> 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();
}
currentState = newState(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<Technology> {
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<TechFactory.Param,Object> 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<String,Layer> layers = new HashMap<String,Layer>();
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<String,ArcProto> arcs = new HashMap<String,ArcProto>();
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 = 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.curvable)
ap.setCurvable();
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<String> gdsLayers = new ArrayList<String>();
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<String> portArcs, Map<String,ArcProto> 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);
String softTechnologies = StartupPrefs.getSoftTechnologies();
for (TechFactory techFactory: TechFactory.getKnownTechs(softTechnologies).values()) {
Map<TechFactory.Param,Object> 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<TechFactory.Param,Object> e: t.getCurrentState().paramValues.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<String,Object> getParamValuesByXmlPath() {
Map<String,Object> paramValuesByXmlPath = new HashMap<String,Object>();
for (TechFactory techFactory: TechFactory.getKnownTechs("").values()) {
Map<TechFactory.Param,Object> paramValues = Technology.paramValuesFromPreferences(techFactory);
for (Map.Entry<TechFactory.Param,Object> 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 initAllTechnologies(EDatabase database, Map<String,Object> paramValuesByXmlPath, String softTechnologies)
{
database.setToolSettings((Setting.RootGroup)ToolSettings.getToolSettings(""));
assert database.getGeneric() == null;
Generic generic = Generic.newInstance(database.getIdManager());
database.addTech(generic);
for (TechFactory techFactory: TechFactory.getKnownTechs(softTechnologies).values()) {
Map<TechFactory.Param,Object> paramValues = new HashMap<TechFactory.Param,Object>();
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);
}
// set the current technology, given priority to user defined
// curLayoutTech = getMocmosTechnology();
// Technology tech = Technology.findTechnology(User.getDefaultTechnology());
// if (tech == null) tech = getMocmosTechnology();
// tech.setCurrent();
}
/*
private void loadValues() {
ProjSettings projSettings = ProjSettings.getSettings();
if (projSettings != null) {
HashSet<Preferences> flushSet = new HashSet<Preferences>();
for (Setting setting: getSettings()) {
Object psVal = projSettings.getValue(setting.getXmlPath());
if (psVal == null)
psVal = setting.getFactoryValue();
if (psVal.equals(setting.getValue()))
continue;
if (psVal.getClass() != setting.getValue().getClass()) {
System.out.println("Warning: Value type mismatch for key " + setting.getXmlPath() + ": " +
psVal.getClass().getName() + " vs " + setting.getValue().getClass().getName());
continue;
}
System.out.println("Warning: For key "+setting.getXmlPath()+": project preferences value of "+psVal+" overrides default of "+setting.getValue());
setting.currentObj = psVal.equals(setting.factoryObj) ? setting.factoryObj : psVal;
setting.saveToPreferences(psVal);
flushSet.add(setting.prefs);
}
for (Preferences preferences: flushSet) {
try {
preferences.flush();
} catch (BackingStoreException e) {
}
}
} else {
for (Setting setting: getSettings())
setting.setCachedObjFromPreferences();
}
}
*/
private static Map<TechFactory.Param,Object> paramValuesFromPreferences(TechFactory techFactory) {
HashMap<TechFactory.Param,Object> paramValues = new HashMap<TechFactory.Param,Object>();
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.State withState(Map<TechFactory.Param,Object> paramValues) {
State newState = newState(paramValues);
if (newState.paramValues.equals(currentState.paramValues)) return currentState;
if (IMMUTABLE_TECHS)
newState = techFactory.newInstance(generic, newState.paramValues).currentState;
return newState;
}
public Technology.State getCurrentState() {
return currentState;
}
protected void copyState(Technology that) {
currentState = new State(that.currentState.paramValues);
xmlTech = that.xmlTech;
factoryMenuPalette = that.factoryMenuPalette;
techDesc = that.techDesc;
cachedRules = factoryRules = null;
assert layers.size() == that.layers.size();
Iterator<Layer> oldItl = layers.iterator();
Iterator<Layer> newItl = that.layers.iterator();
for (int i = 0; i < layers.size(); i++) {
Layer oldL = oldItl.next();
Layer newL = newItl.next();
oldL.copyState(newL);
}
assert !oldItl.hasNext() && !newItl.hasNext();
assert arcs.size() == that.arcs.size();
Iterator<ArcProto> oldIta = arcs.values().iterator();
Iterator<ArcProto> newIta = that.arcs.values().iterator();
for (int i = 0; i < arcs.size(); i++) {
ArcProto oldA = oldIta.next();
ArcProto newA = newIta.next();
oldA.copyState(newA);
}
assert !oldIta.hasNext() && !newIta.hasNext();
assert nodes.size() == that.nodes.size();
Iterator<PrimitiveNode> oldItn = nodes.values().iterator();
Iterator<PrimitiveNode> newItn = that.nodes.values().iterator();
for (int i = 0; i < nodes.size(); i++) {
PrimitiveNode oldN = oldItn.next();
PrimitiveNode newN = newItn.next();
// if (oldN.getPrimitiveNodeGroup() != null) {
// assert newN.getPrimitiveNodeGroup() != null;
// continue;
// }
oldN.copyState(newN);
}
assert !oldItn.hasNext() && !newItn.hasNext();
assert primitiveNodeGroups.size() == that.primitiveNodeGroups.size();
Iterator<PrimitiveNodeGroup> oldItg = primitiveNodeGroups.iterator();
Iterator<PrimitiveNodeGroup> newItg = that.primitiveNodeGroups.iterator();
for (int i = 0; i < primitiveNodeGroups.size(); i++) {
PrimitiveNodeGroup oldG = oldItg.next();
PrimitiveNodeGroup newG = newItg.next();
oldG.copyState(newG);
}
assert !oldItg.hasNext() && !newItg.hasNext();
}
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<Technology> 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<Technology> 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<Setting,Object> 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<Geometric> 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<Setting,Object> 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));
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<String,ArcProto> 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<String,PrimitiveNode> 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<Foundry> it = getFoundries(); it.hasNext();) {
Foundry foundry = it.next();
out.println(" <Foundry name=\"" + foundry.getType().getName() + "\">");
for (Iterator<Layer> 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(" <layerGds layer=\"" + layer.getName() + "\" gds=\"" + gdsStr + "\"/>");
}
// for (Map.Entry<Layer,String> e: foundry.getGDSLayers(sc).entrySet())
// out.println(" <layerGds layer=\"" + e.getKey().getName() + "\" gds=\"" + e.getValue() + "\"/>");
List<DRCTemplate> rules = foundry.getRules();
if (rules != null) {
for (DRCTemplate rule: rules)
DRCTemplate.exportDRCRule(out, rule);
}
out.println(" </Foundry>");
}
}
protected void dumpExtraProjectSettings(PrintWriter out, Map<Setting,Object> settings) {}
protected static void printlnSetting(PrintWriter out, Map<Setting,Object> 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() {
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();
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<Layer> it = getLayers(); it.hasNext(); ) {
Layer layer = it.next();
if (layer.isPseudoLayer()) continue;
t.layers.add(layer.makeXml());
}
// HashSet<PrimitiveNode> arcPins = new HashSet<PrimitiveNode>();
for (Iterator<ArcProto> it = getArcs(); it.hasNext(); ) {
ArcProto ap = it.next();
t.arcs.add(ap.makeXml());
// if (ap.arcPin != null)
// arcPins.add(ap.arcPin);
}
HashSet<PrimitiveNodeGroup> groupsDone = new HashSet<PrimitiveNodeGroup>();
for (Iterator<PrimitiveNode> 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());
}
}
addSpiceHeader(t, 1, getSpiceHeaderLevel1());
addSpiceHeader(t, 2, getSpiceHeaderLevel2());
addSpiceHeader(t, 3, getSpiceHeaderLevel3());
t.menuPalette = getFactoryMenuPalette();
for (Iterator<Foundry> 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<Layer,String> gdsMap = foundry.getGDSLayers();
// for (Map.Entry<Layer,String> e: gdsMap.entrySet()) {
// String gds = e.getValue();
// if (gds.length() == 0) continue;
// f.layerGds.put(e.getKey().getName(), gds);
// }
List<DRCTemplate> 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<Layer> 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<Layer> it = getLayers(); it.hasNext(); )
{
layer = it.next();
if (layer.getName().equalsIgnoreCase(layerName)) return layer;
}
for(Iterator<Layer> 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<PrimitiveNode> 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<Layer> 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<Layer> getLayersSortedByHeight()
{
// determine order of overlappable layers in current technology
List<Layer> layerList = new ArrayList<Layer>();
for(Iterator<Layer> 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<Layer> getLayersSortedByName()
{
List<Layer> layerList = new ArrayList<Layer>();
for(Iterator<Layer> 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<Layer>
{
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].gridExtend == (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<ArcProto> 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<ArcProto> 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<ArcProto> 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);
}
/**
* Fill the polygons that describe arc "a".
* @param b AbstractShapeBuilder to fill polygons.
* @param a the ImmutableArcInst that is being described.
*/
protected void getShapeOfArc(AbstractShapeBuilder b, ImmutableArcInst a) {
getShapeOfArc(b, a, null);
}
/**
* Fill the polygons that describe arc "a".
* @param b AbstractShapeBuilder to fill polygons.
* @param a the ImmutableArcInst that is being described.
* @param graphicsOverride the graphics to use for all generated polygons (if not null).
*/
protected void getShapeOfArc(AbstractShapeBuilder b, ImmutableArcInst a, EGraphics graphicsOverride) {
// get information about the arc
assert a.protoId.techId == techId;
ArcProto ap = getArcProto(a.protoId);
assert ap.getTechnology() == this;
int numArcLayers = ap.getNumArcLayers();
// construct the polygons that describe the basic arc
if (!isNoNegatedArcs() && (a.isHeadNegated() || a.isTailNegated())) {
for (int i = 0; i < numArcLayers; i++) {
Technology.ArcLayer primLayer = ap.getArcLayer(i);
Layer layer = primLayer.getLayer();
// remove a gap for the negating bubble
int angle = a.getAngle();
double gridBubbleSize = Schematics.tech().getNegatingBubbleSize()*DBMath.GRID;
double cosDist = DBMath.cos(angle) * gridBubbleSize;
double sinDist = DBMath.sin(angle) * gridBubbleSize;
if (!b.skipLayer(layer)) {
if (a.isTailNegated())
b.pushPoint(a.tailLocation, cosDist, sinDist);
else
b.pushPoint(a.tailLocation);
if (a.isHeadNegated())
b.pushPoint(a.headLocation, -cosDist, -sinDist);
else
b.pushPoint(a.headLocation);
b.pushPoly(Poly.Type.OPENED, layer, graphicsOverride, null);
}
Layer node_lay = Schematics.tech().node_lay;
if (!b.skipLayer(node_lay)) {
if (a.isTailNegated()) {
b.pushPoint(a.tailLocation, 0.5*cosDist, 0.5*sinDist);
b.pushPoint(a.tailLocation);
b.pushPoly(Poly.Type.CIRCLE, node_lay, null, null);
}
if (a.isHeadNegated()) {
b.pushPoint(a.headLocation, -0.5*cosDist, -0.5*sinDist);
b.pushPoint(a.headLocation);
b.pushPoly(Poly.Type.CIRCLE, node_lay, null, null);
}
}
}
} else {
for (int i = 0; i < numArcLayers; i++) {
Technology.ArcLayer primLayer = ap.getArcLayer(i);
Layer layer = primLayer.getLayer();
if (b.skipLayer(layer)) continue;
b.makeGridPoly(a, 2*(a.getGridExtendOverMin() + ap.getLayerGridExtend(i)), primLayer.getStyle(), layer, graphicsOverride);
}
}
// add an arrow to the arc description
if (!isNoDirectionalArcs() && !b.skipLayer(generic.glyphLay)) {
final double lambdaArrowSize = 1.0*DBMath.GRID;
int angle = a.getAngle();
if (a.isBodyArrowed()) {
b.pushPoint(a.headLocation);
b.pushPoint(a.tailLocation);
b.pushPoly(Poly.Type.VECTORS, generic.glyphLay, null, null);
}
if (a.isTailArrowed()) {
int angleOfArrow = 3300; // -30 degrees
int backAngle1 = angle - angleOfArrow;
int backAngle2 = angle + angleOfArrow;
b.pushPoint(a.tailLocation);
b.pushPoint(a.tailLocation, DBMath.cos(backAngle1)*lambdaArrowSize, DBMath.sin(backAngle1)*lambdaArrowSize);
b.pushPoint(a.tailLocation);
b.pushPoint(a.tailLocation, DBMath.cos(backAngle2)*lambdaArrowSize, DBMath.sin(backAngle2)*lambdaArrowSize);
b.pushPoly(Poly.Type.VECTORS, generic.glyphLay, null, null);
}
if (a.isHeadArrowed()) {
angle = (angle + 1800) % 3600;
int angleOfArrow = 300; // 30 degrees
int backAngle1 = angle - angleOfArrow;
int backAngle2 = angle + angleOfArrow;
b.pushPoint(a.headLocation);
b.pushPoint(a.headLocation, DBMath.cos(backAngle1)*lambdaArrowSize, DBMath.sin(backAngle1)*lambdaArrowSize);
b.pushPoint(a.headLocation);
b.pushPoint(a.headLocation, DBMath.cos(backAngle2)*lambdaArrowSize, DBMath.sin(backAngle2)*lambdaArrowSize);
b.pushPoly(Poly.Type.VECTORS, generic.glyphLay, graphicsOverride, null);
}
}
}
/**
* Tells if arc can be drawn by simplified algorithm
* Overidden ins subclasses
* @param a arc 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(ImmutableArcInst a, boolean explain) {
if (a.isBodyArrowed() || a.isTailArrowed() || a.isHeadArrowed()) {
if (explain) System.out.println("ARROWED");
return false;
}
if (a.isTailNegated() || a.isHeadNegated()) {
if (explain) System.out.println("NEGATED");
return false;
}
ArcProto protoType = getArcProto(a.protoId);
if (protoType.isCurvable() && a.getVar(ImmutableArcInst.ARC_RADIUS) != null) {
if (explain) System.out.println("CURVABLE");
return false;
}
if (!(a.tailLocation.isSmall() && a.headLocation.isSmall())) {
if (explain) System.out.println("LARGE " + a.tailLocation + " " + a.headLocation);
return false;
}
int minLayerExtend = (int)a.getGridExtendOverMin() + protoType.getMinLayerGridExtend();
if (minLayerExtend <= 0) {
if (minLayerExtend != 0 || protoType.getNumArcLayers() != 1) {
if (explain) System.out.println(protoType + " many zero-width layers");
return false;
}
return true;
}
for (int i = 0, numArcLayers = protoType.getNumArcLayers(); i < numArcLayers; i++) {
if (protoType.getLayerStyle(i) != Poly.Type.FILLED) {
if (explain) System.out.println("Wide should be filled");
return false;
}
}
if (!a.isManhattan()) {
if (explain) System.out.println("NON-MANHATTAN");
return false;
}
return true;
}
/**
* 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<String,ArcProto> getOldArcNames() { return new TreeMap<String,ArcProto>(oldArcNames); }
/****************************** NODES ******************************/
/**
* Method to return a sorted list of nodes in the technology
* @return a list with all nodes sorted
*/
public List<PrimitiveNode> getNodesSortedByName()
{
TreeMap<String,PrimitiveNode> sortedMap = new TreeMap<String,PrimitiveNode>(TextUtils.STRING_NUMBER_ORDER);
for(Iterator<PrimitiveNode> it = getNodes(); it.hasNext(); )
{
PrimitiveNode pn = it.next();
sortedMap.put(pn.getName(), pn);
}
return new ArrayList<PrimitiveNode>(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<PrimitiveNode> 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<PrimitiveNode> 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<PrimitiveNode> 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 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;
}
/**
* Method to return the pure "NodeProto Function" a PrimitiveNode in this Technology.
* This method is overridden by technologies (such as Schematics) that know the node's function.
* @param pn PrimitiveNode to check.
* @param techBits tech bits
* @return the PrimitiveNode.Function that describes the PrinitiveNode with specific tech bits.
*/
public PrimitiveNode.Function getPrimitiveFunction(PrimitiveNode pn, int techBits) { return pn.getFunction(); }
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)
*/
public void setPrimitiveNodeSize(NodeInst ni, double width, double length)
{
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;
}
/**
* Method to set the pure "NodeProto Function" for a primitive NodeInst in this Technology.
* This method is overridden by technologies (such as Schematics) that can change a node's function.
* @param ni the NodeInst to check.
* @param function the PrimitiveNode.Function to set on the NodeInst.
*/
public void setPrimitiveFunction(NodeInst ni, PrimitiveNode.Function function) {}
/**
* 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;
}
/**
* Puts into shape builder s the polygons that describe node "n", given a set of
* NodeLayer objects to use.
* This method is overridden by specific Technologys.
* @param b shape builder where to put polygons
* @param n the ImmutableNodeInst that is being described.
* @param pn proto of the ImmutableNodeInst in this Technology
* @param primLayers an array of NodeLayer objects to convert to Poly objects.
* The prototype of this NodeInst must be a PrimitiveNode and not a Cell.
*/
protected void genShapeOfNode(AbstractShapeBuilder b, ImmutableNodeInst n, PrimitiveNode pn, Technology.NodeLayer[] primLayers) {
b.genShapeOfNode(n, pn, primLayers, null);
}
/**
* 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().getGridAdder() + (long)(gridWidth*techPoints[0].getX().getMultiplier());
long hx = techPoints[1].getX().getGridAdder() + (long)(gridWidth*techPoints[1].getX().getMultiplier());
long ly = techPoints[0].getY().getGridAdder() + (long)(gridHeight*techPoints[0].getY().getMultiplier());
long hy = techPoints[1].getY().getGridAdder() + (long)(gridHeight*techPoints[1].getY().getMultiplier());
cutSizeX = cutLayer.cutGridSizeX;
cutSizeY = cutLayer.cutGridSizeY;
cutSep1D = cutLayer.cutGridSep1D;
cutSep2D = cutLayer.cutGridSep2D;
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<String,PrimitiveNode> getOldNodeNames() { return new TreeMap<String,PrimitiveNode>(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)
{
return getShapeOfPort(ni, pp, null);
}
/**
* 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);
}
/**
* Puts into shape builder s the polygons that describe node "n", given a set of
* NodeLayer objects to use.
* This method is overridden by specific Technologys.
* @param b shape builder where to put polygons
* @param n the ImmutableNodeInst that is being described.
* @param pn proto of the ImmutableNodeInst in this Technology
* @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.
* The prototype of this NodeInst must be a PrimitiveNode and not a Cell.
*/
protected void genShapeOfPort(AbstractShapeBuilder b, ImmutableNodeInst n, PrimitiveNode pn, PrimitivePort pp, Point2D selectPt) {
b.genShapeOfPort(n, pn, pp);
}
/**
* 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<Technology> 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 = 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 double getFactoryResolution()
{
return factoryResolution;
}
/**
* Method to retrieve the default scaled resolution associated to the technology.
* This is the minimum size unit that can be represented once the value is scaled.
* @return the technology's default scaled resolution value.
*/
public double getFactoryScaledResolution()
{
return factoryResolution/getScale();
}
/**
* 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<Foundry> 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<Layer,String> getGDSLayers() {
Foundry foundry = getSelectedFoundry();
Map<Layer,String> 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<DRCTemplate> 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 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<Technology> 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<NodeInst> 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<ArcInst> 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<Technology> 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<Layer,ArcProto.Function> layToArcFunction = new HashMap<Layer,ArcProto.Function>();
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<Layer> 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<ArcProto.Function> neededArcFunctions = new HashSet<ArcProto.Function>();
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<ArcProto.Function> foundArcFunctions = new HashSet<ArcProto.Function>();
for(Iterator<PrimitivePort> 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<PrimitivePort> traPorts = new ArrayList<PrimitivePort>();
for(Iterator<PrimitivePort> 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<NodeProto> getMetalContactCluster(Layer l1, Layer l2)
{
List<NodeProto> list = new ArrayList<NodeProto>();
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();
}
}
/**
* Oarses 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<Xml.PrimitiveNodeGroup> xmlNodeGroups = new ArrayList<Xml.PrimitiveNodeGroup>();
HashSet<PrimitiveNodeGroup> groupsDone = new HashSet<PrimitiveNodeGroup>();
for (Iterator<PrimitiveNode> 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;
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<Xml.ArcProto> xmlArcs = new ArrayList<Xml.ArcProto>();
for (ArcProto ap: arcs.values()) {
Xml.ArcProto xap = new Xml.ArcProto();
xap.name = ap.getName();
xmlArcs.add(xap);
}
return Xml.parseComponentMenuXMLTechEdit(nodeGroupXML, xmlNodeGroups, xmlArcs);
}
/**
* 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<List<?>> things = new ArrayList<List<?>>();
for(Iterator<ArcProto> it = getArcs(); it.hasNext(); )
{
ArcProto ap = it.next();
if (ap.isNotUsed()) continue;
Xml.ArcProto xap = new Xml.ArcProto();
xap.name = ap.getName();
List<Xml.ArcProto> list = Collections.singletonList(xap);
things.add(list);
}
Set<PrimitiveNodeGroup> groups = new HashSet<PrimitiveNodeGroup>();
for(Iterator<PrimitiveNode> 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<Xml.MenuNodeInst> list = new ArrayList<Xml.MenuNodeInst>();
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<Xml.PrimitiveNode> list = new ArrayList<Xml.PrimitiveNode>();
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 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;
}
}