All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.electric.technology.Technology Maven / Gradle / Ivy

There is a newer version: 9.02-e
Show newest version
/* -*- tab-width: 4 -*-
 *
 * Electric(tm) VLSI Design System
 *
 * File: Technology.java
 *
 * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
 *
 * Electric(tm) is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Electric(tm) is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Electric(tm); see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, Mass 02111-1307, USA.
 */
package com.sun.electric.technology;

import com.sun.electric.database.EObjectInputStream;
import com.sun.electric.database.EObjectOutputStream;
import com.sun.electric.database.EditingPreferences;
import com.sun.electric.database.Environment;
import com.sun.electric.database.ImmutableArcInst;
import com.sun.electric.database.ImmutableNodeInst;
import com.sun.electric.database.geometry.EPoint;
import com.sun.electric.database.geometry.ERectangle;
import com.sun.electric.database.geometry.Poly;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.EDatabase;
import com.sun.electric.database.id.ArcProtoId;
import com.sun.electric.database.id.IdManager;
import com.sun.electric.database.id.LayerId;
import com.sun.electric.database.id.PrimitiveNodeId;
import com.sun.electric.database.id.TechId;
import com.sun.electric.database.prototype.NodeProto;
import com.sun.electric.database.text.Pref;
import com.sun.electric.database.text.Setting;
import com.sun.electric.database.text.Version;
import com.sun.electric.database.topology.ArcInst;
import com.sun.electric.database.topology.Geometric;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.topology.PortInst;
import com.sun.electric.database.variable.TextDescriptor;
import com.sun.electric.database.variable.VarContext;
import com.sun.electric.database.variable.Variable;
import com.sun.electric.technology.technologies.Artwork;
import com.sun.electric.technology.technologies.GEM;
import com.sun.electric.technology.technologies.Generic;
import com.sun.electric.technology.technologies.Schematics;
import com.sun.electric.tool.Job;
import com.sun.electric.tool.ToolSettings;
import com.sun.electric.tool.user.User;
import com.sun.electric.tool.user.UserInterfaceMain;
import com.sun.electric.util.TextUtils;
import com.sun.electric.util.collections.ImmutableArrayList;
import com.sun.electric.util.math.DBMath;
import com.sun.electric.util.math.ECoord;
import com.sun.electric.util.math.Orientation;

import java.awt.Color;
import java.awt.geom.Point2D;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InvalidObjectException;
import java.io.NotSerializableException;
import java.io.PrintWriter;
import java.io.Serializable;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.TreeMap;
import java.util.prefs.Preferences;

