/* -*- 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);
}
}