/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: EDIF.java
* Input/output tool: EDIF 2.0.0 input
* Original EDIF reader by Glen Lawson.
* Translated into Java and debugged by Steven M. Rubin, Sun Microsystems.
*
* Copyright (c) 2004, 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.tool.io.input;
import com.sun.electric.database.geometry.EPoint;
import com.sun.electric.database.geometry.Poly;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.Export;
import com.sun.electric.database.hierarchy.Library;
import com.sun.electric.database.hierarchy.Nodable;
import com.sun.electric.database.hierarchy.View;
import com.sun.electric.database.id.CellId;
import com.sun.electric.database.network.Netlist;
import com.sun.electric.database.network.Network;
import com.sun.electric.database.prototype.NodeProto;
import com.sun.electric.database.prototype.PortCharacteristic;
import com.sun.electric.database.prototype.PortProto;
import com.sun.electric.database.text.Name;
import com.sun.electric.database.topology.ArcInst;
import com.sun.electric.database.topology.Connection;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.topology.PortInst;
import com.sun.electric.database.topology.RTBounds;
import com.sun.electric.database.variable.CodeExpression;
import com.sun.electric.database.variable.TextDescriptor;
import com.sun.electric.database.variable.Variable;
import com.sun.electric.technology.ArcProto;
import com.sun.electric.technology.Layer;
import com.sun.electric.technology.PrimitiveNode;
import com.sun.electric.technology.Technology;
import com.sun.electric.technology.technologies.Artwork;
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.JobException;
import com.sun.electric.tool.io.IOTool;
import com.sun.electric.tool.io.output.EDIFEquiv;
import com.sun.electric.tool.routing.AutoStitch;
import com.sun.electric.tool.user.IconParameters;
import com.sun.electric.util.TextUtils;
import com.sun.electric.util.math.GenMath;
import com.sun.electric.util.math.Orientation;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* This class reads EDIF files.
* <BR>
* Notes:
* Does not fully support portbundles
* Multiple ports of the same name are named port_x (x is 1 to n duplicate)
* Keywords such as ARRAY have unnamed parameters, ie (array (name..) 5 6)
* this is handled in the processInteger function called by getKeyword,
* this is a hack to fix this problem, a real table driven parser should be used.
* Use circle arcs instead of splines.
* Support text justifications and text height
* Better NAME/RENAME/STRINGDISPLAY/ANNOTATE text handling.
* ANSI prototypes
* Changed arcs to simple polygons plus ARC attribute
*<BR>
* Some examples that can be handled:
*
* ------------------------- LAYOUT -------------------------
* (cell XXXXX (cellType GENERIC)
* (view layout (viewType MASKLAYOUT)
* (interface
* (protectionFrame)
* )
* (contents
* ========== (LAYOUT DESCRIPTION)
* )
* )
* )
* ------------------------- AN ICON -------------------------
* (cell XXXXX (cellType GENERIC)
* (view INTERFACE (viewType NETLIST)
* (interface
* (port A)
* )
* )
* )
* ------------------------- AN ICON -------------------------
* (cell XXXXX (cellType GENERIC)
* (view symbol (viewType SCHEMATIC)
* (interface
* (port A)
* (symbol
* ========== (ICON DESCRIPTION)
* )
* )
* )
* )
* ------------------------- AN ICON -------------------------
* (cell XXXXX (cellType GENERIC)
* (view VLSI_Symbol (viewType SCHEMATIC)
* (interface
* (port A)
* (symbol
* ========== (ICON DESCRIPTION)
* )
* )
* )
* )
* ------------------------- AN ICON -------------------------
* (cell XXXXX (cellType GENERIC)
* (view symbol (viewType GRAPHIC)
* (interface)
* (contents
* ========== (ICON DESCRIPTION)
* )
* )
* )
* ------------------------- AN ICON AND SCHEMATIC -------------------------
* (cell XXXXX (cellType GENERIC)
* (view symbol (viewType SCHEMATIC)
* (interface
* (port A)
* (symbol
* ========== (ICON DESCRIPTION)
* )
* )
* (contents
* (page SH1
* ========== (SCHEMATIC DESCRIPTION)
* )
* )
* )
* )
* ------------------------- AN ICON AND SCHEMATIC -------------------------
* (cell XXXXX (cellType GENERIC)
* (view NETLIST (viewType NETLIST)
* (interface
* (port A)
* )
* (contents
* ========== (SCHEMATIC DESCRIPTION)
* )
* )
* )
* ------------------------- AN ICON, SCHEMATIC, AND LAYOUT -------------------------
* (cell XXXXX (cellType GENERIC)
* (view layout (viewType MASKLAYOUT)
* (interface
* (port A)
* (protectionFrame)
* (contents
* ========== (LAYOUT DESCRIPTION)
* )
* )
* (view schematic (viewType SCHEMATIC)
* (interface
* (port A)
* (contents
* (page SH1
* ========== (SCHEMATIC DESCRIPTION)
* )
* )
* )
* (view symbol (viewType SCHEMATIC)
* (interface
* (port A)
* (symbol
* ========== (ICON DESCRIPTION)
* )
* )
* (contents
* (page SH1
* ========== (SCHEMATIC DESCRIPTION AGAIN!!!)
* )
* )
* )
* )
*/
public class EDIF extends Input<Object>
{
private static final double INCH = 10;
private static final int SHEETWIDTH = 44; // was 32
private static final int SHEETHEIGHT = 20;
// name table for layers
private static class NameEntry
{
/** the original MASK layer */ private String original;
/** the replacement layer */ private String replace;
/** the basic electric node */ private NodeProto node;
/** default text height */ private double textHeight;
/** default justification */ private TextDescriptor.Position justification;
}
// Edif viewtypes ...
private static class ViewType
{
private String name;
ViewType(String name) { this.name = name; }
public String toString() { return "VIEWTYPE "+name; }
}
private static final ViewType VNULL = new ViewType("Null");
private static final ViewType VBEHAVIOR = new ViewType("Behavior");
private static final ViewType VDOCUMENT = new ViewType("Document");
private static final ViewType VGRAPHIC = new ViewType("Graphic");
private static final ViewType VLOGICMODEL = new ViewType("LogicModel");
private static final ViewType VMASKLAYOUT = new ViewType("MaskLayout");
private static final ViewType VNETLIST = new ViewType("Netlist");
private static final ViewType VPCBLAYOUT = new ViewType("PCBLayout");
private static final ViewType VSCHEMATIC = new ViewType("Schematic");
private static final ViewType VSTRANGER = new ViewType("Stranger");
private static final ViewType VSYMBOLIC = new ViewType("Symbolic");
// Edif geometry types ...
private static class GeometryType {}
private static final GeometryType GUNKNOWN = new GeometryType();
private static final GeometryType GINSTANCE = new GeometryType();
private static final GeometryType GPORTIMPLEMENTATION = new GeometryType();
private static final GeometryType GPROTECTIONFRAME = new GeometryType();
private static final GeometryType GNET = new GeometryType();
private static final GeometryType GBUS = new GeometryType();
// 8 standard orientations
private static final Orientation OR0 = Orientation.fromC(0, false);
private static final Orientation OR90 = Orientation.fromC(900, false);
private static final Orientation OR180 = Orientation.fromC(1800, false);
private static final Orientation OR270 = Orientation.fromC(2700, false);
private static final Orientation OMX = Orientation.fromC(2700, true);
private static final Orientation OMY = Orientation.fromC(900, true);
private static final Orientation OMYR90 = Orientation.fromC(0, true);
private static final Orientation OMXR90 = Orientation.fromC(1800, true);
private static class VendorType {}
private static final VendorType EVUNKNOWN = new VendorType();
private static final VendorType EVCADENCE = new VendorType();
private static final VendorType EVVIEWLOGIC = new VendorType();
private static class EDIFProperty
{
private String name;
private Object val;
}
private static class PlannedPort
{
List<EDIFProperty> properties;
PortCharacteristic direction;
boolean knownLocation;
Export createdPort;
double x, y;
String name, alternateName;
NodeInst alreadyThere;
NodeProto pinType;
}
// view information ...
/** indicates we are in a NETLIST view */ private ViewType activeView;
/** the current vendor type */ private VendorType curVendor;
// parser variables ...
/** the current parser state */ private EDIFKEY curKeyword;
/** the read buffer */ private String inputBuffer;
/** the position within the buffer */ private int inputBufferPos;
/** no update flag */ private boolean ignoreBlock;
/** no update flag */ private boolean ignoreHigherBlock;
/** load status */ private int errorCount, warningCount;
// electric context data ...
/** the new library */ private Library curLibrary;
/** the current technology */ private Technology curTech;
/** the current active cell */ private Cell curCell;
/** current Cells in Libraries */ private Map<Library,Cell> currentCells;
/** the current page in cell */ private int curCellPage;
/** the current active instance */ private NodeInst curNode;
/** the current active arc */ private ArcInst curArc;
/** the current figure group node */ private NodeProto curFigureGroup;
/** the cellRef type */ private NodeProto cellRefProto;
/** the cellRef tech bits if primitive */ private PrimitiveNode.Function cellRefProtoFunction;
/** the cellRef addt'l rotation (in degrees) */ private int cellRefProtoRotation;
/** the cellRef offset when mapped */ private double cellRefOffsetX, cellRefOffsetY;
/** the current port proto */ private PortProto curPort;
/** the current portList */ private List<Network> curPortlist;
/** the last portList */ private List<Network> lastPortlist;
/** the current input job */ private Job job;
// general geometry information ...
/** the current geometry type */ private GeometryType curGeometryType;
/** the list of points */ private List<Point2D> curPoints;
/** the orientation of the structure */ private Orientation curOrientation;
/** port direction */ private PortCharacteristic curDirection;
// geometric path constructors ...
/** the width of the path */ private double pathWidth;
/** extend path end flag */ private boolean extendEnd;
// array variables ...
/** set if truely an array */ private boolean isArray;
/** the bounds of the array */ private int arrayXVal, arrayYVal;
/** offsets in x and y for X increment */ private double deltaPointXX, deltaPointXY;
/** offsets in x and y for Y increment */ private double deltaPointYX, deltaPointYY;
/** which offset flag */ private boolean deltaPointsSet;
/** the element of the array */ private int memberXVal, memberYVal;
// text variables ...
/** Text string */ private String textString;
/** the current default text height */ private double textHeight;
/** the current text justificaton */ private TextDescriptor.Position textJustification;
/** origin x and y */ private List<Point2D> saveTextPoints;
/** the height of text */ private double saveTextHeight;
/** justification of the text */ private TextDescriptor.Position saveTextJustification;
// current name and rename of EDIF objects ...
/** the current cell name */ private String cellReference;
/** the current cell name (original) */ private String cellName;
/** the current port name */ private String portReference;
/** the current port name (original) */ private String portName;
/** the current instance name */ private String instanceReference;
/** the current instance name (original) */ private String instanceName;
/** the current bundle name */ private String bundleReference;
/** the current bundle name (original) */ private String bundleName;
/** the current net name */ private String netReference;
/** the current net name (original) */ private String netName;
/** the current property name */ private String propertyReference;
/** the current viewRef name */ private String viewRef;
/** the current cellRef name */ private String cellRef;
/** the current libraryRef name */ private String libraryRef;
/** property value */ private Object propertyValue;
/** the name of the object */ private String objectName;
/** the original name of the object */ private String originalName;
/** cells that have been built so far */ private Set<Cell> builtCells;
/** whether a symbol was found in an interface */ private boolean symbolDefined;
// layer or figure information ...
/** the current name mapping table */ private List<NameEntry> activeFigures;
/** the current name table entry */ private NameEntry curActiveFigure;
/** cell name lookup (from rename) */ private Map<String,NameEntry> cellTable;
// port data for port exporting
/** list of exports in the cell */ private List<PlannedPort> plannedPorts;
/** place for unconnected ports */ private double inputLocY, outputLocY;
// property data for all objects
/** active property list */ private List<EDIFProperty> propertiesList;
// view NETLIST layout
/** current sheet position */ private int sheetXPos, sheetYPos, sheetOffset;
/** stack of keywords at this point */ private EDIFKEY [] keyStack = new EDIFKEY[1000];
/** depth of keyword stack */ private int keyStackDepth;
/** place where ignoring starts */ private int saveStack = -1;
/** Edif equivs for primitives */ private EDIFEquiv equivs;
/** List of ports in net -> joined list */ private List<PortInst> netPortRefs;
/** mapping of renamed objects */ private Map<String,String> renamedObjects;
/** list of nodes that were equived */ private Map<String,EDIFEquiv.NodeEquivalence> mappedNodes;
/** mapping of named arcs in each cell */ private Map<Cell,Map<String,List<ArcInst>>> namedArcs = new HashMap<Cell,Map<String,List<ArcInst>>>();
/** export names needed on current net */ private Set<String> exportsOnNet;
/** arcs placed on current net */ private List<ArcInst> arcsOnNet;
/** nodes placed on current net */ private List<NodeInst> nodesOnNet;
// some standard artwork primitivies
private PortProto defaultPort;
private PortProto defaultBusPort;
/** all keywords for parsing */ private static Map<String,EDIFKEY> edifKeys = new HashMap<String,EDIFKEY>();
/**************************************** MAIN CONTROL ****************************************/
private EDIFPreferences localPrefs;
public static class EDIFPreferences extends InputPreferences
{
public double inputScale;
public String acceptedParameters;
public String configurationFile;
public boolean cadenceCompatibility;
public boolean showArcNames, showNodeNames;
public IconParameters iconParameters;
public AutoStitch.AutoOptions autoParameters;
public EDIFPreferences(boolean factory)
{
super(factory);
iconParameters = IconParameters.makeInstance(!factory);
autoParameters = new AutoStitch.AutoOptions(factory);
if (factory)
{
inputScale = IOTool.getFactoryEDIFInputScale();
acceptedParameters = IOTool.getFactoryEDIFAcceptedParameters();
configurationFile = IOTool.getFactoryEDIFConfigurationFile();
cadenceCompatibility = IOTool.isFactoryEDIFCadenceCompatibility();
showArcNames = IOTool.isFactoryEDIFShowArcNames();
showNodeNames = IOTool.isFactoryEDIFShowNodeNames();
autoParameters.createExports = false;
} else
{
inputScale = IOTool.getEDIFInputScale();
acceptedParameters = IOTool.getEDIFAcceptedParameters();
configurationFile = IOTool.getEDIFConfigurationFile();
cadenceCompatibility = IOTool.isEDIFCadenceCompatibility();
showArcNames = IOTool.isEDIFShowArcNames();
showNodeNames = IOTool.isEDIFShowNodeNames();
}
}
@Override
public Library doInput(URL fileURL, Library lib, Technology tech, Map<Library,Cell> currentCells, Map<CellId,BitSet> nodesToExpand, Job job)
{
EDIF in = new EDIF(this);
in.job = job;
if (in.openTextInput(fileURL)) return null;
lib = in.importALibrary(lib, tech, currentCells);
in.closeInput();
return lib;
}
}
/**
* Creates a new instance of EDIF.
*/
EDIF(EDIFPreferences ap) { localPrefs = ap; }
/**
* Method to import a library from disk.
* @param lib the library to fill
* @param currentCells this map will be filled with currentCells in Libraries found in library file
* @return the created library (null on error).
*/
@Override
protected Library importALibrary(Library lib, Technology tech, Map<Library,Cell> currentCells)
{
// setup keyword prerequisites: XX.stateArray = new EDIFKEY [] {KYY}; means YYs can be found inside of XX: (xx (yy))
KARRAY.stateArray = new EDIFKEY [] {KINSTANCE, KPORT, KNET};
KAUTHOR.stateArray = new EDIFKEY [] {KWRITTEN};
KBOUNDINGBOX.stateArray = new EDIFKEY [] {KSYMBOL, KCONTENTS, KPROTECTIONFRAME};
KCELL.stateArray = new EDIFKEY [] {KEXTERNAL, KLIBRARY};
KCELLREF.stateArray = new EDIFKEY [] {KDESIGN, KVIEWREF, KINSTANCE};
KCELLTYPE.stateArray = new EDIFKEY [] {KCELL};
KCONTENTS.stateArray = new EDIFKEY [] {KVIEW};
KDESIGN.stateArray = new EDIFKEY [] {KEDIF};
KDIRECTION.stateArray = new EDIFKEY [] {KPORT};
KUNUSED.stateArray = new EDIFKEY [] {KPORT};
KEDIF.stateArray = new EDIFKEY [] {KINIT};
KEDIFLEVEL.stateArray = new EDIFKEY [] {KEDIF, KEXTERNAL, KLIBRARY};
KEXTERNAL.stateArray = new EDIFKEY [] {KEDIF};
KINSTANCE.stateArray = new EDIFKEY [] {KCONTENTS, KPAGE, KPORTIMPLEMENTATION, KCOMMENTGRAPHICS};
KINSTANCEREF.stateArray = new EDIFKEY [] {KINSTANCEREF, KPORTREF};
KINTERFACE.stateArray = new EDIFKEY [] {KVIEW};
KJOINED.stateArray = new EDIFKEY [] {KINTERFACE, KNET};
KEDIFKEYMAP.stateArray = new EDIFKEY [] {KEDIF};
KLIBRARYREF.stateArray = new EDIFKEY [] {KCELLREF};
KLISTOFNETS.stateArray = new EDIFKEY [] {KNETBUNDLE};
KNET.stateArray = new EDIFKEY [] {KCONTENTS, KPAGE, KLISTOFNETS};
KNETBUNDLE.stateArray = new EDIFKEY [] {KCONTENTS, KPAGE};
KNUMBERDEFINITION.stateArray = new EDIFKEY [] {KTECHNOLOGY};
KPORT.stateArray = new EDIFKEY [] {KINTERFACE, KLISTOFPORTS};
KPROTECTIONFRAME.stateArray = new EDIFKEY [] {KINTERFACE, KLISTOFPORTS};
KSCALE.stateArray = new EDIFKEY [] {KNUMBERDEFINITION};
KSTATUS.stateArray = new EDIFKEY [] {KCELL, KDESIGN, KEDIF, KEXTERNAL, KLIBRARY, KVIEW};
KSYMBOL.stateArray = new EDIFKEY [] {KINTERFACE};
KTECHNOLOGY.stateArray = new EDIFKEY [] {KEXTERNAL, KLIBRARY};
KTIMESTAMP.stateArray = new EDIFKEY [] {KWRITTEN};
KUNIT.stateArray = new EDIFKEY [] {KPROPERTY, KSCALE};
KVIEW.stateArray = new EDIFKEY [] {KPROPERTY, KCELL};
KVIEWREF.stateArray = new EDIFKEY [] {KINSTANCE, KINSTANCEREF, KPORTREF};
KVIEWTYPE.stateArray = new EDIFKEY [] {KVIEW};
KWRITTEN.stateArray = new EDIFKEY [] {KSTATUS};
// inits
propertyValue = null;
curPoints = new ArrayList<Point2D>();
saveTextPoints = new ArrayList<Point2D>();
// parser inits
curKeyword = KINIT;
inputBuffer = "";
inputBufferPos = 0;
errorCount = warningCount = 0;
ignoreBlock = ignoreHigherBlock = false;
curVendor = EVUNKNOWN;
builtCells = new HashSet<Cell>();
// general inits
curLibrary = lib;
curTech = tech;
cellTable = new HashMap<String,NameEntry>();
propertiesList = new ArrayList<EDIFProperty>();
// active database inits
curCell = null;
this.currentCells = currentCells;
curCellPage = 0;
curNode = null;
curArc = null;
curPort = null;
curFigureGroup = null;
cellRefProto = null;
// name inits
cellReference = "";
portReference = "";
instanceReference = "";
bundleReference = "";
netReference = "";
propertyReference = "";
// geometry inits
activeFigures = new ArrayList<NameEntry>();
curActiveFigure = null;
freePointList();
// text inits
textHeight = 0;
textJustification = TextDescriptor.Position.DOWNRIGHT;
freeSavedPointList();
sheetXPos = sheetYPos = -1;
keyStackDepth = 0;
defaultPort = Schematics.tech().wirePinNode.findPortProto("wire");
defaultBusPort = Schematics.tech().busPinNode.findPortProto("bus");
equivs = new EDIFEquiv(localPrefs.configurationFile);
netPortRefs = new ArrayList<PortInst>();
renamedObjects = new HashMap<String,String>();
// parse the file
try
{
loadEDIF();
} catch (IOException e)
{
System.out.println("line " + lineReader.getLineNumber() + ": " + e.getMessage());
return null;
}
if (errorCount != 0 || warningCount != 0)
System.out.println("A total of " + errorCount + " errors, and " + warningCount + " warnings encountered during load");
if (curLibrary != null && !currentCells.containsKey(curLibrary) && curLibrary.getCells().hasNext())
currentCells.put(curLibrary, curLibrary.getCells().next());
return curLibrary;
}
/**
* Method to load the edif netlist into memory
* Does a simple keyword lookup to load the lisp structured
* EDIF language into Electric's database
*/
private void loadEDIF()
throws IOException
{
// now read and parse the edif netlist
for(;;)
{
String token = getKeyword();
if (token == null) break;
// locate the keyword
EDIFKEY key = edifKeys.get(TextUtils.canonicString(token));
if (key == null)
{
System.out.println("Warning, line " + lineReader.getLineNumber() + ": unknown keyword <" + token + ">");
warningCount++;
keyStack[keyStackDepth++] = curKeyword;
curKeyword = KUNKNOWN;
continue;
}
// found the keyword, check state
if (key.stateArray != null && curKeyword != KUNKNOWN)
{
boolean found = false;
for(int i=0; i<key.stateArray.length; i++)
if (key.stateArray[i] == curKeyword) { found = true; break; }
if (!found)
{
System.out.println("Error, line " + lineReader.getLineNumber() + ": illegal state (" + curKeyword.name + ") for keyword <" + token + ">");
errorCount++;
}
}
// call the function
keyStack[keyStackDepth++] = curKeyword;
curKeyword = key;
if (saveStack >= keyStackDepth)
{
saveStack = -1;
ignoreBlock = false;
}
if (!ignoreBlock)
{
key.push();
if (ignoreHigherBlock)
{
ignoreHigherBlock = false;
ignoreBlock = true;
saveStack = keyStackDepth-1;
}
}
if (ignoreBlock)
{
if (saveStack == -1) saveStack = keyStackDepth;
}
}
if (curKeyword != KINIT)
{
System.out.println("Error, line " + lineReader.getLineNumber() + ": unexpected end-of-file encountered");
errorCount++;
}
cleanupAtEnd();
}
/**
* Method to get a keyword.
*/
private String getKeyword()
throws IOException
{
// look for a '(' before the edif keyword
for(;;)
{
String p = getToken((char)0);
if (p == null) break;
if (p.equals("(")) break;
if (p.equals(")"))
{
// pop the keyword state stack, called when ')' is encountered.
if (keyStackDepth != 0)
{
if (!ignoreBlock)
{
curKeyword.pop();
}
if (keyStackDepth != 0) curKeyword = keyStack[--keyStackDepth]; else
curKeyword = KINIT;
if (saveStack > keyStackDepth)
{
saveStack = -1;
ignoreBlock = false;
}
}
} else
{
if (TextUtils.isANumber(p)) processInteger(TextUtils.atoi(p));
}
}
return getToken((char)0);
}
private void cleanupAtEnd()
{
// clean-up schematic cells with isolated pins
for(Cell cell : builtCells)
{
if (cell.isSchematic())
{
List<NodeInst> deletePins = new ArrayList<NodeInst>();
for(Iterator<NodeInst> it = cell.getNodes(); it.hasNext(); )
{
NodeInst ni = it.next();
if (ni.getProto() == Schematics.tech().wirePinNode)
{
if (!ni.hasConnections() && !ni.hasExports())
deletePins.add(ni);
}
}
for(NodeInst ni : deletePins)
ni.kill();
// now auto-route the schematic to connect everything
if (cell.isLinked())
AutoStitch.runAutoStitch(cell, null, null, job, null, null, false, false, localPrefs.autoParameters, false, null);
}
}
// put names on named arcs
for(Cell cell : namedArcs.keySet())
{
Netlist nl = cell.getNetlist();
Map<String,List<ArcInst>> arcsInCell = namedArcs.get(cell);
Map<ArcInst,String> arcsToName = new HashMap<ArcInst,String>();
for(String name : arcsInCell.keySet())
{
List<ArcInst> arcsWithName = arcsInCell.get(name);
Collections.sort(arcsWithName, new ArcInst.ArcsByLength());
Set<Network> netsNamed = new HashSet<Network>();
for(int i=0; i<arcsWithName.size(); i++)
{
ArcInst ai = arcsWithName.get(i);
if (!ai.isLinked()) continue;
Network net = nl.getNetwork(ai, 0);
if (netsNamed.contains(net)) continue;
netsNamed.add(net);
arcsToName.put(ai, name);
}
}
for(ArcInst ai : arcsToName.keySet())
{
String arcName = arcsToName.get(ai);
if (ai.getName().equals(arcName)) continue;
if (ai.getNameKey().isTempname())
{
ai.setName(arcName);
if (!localPrefs.showArcNames)
{
TextDescriptor td = ai.getTextDescriptor(ArcInst.ARC_NAME);
td = td.withDisplay(TextDescriptor.Display.NONE);
ai.setTextDescriptor(ArcInst.ARC_NAME, td);
}
} else
{
// two names on one arc: duplicate the arc
ArcInst second = ArcInst.newInstanceBase(ai.getProto(), ai.getLambdaBaseWidth(),
ai.getHeadPortInst(), ai.getTailPortInst(), ai.getHeadLocation(), ai.getTailLocation(),
arcName, ai.getAngle(), ai.getD().flags);
TextDescriptor td = TextDescriptor.getArcTextDescriptor().withOff(0, -1);
if (!localPrefs.showArcNames)
td = td.withDisplay(TextDescriptor.Display.NONE);
second.setTextDescriptor(ArcInst.ARC_NAME, td);
}
}
}
}
/**
* Method to do cleanup processing of an integer argument such as in (array (...) 1 2)
*/
private void processInteger(int value)
{
if (keyStackDepth > 0)
{
if (!ignoreBlock)
{
if (curKeyword == KARRAY)
{
if (arrayXVal == 0) arrayXVal = value;
else if (arrayYVal == 0) arrayYVal = value;
} else if (curKeyword == KMEMBER)
{
if (memberXVal == -1) memberXVal = value;
else if (memberYVal == -1) memberYVal = value;
}
}
}
}
/**************************************** SUPPORT ****************************************/
/**
* Method to position to the next token
* @return true on EOF.
*/
private boolean positionToNextToken()
throws IOException
{
for(;;)
{
if (inputBuffer == null) return true;
if (inputBufferPos >= inputBuffer.length())
{
inputBuffer = readWholeLine();
if (inputBuffer == null) return true;
inputBufferPos = 0;
continue;
}
char chr = inputBuffer.charAt(inputBufferPos);
if (chr == ' ' || chr == '\t')
{
inputBufferPos++;
continue;
}
return false;
}
}
/**
* Method to get a delimeter routine
*/
private void getDelimeter(char delim)
throws IOException
{
if (positionToNextToken())
{
throw new IOException("Unexpected end-of-file");
}
char chr = inputBuffer.charAt(inputBufferPos);
if (chr != delim)
{
throw new IOException("Illegal delimeter");
}
inputBufferPos++;
}
/**
* Method to get a token
*/
private String getToken(char iDelim)
throws IOException
{
// locate the first non-white space character for non-delimited searches
char delim = iDelim;
if (delim == 0)
{
if (positionToNextToken()) return null;
}
// set up the string copy
StringBuffer sBuf = new StringBuffer();
char chr = inputBuffer.charAt(inputBufferPos);
if (delim == 0 && chr == '"')
{
// string search
delim = '"';
sBuf.append(chr);
inputBufferPos++;
}
// now locate the next white space or the delimiter
for(;;)
{
if (inputBufferPos >= inputBuffer.length())
{
// end of string, get the next line
inputBuffer = readWholeLine();
if (inputBuffer == null)
{
// end-of-file, if no delimiter return NULL, otherwise the string
if (delim != 0) break;
return sBuf.toString();
}
inputBufferPos = 0;
} else if (delim == 0)
{
chr = inputBuffer.charAt(inputBufferPos);
switch (chr)
{
case ' ':
case '\t':
// skip to the next character
inputBufferPos++;
return sBuf.toString();
// special EDIF delimiters
case '(':
case ')':
if (sBuf.length() == 0)
{
sBuf.append(chr);
inputBufferPos++;
}
return sBuf.toString();
default:
sBuf.append(chr);
inputBufferPos++;
break;
}
} else
{
// check for user specified delimiter
chr = inputBuffer.charAt(inputBufferPos);
if (chr == delim)
{
// skip the delimiter, unless string
if (delim != iDelim) sBuf.append(chr);
inputBufferPos++;
return sBuf.toString();
}
sBuf.append(chr);
inputBufferPos++;
}
}
return null;
}
private void makeFigure()
throws IOException
{
// get the layer name; check for figuregroup override
if (positionToNextToken()) return;
if (inputBuffer.charAt(inputBufferPos) == '(') return;
String layer = getToken((char)0);
// now look for this layer in the list of layers
for(NameEntry nt : activeFigures)
{
if (nt.original.equalsIgnoreCase(layer))
{
// found the layer
curFigureGroup = nt.node;
textHeight = nt.textHeight;
textJustification = nt.justification;
// allow new definitions
curActiveFigure = nt;
return;
}
}
NameEntry nt = new NameEntry();
activeFigures.add(nt);
nt.original = layer;
nt.replace = nt.original;
nt.node = Artwork.tech().boxNode;
curFigureGroup = nt.node;
textHeight = nt.textHeight = 0;
textJustification = nt.justification = TextDescriptor.Position.DOWNRIGHT;
// allow new definitions
curActiveFigure = nt;
}
/**
* Method to determine whether a name has multiple signals in it.
* @param name the name to check.
* @return true if it is a bus name.
*/
private boolean isBusName(String name)
{
if (name == null || name.length() <= 0) return false;
Name nn = Name.findName(name);
if (nn == null) return false;
return nn.isBus();
}
private boolean checkName()
throws IOException
{
positionToNextToken();
char chr = inputBuffer.charAt(inputBufferPos);
if (chr != '(' && chr != ')')
{
String aName = getToken((char)0);
objectName = fixLeadingAmpersand(aName);
return true;
}
return false;
}
private void freePointList()
{
curPoints = new ArrayList<Point2D>();
}
private void freeSavedPointList()
{
saveTextPoints = new ArrayList<Point2D>();
}
private double getNumber()
throws IOException
{
String value = getToken((char)0);
if (value == null) throw new IOException("No integer value");
if (value.startsWith("("))
{
// must be in e notation
value = getToken((char)0);
if (value == null) throw new IOException("Illegal number value");
if (!value.equalsIgnoreCase("e")) throw new IOException("Illegal number value");
// now the matissa
value = getToken((char)0);
if (value == null) throw new IOException("No matissa value");
double matissa = TextUtils.atof(value);
// now the exponent
value = getToken((char)0);
if (value == null) throw new IOException("No exponent value");
double exponent = TextUtils.atof(value);
getDelimeter(')');
return matissa * Math.pow(10.0, exponent);
}
return TextUtils.atof(value);
}
private NodeInst placePin(NodeProto np, double cX, double cY, double sX, double sY, Orientation orient, Cell parent)
{
for(Iterator<NodeInst> it = parent.getNodes(); it.hasNext(); )
{
NodeInst ni = it.next();
if (ni.getProto() != np) continue;
if (!ni.getOrient().equals(orient)) continue;
if (ni.getAnchorCenterX() != cX) continue;
if (ni.getAnchorCenterY() != cY) continue;
return ni;
}
NodeInst ni = NodeInst.makeInstance(np, new Point2D.Double(cX, cY), sX, sY, parent, orient, null);
return ni;
}
/**
* Method to return the text height to use when it says "textheight" units in the EDIF file.
*/
private double convertTextSize(double textHeight)
{
double i = textHeight / 4;
if (i < TextDescriptor.Size.TXTMINQGRID) i = TextDescriptor.Size.TXTMINQGRID;
if (i > TextDescriptor.Size.TXTMAXQGRID) i = TextDescriptor.Size.TXTMAXQGRID;
return i;
}
private void makeArc(double [] x, double [] y)
{
GenMath.MutableDouble [] A = new GenMath.MutableDouble[2];
GenMath.MutableDouble [] B = new GenMath.MutableDouble[2];
GenMath.MutableDouble [] C = new GenMath.MutableDouble[2];
for(int i=0; i<2; i++)
{
A[i] = new GenMath.MutableDouble(0);
B[i] = new GenMath.MutableDouble(0);
C[i] = new GenMath.MutableDouble(0);
}
// get line equations of perpendicular bi-sectors of p1 to p2
double px1 = (x[0] + x[1]) / 2.0;
double py1 = (y[0] + y[1]) / 2.0;
// now rotate end point 90 degrees
double px0 = px1 - (y[0] - py1);
double py0 = py1 + (x[0] - px1);
equationOfALine(px0, py0, px1, py1, A[0], B[0], C[0]);
// get line equations of perpendicular bi-sectors of p2 to p3
px1 = (x[2] + x[1]) / 2.0;
py1 = (y[2] + y[1]) / 2.0;
// now rotate end point 90 degrees
double px2 = px1 - (y[2] - py1);
double py2 = py1 + (x[2] - px1);
equationOfALine(px1, py1, px2, py2, A[1], B[1], C[1]);
// determine the point of intersection
Point2D ctr = determineIntersection(A, B, C);
double ixc = ctr.getX();
double iyc = ctr.getY();
double dx = ixc - x[0];
double dy = iyc - y[0];
double r = Math.hypot(dx, dy);
// now calculate the angle to the start and endpoint
dx = x[0] - ixc; dy = y[0] - iyc;
if (dx == 0.0 && dy == 0.0)
{
System.out.println("Domain error doing arc computation");
return;
}
double a0 = Math.atan2(dy, dx) * 1800.0 / Math.PI;
if (a0 < 0.0) a0 += 3600.0;
dx = x[2] - ixc; dy = y[2] - iyc;
if (dx == 0.0 && dy == 0.0)
{
System.out.println("Domain error doing arc computation");
return;
}
double a2 = Math.atan2(dy, dx) * 1800.0 / Math.PI;
if (a2 < 0.0) a2 += 3600.0;
// determine the angle of rotation, object orientation, and direction
// calculate x1*y2 + x2*y3 + x3*y1 - y1*x2 - y2*x3 - y3*x1
double area = x[0]*y[1] + x[1]*y[2] + x[2]*y[0] - y[0]*x[1] - y[1]*x[2] - y[2]*x[0];
double ar = 0, so = 0;
int rot = 0;
boolean trans = false;
if (area > 0.0)
{
// counter clockwise
if (a2 < a0) a2 += 3600.0;
ar = a2 - a0;
rot = (int)a0;
so = (a0 - rot) * Math.PI / 1800.0;
} else
{
// clockwise
if (a0 > 2700)
{
rot = 3600 - (int)a0 + 2700;
so = ((3600.0 - a0 + 2700.0) - rot) * Math.PI / 1800.0;
} else
{
rot = 2700 - (int)a0;
so = ((2700.0 - a0) - rot) * Math.PI / 1800.0;
}
if (a0 < a2) a0 += 3600;
ar = a0 - a2;
trans = true;
}
// get the bounds of the circle
double sX = r*2;
double sY = r*2;
Orientation or = Orientation.fromC(rot, trans);
if (curCellPage > 0) iyc += (curCellPage-1) * Cell.FrameDescription.MULTIPAGESEPARATION;
NodeInst ni = NodeInst.makeInstance(curFigureGroup != null && curFigureGroup != Artwork.tech().boxNode ?
curFigureGroup : Artwork.tech().circleNode, new Point2D.Double(ixc, iyc), sX, sY, curCell, or, null);
if (ni == null)
{
System.out.println("Error, line " + lineReader.getLineNumber() + ": could not create arc");
errorCount++;
} else
{
// store the angle of the arc
ni.setArcDegrees(so, ar*Math.PI/1800.0);
}
}
private String convertParens(String name)
{
return name.replace('(', '[').replace(')', ']');
}
/**
* Method to determine the intersection of two lines
* Inputs: Ax + By + C = 0 form
* Outputs: x, y - the point of intersection
* returns 1 if found, 0 if non-intersecting
*/
private Point2D determineIntersection(GenMath.MutableDouble [] A, GenMath.MutableDouble [] B, GenMath.MutableDouble [] C)
{
// check for parallel lines
double A1B2 = A[0].doubleValue() * B[1].doubleValue();
double A2B1 = A[1].doubleValue() * B[0].doubleValue();
if (A1B2 == A2B1)
{
// check for coincident lines
if (C[0].doubleValue() == C[1].doubleValue()) return null;
return null;
}
double A1C2 = A[0].doubleValue() * C[1].doubleValue();
double A2C1 = A[1].doubleValue() * C[0].doubleValue();
if (A[0].doubleValue() != 0)
{
double Y = (A2C1 - A1C2) / (A1B2 - A2B1);
double X = -(B[0].doubleValue() * Y + C[0].doubleValue()) / A[0].doubleValue();
return new Point2D.Double(X, Y);
}
double Y = (A1C2 - A2C1) / (A2B1 - A1B2);
double X = -(B[1].doubleValue() * Y + C[1].doubleValue()) / A[1].doubleValue();
return new Point2D.Double(X, Y);
}
/**
* Method to calculate the equation of a line (Ax + By + C = 0)
* Inputs: sx, sy - Start point
* ex, ey - End point
* px, py - Point line should pass through
* Outputs: A, B, C - constants for the line
*/
private void equationOfALine(double sx, double sy, double ex, double ey, GenMath.MutableDouble A, GenMath.MutableDouble B, GenMath.MutableDouble C)
{
if (sx == ex)
{
A.setValue(1.0);
B.setValue(0.0);
C.setValue(-ex);
} else if (sy == ey)
{
A.setValue(0.0);
B.setValue(1.0);
C.setValue(-ey);
} else
{
// let B = 1 then
B.setValue(1.0);
if (sx != 0.0)
{
// Ax1 + y1 + C = 0 => A = -(C + y1) / x1
// C = -Ax2 - y2 => C = (Cx2 + y1x2) / x1 - y2 => Cx1 - Cx2 = y1x2 - y2x1
// C = (y2x1 - y1x2) / (x2 - x1)
C.setValue((ey * sx - sy * ex) / (ex - sx));
A.setValue(-(C.doubleValue() + sy) / sx);
} else
{
C.setValue((sy * ex - ey * sx) / (sx - ex));
A.setValue(-(C.doubleValue() + ey) / ex);
}
}
}
private void nameEDIFArc(ArcInst ai, boolean forceBus)
{
if (isArray)
{
// name the bus
if (netReference.length() > 0)
{
ai.newVar("EDIF_name", stripPercentEscapes(netReference));
}
StringBuffer aName = new StringBuffer();
if (netName.indexOf('[') >= 0)
{
// the name is already indexed: break it apart and reindex it
int xMost = arrayXVal, yMost = arrayYVal;
if (yMost > xMost) { xMost = arrayYVal; yMost = arrayXVal; }
for (int iX = 0; iX < xMost; iX++)
{
for (int iY = 0; iY < yMost; iY++)
{
if (aName.length() > 0) aName.append(',');
aName.append(getMemberName(netName, iX, iY));
}
}
} else
{
if (forceBus)
{
// a typical foreign array bus will have some range value appended
// to the name. This will cause some odd names with duplicate values
for (int iX = 0; iX < arrayXVal; iX++)
{
for (int iY = 0; iY < arrayYVal; iY++)
{
if (aName.length() > 0) aName.append(',');
if (arrayXVal > 1)
{
if (arrayYVal > 1)
aName.append(netName + "[" + iX + "," + iY + "]");
else
aName.append(netName + "[" + iX + "]");
}
else aName.append(netName + "[" + iY + "]");
}
}
} else
{
aName.append(netName);
}
}
putNameOnArcOnce(ai, convertParens(aName.toString()));
} else
{
if (netReference.length() > 0)
ai.newVar("EDIF_name", stripPercentEscapes(netName));
if (netName.length() > 0)
{
// set name of arc but don't display name
putNameOnArcOnce(ai, convertParens(netName));
}
}
}
private void putNameOnArcOnce(ArcInst ai, String name)
{
if (namedArcs != null)
{
Map<String,List<ArcInst>> cellArcNames = namedArcs.get(curCell);
if (cellArcNames == null)
{
cellArcNames = new HashMap<String,List<ArcInst>>();
namedArcs.put(curCell, cellArcNames);
}
List<ArcInst> arcsWithName = cellArcNames.get(name);
if (arcsWithName == null)
{
arcsWithName = new ArrayList<ArcInst>();
cellArcNames.put(name, arcsWithName);
}
arcsWithName.add(ai);
}
}
private void putNameOnNode(NodeInst ni, String name)
{
ni.setName(convertParens(name));
if (!localPrefs.showNodeNames)
{
TextDescriptor td = ni.getTextDescriptor(NodeInst.NODE_NAME);
td = td.withDisplay(TextDescriptor.Display.NONE);
ni.setTextDescriptor(NodeInst.NODE_NAME, td);
}
}
/**
* Method to locate the nodeinstance and portproto corresponding to
* to a direct intersection with the given point.
* inputs:
* cell - cell to search
* x, y - the point to exam
* ap - the arc used to connect port (must match pp)
*/
private List<PortInst> findEDIFPort(Cell cell, double x, double y, ArcProto ap)
{
List<PortInst> ports = new ArrayList<PortInst>();
PortInst bestPi = null;
Point2D pt = new Point2D.Double(x, y);
double bestDist = Double.MAX_VALUE;
ArcInst ai = null;
for(Iterator<RTBounds> sea = cell.searchIterator(new Rectangle2D.Double(x, y, 0, 0)); sea.hasNext(); )
{
RTBounds geom = sea.next();
if (geom instanceof NodeInst)
{
// now locate a portproto
NodeInst ni = (NodeInst)geom;
for(Iterator<PortInst> it = ni.getPortInsts(); it.hasNext(); )
{
PortInst pi = it.next();
Poly poly = pi.getPoly();
if (poly.isInside(pt))
{
// check if port connects to arc ...*/
if (pi.getPortProto().getBasePort().connectsTo(ap))
ports.add(pi);
} else
{
double dist = pt.distance(new Point2D.Double(poly.getCenterX(), poly.getCenterY()));
if (bestPi == null || dist < bestDist) { bestDist = dist; bestPi = pi; }
}
}
} else
{
// only accept valid wires
ArcInst oAi = (ArcInst)geom;
if (oAi.getProto().getTechnology() == Schematics.tech())
{
// make sure the point is really on the arc
if (GenMath.distToLine(oAi.getHeadLocation(), oAi.getTailLocation(), pt) == 0)
ai = oAi;
}
}
}
if (ports.size() == 0 && ai != null)
{
// direct hit on an arc, verify connection
ArcProto nAp = ai.getProto();
PrimitiveNode np = nAp.findPinProto();
if (np == null) return ports;
PortProto pp = np.getPort(0);
if (!pp.getBasePort().connectsTo(ap)) return ports;
// try to split arc (from us_getnodeonarcinst)*/
// break is at (prefx, prefy): save information about the arcinst
PortInst fPi = ai.getHeadPortInst();
Point2D fPt = ai.getHeadLocation();
PortInst tPi = ai.getTailPortInst();
Point2D tPt = ai.getTailLocation();
// create the splitting pin
NodeInst ni = placePin(np, x, y, np.getDefWidth(), np.getDefHeight(), Orientation.IDENT, cell);
if (ni == null)
{
System.out.println("Cannot create splitting pin");
return ports;
}
// set the node, and port
PortInst pi = ni.findPortInstFromProto(pp);
ports.add(pi);
// create the two new arcinsts
ArcInst ar1 = ArcInst.makeInstance(nAp, fPi, pi, fPt, pt, null);
ArcInst ar2 = ArcInst.makeInstance(nAp, pi, tPi, pt, tPt, null);
if (ar1 == null || ar2 == null)
{
System.out.println("Error creating the split arc parts");
return ports;
}
ar1.copyPropertiesFrom(ai);
if (ai.isHeadNegated()) ar1.setHeadNegated(true);
if (ai.isTailNegated()) ar2.setTailNegated(true);
// delete the old arcinst
ai.kill();
}
return ports;
}
private void checkBusNames(ArcInst ai, String base, HashSet<ArcInst> seenArcs)
{
if (ai.getProto() != Schematics.tech().bus_arc)
{
// verify the name
String aName = ai.getName();
{
if (aName.startsWith(base))
{
if (aName.length() > base.length() && TextUtils.isDigit(aName.charAt(base.length())))
{
String newName = base + "[" + aName.substring(base.length()) + "]";
putNameOnArcOnce(ai, newName);
}
}
}
}
seenArcs.add(ai);
for (int i = 0; i < 2; i++)
{
NodeInst ni = ai.getPortInst(i).getNodeInst();
if (ni.getFunction().isPin())
{
// scan through this nodes portarcinst's
for(Iterator<Connection> it = ni.getConnections(); it.hasNext(); )
{
Connection oCon = it.next();
ArcInst pAi = oCon.getArc();
if (!seenArcs.contains(pAi))
checkBusNames(pAi, base, seenArcs);
}
}
}
}
private void doPoly()
{
if (curPoints.size() == 0) return;
// get the bounds of the poly
Point2D p0 = curPoints.get(0);
double lX = p0.getX();
double lY = p0.getY();
double hX = lX;
double hY = lY;
for(int i=1; i<curPoints.size(); i++)
{
Point2D point = curPoints.get(i);
if (lX > point.getX()) lX = point.getX();
if (hX < point.getX()) hX = point.getX();
if (lY > point.getY()) lY = point.getY();
if (hY < point.getY()) hY = point.getY();
}
NodeProto np = curFigureGroup;
if (curFigureGroup == null || curFigureGroup == Artwork.tech().boxNode)
{
if (curKeyword == KPOLYGON) np = Artwork.tech().closedPolygonNode; else
np = Artwork.tech().openedPolygonNode;
}
double sX = hX - lX;
double sY = hY - lY;
double cX = (hX + lX) / 2;
double cY = (hY + lY) / 2;
double yPos = cY;
if (curCellPage > 0) yPos += (curCellPage-1) * Cell.FrameDescription.MULTIPAGESEPARATION;
NodeInst ni = NodeInst.makeInstance(np, new Point2D.Double(cX, yPos), sX, sY,
curCell, curOrientation, null);
if (ni == null)
{
System.out.println("Error, line " + lineReader.getLineNumber() + ": could not create polygon");
errorCount++;
} else
{
EPoint [] trace = new EPoint[curPoints.size()];
for(int i=0; i<curPoints.size(); i++)
{
Point2D point = curPoints.get(i);
trace[i] = new EPoint(point.getX(), point.getY());
}
// store the trace information
ni.setTrace(trace);
}
freePointList();
}
/**
* Method to fix symbols that start with &<number> by removing the ampersand.
* @param inStr the original symbol.
* @return the fixed symbol.
*/
private String fixLeadingAmpersand(String inStr)
{
if (inStr.startsWith("&"))
{
if (inStr.length() > 1 && Character.isDigit(inStr.charAt(1)))
return inStr.substring(1);
}
return inStr;
}
private String fixAngleBracketBusses(String busName)
{
for(;;)
{
int openAngle = busName.indexOf('<');
if (openAngle < 0) break;
int closeAngle = busName.indexOf('>', openAngle);
if (closeAngle < 0) break;
String busPart = busName.substring(openAngle+1, closeAngle);
if (busPart.startsWith("*")) busPart = ""; else
busPart = "[" + busPart + "]";
busName = busName.substring(0, openAngle) + busPart + busName.substring(closeAngle+1);
}
return busName;
}
/**
* Method to convert a bus name to an individual member name.
* @param name the bus name.
* @param ind1 the index of the first entry.
* @param ind2 the index of the second entry.
* @return the specified member name.
*/
private String getMemberName(String name, int ind1, int ind2)
{
// get true name of array specification
String baseName = renamedObjects.get(name);
if (baseName == null) baseName = name;
// find first index entry
int openSq = baseName.indexOf('[');
if (openSq < 0) return baseName;
int closeSq = baseName.indexOf(']', openSq);
if (closeSq < 0) closeSq = baseName.length();
int comma = baseName.indexOf(',', openSq);
if (comma < 0) comma = baseName.length();
int endInd1 = Math.min(closeSq, comma);
if (endInd1 < 0) return baseName;
String index1 = baseName.substring(openSq+1, endInd1);
String index2 = null;
String restOfLine = baseName.substring(endInd1);
if (comma >= 0 && comma < baseName.length())
{
closeSq = baseName.indexOf(']', comma);
if (closeSq >= 0)
{
index2 = baseName.substring(comma+1, closeSq);
restOfLine = baseName.substring(closeSq);
}
}
int [] indices = getIndices(index1);
if (ind1 >= 0 && ind1 < indices.length)
baseName = baseName.substring(0, openSq+1) + indices[ind1];
if (index2 != null)
{
int [] indices2 = getIndices(index2);
if (ind2 >= 0 && ind2 < indices2.length)
baseName += "," + indices2[ind2];
}
baseName += restOfLine;
return baseName;
}
/**
* Method to examine an array specification and return all of the indices.
* @param index the array specification, for example "1:5" or "4:2".
* @return an array of indices, for example [1,2,3,4,5] or [4,3,2].
*/
private int [] getIndices(String index)
{
List<Integer> indices = new ArrayList<Integer>();
for(int pos=0; pos<index.length(); )
{
if (Character.isWhitespace(index.charAt(pos))) { pos++; continue; }
if (Character.isDigit(index.charAt(pos)))
{
int val = TextUtils.atoi(index.substring(pos));
int valEnd = val;
while (pos < index.length() && Character.isDigit(index.charAt(pos))) pos++;
while (pos < index.length() && Character.isWhitespace(index.charAt(pos))) pos++;
if (pos < index.length() && index.charAt(pos) == ':')
{
pos++;
while (pos < index.length() && Character.isWhitespace(index.charAt(pos))) pos++;
if (Character.isDigit(index.charAt(pos)))
{
valEnd = TextUtils.atoi(index.substring(pos));
while (pos < index.length() && Character.isDigit(index.charAt(pos))) pos++;
while (pos < index.length() && Character.isWhitespace(index.charAt(pos))) pos++;
}
}
if (valEnd < val)
{
for(int i=val; i>=valEnd; i--) indices.add(new Integer(i));
} else
{
for(int i=val; i<=valEnd; i++) indices.add(new Integer(i));
}
continue;
}
break;
}
int [] retInd = new int[indices.size()];
for(int i=0; i<indices.size(); i++) retInd[i] = indices.get(i).intValue();
return retInd;
}
/**
* Method to find an existing cell.
* @param libName the name of the library in which the cell resides
* (null to use the current library).
* @param name the name of the cell.
* @param view the view name of the cell.
* @return the cell (null if it does not exist).
*/
private Cell findCell(String libName, String name, String view)
{
Library lib = curLibrary;
if (libName != null)
{
Library namedLib = Library.findLibrary(libName);
if (namedLib != null) lib = namedLib;
}
for(Iterator<Cell> it = lib.getCells(); it.hasNext(); )
{
Cell cell = it.next();
if (cell.getName().equalsIgnoreCase(name) &&
cell.getView().getAbbreviation().equalsIgnoreCase(view)) return cell;
}
return null;
}
/**
* Method to create a new cell.
* @param libName the name of the library in which the cell will be created
* (null to use the current library).
* @param name the name of the cell.
* @param view the view name to create.
* @return the newly created cell (or existing one if allowed).
*/
private Cell createCell(String libName, String name, String view)
{
Cell proto = findCell(libName, name, view);
if (proto != null) return proto;
Library lib = curLibrary;
if (libName != null)
{
Library namedLib = Library.findLibrary(libName);
if (namedLib != null) lib = namedLib;
}
String cName = name;
if (view.length() > 0) cName += "{" + view + "}";
proto = Cell.makeInstance(lib, cName);
if (proto != null)
{
if (view.equals("ic")) proto.setWantExpanded();
builtCells.add(proto);
}
return proto;
}
private void instantiatePlannedPort(PlannedPort plp, Rectangle2D cellBounds)
{
if (plp.createdPort != null) return;
PortInst pi = null;
if (plp.alreadyThere == null)
{
// now create the off-page reference
if (!plp.knownLocation)
{
if (plp.direction == PortCharacteristic.IN || plp.direction == PortCharacteristic.BIDIR)
{
plp.x = cellBounds.getMinX() - INCH/2;
plp.y = cellBounds.getMinY() + inputLocY * INCH/2;
inputLocY++;
} else
{
plp.x = cellBounds.getMaxX() + INCH/2;
plp.y = cellBounds.getMinY() + outputLocY * INCH/2;
outputLocY++;
}
plp.knownLocation = true;
}
NodeProto type = plp.pinType;
if (type == Schematics.tech().offpageNode)
{
if (curCell.getView() == View.LAYOUT)
type = curTech.getNodes().next();
}
if (type == Artwork.tech().boxNode)
{
if (curCell.getView() == View.SCHEMATIC) type = Schematics.tech().offpageNode; else
if (curCell.getView() == View.ICON) type = Schematics.tech().busPinNode;
}
List<PortInst> tList = findEDIFPort(curCell, plp.x, plp.y, type.getPort(0).getBasePort().getConnections()[0]);
if (tList.size() != 0)
{
pi = tList.get(0);
plp.alreadyThere = pi.getNodeInst();
} else
{
double psX = type.getDefWidth();
double psY = type.getDefHeight();
plp.alreadyThere = NodeInst.makeInstance(type, new Point2D.Double(plp.x, plp.y), psX, psY, curCell);
if (plp.alreadyThere == null)
{
System.out.println("Error, line " + lineReader.getLineNumber() + ": could not create external port");
errorCount++;
return;
}
pi = plp.alreadyThere.getPortInst(0);
}
}
if (plp.alreadyThere.getProto() == Schematics.tech().offpageNode)
{
PortProto fPp = Schematics.tech().offpageNode.findPortProto("y");
if (plp.direction == PortCharacteristic.OUT) fPp = Schematics.tech().offpageNode.findPortProto("a");
pi = plp.alreadyThere.findPortInstFromProto(fPp);
}
String name = plp.name;
String exportName = renamedObjects.get(name);
if (exportName != null) name = exportName;
plp.createdPort = Export.newInstance(curCell, pi, convertParens(name), plp.direction, false);
if (plp.createdPort == null)
{
System.out.println("Error, line " + lineReader.getLineNumber() + ": could not create port <" + name + ">");
errorCount++;
}
TextDescriptor td = plp.createdPort.getTextDescriptor(Export.EXPORT_NAME);
td = td.withPos(TextDescriptor.Position.UP);
plp.createdPort.setTextDescriptor(Export.EXPORT_NAME, td);
// when creating an export on a schematic, copy characteristics from the icon
if (curCell.getView() == View.SCHEMATIC)
{
Cell iconCell = curCell.iconView();
if (iconCell != null)
{
Export e = plp.createdPort.findEquivalent(iconCell);
if (e != null)
{
if (plp.direction == PortCharacteristic.UNKNOWN && e.getCharacteristic() != PortCharacteristic.UNKNOWN)
plp.createdPort.setCharacteristic(e.getCharacteristic());
}
}
}
// create the properties on the port
for (EDIFProperty property : plp.properties)
{
plp.createdPort.newVar(stripPercentEscapes(property.name), stripPercentEscapes(property.val.toString()));
}
}
private boolean isSpiceParameter(String x)
{
if (localPrefs.cadenceCompatibility)
{
int parPos = x.indexOf("pPar(");
if (parPos >= 0)
{
int closePos = x.indexOf(")", parPos);
if (closePos >= 0) return true;
}
}
return false;
}
private String stripPercentEscapes(String x)
{
if (localPrefs.cadenceCompatibility)
{
boolean checkAgain = true;
while (checkAgain)
{
checkAgain = false;
int parPos = x.indexOf("pPar(");
if (parPos >= 0)
{
int closePos = x.indexOf(")", parPos);
if (closePos >= 0)
{
String par = x.substring(parPos+5, closePos);
if (par.startsWith("%34%") && par.endsWith("%34%"))
par = par.substring(4, par.length()-4);
x = x.substring(0, parPos) + "@" + par + x.substring(closePos+1);
checkAgain = true;
continue;
}
}
if (x.indexOf("%34%") >= 0)
{
x = x.replaceAll("%34%", "\"");
checkAgain = true;
}
}
}
return x;
}
private PlannedPort addPlannedPort(String name)
{
for(PlannedPort plp : plannedPorts)
if (plp.name.equalsIgnoreCase(name) || plp.alternateName.equalsIgnoreCase(name))
return plp;
PlannedPort plp = new PlannedPort();
plp.name = name;
plp.alternateName = name;
plp.direction = PortCharacteristic.UNKNOWN;
plp.properties = new ArrayList<EDIFProperty>();
plp.pinType = Schematics.tech().offpageNode;
plp.alreadyThere = null;
plannedPorts.add(plp);
return plp;
}
/**
* Method to see if a parameter name is acceptable for placement in the circuit.
* @param param the parameter name.
* @return true if the name should be placed in the circuit.
*/
private boolean isAcceptedParameter(String param)
{
if (localPrefs.acceptedParameters.length() == 0) return false;
String [] params = localPrefs.acceptedParameters.split("/");
for(int i=0; i<params.length; i++)
if (param.equalsIgnoreCase(params[i])) return true;
return false;
}
/**************************************** PARSING TABLE ****************************************/
private class EDIFKEY
{
/** the name of the keyword */ private String name;
/** edif state */ private EDIFKEY [] stateArray;
private EDIFKEY(String name)
{
this.name = name;
edifKeys.put(TextUtils.canonicString(name), this);
}
protected void push() throws IOException {}
protected void pop() throws IOException {}
}
private EDIFKEY KUNKNOWN = new EDIFKEY("");
private EDIFKEY KINIT = new EDIFKEY("");
private EDIFKEY KANNOTATE = new EDIFKEY("annotate");
private EDIFKEY KARC = new KeyArc();
private EDIFKEY KARRAY = new KeyArray();
private EDIFKEY KAUTHOR = new EDIFKEY ("author");
private EDIFKEY KBOOLEAN = new EDIFKEY ("boolean");
private EDIFKEY KBOOLEANMAP = new EDIFKEY("booleanMap");
private EDIFKEY KBORDERPATTERN = new EDIFKEY ("borderpattern");
private EDIFKEY KBOUNDINGBOX = new KeyBoundingBox();
private EDIFKEY KCELL = new KeyCell();
private EDIFKEY KCELLREF = new KeyCellRef();
private EDIFKEY KCELLTYPE = new EDIFKEY("cellType");
private EDIFKEY KCIRCLE = new KeyCircle();
private EDIFKEY KCOLOR = new EDIFKEY("color");
private EDIFKEY KCOMMENT = new EDIFKEY("comment");
private EDIFKEY KCOMMENTGRAPHICS = new EDIFKEY("commentGraphics");
private EDIFKEY KCONNECTLOCATION = new EDIFKEY("connectLocation");
private EDIFKEY KCONTENTS = new KeyContents();
private EDIFKEY KCORNERTYPE = new KeyCornerType();
private EDIFKEY KCURVE = new EDIFKEY("curve");
private EDIFKEY KDATAORIGIN = new EDIFKEY("dataOrigin");
private EDIFKEY KDCFANOUTLOAD = new EDIFKEY("dcFanoutLoad");
private EDIFKEY KDCMAXFANOUT = new EDIFKEY("dcMaxFanout");
private EDIFKEY KDELTA = new KeyDelta();
private EDIFKEY KDESIGN = new KeyDesign();
private EDIFKEY KDESIGNATOR = new EDIFKEY("designator");
private EDIFKEY KDIRECTION = new KeyDirection();
private EDIFKEY KDISPLAY = new EDIFKEY("display");
private EDIFKEY KDOT = new KeyDot();
private EDIFKEY KSCALEDINTEGER = new EDIFKEY("e");
private EDIFKEY KEDIF = new EDIFKEY("edif");
private EDIFKEY KEDIFLEVEL = new EDIFKEY("edifLevel");
private EDIFKEY KEDIFVERSION = new EDIFKEY("edifVersion");
private EDIFKEY KENDTYPE = new KeyEndType();
private EDIFKEY KEXTERNAL = new KeyExternal();
private EDIFKEY KFABRICATE = new KeyFabricate();
private EDIFKEY KFALSE = new KeyFalse();
private EDIFKEY KFIGURE = new KeyFigure();
private EDIFKEY KFIGUREGROUP = new KeyFigureGroup();
private EDIFKEY KFIGUREGROUPOVERRIDE = new KeyFigureGroupOverride();
private EDIFKEY KFILLPATTERN = new EDIFKEY("fillpattern");
private EDIFKEY KGRIDMAP = new EDIFKEY("gridMap");
private EDIFKEY KINSTANCE = new KeyInstance();
private EDIFKEY KINSTANCEREF = new KeyInstanceRef();
private EDIFKEY KINTEGER = new KeyInteger();
private EDIFKEY KINTERFACE = new KeyInterface();
private EDIFKEY KJOINED = new KeyJoined();
private EDIFKEY KJUSTIFY = new KeyJustify();
private EDIFKEY KKEYWORDDISPLAY = new EDIFKEY("keywordDisplay");
private EDIFKEY KEDIFKEYLEVEL = new EDIFKEY("keywordLevel");
private EDIFKEY KEDIFKEYMAP = new EDIFKEY("keywordMap");
private EDIFKEY KLIBRARY = new KeyLibrary();
private EDIFKEY KLIBRARYREF = new LibraryRef();
private EDIFKEY KLISTOFNETS = new EDIFKEY("listOfNets");
private EDIFKEY KLISTOFPORTS = new EDIFKEY("listOfPorts");
private EDIFKEY KLOGICVALUE = new EDIFKEY("logicValue");
private EDIFKEY KMEMBER = new KeyMember();
private EDIFKEY KNAME = new KeyName();
private EDIFKEY KNET = new KeyNet();
private EDIFKEY KNETBUNDLE = new KeyNetBundle();
private EDIFKEY KNUMBER = new KeyNumber();
private EDIFKEY KNUMBERDEFINITION = new EDIFKEY("numberDefinition");
private EDIFKEY KOPENSHAPE = new KeyOpenShape();
private EDIFKEY KORIENTATION = new KeyOrientation();
private EDIFKEY KORIGIN = new EDIFKEY("origin");
private EDIFKEY KOWNER = new EDIFKEY("owner");
private EDIFKEY KPAGE = new EDIFKEY("page");
private EDIFKEY KPAGESIZE = new EDIFKEY("pageSize");
private EDIFKEY KPATH = new KeyPath();
private EDIFKEY KPATHWIDTH = new KeyPathWidth();
private EDIFKEY KPOINT = new EDIFKEY("point");
private EDIFKEY KPOINTLIST = new EDIFKEY("pointList");
private EDIFKEY KPOLYGON = new KeyPolygon();
private EDIFKEY KPORT = new KeyPort();
private EDIFKEY KPORTBUNDLE = new EDIFKEY("portBundle");
private EDIFKEY KPORTIMPLEMENTATION = new KeyPortImplementation();
private EDIFKEY KPORTINSTANCE = new EDIFKEY("portInstance");
private EDIFKEY KPORTLIST = new KeyPortList();
private EDIFKEY KPORTREF = new KeyPortRef();
private EDIFKEY KPROGRAM = new KeyProgram();
private EDIFKEY KPROPERTY = new KeyProperty();
private EDIFKEY KPROPERTYDISPLAY = new EDIFKEY("propertyDisplay");
private EDIFKEY KPROTECTIONFRAME = new KeyProtectionFrame();
private EDIFKEY KPT = new KeyPt();
private EDIFKEY KRECTANGLE = new KeyRectangle();
private EDIFKEY KRENAME = new KeyRename();
private EDIFKEY KSCALE = new EDIFKEY("scale");
private EDIFKEY KSCALEX = new EDIFKEY("scaleX");
private EDIFKEY KSCALEY = new EDIFKEY("scaleY");
private EDIFKEY KSHAPE = new EDIFKEY("shape");
private EDIFKEY KSIMULATIONINFO = new EDIFKEY("simulationInfo");
private EDIFKEY KSTATUS = new EDIFKEY("status");
private EDIFKEY KSTRING = new KeyString();
private EDIFKEY KSTRINGDISPLAY = new KeyStringDisplay();
private EDIFKEY KSYMBOL = new KeySymbol();
private EDIFKEY KTECHNOLOGY = new EDIFKEY("technology");
private EDIFKEY KTEXTHEIGHT = new KeyTextHeight();
private EDIFKEY KTIMESTAMP = new EDIFKEY("timestamp");
private EDIFKEY KTRANSFORM = new EDIFKEY("transform");
private EDIFKEY KTRUE = new KeyTrue();
private EDIFKEY KUNIT = new KeyUnit();
private EDIFKEY KUNUSED = new KeyUnused(); // TODO: fix
private EDIFKEY KUSERDATA = new EDIFKEY("userData");
private EDIFKEY KVERSION = new EDIFKEY("version");
private EDIFKEY KVIEW = new KeyView();
private EDIFKEY KVIEWREF = new ViewRef();
private EDIFKEY KVIEWTYPE = new KeyViewType();
private EDIFKEY KVISIBLE = new EDIFKEY("visible");
private EDIFKEY KWRITTEN = new EDIFKEY("written");
private class KeyArc extends EDIFKEY
{
private KeyArc() { super("arc"); }
protected void pop()
{
// set array values
if (curPoints.size() >= 3)
{
double [] x = new double[3];
double [] y = new double[3];
Point2D p0 = curPoints.get(0);
Point2D p1 = curPoints.get(1);
Point2D p2 = curPoints.get(2);
x[0] = p0.getX(); y[0] = p0.getY();
x[1] = p1.getX(); y[1] = p1.getY();
x[2] = p2.getX(); y[2] = p2.getY();
makeArc(x, y);
}
freePointList();
}
}
private class KeyArray extends EDIFKEY
{
private KeyArray() { super("array"); }
protected void push()
throws IOException
{
// note array is a special process integer value function
isArray = true;
arrayXVal = arrayYVal = 0;
deltaPointXX = deltaPointXY = 0;
deltaPointYX = deltaPointYY = 0;
deltaPointsSet = false;
if (checkName())
{
if (keyStack[keyStackDepth-1] == KCELL)
{
cellName = cellReference = fixLeadingAmpersand(objectName);
} else if (keyStack[keyStackDepth-1] == KPORT)
{
portName = portReference = fixLeadingAmpersand(objectName);
} else if (keyStack[keyStackDepth-1] == KINSTANCE)
{
instanceName = instanceReference = objectName;
} else if (keyStack[keyStackDepth-1] == KNET)
{
netReference = netName = fixLeadingAmpersand(objectName);
} else if (keyStack[keyStackDepth-1] == KPROPERTY)
{
propertyReference = objectName;
}
}
}
protected void pop()
{
if (arrayXVal == 0) arrayXVal = 1;
if (arrayYVal == 0) arrayYVal = 1;
}
}
private class KeyBoundingBox extends EDIFKEY
{
private KeyBoundingBox() { super("boundingBox"); }
protected void push()
{
curFigureGroup = Artwork.tech().openedDottedPolygonNode;
}
protected void pop()
{
curFigureGroup = null;
}
}
private class KeyCell extends EDIFKEY
{
private KeyCell() { super("cell"); }
protected void push()
throws IOException
{
activeView = VNULL;
objectName = ""; originalName = "";
sheetXPos = sheetYPos = -1;
if (checkName())
{
cellName = cellReference = fixLeadingAmpersand(objectName);
}
}
}
private class KeyCellRef extends EDIFKEY
{
private KeyCellRef() { super("cellRef"); }
protected void push()
throws IOException
{
cellRef = fixLeadingAmpersand(getToken((char)0));
libraryRef = null;
}
protected void pop()
{
// get the name of the cell
String aName = cellRef;
cellRefProtoFunction = PrimitiveNode.Function.UNKNOWN;
cellRefProtoRotation = 0;
cellRefOffsetX = cellRefOffsetY = 0;
String view = "lay";
if (activeView != VMASKLAYOUT)
{
if (keyStack[keyStackDepth - 1] == KDESIGN) view = "sch"; else
view = "ic";
}
if (curVendor == EVVIEWLOGIC && aName.equalsIgnoreCase("SPLITTER"))
{
cellRefProto = null;
return;
}
// look for an equivalent primitive
String libName = libraryRef;
if (libName == null) libName = curLibrary.getName();
EDIFEquiv.NodeEquivalence ne = equivs.getNodeEquivalence(libName, cellRef, viewRef);
if (ne != null && ne.np != null)
{
mappedNodes.put(instanceName, ne);
cellRefProto = ne.np;
cellRefProtoFunction = PrimitiveNode.Function.UNKNOWN;
cellRefProtoRotation = ne.rotation;
// determine the offset
cellRefOffsetX = ne.xOffset;
cellRefOffsetY = ne.yOffset;
if (cellRefProto instanceof PrimitiveNode)
{
Technology tech = cellRefProto.getTechnology();
if (tech instanceof Schematics)
cellRefProtoFunction = ne.function;
}
return;
}
// look for this cell name in the cell list
NameEntry nt = cellTable.get(aName);
if (nt == null)
{
String alternateName = renamedObjects.get(aName);
if (alternateName != null)
nt = cellTable.get(alternateName);
}
if (nt != null)
{
aName = nt.replace;
} else
{
System.out.println("could not find cellRef <" + aName + ">");
}
// create cell if not already there
Cell proto = createCell(libraryRef, aName, view);
if (proto == null)
System.out.println("Error, cannot create cell "+aName+" in library "+libraryRef);
// set the parent
cellRefProto = proto;
}
}
private class KeyCircle extends EDIFKEY
{
private KeyCircle() { super("circle"); }
protected void push()
{
freePointList();
curOrientation = OR0;
}
protected void pop()
{
if (curPoints.size() == 2)
{
Point2D p0 = curPoints.get(0);
Point2D p1 = curPoints.get(1);
double lX = Math.min(p0.getX(), p1.getX());
double hX = Math.max(p0.getX(), p1.getX());
double lY = Math.min(p0.getY(), p1.getY());
double hY = Math.max(p0.getY(), p1.getY());
if (lX == hX)
{
lX -= (hY - lY) / 2;
hX += (hY - lY) / 2;
} else
{
lY -= (hX - lX) / 2;
hY += (hX - lX) / 2;
}
double sX = hX - lX;
double sY = hY - lY;
// create the node instance
double cX = (hX + lX) / 2;
double cY = (hY + lY) / 2;
if (curCellPage > 0) cY += (curCellPage-1) * Cell.FrameDescription.MULTIPAGESEPARATION;
NodeInst ni = NodeInst.makeInstance(Artwork.tech().circleNode, new Point2D.Double(cX, cY),
sX, sY, curCell, curOrientation, null);
if (ni == null)
{
System.out.println("Error, line " + lineReader.getLineNumber() + ": could not create circle");
errorCount++;
}
}
freePointList();
}
}
private class KeyContents extends EDIFKEY
{
private KeyContents() { super("contents"); }
protected void push()
throws IOException
{
if (activeView != VNETLIST)
{
View view = View.SCHEMATIC;
if (activeView == VMASKLAYOUT) view = View.LAYOUT; else
if (activeView == VGRAPHIC) view = View.ICON;
// check for the name
checkName();
// locate this in the list of cells
Cell proto = findCell(null, cellName, view.getAbbreviation());
if (proto == null)
{
// allocate the cell
proto = createCell(null, cellName, view.getAbbreviation());
if (proto == null) throw new IOException("Error creating cell");
} else
{
if (activeView == VSCHEMATIC) ignoreBlock = true;
}
curCell = proto;
curCellPage = 0;
inputLocY = outputLocY = 0;
}
plannedPorts = new ArrayList<PlannedPort>();
}
protected void pop()
{
Rectangle2D cellBounds = curCell.getBounds();
for(PlannedPort plp : plannedPorts)
instantiatePlannedPort(plp, cellBounds);
plannedPorts = null;
}
}
private class KeyCornerType extends EDIFKEY
{
private KeyCornerType() { super("cornerType"); }
protected void push()
throws IOException
{
// ignore the endtype
getToken((char)0);
}
}
private class KeyDelta extends EDIFKEY
{
private KeyDelta() { super("delta"); }
protected void push()
{
deltaPointXX = deltaPointXY = 0;
deltaPointYX = deltaPointYY = 0;
deltaPointsSet = false;
}
}
private class KeyDesign extends EDIFKEY
{
private KeyDesign() { super("design"); }
protected void push()
throws IOException
{
// ignore the name of the cell
getToken((char)0);
}
protected void pop()
{
if (cellRefProto != null)
{
currentCells.put(curLibrary, (Cell)cellRefProto);
}
}
}
private class KeyDirection extends EDIFKEY
{
private KeyDirection() { super("direction"); }
protected void push()
throws IOException
{
// get the direction
String aName = getToken((char)0);
if (aName.equalsIgnoreCase("INPUT")) curDirection = PortCharacteristic.IN; else
if (aName.equalsIgnoreCase("INOUT")) curDirection = PortCharacteristic.BIDIR; else
if (aName.equalsIgnoreCase("OUTPUT")) curDirection = PortCharacteristic.OUT;
}
}
private class KeyDot extends EDIFKEY
{
private KeyDot() { super("dot"); }
protected void push()
{
freePointList();
curOrientation = OR0;
}
protected void pop()
{
if (curGeometryType == GPORTIMPLEMENTATION)
{
// inside a PortImplementation
String exportName = renamedObjects.get(objectName);
if (exportName == null) exportName = objectName;
PlannedPort plp = addPlannedPort(exportName);
plp.pinType = cellRefProto;
plp.knownLocation = true;
Point2D p0 = curPoints.get(0);
plp.x = p0.getX();
plp.y = p0.getY();
if (curCellPage > 0) plp.y += (curCellPage-1) * Cell.FrameDescription.MULTIPAGESEPARATION;
} else
{
// create the node instance
Point2D p0 = curPoints.get(0);
double xPos = p0.getX();
double yPos = p0.getY();
if (curCellPage > 0) yPos += (curCellPage-1) * Cell.FrameDescription.MULTIPAGESEPARATION;
NodeInst ni = NodeInst.makeInstance(curFigureGroup != null ? curFigureGroup : Artwork.tech().boxNode,
new Point2D.Double(xPos, yPos), 0, 0, curCell);
if (ni == null)
{
System.out.println("Error, line " + lineReader.getLineNumber() + ": could not create rectangle");
errorCount++;
}
}
freePointList();
}
}
private class KeyEndType extends EDIFKEY
{
private KeyEndType() { super("endType"); }
protected void push()
throws IOException
{
// get the endtype
String type = getToken((char)0);
if (type.equalsIgnoreCase("EXTEND")) extendEnd = true;
}
}
private class KeyExternal extends EDIFKEY
{
private KeyExternal() { super("external"); }
protected void push()
throws IOException
{
// ignore the name of the library
String libName = getToken((char)0);
curLibrary = Library.findLibrary(libName);
if (curLibrary == null)
curLibrary = Library.newInstance(libName, null);
}
}
private class KeyFabricate extends EDIFKEY
{
private KeyFabricate() { super("fabricate"); }
protected void push()
throws IOException
{
NameEntry nt = new NameEntry();
activeFigures.add(nt);
// first get the original and replacement layers
nt.original = getToken((char)0);
nt.replace = getToken((char)0);
nt.textHeight = 0;
nt.justification = TextDescriptor.Position.DOWNRIGHT;
}
}
private class KeyFalse extends EDIFKEY
{
private KeyFalse() { super("false"); }
protected void push()
{
propertyValue = new Boolean(false);
}
}
private class KeyFigure extends EDIFKEY
{
private KeyFigure() { super("figure"); }
protected void push()
throws IOException
{
makeFigure();
extendEnd = false;
pathWidth = 0;
}
protected void pop()
{
curActiveFigure = null;
textJustification = TextDescriptor.Position.DOWNRIGHT;
textHeight = 0;
if (curGeometryType == GPORTIMPLEMENTATION)
{
String exportName = renamedObjects.get(objectName);
if (exportName == null) exportName = objectName;
PlannedPort plp = addPlannedPort(exportName);
plp.pinType = curFigureGroup;
}
}
}
private class KeyFigureGroup extends EDIFKEY
{
private KeyFigureGroup() { super("figureGroup"); }
protected void push()
throws IOException
{
makeFigure();
}
protected void pop()
{
curActiveFigure = null;
}
}
private class KeyFigureGroupOverride extends EDIFKEY
{
private KeyFigureGroupOverride() { super("figureGroupOverride"); }
protected void push()
throws IOException
{
makeFigure();
}
}
private class KeyInstance extends EDIFKEY
{
private KeyInstance() { super("instance"); }
protected void push()
throws IOException
{
// set the current geometry type
freePointList();
cellRefProto = null;
curGeometryType = GINSTANCE;
curOrientation = OR0;
isArray = false;
arrayXVal = arrayYVal = 1;
objectName = ""; originalName = "";
instanceReference = "";
curNode = null;
if (checkName())
{
instanceReference = objectName;
instanceName = objectName;
}
}
protected void pop()
throws IOException
{
if (activeView == VNETLIST)
{
for (int iX = 0; iX < arrayXVal; iX++)
{
for (int iY = 0; iY < arrayYVal; iY++)
{
// create this instance in the current sheet
double width = cellRefProto.getDefWidth();
double height = cellRefProto.getDefHeight();
width = (width + INCH - 1) / INCH;
height = (height + INCH - 1) / INCH;
if (sheetXPos == -1)
{
curCell = createCell(null, cellName, "sch");
if (curCell == null) throw new IOException("Error creating cell");
sheetXPos = sheetYPos = 1;
sheetOffset = 2;
}
// create this instance
// find out where true center moves
double cX = ((sheetXPos - (SHEETWIDTH / 2)) * INCH);
double cY = ((sheetYPos - (SHEETHEIGHT / 2)) * INCH);
if (curCellPage > 0) cY += (curCellPage-1) * Cell.FrameDescription.MULTIPAGESEPARATION;
Orientation orient = curOrientation.concatenate(Orientation.fromAngle(cellRefProtoRotation*10));
NodeInst ni = NodeInst.makeInstance(cellRefProto, new Point2D.Double(cX+cellRefOffsetX, cY+cellRefOffsetY),
cellRefProto.getDefWidth(), cellRefProto.getDefHeight(), curCell, orient, null, cellRefProtoFunction);
curNode = ni;
if (ni == null)
{
System.out.println("Error, line " + lineReader.getLineNumber() + ": could not create instance");
errorCount++;
break;
}
// update the current position
if ((width + 2) > sheetOffset)
sheetOffset = (int)width + 2;
if ((sheetYPos += (height + 1)) >= SHEETHEIGHT)
{
sheetYPos = 1;
sheetXPos += sheetOffset;
sheetOffset = 2;
}
// name the instance
if (instanceReference.length() > 0)
{
// if single element or array with no offset
// construct the representative extended EDIF name (includes [...])
String nodeName = instanceReference;
if ((arrayXVal > 1 || arrayYVal > 1) &&
(deltaPointXX != 0 || deltaPointXY != 0 || deltaPointYX != 0 || deltaPointYY != 0))
{
// if array in the x dimension
if (arrayXVal > 1)
{
if (arrayYVal > 1)
nodeName = instanceReference + "[" + iX + "," + iY + "]";
else
nodeName = instanceReference + "[" + iX + "]";
} else if (arrayYVal > 1)
nodeName = instanceReference + "[" + iY + "]";
}
// check for array element descriptor
if (arrayXVal > 1 || arrayYVal > 1)
{
// array descriptor is of the form index:index:range index:index:range
String baseName = iX + ":" + ((deltaPointXX == 0 && deltaPointYX == 0) ? arrayXVal-1:iX) + ":" + arrayXVal +
" " + iY + ":" + ((deltaPointXY == 0 && deltaPointYY == 0) ? arrayYVal-1:iY) + ":" + arrayYVal;
ni.newVar("EDIF_array", stripPercentEscapes(baseName));
}
/* now set the name of the component (note that Electric allows any string
* of characters as a name, this name is open to the user, for ECO and other
* consistancies, the EDIF_name is saved on a variable)
*/
if (instanceReference.equalsIgnoreCase(instanceName))
{
putNameOnNode(ni, nodeName);
} else
{
// now add the original name as the displayed name (only to the first element)
if (iX == 0 && iY == 0)
putNameOnNode(ni, instanceName);
// now save the EDIF name (not displayed)
ni.newVar("EDIF_name", stripPercentEscapes(nodeName));
}
}
}
}
} else
{
// get the corner offset
double instPtX = 0, instPtY = 0;
int instCount = curPoints.size();
if (instCount > 0)
{
Point2D point = curPoints.get(0);
instPtX = point.getX();
instPtY = point.getY();
}
// if no points are specified, presume the origin
if (instCount == 0) instCount = 1;
if (instCount == 1 && cellRefProto != null)
{
for (int iX = 0; iX < arrayXVal; iX++)
{
// ignore placement of schematic frames when using Cadence EDIF
if (localPrefs.cadenceCompatibility)
{
if (cellRefProto instanceof Cell)
{
Cell cellRefCell = (Cell)cellRefProto;
if (cellRefCell.getView() == View.ICON &&
cellRefCell.getLibrary().getName().equals("primitive"))
{
if (cellRefProto.getName().equals("Asize_c")) continue;
if (cellRefProto.getName().equals("Bsize_c")) continue;
if (cellRefProto.getName().equals("CsizeB_c")) continue;
}
}
}
double lX = instPtX + iX * deltaPointXX;
double lY = instPtY + iX * deltaPointXY;
for (int iY = 0; iY < arrayYVal; iY++)
{
double yPos = lY;
if (curCellPage > 0) yPos += (curCellPage-1) * Cell.FrameDescription.MULTIPAGESEPARATION;
Orientation orient = curOrientation.concatenate(Orientation.fromAngle(cellRefProtoRotation*10));
// TODO Oh Dima!
if (cellRefProto instanceof Cell && Cell.isInstantiationRecursive((Cell)cellRefProto, curCell) && curCell.getView() == View.ICON)
{
System.out.println("Cannot create instance of " + cellRefProto + " in icon cell " + curCell);
if (deltaPointYX == 0 && deltaPointYY == 0) break;
lX += deltaPointYX;
lY += deltaPointYY;
continue;
}
NodeInst ni = NodeInst.makeInstance(cellRefProto, new Point2D.Double(lX+cellRefOffsetX, yPos+cellRefOffsetY),
cellRefProto.getDefWidth(), cellRefProto.getDefHeight(), curCell, orient, null, cellRefProtoFunction);
curNode = ni;
if (ni == null)
{
System.out.println("Error, line " + lineReader.getLineNumber() + ": could not create instance");
errorCount++;
// and exit for loop
iX = arrayXVal;
iY = arrayYVal;
freePointList();
return;
}
if (curGeometryType == GPORTIMPLEMENTATION && lX == 0 && lY == 0)
{
// inside a PortImplementation: determine an appropriate port name
String pName = portName;
for (int dup = 0; ; dup++)
{
PortProto ppt = curCell.findPortProto(pName);
if (ppt == null) break;
pName = portName + "_" + (dup+1);
}
// only once
iX = arrayXVal;
iY = arrayYVal;
// locate the direction of the port
PlannedPort plp = addPlannedPort(pName);
plp.alreadyThere = ni;
} else
{
// name the instance
if (instanceReference.length() > 0)
{
String nodeName = instanceReference;
if ((arrayXVal > 1 || arrayYVal > 1) &&
(deltaPointXX != 0 || deltaPointXY != 0 || deltaPointYX != 0 || deltaPointYY != 0))
{
// if array in the x dimension
if (arrayXVal > 1)
{
if (arrayYVal > 1) nodeName = instanceReference + "[" + iX + "," + iY + "]"; else
nodeName = instanceReference + "[" + iX + "]";
} else if (arrayYVal > 1)
nodeName = instanceReference + "[" + iY + "]";
}
// check for array element descriptor
if (arrayXVal > 1 || arrayYVal > 1)
{
// array descriptor is of the form index:index:range index:index:range
String baseName = iX + ":" + ((deltaPointXX == 0 && deltaPointYX == 0) ? arrayXVal-1:iX) + ":" + arrayXVal +
" " + iY + ":" + ((deltaPointXY == 0 && deltaPointYY == 0) ? arrayYVal-1:iY) + ":" + arrayYVal;
ni.newVar("EDIF_array", stripPercentEscapes(baseName));
}
// now set the name of the component (note that Electric allows any string
// of characters as a name, this name is open to the user, for ECO and other
// consistancies, the EDIF_name is saved on a variable)
Variable.Key varKey;
if (instanceReference.equalsIgnoreCase(instanceName))
{
putNameOnNode(ni, nodeName);
varKey = NodeInst.NODE_NAME;
} else
{
// now add the original name as the displayed name (only to the first element)
if (iX == 0 && iY == 0)
putNameOnNode(ni, instanceName);
// now save the EDIF name (not displayed)
Variable var = ni.newVar("EDIF_name", stripPercentEscapes(nodeName));
varKey = var.getKey();
}
// now check for saved name attributes
if (saveTextPoints.size() != 0)
{
// now set the position, relative to the center of the current object
Point2D sP0 = saveTextPoints.get(0);
double xOff = sP0.getX() - ni.getTrueCenterX();
double yOff = sP0.getY() - ni.getTrueCenterY();
// determine the size of text, 0.0278 in == 2 points or 36 (2xpixels) == 1 in fonts range from 4 to 20 points
if (varKey != NodeInst.NODE_NAME)
{
TextDescriptor td = ni.getTextDescriptor(varKey);
td = td.withRelSize(convertTextSize(saveTextHeight)).withPos(saveTextJustification).withOff(xOff, yOff);
ni.setTextDescriptor(varKey, td);
}
}
}
}
if (deltaPointYX == 0 && deltaPointYY == 0) break;
// bump the y delta and x deltas
lX += deltaPointYX;
lY += deltaPointYY;
}
if (deltaPointXX == 0 && deltaPointXY == 0) break;
}
}
freePointList();
}
// move the property list to the free list
for (EDIFProperty property : propertiesList)
{
if (curNode != null)
{
String varName = property.name;
Object varValue = property.val;
String varNameLookup = varName;
if (varNameLookup.startsWith("ATTR_")) varNameLookup = varNameLookup.substring(5);
if (isAcceptedParameter(varNameLookup))
{
EDIFEquiv.VariableEquivalence ve = equivs.getExternalVariableEquivalence(varNameLookup);
if (ve != null)
{
varName = "ATTR_" + ve.elecVarName;
if (ve.appendElecOutput.length() > 0)
{
String varValueString = varValue.toString();
if (varValueString.endsWith(ve.appendElecOutput))
{
varValue = varValueString.substring(0, varValueString.length() - ve.appendElecOutput.length());
}
}
if (ve.scale != 1)
{
String varValueString = varValue.toString();
double newValue = TextUtils.atof(varValueString) / ve.scale;
varValue = Double.toString(newValue);
}
}
TextDescriptor td = TextDescriptor.getNodeTextDescriptor().withDisplay(true).
withDispPart(TextDescriptor.DispPos.NAMEVALUE).withPos(TextDescriptor.Position.DOWN);
Cell parent = (Cell)curNode.getProto();
for(Iterator<Variable> it = parent.getParameters(); it.hasNext(); )
{
Variable var = it.next();
if (var.getKey().getName().equals(varName))
{
td = td.withOff(var.getXOff(), var.getYOff());
break;
}
}
String objStr = varValue.toString();
Object newV = stripPercentEscapes(objStr);
if (isSpiceParameter(objStr))
newV = Variable.withCode(newV, CodeExpression.Code.SPICE);
curNode.newVar(Variable.newKey(varName), newV, td);
}
}
}
propertiesList = new ArrayList<EDIFProperty>();
instanceReference = "";
curNode = null;
freeSavedPointList();
}
}
private class KeyInstanceRef extends EDIFKEY
{
private KeyInstanceRef() { super("instanceRef"); }
protected void push()
throws IOException
{
instanceReference = "";
if (checkName())
{
instanceReference = objectName;
}
}
}
private class KeyInteger extends EDIFKEY
{
private KeyInteger() { super("integer"); }
protected void push()
throws IOException
{
String value = getToken((char)0);
propertyValue = new Integer(TextUtils.atoi(value));
}
}
private class KeyInterface extends EDIFKEY
{
private KeyInterface() { super("interface"); }
protected void push()
throws IOException
{
if (activeView != VNETLIST)
{
String viewName = "ic";
if (activeView == VMASKLAYOUT) viewName = "lay";
curCell = findCell(null, cellName, viewName);
if (curCell == null)
{
curCell = createCell(null, cellName, viewName);
if (curCell == null) throw new IOException("Error creating cell");
} else
{
// if (activeView == VGRAPHIC) // TODO: latest change to prevent icon port duplication
ignoreBlock = true;
}
curCellPage = 0;
inputLocY = outputLocY = 0;
}
plannedPorts = new ArrayList<PlannedPort>();
symbolDefined = false;
}
protected void pop()
{
if (activeView == VNETLIST)
{
// create a black-box symbol
boolean hadSchematic = (curCell != null);
if (!hadSchematic)
{
// no contents: create the schematic so the icon can be generated
curCell = createCell(null, cellName, "sch");
if (curCell == null) return;
Rectangle2D cellBounds = curCell.getBounds();
for(PlannedPort plp : plannedPorts)
instantiatePlannedPort(plp, cellBounds);
}
Cell nnp = null;
try
{
nnp = localPrefs.iconParameters.makeIconForCell(curCell);
} catch (JobException e) {}
if (nnp == null)
{
System.out.println("Error, line " + lineReader.getLineNumber() +
", could not create icon <" + curCell.describe(true) + ">");
errorCount++;
} else if (!hadSchematic)
{
curCell.kill();
curCell = null;
for(PlannedPort plp : plannedPorts)
{
plp.alreadyThere = null;
plp.knownLocation = false;
plp.createdPort = null;
}
}
} else
{
if (symbolDefined)
{
Rectangle2D cellBounds = curCell.getBounds();
for(PlannedPort plp : plannedPorts)
instantiatePlannedPort(plp, cellBounds);
// add cell name in Cadence mode
if (localPrefs.cadenceCompatibility && curCell.getView() == View.ICON)
{
// add icon name in Cadence compatibility mode
TextDescriptor td = TextDescriptor.getAnnotationTextDescriptor();
double xPos = curCell.getBounds().getCenterX();
double yPos = curCell.getBounds().getMaxY() - td.getSize().getSize()/2;
NodeInst ni = NodeInst.makeInstance(Generic.tech().invisiblePinNode, new Point2D.Double(xPos, yPos), 0, 0, curCell);
if (ni != null)
{
td = td.withDisplay(true);
ni.newVar(Artwork.ART_MESSAGE, curCell.getName(), td);
}
}
}
}
plannedPorts = null;
}
}
private class KeyJoined extends EDIFKEY
{
private KeyJoined() { super("joined"); }
protected void push()
{
lastPortlist = null;
}
}
private class KeyJustify extends EDIFKEY
{
private KeyJustify() { super("justify"); }
protected void push()
throws IOException
{
// get the textheight value of the point
String val = getToken((char)0);
if (val.equalsIgnoreCase("UPPERLEFT")) textJustification = TextDescriptor.Position.DOWNRIGHT;
else if (val.equalsIgnoreCase("UPPERCENTER")) textJustification = TextDescriptor.Position.DOWN;
else if (val.equalsIgnoreCase("UPPERRIGHT")) textJustification = TextDescriptor.Position.DOWNLEFT;
else if (val.equalsIgnoreCase("CENTERLEFT")) textJustification = TextDescriptor.Position.RIGHT;
else if (val.equalsIgnoreCase("CENTERCENTER")) textJustification = TextDescriptor.Position.CENT;
else if (val.equalsIgnoreCase("CENTERRIGHT")) textJustification = TextDescriptor.Position.LEFT;
else if (val.equalsIgnoreCase("LOWERLEFT")) textJustification = TextDescriptor.Position.UPRIGHT;
else if (val.equalsIgnoreCase("LOWERCENTER")) textJustification = TextDescriptor.Position.UP;
else if (val.equalsIgnoreCase("LOWERRIGHT")) textJustification = TextDescriptor.Position.UPLEFT;
else
{
System.out.println("Warning, line " + lineReader.getLineNumber() + ": unknown keyword <" + val + ">");
warningCount++;
return;
}
if (curActiveFigure != null)
curActiveFigure.justification = textJustification;
}
}
private class KeyLibrary extends EDIFKEY
{
private KeyLibrary() { super("library"); }
protected void push()
throws IOException
{
// get the name of the library
String libName = getToken((char)0);
curLibrary = Library.findLibrary(libName);
if (curLibrary == null)
curLibrary = Library.newInstance(libName, null);
}
}
private class LibraryRef extends EDIFKEY
{
private LibraryRef() { super ("libraryRef"); }
protected void push()
throws IOException
{
// get the name of the library
libraryRef = getToken((char)0);
}
}
private class KeyMember extends EDIFKEY
{
private KeyMember() { super("member"); }
protected void push()
throws IOException
{
memberXVal = -1; // no member
memberYVal = -1; // no member
if (checkName())
{
if (keyStack[keyStackDepth-1] == KPORTREF) portReference = objectName; else
if (keyStack[keyStackDepth-1] == KINSTANCEREF) instanceReference = objectName;
}
}
protected void pop()
{
if (memberXVal != -1)
{
// adjust the name of the current INSTANCE/NET/PORT(/VALUE)
if (keyStack[keyStackDepth-1] == KINSTANCEREF)
{
instanceReference = getMemberName(instanceReference, memberXVal, memberYVal);
} else if (keyStack[keyStackDepth-1] == KPORTREF)
{
portReference = getMemberName(portReference, memberXVal, memberYVal);
}
}
}
}
private class KeyName extends EDIFKEY
{
private KeyName() { super("name"); }
protected void push()
throws IOException
{
int kPtr = keyStackDepth - 1;
if (keyStack[keyStackDepth-1] == KARRAY || keyStack[keyStackDepth-1] == KMEMBER) kPtr = keyStackDepth-2;
if (checkName())
{
if (keyStack[kPtr] == KCELL)
{
cellName = cellReference = fixLeadingAmpersand(objectName);
} else if (keyStack[kPtr] == KPORTIMPLEMENTATION || keyStack[kPtr] == KPORT)
{
portName = portReference = fixLeadingAmpersand(objectName);
} else if (keyStack[kPtr] == KPORTREF)
{
portReference = fixLeadingAmpersand(objectName);
} else if (keyStack[kPtr] == KINSTANCE)
{
instanceName = instanceReference = objectName;
} else if (keyStack[kPtr] == KINSTANCEREF)
{
instanceReference = objectName;
} else if (keyStack[kPtr] == KNET)
{
netReference = netName = fixLeadingAmpersand(objectName);
} else if (keyStack[kPtr] == KPROPERTY)
{
propertyReference = objectName;
}
// init the point lists
freePointList();
curOrientation = OR0;
textJustification = TextDescriptor.Position.DOWNRIGHT;
textHeight = 0;
textString = objectName;
}
}
protected void pop()
{
// save the data and break
freeSavedPointList();
textString = "";
saveTextPoints = curPoints;
curPoints = new ArrayList<Point2D>();
saveTextHeight = textHeight;
textHeight = 0;
saveTextJustification = textJustification;
textJustification = TextDescriptor.Position.DOWNRIGHT;
curOrientation = OR0;
}
}
/**
* net: Define a net name followed by edifgbl and local pin list
* (net NAME
* (joined
* (portRef NAME (instanceRef NAME))
* (portRef NAME)))
*/
private class KeyNet extends EDIFKEY
{
private KeyNet() { super("net"); }
protected void push()
throws IOException
{
netReference = "";
objectName = ""; originalName = "";
curArc = null;
curNode = null;
curPort = null;
isArray = false;
arrayXVal = arrayYVal = 1;
if (keyStack[keyStackDepth-2] != KNETBUNDLE) curGeometryType = GNET;
if (checkName())
{
netReference = objectName;
netName = objectName;
}
exportsOnNet = new HashSet<String>();
arcsOnNet = new ArrayList<ArcInst>();
nodesOnNet = new ArrayList<NodeInst>();
}
protected void pop()
{
// move the property list to the free list
for (EDIFProperty property : propertiesList)
{
if (curArc != null)
{
String objStr = property.val.toString();
Object newV = stripPercentEscapes(objStr);
if (isSpiceParameter(objStr))
newV = Variable.withCode(newV, CodeExpression.Code.SPICE);
curArc.newVar(stripPercentEscapes(property.name), newV);
}
}
propertiesList = new ArrayList<EDIFProperty>();
netReference = "";
curArc = null;
if (curGeometryType != GBUS) curGeometryType = GUNKNOWN;
freeSavedPointList();
netPortRefs.clear();
// make sure all exports are on some arc
for(String exportName : exportsOnNet)
{
ArcInst unNamedArc = null;
boolean nameFound = false;
for(ArcInst ai : arcsOnNet)
{
String arcName = ai.getName();
if (arcName.equals(exportName)) nameFound = true;
if (ai.getNameKey().isTempname()) unNamedArc = ai;
}
if (nameFound) continue;
if (unNamedArc != null)
{
unNamedArc.setName(exportName);
if (!localPrefs.showArcNames)
{
TextDescriptor td = unNamedArc.getTextDescriptor(ArcInst.ARC_NAME);
td = td.withDisplay(TextDescriptor.Display.NONE);
unNamedArc.setTextDescriptor(ArcInst.ARC_NAME, td);
}
} else
{
if (arcsOnNet.size() > 0)
{
// two names on one arc: duplicate the arc
ArcInst ai = arcsOnNet.get(0);
ArcInst second = ArcInst.newInstanceBase(ai.getProto(), ai.getLambdaBaseWidth(),
ai.getHeadPortInst(), ai.getTailPortInst(), ai.getHeadLocation(), ai.getTailLocation(),
exportName, ai.getAngle(), ai.getD().flags);
TextDescriptor td = TextDescriptor.getArcTextDescriptor().withOff(0, -1);
if (!localPrefs.showArcNames)
td = td.withDisplay(TextDescriptor.Display.NONE);
second.setTextDescriptor(ArcInst.ARC_NAME, td);
} else if (nodesOnNet.size() > 0)
{
// find port
for(PlannedPort plp : plannedPorts)
{
if (plp.name.equalsIgnoreCase(exportName) || plp.alternateName.equalsIgnoreCase(exportName))
{
if (plp.alreadyThere == null)
plp.alreadyThere = nodesOnNet.get(0);
break;
}
}
}
}
}
exportsOnNet = null;
arcsOnNet = null;
nodesOnNet = null;
}
}
private class KeyNetBundle extends EDIFKEY
{
private KeyNetBundle() { super("netBundle"); }
protected void push()
throws IOException
{
curGeometryType = GBUS;
bundleReference = "";
objectName = ""; originalName = "";
isArray = false;
if (checkName())
{
bundleReference = objectName;
bundleName = objectName;
}
}
protected void pop()
{
bundleReference = "";
curArc = null;
curGeometryType = GUNKNOWN;
freeSavedPointList();
}
}
private class KeyNumber extends EDIFKEY
{
private KeyNumber() { super("number"); }
protected void push()
throws IOException
{
propertyValue = new Double(getNumber());
}
}
private class KeyOpenShape extends EDIFKEY
{
private KeyOpenShape() { super("openShape"); }
protected void push()
{
freePointList();
curOrientation = OR0;
}
protected void pop()
{
doPoly();
}
}
private class KeyOrientation extends EDIFKEY
{
private KeyOrientation() { super("orientation"); }
protected void push()
throws IOException
{
// get the orientation keyword
String orient = getToken((char)0);
if (orient.equalsIgnoreCase("R0")) curOrientation = OR0;
else if (orient.equalsIgnoreCase("R90")) curOrientation = OR90;
else if (orient.equalsIgnoreCase("R180")) curOrientation = OR180;
else if (orient.equalsIgnoreCase("R270")) curOrientation = OR270;
else if (orient.equalsIgnoreCase("MY")) curOrientation = OMY;
else if (orient.equalsIgnoreCase("MX")) curOrientation = OMX;
else if (orient.equalsIgnoreCase("MYR90")) curOrientation = OMYR90;
else if (orient.equalsIgnoreCase("MXR90")) curOrientation = OMXR90;
else
{
System.out.println("Warning, line " + lineReader.getLineNumber() + ": unknown orientation value <" + orient + ">");
warningCount++;
}
}
}
private class KeyPath extends EDIFKEY
{
private KeyPath() { super("path"); }
protected void push()
{
freePointList();
curOrientation = OR0;
}
protected void pop()
{
// check for openShape type path
if (pathWidth == 0 && curGeometryType != GNET && curGeometryType != GBUS)
{
doPoly();
return;
}
List<PortInst> fList = new ArrayList<PortInst>();
NodeProto np = Schematics.tech().wirePinNode;
if (curGeometryType == GBUS || isArray) np = Schematics.tech().busPinNode;
if (curGeometryType == GNET)
{
if (isBusName(netName))
np = Schematics.tech().busPinNode;
}
for(int i=0; i<curPoints.size()-1; i++)
{
Point2D fPoint = curPoints.get(i);
Point2D tPoint = curPoints.get(i+1);
double fX = fPoint.getX(); double fY = fPoint.getY();
double tX = tPoint.getX(); double tY = tPoint.getY();
if (curCellPage > 0)
{
fY += (curCellPage-1) * Cell.FrameDescription.MULTIPAGESEPARATION;
tY += (curCellPage-1) * Cell.FrameDescription.MULTIPAGESEPARATION;
}
if (curGeometryType == GNET || curGeometryType == GBUS)
{
// create a pin to pin connection
if (fList.size() == 0)
{
// look for the first pin
fList = findEDIFPort(curCell, fX, fY, Schematics.tech().wire_arc);
if (fList.size() == 0)
{
// check for NodeEquivalences with translated ports
for (PortInst pi : netPortRefs)
{
EDIFEquiv.NodeEquivalence ne = equivs.getNodeEquivalence(pi.getNodeInst());
if (ne != null)
{
Point2D curPoint = new Point2D.Double(fX, fY);
String orientation = com.sun.electric.tool.io.output.EDIF.getOrientation(pi.getNodeInst(), 0);
String port = ne.getPortEquivElec(pi.getPortProto().getName()).getExtPort().name;
curPoint = equivs.translatePortConnection(curPoint, ne.externalLib, ne.externalCell,
ne.externalView, port, orientation);
if ((curPoint.getX() != fX) || (curPoint.getY() != fY))
{
fList = findEDIFPort(curCell, curPoint.getX(), curPoint.getY(), Schematics.tech().wire_arc);
if (fList.size() != 0)
{
// found exact match, move port
fX = curPoint.getX();
fY = curPoint.getY();
break;
}
}
}
}
}
if (fList.size() == 0)
{
// create the "from" pin
NodeInst ni = placePin(np, fX, fY, np.getDefWidth(), np.getDefHeight(), Orientation.IDENT, curCell);
if (ni != null) fList.add(ni.getOnlyPortInst());
}
}
// now the second ...
List<PortInst> tList = findEDIFPort(curCell, tX, tY, Schematics.tech().wire_arc);
if (tList.size() == 0)
{
// check for NodeEquivalences with translated ports
for (PortInst pi : netPortRefs)
{
EDIFEquiv.NodeEquivalence ne = equivs.getNodeEquivalence(pi.getNodeInst());
if (ne != null)
{
Point2D curPoint = new Point2D.Double(tX, tY);
String orientation = com.sun.electric.tool.io.output.EDIF.getOrientation(pi.getNodeInst(), 0);
String port = ne.getPortEquivElec(pi.getPortProto().getName()).getExtPort().name;
curPoint = equivs.translatePortConnection(curPoint, ne.externalLib, ne.externalCell,
ne.externalView, port, orientation);
if (curPoint.getX() != tX || curPoint.getY() != tY)
{
tList = findEDIFPort(curCell, curPoint.getX(), curPoint.getY(), Schematics.tech().wire_arc);
if (tList.size() != 0)
{
// found exact match, move port
tX = curPoint.getX();
tY = curPoint.getY();
break;
}
}
}
}
}
if (tList.size() == 0)
{
// create the "to" pin
if (curCellPage > 0) tY += (curCellPage-1) * Cell.FrameDescription.MULTIPAGESEPARATION;
NodeInst ni = placePin(np, tX, tY, np.getDefWidth(), np.getDefHeight(), Orientation.IDENT, curCell);
if (ni != null) tList.add(ni.getOnlyPortInst());
}
if (fList.size() == 0 || tList.size() == 0)
{
System.out.println("Error, line " + lineReader.getLineNumber() + ": could not create path");
errorCount++;
} else
{
// connect it
ArcInst ai = null;
PortInst fPi = null;
PortInst tPi = null;
for (int count = 0; count < fList.size() || count < tList.size(); count++)
{
boolean fbus = false;
boolean tbus = false;
if (count < fList.size())
{
fPi = fList.get(count);
// check node for array variable
NodeInst ni = fPi.getNodeInst();
Variable var = ni.getVar("EDIF_array");
if (var != null) fbus = true; else
{
if (isBusName(fPi.getPortProto().getName())) fbus = true;
}
}
if (count < tList.size())
{
tPi = tList.get(count);
// check node for array variable
NodeInst ni = tPi.getNodeInst();
Variable var = ni.getVar("EDIF_array");
if (var != null) tbus = true; else
{
if (isBusName(tPi.getPortProto().getName())) tbus = true;
}
}
// if bus to bus
ArcProto ap = Schematics.tech().wire_arc;
if ((fPi.getPortProto() == defaultBusPort || fbus) &&
(tPi.getPortProto() == defaultBusPort || tbus))
{
ap = Schematics.tech().bus_arc;
} else
{
if (curGeometryType == GNET)
{
if (isBusName(netName)) ap = Schematics.tech().bus_arc;
} else if (curGeometryType == GBUS)
{
if (isBusName(bundleName)) ap = Schematics.tech().bus_arc;
}
}
Point2D fromPoint = new Point2D.Double(fX, fY);
if (!fPi.getPoly().contains(fromPoint)) fromPoint = fPi.getPoly().getCenter();
Point2D toPoint = new Point2D.Double(tX, tY);
if (!tPi.getPoly().contains(toPoint)) toPoint = tPi.getPoly().getCenter();
// check for wire connecting to a bus port: insert a Join
if (ap == Schematics.tech().wire_arc)
{
if (isBusName(fPi.getPortProto().getName()))
{
PrimitiveNode joinNode = Schematics.tech().wireConNode;
Point2D ctrPoint = new Point2D.Double(fromPoint.getX() + (toPoint.getX()-fromPoint.getX())/3,
fromPoint.getY() + (toPoint.getY()-fromPoint.getY())/3);
NodeInst ni = NodeInst.makeInstance(joinNode, ctrPoint,
joinNode.getDefWidth(), joinNode.getDefHeight(), curCell);
PortInst newFrom = ni.getOnlyPortInst();
ArcInst.makeInstance(Schematics.tech().bus_arc, fPi, newFrom);
fPi = newFrom;
fromPoint = ctrPoint;
}
if (isBusName(tPi.getPortProto().getName()))
{
PrimitiveNode joinNode = Schematics.tech().wireConNode;
Point2D ctrPoint = new Point2D.Double(toPoint.getX() + (fromPoint.getX()-toPoint.getX())/3,
toPoint.getY() + (fromPoint.getY()-toPoint.getY())/3);
NodeInst ni = NodeInst.makeInstance(joinNode, ctrPoint,
joinNode.getDefWidth(), joinNode.getDefHeight(), curCell);
PortInst newFrom = ni.getOnlyPortInst();
ArcInst.makeInstance(Schematics.tech().bus_arc, tPi, newFrom);
tPi = newFrom;
toPoint = ctrPoint;
}
} else if (ap == Schematics.tech().bus_arc)
{
if (fPi.getNodeInst().getProto() == Schematics.tech().wirePinNode)
{
NodeInst nowBus = fPi.getNodeInst().replace(Schematics.tech().busPinNode, true, true);
fPi = nowBus.getOnlyPortInst();
}
if (tPi.getNodeInst().getProto() == Schematics.tech().wirePinNode)
{
NodeInst nowBus = tPi.getNodeInst().replace(Schematics.tech().busPinNode, true, true);
tPi = nowBus.getOnlyPortInst();
}
}
if (fPi != tPi)
{
ai = ArcInst.makeInstance(ap, fPi, tPi, fromPoint, toPoint, null);
if (ai == null)
{
System.out.println("Error, line " + lineReader.getLineNumber() + ": could not create path (arc)");
errorCount++;
} else
{
if (arcsOnNet != null) arcsOnNet.add(ai);
if (curGeometryType == GNET && i == 0)
{
if (netReference.length() > 0) ai.newVar("EDIF_name", stripPercentEscapes(netReference));
if (netName.length() > 0) putNameOnArcOnce(ai, convertParens(netName));
} else if (curGeometryType == GBUS && i == 0)
{
if (bundleReference.length() > 0) ai.newVar("EDIF_name", stripPercentEscapes(bundleReference));
if (bundleName.length() > 0) putNameOnArcOnce(ai, convertParens(bundleName));
}
}
}
}
if (ai != null) curArc = ai;
fList = tList;
}
} else
{
// rectalinear paths with some width
// create a path from here to there (orthogonal only now)
if (fY == tY || extendEnd)
{
fY -= pathWidth/2;
tY += pathWidth/2;
}
if (fX == tX || extendEnd)
{
fX -= pathWidth/2;
tX += pathWidth/2;
}
double cY = (fY+tY)/2;
double cX = (fX+tX)/2;
if (curCellPage > 0) cY += (curCellPage-1) * Cell.FrameDescription.MULTIPAGESEPARATION;
NodeInst ni = placePin(curFigureGroup, cX, cY, Math.abs(fX-tX), Math.abs(fY-tY), curOrientation, curCell);
if (ni == null)
{
System.out.println("Error, line " + lineReader.getLineNumber() + ": could not create path");
errorCount++;
}
}
}
freePointList();
}
}
private class KeyPathWidth extends EDIFKEY
{
private KeyPathWidth() { super("pathWidth"); }
protected void push()
throws IOException
{
// get the width string
String width = getToken((char)0);
pathWidth = TextUtils.atoi(width) * localPrefs.inputScale;
}
}
private class KeyPolygon extends EDIFKEY
{
private KeyPolygon() { super("polygon"); }
protected void push()
throws IOException
{
freePointList();
curOrientation = OR0;
}
protected void pop()
{
doPoly();
}
}
private class KeyPort extends EDIFKEY
{
private KeyPort() { super("port"); }
protected void push()
throws IOException
{
objectName = ""; originalName = "";
curDirection = PortCharacteristic.IN;
portReference = "";
isArray = false;
arrayXVal = arrayYVal = 1;
if (checkName())
{
portReference = objectName;
portName = objectName;
}
}
protected void pop()
{
PlannedPort plp = addPlannedPort(portName);
plp.alternateName = objectName;
plp.direction = curDirection;
plp.knownLocation = false;
plp.x = plp.y = 0;
if (curCellPage > 0) plp.y += (curCellPage-1) * Cell.FrameDescription.MULTIPAGESEPARATION;
for(EDIFProperty property : propertiesList) plp.properties.add(property);
portReference = "";
propertiesList = new ArrayList<EDIFProperty>();
}
}
private class KeyPortImplementation extends EDIFKEY
{
private KeyPortImplementation() { super("portImplementation"); }
protected void push()
throws IOException
{
// set the current geometry type
freePointList();
cellRefProto = Schematics.tech().busPinNode;
curGeometryType = GPORTIMPLEMENTATION;
curOrientation = OR0;
isArray = false;
arrayXVal = arrayYVal = 1;
objectName = ""; originalName = "";
checkName();
}
protected void pop()
{
curGeometryType = GUNKNOWN;
}
}
private class KeyPortList extends EDIFKEY
{
private KeyPortList() { super("portList"); }
protected void push()
{
curPortlist = new ArrayList<Network>();
}
protected void pop()
{
if (keyStack[keyStackDepth-1] == KJOINED && curPortlist != null)
{
if (lastPortlist != null && curPortlist.size() > 0)
{
// connect two busses
if (lastPortlist.size() != curPortlist.size())
{
String errorMsg = "Error, line " + lineReader.getLineNumber() +
": net " + netName + " joins portlists with different length (" + lastPortlist.size() +
" and "+curPortlist.size() + ") in cell " + curCell.describe(false);
System.out.println(errorMsg);
}
}
lastPortlist = curPortlist;
}
}
}
private class KeyPortRef extends EDIFKEY
{
private KeyPortRef() { super("portRef"); }
protected void push()
throws IOException
{
portReference = "";
instanceReference = "";
if (checkName())
{
portReference = objectName;
}
}
protected void pop()
{
// must have gathered a port reference
if (portReference.length() <= 0) return;
// check for the last pin
NodeInst fNi = curNode;
PortProto fPp = curPort;
// For internal pins of an instance, determine the base port location and other pin assignments
ArcProto ap = Generic.tech().unrouted_arc;
NodeInst ni = null;
Nodable no = null;
PortProto pp = null;
if (instanceReference.length() > 0)
{
String nodeName = instanceReference;
String alternateInstName = renamedObjects.get(nodeName);
if (alternateInstName != null) nodeName = alternateInstName;
// locate the node and and port
if (activeView == VNETLIST)
{
// scan all pages for this nodeinst
for(Iterator<Cell> it = curLibrary.getCells(); it.hasNext(); )
{
Cell cell = it.next();
if (!cell.getName().equalsIgnoreCase(cellName)) continue;
for(Iterator<NodeInst> nIt = cell.getNodes(); nIt.hasNext(); )
{
NodeInst oNi = nIt.next();
Variable var = oNi.getVar("EDIF_name");
if (var != null && var.getPureValue(-1).equalsIgnoreCase(nodeName)) { ni = oNi; break; }
String name = oNi.getName();
if (name.equalsIgnoreCase(nodeName)) { ni = oNi; break; }
}
if (ni != null) break;
}
if (ni == null)
{
System.out.println("error, line " + lineReader.getLineNumber() + ": could not locate netlist node (" + nodeName + ")");
return;
}
} else
{
// net always references the current page
for(Iterator<NodeInst> nIt = curCell.getNodes(); nIt.hasNext(); )
{
NodeInst oNi = nIt.next();
Variable var = oNi.getVar("EDIF_name");
if (var != null && var.getPureValue(-1).equalsIgnoreCase(nodeName)) { ni = oNi; break; }
String name = oNi.getName();
if (name.equalsIgnoreCase(nodeName)) { ni = oNi; break; }
}
if (ni == null)
{
// might be an instance of an arrayed node
for(Iterator<Nodable> nIt = curCell.getNetlist().getNodables(); nIt.hasNext(); )
{
Nodable oNo = nIt.next();
if (oNo.getName().equalsIgnoreCase(nodeName))
{
no = oNo;
ni = no.getNodeInst();
break;
}
}
}
if (ni == null)
{
System.out.println("error, line " + lineReader.getLineNumber() + ": could not locate schematic node '" +
nodeName + "' in " + curCell);
return;
}
if (!isArray) ap = Schematics.tech().wire_arc; else
ap = Schematics.tech().bus_arc;
}
// locate the port for this portref
pp = ni.getProto().findPortProto(portReference);
if (pp == null)
{
String alternateName = renamedObjects.get(portReference);
if (alternateName != null)
{
alternateName = convertParens(alternateName);
pp = ni.getProto().findPortProto(alternateName);
}
if (pp == null)
{
EDIFEquiv.NodeEquivalence ne = mappedNodes.get(nodeName);
if (ne != null)
{
for(EDIFEquiv.PortEquivalence pe : ne.portEquivs)
{
if (pe.getExtPort().name.equals(portReference))
{
pp = ni.getProto().findPortProto(pe.getElecPort().name);
break;
}
if (alternateName != null && pe.getExtPort().name.equals(alternateName))
{
pp = ni.getProto().findPortProto(pe.getElecPort().name);
break;
}
}
}
}
if (pp == null)
{
String errorMsg = "Error, line " + lineReader.getLineNumber() +
": could not find port '" + portReference;
if (alternateName != null) errorMsg += "' or '" + alternateName;
errorMsg += "' on node '" + nodeName + "' in cell " + curCell.describe(false);
System.out.println(errorMsg);
return;
}
}
// // special case when connecting an arrayed node to a bus
// if (no != null && netName.indexOf('[') >= 0)
// {
// // run a zero-length bus to a bus pin, then a named arc to a second pin, use the second pin
// PrimitiveNode busPin = Schematics.tech().busPinNode;
// PortInst pi = ni.findPortInstFromProto(pp);
// Poly poly = pi.getPoly();
// NodeInst ni1 = placePin(busPin, poly.getCenterX()+1, poly.getCenterY(),
// busPin.getDefaultLambdaBaseWidth(), busPin.getDefaultLambdaBaseHeight(), Orientation.IDENT, curCell);
// if (ni1 == null)
// {
// System.out.println("error, line " + lineReader.getLineNumber() + ": could not create bus pin");
// return;
// }
// PortInst busPinPort = ni1.getOnlyPortInst();
// boolean found = false;
// for(Iterator<ArcInst> aIt = curCell.getArcs(); aIt.hasNext(); )
// {
// ArcInst ai = aIt.next();
// if ((ai.getHeadPortInst() == busPinPort && ai.getTailPortInst() == pi) ||
// (ai.getTailPortInst() == busPinPort && ai.getHeadPortInst() == pi))
// {
// found = true;
// break;
// }
// }
// if (!found) ArcInst.makeInstance(Schematics.tech().bus_arc, busPinPort, pi);
//
// // now the named wire arc
// PrimitiveNode wirePin = Schematics.tech().wirePinNode;
// NodeInst ni2 = NodeInst.makeInstance(wirePin, new Point2D.Double(poly.getCenterX()+1, poly.getCenterY()+1),
// wirePin.getDefaultLambdaBaseWidth(), wirePin.getDefaultLambdaBaseHeight(), curCell, Orientation.IDENT, null, 0);
// if (ni2 == null)
// {
// System.out.println("error, line " + lineReader.getLineNumber() + ": could not create wire pin");
// return;
// }
// PortInst wirePinPort = ni2.getOnlyPortInst();
// ArcInst wireArc = ArcInst.makeInstance(Schematics.tech().wire_arc, wirePinPort, busPinPort);
// int indPos = instanceReference.lastIndexOf('[');
// int namePos = netName.lastIndexOf('[');
// if (indPos > 0 && namePos > 0)
// {
// String newName = netName.substring(0, namePos) + instanceReference.substring(indPos);
// wireArc.setName(newName);
// }
//
// // remember the end of the named wire arc as the true location of this portRef
// ni = ni2;
// pp = wirePinPort.getPortProto();
// ap = Schematics.tech().wire_arc;
// }
// we have both, set global variable
curNode = ni;
curPort = pp;
netPortRefs.add(ni.findPortInstFromProto(pp));
// create extensions for net labels on single pin nets (externals), and placeholder for auto-routing later
if (activeView == VNETLIST)
{
// route all pins with an extension
if (ni != null)
{
Poly portPoly = ni.findPortInstFromProto(pp).getPoly();
double hX = portPoly.getCenterX();
double hY = portPoly.getCenterY();
double lX = hX;
double lY = hY;
if (pp.getCharacteristic() == PortCharacteristic.IN) lX = hX - (INCH/10); else
if (pp.getCharacteristic() == PortCharacteristic.BIDIR) lY = hY - (INCH/10); else
if (pp.getCharacteristic() == PortCharacteristic.OUT)
{
lX = hX;
hX = hX + (INCH/10);
}
// need to create a destination for the wire
ArcProto lAp = Schematics.tech().bus_arc;
PortProto lPp = defaultBusPort;
NodeInst lNi = null;
if (isArray)
{
lNi = placePin(Schematics.tech().busPinNode, (lX+hX)/2, (lY+hY)/2, hX-lX, hY-lY, Orientation.IDENT, curCell);
if (lNi == null)
{
System.out.println("error, line " + lineReader.getLineNumber() + ": could not create bus pin");
return;
}
} else
{
lNi = placePin(Schematics.tech().wirePinNode, (lX+hX)/2, (lY+hY)/2, hX-lX, hY-lY, Orientation.IDENT, curCell);
if (lNi == null)
{
System.out.println("error, line " + lineReader.getLineNumber() + ": could not create wire pin");
return;
}
lPp = defaultPort;
lAp = Schematics.tech().wire_arc;
}
PortInst head = lNi.findPortInstFromProto(lPp);
PortInst tail = ni.findPortInstFromProto(pp);
curArc = ArcInst.makeInstance(lAp, head, tail);
if (curArc == null)
System.out.println("error, line " + lineReader.getLineNumber() + ": could not create auto-path");
else
nameEDIFArc(curArc, true);
}
}
} else
{
// external port reference, look for a off-page reference in {sch} with this port name
if (exportsOnNet != null)
{
String alternateName = renamedObjects.get(portReference);
if (alternateName == null) alternateName = portReference;
exportsOnNet.add(alternateName);
}
if (activeView == VNETLIST)
{
Cell np = null;
for(Iterator<Cell> it = curLibrary.getCells(); it.hasNext(); )
{
Cell cell = it.next();
if (cell.getName().equalsIgnoreCase(cellName) && cell.isSchematic())
{
np = cell;
break;
}
}
if (np == null)
{
System.out.println("error, line " + lineReader.getLineNumber() + ": could not locate top level schematic");
return;
}
// now look for an instance with the correct port name
pp = np.findPortProto(portReference);
if (pp == null)
{
if (originalName.length() > 0)
pp = np.findPortProto(originalName);
String alternateName = portReference;
if (pp == null)
{
String altName = renamedObjects.get(portReference);
if (altName != null)
pp = np.findPortProto(alternateName = altName);
}
if (pp == null)
{
PlannedPort plp = addPlannedPort(alternateName);
Rectangle2D cellBounds = curCell.getBounds();
instantiatePlannedPort(plp, cellBounds);
pp = plp.createdPort;
}
if (pp == null)
{
System.out.println("Error, line " + lineReader.getLineNumber() + ": could not locate port '" +
portReference + "' on cell " + np.describe(false));
return;
}
}
fNi = ((Export)pp).getOriginalPort().getNodeInst();
fPp = ((Export)pp).getOriginalPort().getPortProto();
Poly portPoly = fNi.findPortInstFromProto(fPp).getPoly();
double lX = portPoly.getCenterX();
double lY = portPoly.getCenterY();
// determine x position by original placement
if (pp.getCharacteristic() == PortCharacteristic.IN) lX = 1*INCH; else
if (pp.getCharacteristic() == PortCharacteristic.BIDIR) lY = 4*INCH; else
if (pp.getCharacteristic() == PortCharacteristic.OUT) lX = 5*INCH;
// need to create a destination for the wire
if (isArray)
{
ni = placePin(Schematics.tech().busPinNode, lX, lY,
Schematics.tech().busPinNode.getDefWidth(), Schematics.tech().busPinNode.getDefHeight(), Orientation.IDENT, np);
if (ni == null)
{
System.out.println("error, line " + lineReader.getLineNumber() + ": could not create bus pin");
return;
}
pp = defaultBusPort;
} else
{
ni = placePin(Schematics.tech().wirePinNode, lX, lY,
Schematics.tech().wirePinNode.getDefWidth(), Schematics.tech().wirePinNode.getDefHeight(), Orientation.IDENT, np);
if (ni == null)
{
System.out.println("error, line " + lineReader.getLineNumber() + ": could not create wire pin");
return;
}
pp = defaultPort;
}
if (!isArray) ap = Schematics.tech().wire_arc; else
ap = Schematics.tech().bus_arc;
}
}
// now connect if we have from node and port
if (fNi != null && fPp != null)
{
if (fNi.getParent() != ni.getParent())
{
System.out.println("error, line " + lineReader.getLineNumber() + ": could not create path (arc) between " +
fNi.getParent() + " and " + ni.getParent());
} else
{
// locate the position of the new ports
Poly fPortPoly = fNi.findPortInstFromProto(fPp).getPoly();
double lX = fPortPoly.getCenterX();
double lY = fPortPoly.getCenterY();
Poly portPoly = ni.findPortInstFromProto(pp).getPoly();
double hX = portPoly.getCenterX();
double hY = portPoly.getCenterY();
// for nets with no physical representation ...
curArc = null;
PortInst head = fNi.findPortInstFromProto(fPp);
PortInst tail = ni.findPortInstFromProto(pp);
if (head != tail)
{
Point2D headPt = new Point2D.Double(lX, lY);
Point2D tailPt = new Point2D.Double(hX, hY);
double dist = 0;
if (lX != hX || lY != hY) dist = headPt.distance(tailPt);
if (dist <= 1)
{
if (!head.getPortProto().connectsTo(ap) || !tail.getPortProto().connectsTo(ap))
{
ArcProto [] headList = head.getPortProto().getBasePort().getConnections();
for(int i=0; i<headList.length; i++)
{
ArcProto apAlt = headList[i];
if (tail.getPortProto().connectsTo(apAlt))
{
ap = apAlt;
break;
}
}
}
curArc = ArcInst.makeInstance(ap, head, tail, headPt, tailPt, null);
if (curArc == null)
{
System.out.println("error, line " + lineReader.getLineNumber() + ": could not create path (arc) among cells");
}
} else if (activeView == VNETLIST)
{
// use unrouted connection for NETLIST views
curArc = ArcInst.makeInstance(ap, head, tail, headPt, tailPt, null);
if (curArc == null)
{
System.out.println("error, line " + lineReader.getLineNumber() + ": could not create auto-path in portRef");
}
}
// add the net name
if (curArc != null && no == null)
nameEDIFArc(curArc, false);
}
}
}
}
}
private class KeyProgram extends EDIFKEY
{
private KeyProgram() { super("program"); }
protected void push()
throws IOException
{
String program = getToken((char)0);
if (program.substring(1).startsWith("VIEWlogic"))
{
curVendor = EVVIEWLOGIC;
} else if (program.substring(1).startsWith("edifout"))
{
curVendor = EVCADENCE;
}
}
}
private class KeyProperty extends EDIFKEY
{
private KeyProperty() { super("property"); }
protected void push()
throws IOException
{
propertyReference = "";
objectName = ""; originalName = "";
propertyValue = null;
if (checkName())
{
propertyReference = objectName;
}
}
protected void pop()
throws IOException
{
// add as a variable to the current object
if (keyStack[keyStackDepth - 1] == KINTERFACE)
{
// add to the current property list, will be added latter
EDIFProperty property = new EDIFProperty();
propertiesList.add(property);
property.name = "ATTR_" + propertyReference;
property.val = propertyValue;
} else if (keyStack[keyStackDepth - 1] == KINSTANCE || keyStack[keyStackDepth - 1] == KNET ||
keyStack[keyStackDepth - 1] == KPORT)
{
// add to the current property list, will be added latter
EDIFProperty property = new EDIFProperty();
propertiesList.add(property);
property.name = "ATTR_" + propertyReference;
property.val = propertyValue;
} else if (keyStack[keyStackDepth - 1] == KCELL)
{
if (isAcceptedParameter(propertyReference))
{
TextDescriptor td = TextDescriptor.getCellTextDescriptor().withDispPart(TextDescriptor.DispPos.NAMEVALUE).
withInherit(true).withParam(true).withDispPart(TextDescriptor.DispPos.NAMEVALUE);
Variable param = Variable.newInstance(Variable.newKey("ATTR_" + propertyReference), propertyValue, td);
curCell.getCellGroup().addParam(param);
}
}
if (curActiveFigure != null)
{
if (propertyReference.equals("layerNumber"))
{
String value = propertyValue.toString();
if (TextUtils.isANumber(value))
{
int layerNum = TextUtils.atoi(value);
for (Map.Entry<Layer,String> e : curTech.getGDSLayers().entrySet())
{
Layer layer = e.getKey();
String gdsLayer = e.getValue();
if (layerNum != TextUtils.atoi(gdsLayer)) continue;
PrimitiveNode pure = layer.getPureLayerNode();
if (pure == null) continue;
curActiveFigure.node = pure;
break;
}
}
}
}
propertyReference = "";
freeSavedPointList();
}
}
private class KeyProtectionFrame extends EDIFKEY
{
private KeyProtectionFrame() { super("protectionFrame"); }
protected void push()
{
curGeometryType = GPROTECTIONFRAME;
}
protected void pop()
{
curGeometryType = GUNKNOWN;
}
}
private class KeyPt extends EDIFKEY
{
private KeyPt() { super("pt"); }
protected void push()
throws IOException
{
// get the x and y values of the point
String xStr = getToken((char)0);
if (xStr == null) throw new IOException("Unexpected end-of-file");
String yStr = getToken((char)0);
if (yStr == null) throw new IOException("Unexpected end-of-file");
if (keyStackDepth > 1 && keyStack[keyStackDepth-1] == KDELTA)
{
double x = TextUtils.atof(xStr) * localPrefs.inputScale;
double y = TextUtils.atof(yStr) * localPrefs.inputScale;
// transform the points per orientation
if (curOrientation == OR90) { double s = x; x = -y; y = s; } else
if (curOrientation == OR180) { x = -x; y = -y; } else
if (curOrientation == OR270) { double s = x; x = y; y = -s; } else
if (curOrientation == OMY) { x = -x; } else
if (curOrientation == OMX) { y = -y; } else
if (curOrientation == OMYR90) { double s = y; y = -x; x = -s; } else
if (curOrientation == OMXR90) { double s = x; x = y; y = s; }
// set the array deltas
if (!deltaPointsSet)
{
deltaPointXX = x;
deltaPointXY = y;
} else
{
deltaPointYX = x;
deltaPointYY = y;
}
deltaPointsSet = true;
} else
{
// allocate a point to read
Point2D point = new Point2D.Double(TextUtils.atof(xStr) * localPrefs.inputScale, TextUtils.atof(yStr) * localPrefs.inputScale);
// add it to the list of points
curPoints.add(point);
}
}
}
private class KeyRectangle extends EDIFKEY
{
private KeyRectangle() { super("rectangle"); }
protected void push()
{
freePointList();
curOrientation = OR0;
}
protected void pop()
{
if (keyStackDepth > 1 && (keyStack[keyStackDepth-1] == KPAGESIZE ||
keyStack[keyStackDepth-1] == KBOUNDINGBOX))
{
freePointList();
return;
}
if (curPoints.size() == 2)
{
// create the node instance
Point2D p0 = curPoints.get(0);
Point2D p1 = curPoints.get(1);
double hX = p1.getX();
double lX = p0.getX();
if (p0.getX() > p1.getX())
{
lX = p1.getX();
hX = p0.getX();
}
double hY = p1.getY();
double lY = p0.getY();
if (p0.getY() > p1.getY())
{
lY = p1.getY();
hY = p0.getY();
}
double sX = hX - lX;
double sY = hY - lY;
double yPos = (lY+hY)/2;
double xPos = (lX+hX)/2;
if (curCellPage > 0) yPos += (curCellPage-1) * Cell.FrameDescription.MULTIPAGESEPARATION;
if (curGeometryType == GPROTECTIONFRAME)
{
// inside a protection frame
PrimitiveNode eb = Generic.tech().essentialBoundsNode;
double wid = eb.getDefWidth();
double hei = eb.getDefHeight();
NodeInst ni1 = NodeInst.makeInstance(eb, new Point2D.Double(hX, hY), wid, hei, curCell, Orientation.IDENT, null);
NodeInst ni2 = NodeInst.makeInstance(eb, new Point2D.Double(lX, hY), wid, hei, curCell, Orientation.R, null);
NodeInst ni3 = NodeInst.makeInstance(eb, new Point2D.Double(lX, lY), wid, hei, curCell, Orientation.RR, null);
NodeInst ni4 = NodeInst.makeInstance(eb, new Point2D.Double(hX, lY), wid, hei, curCell, Orientation.RRR, null);
if (ni1 != null) ni1.setHardSelect();
if (ni2 != null) ni2.setHardSelect();
if (ni3 != null) ni3.setHardSelect();
if (ni4 != null) ni4.setHardSelect();
} else
{
NodeInst ni = NodeInst.makeInstance(curFigureGroup != null ? curFigureGroup : Artwork.tech().boxNode,
new Point2D.Double(xPos, yPos), sX, sY, curCell, curOrientation, null);
if (ni == null)
{
System.out.println("Error, line " + lineReader.getLineNumber() + ": could not create rectangle");
errorCount++;
} else if (curFigureGroup == Artwork.tech().openedDottedPolygonNode)
{
EPoint [] pts = new EPoint[5];
pts[0] = new EPoint(p0.getX(), p0.getY());
pts[1] = new EPoint(p0.getX(), p1.getY());
pts[2] = new EPoint(p1.getX(), p1.getY());
pts[3] = new EPoint(p1.getX(), p0.getY());
pts[4] = new EPoint(p0.getX(), p0.getY());
// store the trace information
ni.setTrace(pts);
} else if (curGeometryType == GPORTIMPLEMENTATION)
{
// inside a PortImplementation
String exportName = renamedObjects.get(objectName);
if (exportName == null) exportName = objectName;
PlannedPort plp = addPlannedPort(exportName);
plp.pinType = cellRefProto;
plp.knownLocation = true;
plp.x = (lX+hX) / 2;
plp.y = (lY+hY) / 2;
if (curCellPage > 0) plp.y += (curCellPage-1) * Cell.FrameDescription.MULTIPAGESEPARATION;
} else if (nodesOnNet != null)
{
nodesOnNet.add(ni);
}
}
}
freePointList();
}
}
private class KeyRename extends EDIFKEY
{
private KeyRename() { super("rename"); }
protected void push()
throws IOException
{
// get the name of the object
String aName = getToken((char)0);
objectName = aName;
// and the original name
positionToNextToken();
char chr = inputBuffer.charAt(inputBufferPos);
if (chr == '(')
{
// must be stringDisplay, copy name to original
originalName = objectName;
} else
{
aName = getToken((char)0);
// copy name without quotes
originalName = aName.substring(1, aName.length()-1);
}
originalName = fixAngleBracketBusses(fixLeadingAmpersand(originalName));
int kPtr = keyStackDepth;
if (keyStack[keyStackDepth - 1] == KNAME) kPtr = keyStackDepth - 1;
if (keyStack[kPtr - 1] == KARRAY) kPtr = kPtr - 2; else
kPtr = kPtr -1;
if (keyStack[kPtr] == KCELL)
{
cellName = cellReference = originalName;
} else if (keyStack[kPtr] == KPORT)
{
// convert <> to [] in port names
portReference = portName = originalName;
} else if (keyStack[kPtr] == KINSTANCE)
{
instanceReference = instanceName = originalName;
} else if (keyStack[kPtr] == KNETBUNDLE)
{
bundleReference = bundleName = originalName;
} else if (keyStack[kPtr] == KNET)
{
netReference = netName = originalName;
} else if (keyStack[kPtr] == KPROPERTY)
{
propertyReference = objectName;
}
if (!objectName.equals(originalName))
renamedObjects.put(objectName, originalName);
}
}
private class KeyString extends EDIFKEY
{
private KeyString() { super("string"); }
protected void push()
throws IOException
{
positionToNextToken();
char chr = inputBuffer.charAt(inputBufferPos);
if (chr != '(' && chr != ')')
{
String value = getToken((char)0);
if (value == null) throw new IOException("Unexpected end-of-file");
propertyValue = value.substring(1, value.length()-1);
}
}
}
private class KeyStringDisplay extends EDIFKEY
{
private KeyStringDisplay() { super("stringDisplay"); }
protected void push()
throws IOException
{
// init the point lists
freePointList();
curOrientation = OR0;
textJustification = TextDescriptor.Position.DOWNRIGHT;
textHeight = 0;
// get the string, remove the quote
getDelimeter('\"');
textString = getToken('\"');
if (textString == null) throw new IOException("Unexpected end-of-file");
// check for RENAME
if (keyStack[keyStackDepth-1] != KRENAME) return;
originalName = fixAngleBracketBusses(textString);
int kPtr = keyStackDepth - 2;
if (keyStack[keyStackDepth - 2] == KARRAY) kPtr = keyStackDepth - 3;
if (keyStack[kPtr] == KCELL)
{
cellName = fixLeadingAmpersand(originalName);
} else if (keyStack[kPtr] == KPORT)
{
portName = fixLeadingAmpersand(originalName);
} else if (keyStack[kPtr] == KINSTANCE)
{
instanceName = originalName;
} else if (keyStack[kPtr] == KNET)
{
netName = fixLeadingAmpersand(originalName);
} else if (keyStack[kPtr] == KNETBUNDLE)
{
bundleName = originalName;
}
}
protected void pop()
{
if (keyStackDepth <= 1)
{
System.out.println("Error, line " + lineReader.getLineNumber() + ": bad location for \"stringDisplay\"");
errorCount++;
} else if (keyStack[keyStackDepth-1] == KRENAME)
{
// save the data and break
freeSavedPointList();
textString = "";
saveTextPoints = curPoints;
curPoints = new ArrayList<Point2D>();
saveTextHeight = textHeight;
textHeight = 0;
saveTextJustification = textJustification;
textJustification = TextDescriptor.Position.DOWNRIGHT;
curOrientation = OR0;
}
// // output the data for annotate (display graphics) and string (on properties)
// else if (keyStack[keyStackDepth-1] == KANNOTATE || keyStack[keyStackDepth-1] == KSTRING)
// {
// // Suppress this if it starts with "["
// if (!textString.startsWith("[") && curPoints.size() != 0)
// {
// // see if a pre-existing node or arc exists to add text
// ArcInst ai = null;
// NodeInst ni = null;
// String key = propertyReference;
// Point2D p0 = curPoints.get(0);
// double xOff = 0, yOff = 0;
// if (propertyReference.length() > 0 && curNode != null)
// {
// ni = curNode;
// xOff = p0.getX() - ni.getAnchorCenterX();
// yOff = p0.getY() - ni.getAnchorCenterY();
// }
// else if (propertyReference.length() > 0 && curArc != null)
// {
// ai = curArc;
// xOff = p0.getX() - (ai.getHeadLocation().getX() + ai.getTailLocation().getX()) / 2;
// yOff = p0.getY() - (ai.getHeadLocation().getY() + ai.getTailLocation().getY()) / 2;
// } else
// {
// // create the node instance
// double xPos = p0.getX();
// double yPos = p0.getY();
// if (curCellPage > 0) yPos += (curCellPage-1) * Cell.FrameDescription.MULTIPAGESEPARATION;
// ni = NodeInst.makeInstance(Generic.tech().invisiblePinNode, new Point2D.Double(xPos, yPos), 0, 0, curCell);
// key = Artwork.ART_MESSAGE.getName(); // "EDIF_annotate";
// }
// if (ni != null || ai != null)
// {
// Variable.Key varKey = Variable.newKey(key);
// // determine the size of text, 0.0278 in == 2 points or 36 (2xpixels) == 1 in fonts range from 4 to 31
// double relSize = convertTextSize(textHeight);
// if (ni != null)
// {
// TextDescriptor td = TextDescriptor.getNodeTextDescriptor();
// // now set the position, relative to the center of the current object
// xOff = p0.getX() - ni.getAnchorCenterX();
// yOff = p0.getY() - ni.getAnchorCenterY();
// td = td.withDisplay(true).withRelSize(relSize).withPos(textJustification).withOff(xOff, yOff);
// ni.newVar(varKey, textString, td);
// } else
// {
// TextDescriptor td = TextDescriptor.getArcTextDescriptor();
// // now set the position, relative to the center of the current object
// xOff = p0.getX() - (ai.getHeadLocation().getX() + ai.getTailLocation().getX()) / 2;
// yOff = p0.getY() - (ai.getHeadLocation().getY() + ai.getTailLocation().getY()) / 2;
// td = td.withDisplay(true).withRelSize(relSize).withPos(textJustification).withOff(xOff, yOff);
// ai.newVar(varKey, textString, td);
// }
// } else
// {
// System.out.println("Error, line " + lineReader.getLineNumber() + ": nothing to attach text to");
// errorCount++;
// }
// }
// }
// clean up DISPLAY attributes
freePointList();
textJustification = TextDescriptor.Position.DOWNRIGHT;
textHeight = 0;
}
}
private class KeySymbol extends EDIFKEY
{
private KeySymbol() { super("symbol"); }
protected void push()
{
symbolDefined = true;
}
}
private class KeyTextHeight extends EDIFKEY
{
private KeyTextHeight() { super("textHeight"); }
protected void push()
throws IOException
{
// get the textheight value of the point
String val = getToken((char)0);
textHeight = TextUtils.atoi(val) * localPrefs.inputScale;
if (curActiveFigure != null)
curActiveFigure.textHeight = textHeight;
}
}
private class KeyTrue extends EDIFKEY
{
private KeyTrue() { super("true"); }
protected void push()
{
propertyValue = new Boolean(true);
}
}
private class KeyUnit extends EDIFKEY
{
private KeyUnit() { super("unit"); }
protected void push()
throws IOException
{
getToken((char)0);
}
}
private class KeyUnused extends EDIFKEY
{
private KeyUnused() { super("unused"); }
protected void push()
throws IOException
{
curDirection = PortCharacteristic.UNKNOWN;
}
}
private class KeyView extends EDIFKEY
{
private KeyView() { super("view"); }
protected void push()
{
activeView = VNULL;
mappedNodes = new HashMap<String,EDIFEquiv.NodeEquivalence>();
}
protected void pop()
{
if (curVendor == EVVIEWLOGIC && activeView != VNETLIST)
{
// now scan for BUS nets, and verify all wires connected to bus
HashSet<ArcInst> seenArcs = new HashSet<ArcInst>();
for(Iterator<ArcInst> it = curCell.getArcs(); it.hasNext(); )
{
ArcInst ai = it.next();
if (!seenArcs.contains(ai) && ai.getProto() == Schematics.tech().bus_arc)
{
// get name of arc
String baseName = ai.getName();
int openPos = baseName.indexOf('[');
if (openPos >= 0) baseName = baseName.substring(0, openPos);
// expand this arc, and locate non-bracketed names
checkBusNames(ai, baseName, seenArcs);
}
}
}
mappedNodes = null;
}
}
private class ViewRef extends EDIFKEY
{
private ViewRef() { super("viewRef"); }
protected void push()
throws IOException
{
viewRef = getToken((char)0);
}
protected void pop()
{
viewRef = null;
}
}
/**
* viewType: Indicates the view style for this cell, ie
* BEHAVIOR, DOCUMENT, GRAPHIC, LOGICMODEL, MASKLAYOUT, NETLIST,
* PCBLAYOUT, SCHEMATIC, STRANGER, SYMBOLIC.
*/
private class KeyViewType extends EDIFKEY
{
private KeyViewType() { super("viewType"); }
protected void push()
throws IOException
{
// get the viewType
String aName = getToken((char)0);
if (aName.equalsIgnoreCase("BEHAVIOR")) activeView = VBEHAVIOR; else
if (aName.equalsIgnoreCase("DOCUMENT")) activeView = VDOCUMENT; else
if (aName.equalsIgnoreCase("GRAPHIC")) activeView = VGRAPHIC; else
if (aName.equalsIgnoreCase("LOGICMODEL")) activeView = VLOGICMODEL; else
if (aName.equalsIgnoreCase("MASKLAYOUT")) activeView = VMASKLAYOUT; else
if (aName.equalsIgnoreCase("NETLIST")) activeView = VNETLIST; else
if (aName.equalsIgnoreCase("PCBLAYOUT")) activeView = VPCBLAYOUT; else
if (aName.equalsIgnoreCase("SCHEMATIC")) activeView = VSCHEMATIC; else
if (aName.equalsIgnoreCase("STRANGER")) activeView = VSTRANGER; else
if (aName.equalsIgnoreCase("SYMBOLIC")) activeView = VSYMBOLIC;
// add the name to the cellTable
NameEntry nt = new NameEntry();
nt.original = cellReference;
nt.replace = cellName;
cellTable.put(cellReference, nt);
}
}
}