/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: Info.java * Technology Editor, information superclass * Written by Steven M. Rubin, Sun Microsystems. * * Copyright (c) 2005 Sun Microsystems and Static Free Software * * Electric(tm) is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Electric(tm) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Electric(tm); see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, Mass 02111-1307, USA. */ package com.sun.electric.tool.user.tecEdit; import com.sun.electric.database.geometry.EGraphics; import com.sun.electric.database.hierarchy.Cell; import com.sun.electric.database.hierarchy.Library; import com.sun.electric.technology.ArcProto; import com.sun.electric.database.prototype.NodeProto; import com.sun.electric.database.topology.NodeInst; import com.sun.electric.database.variable.Variable; import com.sun.electric.technology.Layer; import com.sun.electric.technology.PrimitiveNode; import com.sun.electric.technology.technologies.Artwork; import com.sun.electric.technology.technologies.Generic; import java.awt.Color; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * This class is the superclass for all information extraction classes in the Technology Editor. */ public class Info { /* * the meaning of OPTION_KEY on nodes * Note that these values are stored in the technology libraries and therefore cannot be changed. * Gaps in the table are where older values became obsolete. * Do not reuse lower numbers when creating a new attribute: add at the end * (as Ivan Sutherland likes to say, numbers are cheap). */ /** transparency layer (layer cell) */ static final int LAYERTRANSPARENCY = 1; /** style (layer cell) */ static final int LAYERSTYLE = 2; /** CIF name (layer cell) */ static final int LAYERCIF = 3; /** function (layer cell) */ static final int LAYERFUNCTION = 4; /** letters (layer cell) */ static final int LAYERLETTERS = 5; /** pattern (layer cell) */ static final int LAYERPATTERN = 6; /** pattern control (layer cell) */ static final int LAYERPATCONT = 7; /** patch of layer (node/arc cell) */ static final int LAYERPATCH = 8; /** function (arc cell) */ static final int ARCFUNCTION = 9; /** function (node cell) */ static final int NODEFUNCTION = 10; /** fixed-angle (arc cell) */ static final int ARCFIXANG = 11; /** wipes pins (arc cell) */ static final int ARCWIPESPINS = 12; /** end extension (arc cell) */ static final int ARCNOEXTEND = 13; /** scale (info cell) */ static final int TECHSCALE = 14; /** description (info cell) */ static final int TECHDESCRIPT = 15; /** serpentine MOS trans (node cell) */ static final int NODESERPENTINE = 16; /** DRC minimum width (layer cell, OBSOLETE) */ static final int LAYERDRCMINWID = 17; /** port object (node cell) */ static final int PORTOBJ = 18; /** highlight object (node/arc cell) */ public static final int HIGHLIGHTOBJ = 19; /** Calma GDS-II layer (layer cell) */ static final int LAYERGDS = 20; /** square node (node cell) */ static final int NODESQUARE = 21; /** pin node can disappear (node cell) */ static final int NODEWIPES = 22; /** increment for arc angles (arc cell) */ static final int ARCINC = 23; /** separation of multiple contact cuts (node cell) */ static final int NODEMULTICUT = 24; /** lockable primitive (node cell) */ static final int NODELOCKABLE = 25; /** grab point object (node cell) */ static final int CENTEROBJ = 26; /** SPICE resistance (layer cell) */ static final int LAYERSPIRES = 27; /** SPICE capacitance (layer cell) */ static final int LAYERSPICAP = 28; /** SPICE edge capacitance (layer cell) */ static final int LAYERSPIECAP = 29; /** DXF layer (layer cell) */ static final int LAYERDXF = 30; /** 3D height (layer cell) */ static final int LAYER3DHEIGHT = 31; /** 3D thickness (layer cell) */ static final int LAYER3DTHICK = 32; /** color (layer cell) */ static final int LAYERCOLOR = 33; /** clear the pattern (layer cell) */ static final int LAYERPATCLEAR = 34; /** invert the pattern (layer cell) */ static final int LAYERPATINVERT = 35; /** copy the pattern (layer cell) */ static final int LAYERPATCOPY = 36; /** copy the pattern (layer cell) */ static final int LAYERPATPASTE = 37; /** Minimum resistance of SPICE elements (info cell) */ static final int TECHSPICEMINRES = 38; /** Minimum capacitance of SPICE elements (info cell) */ static final int TECHSPICEMINCAP = 39; /** Maximum antenna ratio (arc cell) */ static final int ARCANTENNARATIO = 40; /** Desired coverage percentage (layer cell) */ static final int LAYERCOVERAGE = 41; /** gate shrinkage, in um (info cell) */ static final int TECHGATESHRINK = 42; /** true if gate is included in resistance (info cell) */ static final int TECHGATEINCLUDED = 43; /** true to include the ground network (info cell) */ static final int TECHGROUNDINCLUDED= 44; /** the transparent colors (info cell) */ static final int TECHTRANSPCOLORS = 45; /** short name (info cell) */ static final int TECHSHORTNAME = 46; /** default foundry name (info cell) */ static final int TECHFOUNDRY = 47; /** default number of metals (info cell) */ static final int TECHDEFMETALS = 48; /** maximum series resistance (info cell) */ static final int TECHMAXSERIESRES = 49; /** spice level 1 header (info cell) */ static final int TECHSPICELEVEL1 = 50; /** spice level 2 header (info cell) */ static final int TECHSPICELEVEL2 = 51; /** spice level 3 header (info cell) */ static final int TECHSPICELEVEL3 = 52; /** is technology scale relevant (info cell) */ static final int TECHSCALERELEVANT = 53; /** array of distances (connected case) (info cell) */ static final int TECHCONDIST = 54; /** array of distances (unconnected case) (info cell) */ static final int TECHUNCONDIST = 55; /** description of menu palette (info cell) */ static final int TECHPALETTE = 56; /** curvable (arc cell) */ static final int ARCCURVABLE = 57; /** shrinks arcs (node cell) */ static final int NODESHRINKSARCS = 58; /** 3D transparency mode (layer cell) */ static final int LAYER3DMODE = 59; /** 3D transparency factor (layer cell) */ static final int LAYER3DFACTOR = 60; /** Spice template (node cell) */ static final int NODESPICETEMPLATE = 61; /** Elib width offset (arc cell) */ static final int ARCWIDTHOFFSET = 62; /** Factory min resolution (info tech) */ static final int TECHRESOLUTION = 63; /** key of Variable holding layer information. */ public static final Variable.Key LAYER_KEY = Variable.newKey("EDTEC_layer"); /** key of Variable holding option information. */ public static final Variable.Key OPTION_KEY = Variable.newKey("EDTEC_option"); /** key of Variable holding component menu info. */ public static final Variable.Key COMPMENU_KEY = Variable.newKey("EDTEC_componentmenu"); /** key of Variable holding arc ordering. */ static final Variable.Key ARCSEQUENCE_KEY = Variable.newKey("EDTEC_arcsequence"); /** key of Variable holding node ordering. */ static final Variable.Key NODESEQUENCE_KEY = Variable.newKey("EDTEC_nodesequence"); /** key of Variable holding layer ordering. */ static final Variable.Key LAYERSEQUENCE_KEY = Variable.newKey("EDTEC_layersequence"); /** key of Variable marking geometry as min-size. */static final Variable.Key MINSIZEBOX_KEY = Variable.newKey("EDTEC_minbox"); /** key of Variable holding port name. */ static final Variable.Key PORTNAME_KEY = Variable.newKey("EDTEC_portname"); /** key of Variable holding port angle. */ static final Variable.Key PORTANGLE_KEY = Variable.newKey("EDTEC_portangle"); /** key of Variable holding port range. */ static final Variable.Key PORTRANGE_KEY = Variable.newKey("EDTEC_portrange"); /** key of Variable holding arc connection list. */ static final Variable.Key CONNECTION_KEY = Variable.newKey("EDTEC_connects"); /** key of Variable with color map table. */ static final Variable.Key COLORMAP_KEY = Variable.newKey("EDTEC_colormap"); /** key of Variable with color map table. */ static final Variable.Key DEPENDENTLIB_KEY = Variable.newKey("EDTEC_dependent_libraries"); /** key of Variable with transparent color list. */ static final Variable.Key TRANSLAYER_KEY = Variable.newKey("EDTEC_transparent_layers"); /** key of Variable holding port meaning. */ static final Variable.Key PORTMEANING_KEY = Variable.newKey("EDTEC_portmeaning"); /** * Class for describing special text in a cell */ protected static class SpecialTextDescr { NodeInst ni; Object value; int extra; double x, y; int funct; protected SpecialTextDescr(double x, double y, int funct) { ni = null; value = null; this.x = x; this.y = y; this.funct = funct; } }; /** * Method to create special text geometry described by "table" in cell "np". */ protected static void createSpecialText(Cell np, SpecialTextDescr [] table) { // don't create any nodes already there for(int i=0; i < table.length; i++) table[i].ni = null; for(Iterator<NodeInst> it = np.getNodes(); it.hasNext(); ) { NodeInst ni = it.next(); Variable var = ni.getVar(OPTION_KEY); if (var == null) continue; foundNodeForFunction(ni, ((Integer)var.getObject()).intValue(), table); } for(int i=0; i < table.length; i++) { if (table[i].ni != null) continue; table[i].ni = NodeInst.makeInstance(Generic.tech().invisiblePinNode, new Point2D.Double(table[i].x, table[i].y), 0, 0, np); if (table[i].ni == null) return; switch (table[i].funct) { case TECHSHORTNAME: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "ShortName: " + (String)table[i].value); break; case TECHSCALE: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Scale: " + ((Double)table[i].value).doubleValue()); break; case TECHFOUNDRY: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "DefaultFoundry: " + (String)table[i].value); break; case TECHDEFMETALS: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Default Number Of Metals: " + ((Integer)table[i].value).intValue()); break; case TECHDESCRIPT: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Description: " + (String)table[i].value); break; case TECHSPICEMINRES: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Minimum Resistance: " + ((Double)table[i].value).doubleValue()); break; case TECHSPICEMINCAP: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Minimum Capacitance: " + ((Double)table[i].value).doubleValue()); break; case TECHMAXSERIESRES: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Max Series Resistance: " + ((Double)table[i].value).doubleValue()); break; case TECHGATESHRINK: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Gate Shrinkage: " + ((Double)table[i].value).doubleValue()); break; case TECHGATEINCLUDED: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Gates Included in Resistance: " + (((Boolean)table[i].value).booleanValue() ? "Yes" : "No")); break; case TECHGROUNDINCLUDED: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Parasitics Includes Ground: " + (((Boolean)table[i].value).booleanValue() ? "Yes" : "No")); break; case TECHTRANSPCOLORS: table[i].ni.newVar(TRANSLAYER_KEY, GeneralInfo.makeTransparentColorsLine((Color [])table[i].value)); table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Transparent Colors"); break; case LAYERFUNCTION: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Function: " + LayerInfo.makeLayerFunctionName((Layer.Function)table[i].value, table[i].extra)); break; case LAYERCOLOR: EGraphics desc = (EGraphics)table[i].value; table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Color: " + desc.getColor().getRed() + "," + desc.getColor().getGreen() + "," + desc.getColor().getBlue() + ", " + desc.getOpacity() + "," + (desc.getForeground() ? "on" : "off")); break; case LAYERTRANSPARENCY: desc = (EGraphics)table[i].value; table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Transparency: " + (desc.getTransparentLayer() == 0 ? "none" : "layer-" + desc.getTransparentLayer())); break; case LAYERSTYLE: desc = (EGraphics)table[i].value; String str = "Style: "; if (desc.isPatternedOnDisplay()) { EGraphics.Outline o = desc.getOutlined(); str += "Patterned/Outline=" + o.getName(); } else { str += "Solid"; } if (!desc.isPatternedOnPrinter()) str += ",PrintSolid"; table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, str); break; case LAYERCIF: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "CIF Layer: " + (String)table[i].value); break; case LAYERGDS: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "GDS-II Layer: " + (String)table[i].value); break; case LAYERSPIRES: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "SPICE Resistance: " + ((Double)table[i].value).doubleValue()); break; case LAYERSPICAP: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "SPICE Capacitance: " + ((Double)table[i].value).doubleValue()); break; case LAYERSPIECAP: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "SPICE Edge Capacitance: " + ((Double)table[i].value).doubleValue()); break; case LAYER3DHEIGHT: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "3D Height: " + ((Double)table[i].value).doubleValue()); break; case LAYER3DTHICK: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "3D Thickness: " + ((Double)table[i].value).doubleValue()); break; case LAYERCOVERAGE: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Coverage percent: " + ((Double)table[i].value).doubleValue()); break; case ARCFUNCTION: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Function: " + ((ArcProto.Function)table[i].value).toString()); break; case ARCFIXANG: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Fixed-angle: " + (((Boolean)table[i].value).booleanValue() ? "Yes" : "No")); break; case ARCWIPESPINS: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Wipes pins: " + (((Boolean)table[i].value).booleanValue() ? "Yes" : "No")); break; case ARCNOEXTEND: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Extend arcs: " + (((Boolean)table[i].value).booleanValue() ? "No" : "Yes")); break; case ARCINC: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Angle increment: " + ((Integer)table[i].value).intValue()); break; case ARCANTENNARATIO: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Antenna Ratio: " + ((Double)table[i].value).doubleValue()); break; case ARCWIDTHOFFSET: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "ELIB width offset: " + ((Double)table[i].value).doubleValue()); break; case NODEFUNCTION: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Function: " + ((PrimitiveNode.Function)table[i].value).toString()); break; case NODESERPENTINE: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Serpentine transistor: " + (((Boolean)table[i].value).booleanValue() ? "Yes" : "No")); break; case NODESQUARE: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Square node: " + (((Boolean)table[i].value).booleanValue() ? "Yes" : "No")); break; case NODEWIPES: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Invisible with 1 or 2 arcs: " + (((Boolean)table[i].value).booleanValue() ? "Yes" : "No")); break; case NODELOCKABLE: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Lockable: " + (((Boolean)table[i].value).booleanValue() ? "Yes" : "No")); break; case NODESPICETEMPLATE: table[i].ni.newDisplayVar(Artwork.ART_MESSAGE, "Spice template: " + (table[i].value == null ? "" : table[i].value)); break; } table[i].ni.newVar(OPTION_KEY, new Integer(table[i].funct)); } } private static void foundNodeForFunction(NodeInst ni, int func, Info.SpecialTextDescr [] table) { for(int i=0; i<table.length; i++) { if (table[i].funct == func) { table[i].ni = ni; return; } } } protected static void loadTableEntry(SpecialTextDescr [] table, int func, Object value) { for(int i=0; i<table.length; i++) { if (func == table[i].funct) { table[i].value = value; return; } } } /** * Method to get the list of libraries that are used in the construction * of library "lib". Returns an array of libraries, terminated with "lib". */ static Library [] getDependentLibraries(Library lib) { // get list of dependent libraries List<Library> dependentLibs = new ArrayList<Library>(); Variable var = lib.getVar(Info.DEPENDENTLIB_KEY); if (var != null) { String [] libNames = (String [])var.getObject(); for(int i=0; i<libNames.length; i++) { String pt = libNames[i]; Library dLib = Library.findLibrary(pt); if (dLib == null) { System.out.println("Cannot find dependent technology library " + pt + ", ignoring"); continue; } if (dLib == lib) { System.out.println("Library '" + lib.getName() + "' cannot depend on itself, ignoring dependency"); continue; } dependentLibs.add(dLib); } } dependentLibs.add(lib); Library [] theLibs = new Library[dependentLibs.size()]; for(int i=0; i<dependentLibs.size(); i++) theLibs[i] = dependentLibs.get(i); return theLibs; } /** * general-purpose method to scan the libraries in "dependentlibs", * looking for cells that begin with the string "match". It then uses the * variable "seqname" on the last library to determine an ordering of the cells. * Then, it returns the cells in an array. */ static Cell [] findCellSequence(Library [] dependentlibs, String match, Variable.Key seqKey) { // look backwards through libraries for the appropriate cells List<Cell> npList = new ArrayList<Cell>(); for(int i=dependentlibs.length-1; i>=0; i--) { Library olderlib = dependentlibs[i]; for(Iterator<Cell> it = olderlib.getCells(); it.hasNext(); ) { Cell np = it.next(); if (!np.getName().startsWith(match)) continue; // see if this cell is used in a later library boolean foundInLater = false; for(int j=i+1; j<dependentlibs.length; j++) { Library laterLib = dependentlibs[j]; for(Iterator<Cell> oIt = laterLib.getCells(); oIt.hasNext(); ) { Cell lNp = oIt.next(); if (!lNp.getName().equals(np.getName())) continue; foundInLater = true; // got older and later version of same cell: check dates if (lNp.getRevisionDate().before(np.getRevisionDate())) System.out.println("Warning: " + olderlib + " has newer " + np.getName() + " than " + laterLib); break; } if (foundInLater) break; } // if no later library has this, add to total if (!foundInLater) npList.add(np); } } // if there is no sequence, simply return the list Variable var = dependentlibs[dependentlibs.length-1].getVar(seqKey); // if (var == null) return (Cell [])npList.toArray(); // build a new list with the sequence List<Cell> sequence = new ArrayList<Cell>(); String [] sequenceNames = var != null ? (String [])var.getObject() : new String[0]; for(int i=0; i<sequenceNames.length; i++) { Cell foundCell = null; for(int l = 0; l < npList.size(); l++) { Cell np = npList.get(l); if (np.getName().substring(match.length()).equals(sequenceNames[i])) { foundCell = np; break; } } if (foundCell != null) { sequence.add(foundCell); npList.remove(foundCell); } } for(Cell c: npList) sequence.add(c); Cell [] theCells = new Cell[sequence.size()]; for(int i=0; i<sequence.size(); i++) theCells[i] = sequence.get(i); return theCells; } /** * Method to return the name of the technology-edit port on node "ni". Typically, * this is stored on the PORTNAME_KEY variable, but it may also be the node's name. */ static String getPortName(NodeInst ni) { Variable var = ni.getVar(PORTNAME_KEY); if (var != null) return (String)var.getObject(); var = ni.getVar(NodeInst.NODE_NAME); if (var != null) return (String)var.getObject(); return null; } static String getValueOnNode(NodeInst ni) { String initial = ni.getVarValue(Artwork.ART_MESSAGE, String.class, ""); int colonPos = initial.indexOf(':'); if (colonPos > 0) initial = initial.substring(colonPos+2); return initial; } static String getSampleName(NodeProto layerCell) { if (layerCell == Generic.tech().portNode) return "PORT"; if (layerCell == Generic.tech().cellCenterNode) return "GRAB"; if (layerCell == null) return "HIGHLIGHT"; return layerCell.getName().substring(6); } }