/**
 * Technology is the base class for all of the specific technologies in Electric.
 *
 * It is organized into two main areas: nodes and arcs.
 * Both nodes and arcs are composed of Layers.
 *

* Subclasses of Technology usually start by defining the Layers (such as Metal-1, Metal-2, etc.) * Then the ArcProto objects are created, built entirely from Layers. * Next PrimitiveNode objects are created, and they have Layers as well as connectivity to the ArcProtos. * The Technology concludes with miscellaneous data assignments of technology-wide information. *

* Here are the nodes in a sample CMOS technology. * Note that there are two types of transistors and diffusion contacts, one for Well and one for Substrate. * Each layer that can exist as a wire must have a pin node (in this case, metal, polysilicon, and two flavors of diffusion. * Note that there are pure-layer nodes at the bottom which allow arbitrary geometry to be constructed. *

*

* The Schematic technology has some unusual features. *

*

* Conceptually, a Technology has 3 types of information: *

  • Geometry. Each node and arc can be described in terms of polygons on differnt Layers. * The ArcLayer and NodeLayer subclasses help define those polygons. *
  • Connectivity. The very structure of the nodes and arcs establisheds a set of rules of connectivity. * Examples include the list of allowable arc types that may connect to each port, and the use of port "network numbers" * to identify those that are connected internally. *
  • Behavior. Behavioral information takes many forms, but they can all find a place here. * For example, each layer, node, and arc has a "function" that describes its general behavior. * Some information applies to the technology as a whole, for example SPICE model cards. * Other examples include Design Rules and technology characteristics. *
* @author Steven M. Rubin */ public class Technology implements Comparable, Serializable { /** Jelib writes base sizes since this Electric Version */ public static final Version DISK_VERSION_1 = Version.parseVersion("8.05g"); /** Jelib writes oversize over standard primitive since this Electric Version */ public static final Version DISK_VERSION_2 = Version.parseVersion("8.05o"); public static final Technology[] NULL_ARRAY = {}; public static final ImmutableArrayList EMPTY_LIST = new ImmutableArrayList(NULL_ARRAY); /** key of Variable for saving scalable transistor contact information. */ public static final Variable.Key TRANS_CONTACT = Variable.newKey("MOCMOS_transcontacts"); /** Relative path in Preferences where technology Settings and Preferences are stored */ public static final String TECH_NODE = "technology/technologies"; // strings used in the Component MenuNodeLayer public static final String SPECIALMENUCELL = "Cell"; public static final String SPECIALMENUMISC = "Misc."; public static final String SPECIALMENUPURE = "Pure"; public static final String SPECIALMENUSPICE = "Spice"; public static final String SPECIALMENUEXPORT = "Export"; public static final String SPECIALMENUTEXT = "Text"; public static final String SPECIALMENUHIGH = "High"; public static final String SPECIALMENUPORT = "Port"; public static final String SPECIALMENUSEPARATOR = "-"; /** * Defines a single layer of a ArcProto. * A ArcProto has a list of these ArcLayer objects, one for * each layer in a typical ArcInst. * Each ArcProto is composed of a number of ArcLayer descriptors. * A descriptor converts a specific ArcInst into a polygon that describe this particular layer. */ public static class ArcLayer { private final Layer layer; private final Poly.Type style; private ECoord extend; /** * Constructs an ArcLayer with the specified description. * @param layer the Layer of this ArcLayer. * @param arcLayerWidth the width of this ArcLayer in standard ArcInst. * @param style the Poly.Style of this ArcLayer. */ public ArcLayer(Layer layer, double arcLayerWidth, Poly.Type style) { this(layer, style, 0.5 * arcLayerWidth); } /** * Constructs an ArcLayer with the specified description. * @param layer the Layer of this ArcLayer. * @param style the Poly.Style of this ArcLayer. * @param lambdaExtend lambda fraction of extend */ public ArcLayer(Layer layer, Poly.Type style, double lambdaExtend) { this.layer = layer; this.style = style; extend = ECoord.fromLambdaRoundGrid(lambdaExtend); if (extend.getGrid() < 0 || extend.getGrid() >= Integer.MAX_VALUE / 8) { throw new IllegalArgumentException("extend=" + extend); } } /** * Returns the Layer from the Technology to be used for this ArcLayer. * @return the Layer from the Technology to be used for this ArcLayer. */ public Layer getLayer() { return layer; } /** * Returns the distance from the center of the standard ArcInst to the outsize of this ArcLayer as ECoord object. * The distance from the center of arbitrary ArcInst ai to the outsize of its ArcLayer is * ai.getD().getExtendOverMin() + arcLayer.getGridExtend() * @return the distance from the outside of the ArcInst to this ArcLayer as ECoord object. */ public ECoord getExtend() { return extend; } /** * Returns the Poly.Style of this ArcLayer. * @return the Poly.Style of this ArcLayer. */ public Poly.Type getStyle() { return style; } void dump(PrintWriter out) { out.println("\t\tarcLayer layer=" + layer.getName() + " style=" + style.name() + " extend=" + extend); } Xml.ArcLayer makeXml() { Xml.ArcLayer al = new Xml.ArcLayer(); al.layer = layer.getName(); al.style = style; al.extend.addLambda(extend.getLambda()); return al; } } /** * Defines a point in space that is relative to a NodeInst's bounds. * The TechPoint has two coordinates: X and Y. * Each of these coordinates is represented by an Edge class (EdgeH for X * and EdgeV for Y). * The Edge classes have two numbers: a multiplier and an adder. * The desired coordinate takes the NodeInst's center, adds in the * product of the Edge multiplier and the NodeInst's size, and then adds * in the Edge adder. *

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





© 2015 - 2025 Weber Informatics LLC | Privacy Policy