/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: ELIB.java * Input/output tool: ELIB Library input * Written by Steven M. Rubin, Sun Microsystems. * * Copyright (c) 2003 Sun Microsystems and Static Free Software * * Electric(tm) is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Electric(tm) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Electric(tm); see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, Mass 02111-1307, USA. */ package com.sun.electric.tool.io.input; import com.sun.electric.database.ImmutableArcInst; import com.sun.electric.database.ImmutableExport; import com.sun.electric.database.geometry.EPoint; import com.sun.electric.database.geometry.GenMath; import com.sun.electric.database.geometry.Orientation; import com.sun.electric.database.geometry.Poly; import com.sun.electric.database.hierarchy.Cell; import com.sun.electric.database.hierarchy.Export; import com.sun.electric.database.hierarchy.Library; import com.sun.electric.database.hierarchy.View; import com.sun.electric.database.id.ArcProtoId; import com.sun.electric.database.id.CellId; import com.sun.electric.database.id.ExportId; import com.sun.electric.database.id.IdManager; import com.sun.electric.database.id.LibId; import com.sun.electric.database.id.NodeProtoId; import com.sun.electric.database.id.PrimitiveNodeId; import com.sun.electric.database.id.PrimitivePortId; import com.sun.electric.database.id.TechId; 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.text.TextUtils; import com.sun.electric.database.text.Version; import com.sun.electric.database.topology.ArcInst; import com.sun.electric.database.topology.NodeInst; import com.sun.electric.database.topology.PortInst; 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.PrimitiveNode; import com.sun.electric.technology.PrimitivePort; 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.Tool; import com.sun.electric.tool.io.ELIBConstants; import com.sun.electric.tool.io.FileType; import com.sun.electric.tool.ncc.basic.TransitiveRelation; import com.sun.electric.tool.user.ErrorLogger; import com.sun.electric.tool.user.IconParameters; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; import java.net.URL; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeSet; /** * This class reads files in binary (.elib) format. */ public class ELIB extends LibraryFiles { public static class Header implements Comparable, Serializable { /** current header */ static final Header DEFAULT = new Header(ELIBConstants.MAGIC13, ByteOrder.BIG_ENDIAN, 4, 2, 1); /** the magic number in the library file */ private final int magic; // characteristics of the file /** byte order on disk */ private transient ByteOrder byteOrder; /** true if BIG_ENDIAN byte order on disk */ private final boolean bytesSwapped; /** the size of a "big" integer on disk (4 or more bytes) */ private final int sizeOfBig; /** the size of a "small" integer on disk (2 or more bytes) */ private final int sizeOfSmall; /** the size of a character on disk (1 or 2 bytes) */ private final int sizeOfChar; /** string description */ private final String s; Header(int magic, ByteOrder byteOrder, int sizeOfBig, int sizeOfSmall, int sizeOfChar) { this.magic = magic; this.byteOrder = byteOrder; this.bytesSwapped = (byteOrder == ByteOrder.BIG_ENDIAN); this.sizeOfBig = sizeOfBig; this.sizeOfSmall = sizeOfSmall; this.sizeOfChar = sizeOfChar; int magicNum = ELIBConstants.MAGIC1 + 2 - magic; String s = "MAGIC" + (magicNum/2); if (magicNum%2 != 0) s += "?"; if (byteOrder != ByteOrder.BIG_ENDIAN) s += "L"; if (sizeOfBig != 4) s += "I" + sizeOfBig; if (sizeOfSmall != 2) s += "S" + sizeOfSmall; if (sizeOfChar != 1) s += "C" + sizeOfChar; this.s = s; } private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); byteOrder = bytesSwapped ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; } /** * Returns a hash code for this <code>Header</code>. * @return a hash code value for this Header. */ @Override public int hashCode() { return s.hashCode(); } /** * Compares this Header object to the specified object. The result is * <code>true</code> if and only if the argument is not * <code>null</code> and is an <code>Header</code> object that * contains the same <code>version</code>, <code>view</code> and case-insensitive <code>name</code> as this Header. * * @param obj the object to compare with. * @return <code>true</code> if the objects are the same; * <code>false</code> otherwise. */ @Override public boolean equals(Object obj) { if (obj instanceof Header) { Header h = (Header)obj; return s.equals(h.s); } return false; } /** * Compares two <code>Header</code> objects. * @param o the object to be compared. * @return the result of comparision. */ public int compareTo(Object o) { Header h = (Header)o; return TextUtils.STRING_NUMBER_ORDER.compare(s, h.s); } /** * Returns string description of this Header. * @return the string description of this Header. */ @Override public String toString() { return s; } } // ------------------------- private data ---------------------------- /** header of the file */ private Header header; // statistics about the file /** the number of integers on disk that got clipped during input */ private int clippedIntegers; // the tool information /** the number of tools in the file */ private int toolCount; /** the number of tools in older files */ private int toolBCount; /** list of all tools in the library */ private Tool [] toolList; /** list of all tool-related errors in the library */ private String [] toolError; /** list of all tool variables */ private Variable [][] toolVars; /** the library userbits */ private int libUserBits; /** the library variables */ private Variable[] libVars; // the technology information /** the number of technologies in the file */ private int techCount; /** list of all TechIds in the library */ private TechId [] techIdList; /** list of all Technologies in the library */ private Technology [] techList; /** list of all technology-related errors in the library */ private String [] techError; /** list of all technology variables in the library */ private Variable [][] techVars; /** list of technology lambda values in the library */ private int [] techLambda; /** scale factors for each technology in the library */ private HashMap<Technology,Double> techScale = new HashMap<Technology,Double>(); /** the number of ArcProtos in the file */ private int arcProtoCount; /** list of all ArcProtoIds in the library */ private ArcProtoId [] arcProtoIdList; /** list of all ArcProtos in the library */ private ArcProto [] arcProtoList; /** list of all ArcProto-related errors in the library */ private String [] arcProtoError; /** the number of primitive NodeProtos in the file */ private int primNodeProtoCount; /** list of all PrimitiveNodeIds in the library */ private PrimitiveNodeId [] primitiveNodeIdList; /** list of all Primitive NodeProtos in the library */ private PrimitiveNode [] primNodeProtoList; /** list of the primitive-NodeProto-related errors in the library */ private boolean [] primNodeProtoError; /** list of the original primitive NodeProtos in the library */ private String [] primNodeProtoOrig; /** list of all NodeProto technologies in the library */ private int [] primNodeProtoTech; /** the number of primitive PortProtos in the file */ private int primPortProtoCount; /** list of all PrimitivePortIds in the library */ private PrimitivePortId [] primitivePortIdList; /** list of all Primitive PortProtos in the library */ private PrimitivePort [] primPortProtoList; /** list of all Primitive-PortProto-related errors in the library */ private String [] primPortProtoError; // the cell information /** the number of Cells in the file */ private int cellCount; /** list of all former cells in the library */ private FakeCell [] fakeCellList; /** list of Cell full names in the library */ private String [] cellProtoName; /** list of Cell creation dates in the library */ private int [] cellCreationDate; /** list of Cell revision dates in the library */ private int [] cellRevisionDate; /** list of Cell user bits in the library */ private int [] cellUserBits; /** list of Cell variables in the library */ private Variable [][] cellVars; /** list of Cell low X coordinates in the library */ private int [] cellLowX; /** list of Cell high X coordinates in the library */ private int [] cellHighX; /** list of Cell low Y coordinates in the library */ private int [] cellLowY; /** list of Cell high Y coordinates in the library */ private int [] cellHighY; /** list of Cell library paths in the library */ private String [] cellLibraryPath; /** list of number of NodeInsts in each Cell of the library */ private int [] nodeCounts; /** index of first NodeInst in each cell of the library */ private int [] firstNodeIndex; /** list of number of ArcInsts in each Cell of the library */ private int [] arcCounts; /** index of first ArcInst in each cell of the library */ private int [] firstArcIndex; /** list of all Exports in each Cell of the library */ private int [] portCounts; /** index of first Export in each cell of the library */ private int [] firstPortIndex; /** X center each cell of the library */ private int [] cellXOff; /** Y center each cell of the library */ private int [] cellYOff; /** a next cell index in the same next group of the library */ private int [] cellNextInCellGroup; /** true if this x-lib cell ref is satisfied */ private boolean [] xLibRefSatisfied; /** mapping view indices to views */ private HashMap<Integer,View> viewMapping; // the NodeInsts in the library /** the number of NodeInsts in the library */ private int nodeCount; /** All data for NodeInsts in each Cell. */ private LibraryFiles.NodeInstList nodeInstList; /** List of prototypes of the NodeInsts in the library */ private int [] nodeTypeList; // the ArcInsts in the library /** the number of ArcInsts in the library */ private int arcCount; /** list of all ArcInsts in the library */ private ArcInst [] arcList; /** list of the prototype of the ArcInsts in the library */ private int [] arcTypeList; /** list of the Names of the ArcInsts in the library */ private String [] arcNameList; /** list of the name descriptors of the ArcInsts in the library */ private TextDescriptor[] arcNameDescriptorList; /** list of the width of the ArcInsts in the library */ private int [] arcWidthList; /** list of the head X of the ArcInsts in the library */ private int [] arcHeadXPosList; /** list of the head Y of the ArcInsts in the library */ private int [] arcHeadYPosList; /** list of the head node of the ArcInsts in the library */ private int [] arcHeadNodeList; /** list of the head port of the ArcInsts in the library */ private int [] arcHeadPortList; /** list of the tail X of the ArcInsts in the library */ private int [] arcTailXPosList; /** list of the tail Y of the ArcInsts in the library */ private int [] arcTailYPosList; /** list of the tail node of the ArcInsts in the library */ private int [] arcTailNodeList; /** list of the tail port of the ArcInsts in the library */ private int [] arcTailPortList; /** list of the user flags on the ArcInsts in the library */ private int [] arcUserBits; /** list of the variables on the ArcInsts in the library */ private Variable [][] arcVariables; // the Exports in the library /** the number of Exports in the library */ private int exportCount; /** counter for Exports in the library */ private int exportIndex; /** list of all Exports in the library */ private Object [] exportList; /** list of NodeInsts that are origins of Exports in the library */ private int [] exportSubNodeList; /** list of PortProtos that are origins of Exports in the library */ private int [] exportSubPortList; /** list of Export names in the library */ private String [] exportNameList; /** list of Export name descriptors in the library */ private TextDescriptor[] exportNameDescriptors; /** list of Export userbits in the library */ private int [] exportUserbits; /** list of variables on Exports in the library */ private Variable [][] exportVariables; // the geometric information (only used for old format files) /** the number of Geometrics in the file */ private int geomCount; /** list of all Geometric types in the library */ private boolean [] geomType; /** list of all Geometric up-pointers in the library */ private int [] geomMoreUp; // the variable information /** variable names possibly in the library */ private String varNames[]; /** variable keys possibly in the library */ private Variable.Key[] varKeys; /** true to convert all text descriptor values */ private boolean convertTextDescriptors; /** true to require text descriptor values */ private boolean alwaysTextDescriptors; /** icon parameters for exports */ private IconParameters iconParameters; /** * This class is used to convert old "facet" style Libraries to pure Cell Libraries. */ private static class FakeCell { String cellName; NodeProto firstInCell; } ELIB(IconParameters iconParams) { iconParameters = iconParams; } // ----------------------- public methods ------------------------------- /** * Method to read a Library from disk. * This method is for reading full Electric libraries in ELIB, JELIB, and Readable Dump format. * @param fileURL the URL to the disk file. * @return the read Library, or null if an error occurred. */ // public static synchronized Header readLibraryHeader(URL fileURL, ErrorLogger errorLogger) // { // try { // ELIB in = new ELIB(); // if (in.openBinaryInput(fileURL)) return null; // Header header = in.readHeader(); // // read the library // in.closeInput(); // return header; // } catch (Exception e) // { // errorLogger.logError("Error " + e + " on " + fileURL, -1); // } // return null; // } /** * Method to read a Library from disk. * This method is for reading full Electric libraries in ELIB, JELIB, and Readable Dump format. * @param fileURL the URL to the disk file. * @return the read Library, or null if an error occurred. */ public static synchronized boolean readStatistics(URL fileURL, ErrorLogger errorLogger, LibraryStatistics.FileContents fc) { try { ELIB in = new ELIB(null); if (in.openBinaryInput(fileURL)) return true; boolean error = in.readTheLibrary(true, fc); // read the library in.closeInput(); return error; } catch (Exception e) { errorLogger.logError("Error " + e + " on " + fileURL, -1); e.printStackTrace(); } return true; } @Override protected boolean readProjectSettings() { try { if (readTheLibrary(true, null)) return true; createLibraryCells(true); return false; } catch (IOException e) { System.out.println("End of file reached while reading " + filePath); return true; } } /** * Method to read the .elib file. * returns true on error. */ @Override boolean readTheLibrary(boolean onlyProjectSettings, LibraryStatistics.FileContents fc) throws IOException { // initialize clippedIntegers = 0; byteCount = 0; // read the magic number and determine whether bytes are swapped header = readHeader(); if (header == null) { System.out.println("Error reading header"); return true; } if (fc != null) fc.header = header; // get count of objects in the file toolCount = readBigInteger(); techCount = readBigInteger(); primNodeProtoCount = readBigInteger(); primPortProtoCount = readBigInteger(); arcProtoCount = readBigInteger(); nodeProtoCount = readBigInteger(); nodeCount = readBigInteger(); exportCount = readBigInteger(); arcCount = readBigInteger(); geomCount = readBigInteger(); if (header.magic <= ELIBConstants.MAGIC9 && header.magic >= ELIBConstants.MAGIC11) { // versions 9 through 11 stored a "cell count" cellCount = readBigInteger(); } else { cellCount = nodeProtoCount; } readBigInteger(); // ignore current cell // get the Electric version (version 8 and later) String versionString; if (header.magic <= ELIBConstants.MAGIC8) versionString = readString(); else versionString = "3.35"; version = Version.parseVersion(versionString); if (fc != null) fc.version = version; // for versions before 6.03q, convert MOSIS CMOS technology names convertMosisCmosTechnologies = version.compareTo(Version.parseVersion("6.03q")) < 0; // for versions before 6.04c, convert text descriptor values convertTextDescriptors = version.compareTo(Version.parseVersion("6.04c")) < 0; // for versions 6.05x and later, always have text descriptor values alwaysTextDescriptors = version.compareTo(Version.parseVersion("6.05x")) >= 0; // for Electric version 4 or earlier, scale lambda by 20 scaleLambdaBy20 = version.compareTo(Version.parseVersion("5")) < 0; // mirror bits rotationMirrorBits = version.compareTo(Version.parseVersion("7.01")) >= 0; // get the newly created views (version 9 and later) viewMapping = new HashMap<Integer,View>(); viewMapping.put(new Integer(-1), View.UNKNOWN); viewMapping.put(new Integer(-2), View.LAYOUT); viewMapping.put(new Integer(-3), View.SCHEMATIC); viewMapping.put(new Integer(-4), View.ICON); viewMapping.put(new Integer(-5), View.DOCWAVE); viewMapping.put(new Integer(-6), View.LAYOUTSKEL); viewMapping.put(new Integer(-7), View.VHDL); viewMapping.put(new Integer(-8), View.NETLIST); viewMapping.put(new Integer(-9), View.DOC); viewMapping.put(new Integer(-10), View.NETLISTNETLISP); viewMapping.put(new Integer(-11), View.NETLISTALS); viewMapping.put(new Integer(-12), View.NETLISTQUISC); viewMapping.put(new Integer(-13), View.NETLISTRSIM); viewMapping.put(new Integer(-14), View.NETLISTSILOS); viewMapping.put(new Integer(-15), View.VERILOG); viewMapping.put(new Integer(-16), View.LAYOUTCOMP); if (header.magic <= ELIBConstants.MAGIC9) { int numExtraViews = readBigInteger(); for(int i=0; i<numExtraViews; i++) { String viewName = readString(); String viewShortName = readString(); View view = View.findView(viewName); if (view == null) { // special conversion from old view names view = findOldViewName(viewName); if (view == null && !onlyProjectSettings) { view = View.newInstance(viewName, viewShortName); if (view == null) return true; } } viewMapping.put(new Integer(i+1), view); } } // get the number of toolbits to ignore if (header.magic <= ELIBConstants.MAGIC3 && header.magic >= ELIBConstants.MAGIC6) { // versions 3, 4, 5, and 6 find this in the file toolBCount = readBigInteger(); } else { // versions 1 and 2 compute this (versions 7 and later ignore it) toolBCount = toolCount; } // allocate pointers for the Technologies techIdList = new TechId[techCount]; techList = new Technology[techCount]; techError = new String[techCount]; techVars = new Variable[techCount][]; techLambda = new int[techCount]; arcProtoIdList = new ArcProtoId[arcProtoCount]; arcProtoList = new ArcProto[arcProtoCount]; arcProtoError = new String[arcProtoCount]; primitiveNodeIdList = new PrimitiveNodeId[primNodeProtoCount]; primNodeProtoList = new PrimitiveNode[primNodeProtoCount]; primNodeProtoError = new boolean[primNodeProtoCount]; primNodeProtoOrig = new String[primNodeProtoCount]; primNodeProtoTech = new int[primNodeProtoCount]; primitivePortIdList = new PrimitivePortId[primPortProtoCount]; primPortProtoList = new PrimitivePort[primPortProtoCount]; primPortProtoError = new String[primPortProtoCount]; // allocate pointers for the Tools toolList = new Tool[toolCount]; toolError = new String[toolCount]; toolVars = new Variable[toolCount][]; // allocate pointers for the Cells nodeProtoList = new Cell[nodeProtoCount]; cellProtoName = new String[nodeProtoCount]; cellCreationDate = new int[nodeProtoCount]; cellRevisionDate = new int[nodeProtoCount]; cellUserBits = new int[nodeProtoCount]; cellVars = new Variable[nodeProtoCount][]; cellLowX = new int[nodeProtoCount]; cellHighX = new int[nodeProtoCount]; cellLowY = new int[nodeProtoCount]; cellHighY = new int[nodeProtoCount]; cellLibraryPath = new String[nodeProtoCount]; nodeCounts = new int[nodeProtoCount]; firstNodeIndex = new int[nodeProtoCount+1]; arcCounts = new int[nodeProtoCount]; firstArcIndex = new int[nodeProtoCount+1]; portCounts = new int[nodeProtoCount]; firstPortIndex = new int[nodeProtoCount]; cellLambda = new double[nodeProtoCount]; cellXOff = new int[nodeProtoCount]; cellYOff = new int[nodeProtoCount]; cellNextInCellGroup = new int[nodeProtoCount]; xLibRefSatisfied = new boolean[nodeProtoCount]; Arrays.fill(cellNextInCellGroup, -1); // allocate pointers for the NodeInsts boolean hasAnchor = header.magic <= ELIBConstants.MAGIC13; nodeInstList = new LibraryFiles.NodeInstList(nodeCount, hasAnchor); nodeTypeList = new int[nodeCount]; // allocate pointers for the ArcInsts arcList = new ArcInst[arcCount]; arcTypeList = new int[arcCount]; arcNameList = new String[arcCount]; arcNameDescriptorList = new TextDescriptor[arcCount]; arcWidthList = new int[arcCount]; arcHeadXPosList = new int[arcCount]; arcHeadYPosList = new int[arcCount]; arcHeadNodeList = new int[arcCount]; arcHeadPortList = new int[arcCount]; arcTailXPosList = new int[arcCount]; arcTailYPosList = new int[arcCount]; arcTailNodeList = new int[arcCount]; arcTailPortList = new int[arcCount]; arcUserBits = new int[arcCount]; arcVariables = new Variable[arcCount][]; for(int i = 0; i < arcCount; i++) { arcHeadNodeList[i] = -1; arcHeadPortList[i] = -1; arcTailNodeList[i] = -1; arcTailPortList[i] = -1; arcNameList[i] = null; arcUserBits[i] = 0; } // allocate pointers for the Exports exportList = new Object[exportCount]; exportSubNodeList = new int[exportCount]; exportSubPortList = new int[exportCount]; exportNameList = new String[exportCount]; exportNameDescriptors = new TextDescriptor[exportCount]; exportUserbits = new int[exportCount]; exportVariables = new Variable[exportCount][]; // versions 9 to 11 allocate fake-cell pointers if (header.magic <= ELIBConstants.MAGIC9 && header.magic >= ELIBConstants.MAGIC11) { fakeCellList = new FakeCell[cellCount]; for(int i=0; i<cellCount; i++) fakeCellList[i] = new FakeCell(); } // versions 4 and earlier allocate geometric pointers if (header.magic > ELIBConstants.MAGIC5) { geomType = new boolean [geomCount]; geomMoreUp = new int [geomCount]; } // get number of arcinsts and nodeinsts in each cell if (header.magic != ELIBConstants.MAGIC1) { // versions 2 and later find this in the file int nodeInstPos = 0, arcInstPos = 0, portProtoPos = 0; for(int i=0; i<nodeProtoCount; i++) { arcCounts[i] = readBigInteger(); nodeCounts[i] = readBigInteger(); portCounts[i] = readBigInteger(); // the arc and node counts are negative for external cell references if (arcCounts[i] > 0 || nodeCounts[i] > 0) { arcInstPos += arcCounts[i]; nodeInstPos += nodeCounts[i]; } portProtoPos += portCounts[i]; } // verify that the number of node instances is equal to the total in the file if (nodeInstPos != nodeCount) { System.out.println("Error: cells have " + nodeInstPos + " nodes but library has " + nodeCount); return true; } if (arcInstPos != arcCount) { System.out.println("Error: cells have " + arcInstPos + " arcs but library has " + arcCount); return true; } if (portProtoPos != exportCount) { System.out.println("Error: cells have " + portProtoPos + " ports but library has " + exportCount); return true; } } else { // version 1 computes this information arcCounts[0] = arcCount; nodeCounts[0] = nodeCount; portCounts[0] = exportCount; for(int i=1; i<nodeProtoCount; i++) arcCounts[i] = nodeCounts[i] = portCounts[i] = 0; } // // allocate all cells in the library // for(int i=0; i<nodeProtoCount; i++) // { // if (arcCounts[i] < 0 && nodeCounts[i] < 0) // { // // this cell is from an external library // nodeProtoList[i] = null; // xLibRefSatisfied[i] = false; // } else // { // nodeProtoList[i] = Cell.lowLevelAllocate(lib); // if (nodeProtoList[i] == null) return true; // xLibRefSatisfied[i] = true; // } // } // setup pointers for technology and primitive ids IdManager idManager = fc != null ? fc.idManager() : this.idManager; primNodeProtoCount = 0; primPortProtoCount = 0; arcProtoCount = 0; for(int techIndex=0; techIndex<techCount; techIndex++) { // get the technology String name = readString(); TechId techId = idManager.newTechId(name); techIdList[techIndex] = techId; // get the number of primitive node prototypes int numPrimNodes = readBigInteger(); for(int j=0; j<numPrimNodes; j++) { name = readString(); PrimitiveNodeId primitiveNodeId = techId.newPrimitiveNodeId(name); primitiveNodeIdList[primNodeProtoCount] = primitiveNodeId; primNodeProtoTech[primNodeProtoCount] = techIndex; // get the number of primitive port prototypes int numPrimPorts = readBigInteger(); for(int i=0; i<numPrimPorts; i++) { name = readString(); PrimitivePortId primitivePortId = primitiveNodeId.newPortId(name); primitivePortIdList[primPortProtoCount++] = primitivePortId; } primNodeProtoCount++; } // get the number of arc prototypes int numArcProtos = readBigInteger(); for(int j=0; j<numArcProtos; j++) { name = readString(); ArcProtoId arcProtoId = techId.newArcProtoId(name); arcProtoIdList[arcProtoCount++] = arcProtoId; } } // setup pointers for tools for(int i=0; i<toolCount; i++) { String name = readString(); toolError[i] = null; Tool t = Tool.findTool(name); if (t == null) { toolError[i] = name; } toolList[i] = t; } if (header.magic <= ELIBConstants.MAGIC3 && header.magic >= ELIBConstants.MAGIC6) { // versions 3, 4, 5, and 6 must ignore toolbits associations for(int i=0; i<toolBCount; i++) readString(); } // get the library userbits if (header.magic <= ELIBConstants.MAGIC7) { // version 7 and later simply read the relevant data libUserBits = readBigInteger(); } else { // version 6 and earlier must sift through the information if (toolBCount >= 1) libUserBits = readBigInteger(); for(int i=1; i<toolBCount; i++) readBigInteger(); } // get the lambda values in the library for(int i=0; i<techCount; i++) { techLambda[i] = readBigInteger(); } // read the global namespace readNameSpace(); // read the library variables libVars = readVariables(); for (int i = 0; i < libVars.length; i++) { Variable var = libVars[i]; if (var == null || var.getKey() != Library.FONT_ASSOCIATIONS) continue; Object value = var.getObject(); if (!(value instanceof String[])) continue; setFontNames((String[])value); libVars[i] = null; } // read the tool variables for(int i=0; i<toolCount; i++) { toolVars[i] = readVariables(); } // read the technology variables for(int i=0; i<techCount; i++) { techVars[i] = readVariables(); } // read the arcproto variables for(int i=0; i<arcProtoCount; i++) readVariables(); // read the primitive nodeproto variables for(int i=0; i<primNodeProtoCount; i++) readVariables(); // read the primitive portproto variables for(int i=0; i<primPortProtoCount; i++) readVariables(); // read the view variables (version 9 and later) if (header.magic <= ELIBConstants.MAGIC9) { int count = readBigInteger(); for(int i=0; i<count; i++) { int j = readBigInteger(); View v = getView(j); if (v == null) System.out.println("View index " + j + " not found"); readVariables(); } } // setup fake cell structures (version 9 to 11) if (header.magic <= ELIBConstants.MAGIC9 && header.magic >= ELIBConstants.MAGIC11) { for(int i=0; i<cellCount; i++) { String thecellname = readString(); readVariables(); fakeCellList[i].cellName = convertCellName(thecellname); } } // read the cells exportIndex = 0; for(int i=0; i<nodeProtoCount; i++) { if (arcCounts[i] < 0 && nodeCounts[i] < 0) continue; if (readNodeProto(i)) { System.out.println("Error reading cell"); return true; } } // now read external cells for(int i=0; i<nodeProtoCount; i++) { if (arcCounts[i] >= 0 || nodeCounts[i] >= 0) continue; if (readExternalNodeProto(i)) { System.out.println("Error reading external cell"); return true; } } if (fc != null) { for (int cellIndex = 0; cellIndex < nodeProtoCount; cellIndex++) { if (arcCounts[cellIndex] >= 0 || nodeCounts[cellIndex] >= 0) { fc.localCells.add(cellProtoName[cellIndex]); } else { fc.externalCells.add(new LibraryStatistics.ExternalCell(cellLibraryPath[cellIndex], null, cellProtoName[cellIndex])); } } return false; } // read the cell contents: arcs and nodes int nodeIndex = 0, arcIndex = 0, geomIndex = 0; for(int cellIndex=0; cellIndex<nodeProtoCount; cellIndex++) { Cell cell = nodeProtoList[cellIndex]; firstNodeIndex[cellIndex] = nodeIndex; firstArcIndex[cellIndex] = arcIndex; if (header.magic > ELIBConstants.MAGIC5) { // versions 4 and earlier must read some geometric information int j = geomIndex; readGeom(geomType, geomMoreUp, j); j++; readGeom(geomType, geomMoreUp, j); j++; int top = j; readGeom(geomType, geomMoreUp, j); j++; int bot = j; readGeom(geomType, geomMoreUp, j); j++; for(;;) { readGeom(geomType, geomMoreUp, j); j++; if (geomMoreUp[j-1] == top) break; } geomIndex = j; for(int look = bot; look != top; look = geomMoreUp[look]) if (!geomType[look]) { if (readArcInst(arcIndex)) { System.out.println("Error reading arc"); Input.errorLogger.logError("Error reading arc index "+ arcIndex, cell, 1); return true; } arcIndex++; } else { if (readNodeInst(nodeIndex, cellIndex)) { System.out.println("Error reading node"); Input.errorLogger.logError("Error reading node index "+ nodeIndex, cell, 1); return true; } nodeIndex++; } } else { // version 5 and later find the arcs and nodes in linear order for(int j=0; j<arcCounts[cellIndex]; j++) { if (readArcInst(arcIndex)) { System.out.println("Error reading arc"); Input.errorLogger.logError("Error reading arc index "+ arcIndex, cell, 1); return true; } arcIndex++; } for(int j=0; j<nodeCounts[cellIndex]; j++) { if (readNodeInst(nodeIndex, cellIndex)) { System.out.println("Error reading node index " + nodeIndex + " in " + cell + " of " + lib); Input.errorLogger.logError("Error reading node index " + nodeIndex + " in " + cell + " of " + lib, cell, 1); return true; } nodeIndex++; } } } firstNodeIndex[nodeProtoCount] = nodeIndex; firstArcIndex[nodeProtoCount] = arcIndex; // library read successfully if (LibraryFiles.VERBOSE) System.out.println("Binary: finished reading data for " + lib); return false; } @Override Map<Cell,Variable[]> createLibraryCells(boolean onlyProjectSettings) { // setup pointers for technologies and primitives primNodeProtoCount = 0; primPortProtoCount = 0; arcProtoCount = 0; for(int techIndex=0; techIndex<techCount; techIndex++) { // get the technology TechId techId = techIdList[techIndex]; String name = techId.techName; Technology tech = findTechnologyName(name); boolean imosconv = false; if (name.equals("imos")) { tech = Technology.getMocmosTechnology(); imosconv = true; } if (tech == null) { // cannot figure it out: just pick the generic technology tech = Generic.tech(); techError[techIndex] = name; } else techError[techIndex] = null; techList[techIndex] = tech; // get the number of primitive node prototypes while (primNodeProtoCount < primitiveNodeIdList.length) { PrimitiveNodeId primitiveNodeId = primitiveNodeIdList[primNodeProtoCount]; if (primitiveNodeId.techId != techId) break; primNodeProtoOrig[primNodeProtoCount] = null; primNodeProtoError[primNodeProtoCount] = false; name = primitiveNodeId.name; if (imosconv) name = name.substring(6); PrimitiveNode pnp = tech.findNodeProto(name); if (pnp == null) { // automatic conversion of "Active-Node" in to "P-Active-Node" (MOSIS CMOS) if (name.equals("Active-Node")) pnp = tech.findNodeProto("P-Active-Node"); } if (pnp == null) { boolean advise = true; // look for substring name match at start of name for(Iterator<PrimitiveNode> it = tech.getNodes(); it.hasNext();) { PrimitiveNode opnp = it.next(); String primName = opnp.getName(); if (primName.startsWith(name) || name.startsWith(primName)) { pnp = opnp; break; } } // look for substring match at end of name if (pnp == null) { for(Iterator<PrimitiveNode> it = tech.getNodes(); it.hasNext();) { PrimitiveNode opnp = it.next(); String primName = opnp.getName(); if (primName.endsWith(name) || name.endsWith(primName)) { pnp = opnp; break; } } } // special cases: convert special primitives that are known to the technologies if (pnp == null) { pnp = tech.convertOldNodeName(name); if (pnp != null) advise = false; } // give up and use first primitive in this technology if (pnp == null) { Iterator<PrimitiveNode> it = tech.getNodes(); pnp = it.next(); } // construct the error message if (advise) { String errorMessage; if (techError[techIndex] != null) errorMessage = techError[techIndex]; else errorMessage = tech.getTechName(); errorMessage += ":" + name; primNodeProtoOrig[primNodeProtoCount] = errorMessage; primNodeProtoError[primNodeProtoCount] = true; } } primNodeProtoTech[primNodeProtoCount] = techIndex; primNodeProtoList[primNodeProtoCount] = pnp; // get the number of primitive port prototypes while (primPortProtoCount < primitivePortIdList.length) { PrimitivePortId primitivePortId = primitivePortIdList[primPortProtoCount]; if (primitivePortId.parentId != primitiveNodeId) break; primPortProtoError[primPortProtoCount] = null; name = primitivePortId.externalId; PrimitivePort pp = (PrimitivePort)pnp.findPortProto(name); // convert special port names if (pp == null) pp = tech.convertOldPortName(name, pnp); if (pp == null) { Iterator<PrimitivePort> it = pnp.getPrimitivePorts(); if (it.hasNext()) { pp = it.next(); if (!primNodeProtoError[primNodeProtoCount]) { String errorMessage = name + " on "; if (primNodeProtoOrig[primNodeProtoCount] != null) errorMessage += primNodeProtoOrig[primNodeProtoCount]; else { if (techError[techIndex] != null) errorMessage += techError[techIndex]; else errorMessage += tech.getTechName(); errorMessage += ":" + pnp.getName(); } primPortProtoError[primPortProtoCount] = errorMessage; } } } primPortProtoList[primPortProtoCount++] = pp; } primNodeProtoCount++; } // get the number of arc prototypes while (arcProtoCount < arcProtoIdList.length) { ArcProtoId arcProtoId = arcProtoIdList[arcProtoCount]; if (arcProtoId.techId != techId) break; arcProtoError[arcProtoCount] = null; name = arcProtoId.name; if (imosconv) name = name.substring(6); ArcProto ap = tech.findArcProto(name); if (ap == null) { ap = tech.convertOldArcName(name); } if (ap == null) { Iterator<ArcProto> it = tech.getArcs(); ap = it.next(); String errorMessage; if (techError[techIndex] != null) errorMessage = techError[techIndex]; else errorMessage = tech.getTechName(); errorMessage += ":" + name; arcProtoError[arcProtoCount] = errorMessage; } arcProtoList[arcProtoCount++] = ap; } } // get the lambda values in the library for(int i=0; i<techCount; i++) { int lambda = techLambda[i]; if (techError[i] != null) continue; Technology tech = techList[i]; // for Electric version 4 or earlier, scale lambda by 20 if (scaleLambdaBy20) lambda *= 20; techScale.put(tech, Double.valueOf(lambda)); String varName = tech.getScaleVariableName(); Variable var = Variable.newInstance(Variable.newKey(varName), new Double(lambda/2), TextDescriptor.EMPTY); realizeMeaningPrefs(tech, new Variable[] { var }); } // read the tool variables for(int i=0; i<toolCount; i++) { Tool tool = toolList[i]; if (tool != null) realizeMeaningPrefs(tool, toolVars[i]); } // read the technology variables for(int i=0; i<techCount; i++) { Technology tech = techList[i]; if (tech != null) realizeMeaningPrefs(tech, techVars[i]); // getTechList(i); } if (onlyProjectSettings) return null; // erase the current database lib.erase(); lib.lowLevelSetUserBits(libUserBits); lib.setFromDisk(); lib.setVersion(version); realizeVariables(lib, libVars); // read the cells HashMap<Cell,Variable[]> originalVars = new HashMap<Cell,Variable[]>(); for(int i=0; i<nodeProtoCount; i++) { if (arcCounts[i] < 0 && nodeCounts[i] < 0) continue; xLibRefSatisfied[i] = true; realizeNodeProto(i, originalVars); } // collect the cells by common protoName and by "nextInCellGroup" relation TransitiveRelation<Object> transitive = new TransitiveRelation<Object>(); HashMap<String,String> protoNames = new HashMap<String,String>(); for(int cellIndex=0; cellIndex<nodeProtoCount; cellIndex++) { Cell cell = nodeProtoList[cellIndex]; if (cell == null || cell.getLibrary() != lib) continue; String protoName = protoNames.get(cell.getName()); if (protoName == null) { protoName = cell.getName(); protoNames.put(protoName, protoName); } transitive.theseAreRelated(cell, protoName); Cell otherCell = null; int nextInCell = cellNextInCellGroup[cellIndex]; if (nextInCell >= 0) otherCell = nodeProtoList[nextInCell]; if (otherCell != null && cell.getLibrary() == lib) transitive.theseAreRelated(cell, otherCell); } // // link the cells // for(int cellIndex=0; cellIndex<nodeProtoCount; cellIndex++) // { // Cell cell = nodeProtoList[cellIndex]; // if (cell == null) continue; // cell.lowLevelLink(); // } // join the cell groups for (Iterator<Set<Object>> git = transitive.getSetsOfRelatives(); git.hasNext();) { Set<Object> group = git.next(); Cell firstCell = null; for (Object o : group) { if (!(o instanceof Cell)) continue; Cell cell = (Cell)o; if (firstCell == null) firstCell = cell; else cell.joinGroup(firstCell); } } // now read external cells for(int i=0; i<nodeProtoCount; i++) { Cell cell = nodeProtoList[i]; if (cell != null) continue; realizeExternalNodeProto(lib, i); } // warn if any dummy cells were read in for (Iterator<Cell> it = lib.getCells(); it.hasNext(); ) { Cell c = it.next(); if (c.getVar(IO_DUMMY_OBJECT) != null) { System.out.println("WARNING: "+lib+" contains DUMMY cell "+c.noLibDescribe()); } } return originalVars; } @Override Variable[] findVarsOnExampleIcon(Cell parentCell, Cell iconCell) { // get information about this cell int cellIndex; for (cellIndex = 0; cellIndex < nodeProtoList.length; cellIndex++) { if (nodeProtoList[cellIndex] == parentCell) break; } if (cellIndex+1 >= firstNodeIndex.length) return null; int startNode = firstNodeIndex[cellIndex]; int endNode = firstNodeIndex[cellIndex+1]; for (int i = startNode; i < endNode; i++) { NodeProto np = convertNodeProto(nodeTypeList[i]); if (np == iconCell) return nodeInstList.vars[i]; } return null; } // *************************** THE CELL CLEANUP INTERFACE *************************** /** * Method to recursively create the contents of each cell in the library. */ protected void realizeCellsRecursively(Cell cell, HashSet<Cell> recursiveSetupFlag, String scaledCellName, double scale) { // do not realize cross-library references if (cell.getLibrary() != lib) return; // skip if dummy cell, already created boolean dummyCell = (cell.getVar(IO_DUMMY_OBJECT) != null) ? true : false; if (dummyCell) return; // get information about this cell int cellIndex = cell.getTempInt(); if (cellIndex+1 >= firstNodeIndex.length) return; int startNode = firstNodeIndex[cellIndex]; int endNode = firstNodeIndex[cellIndex+1]; // recursively ensure that external library references are satisfied for(int i=startNode; i<endNode; i++) { NodeProto np = nodeInstList.protoType[i]; if (np instanceof PrimitiveNode) continue; Cell subCell = (Cell)np; if (subCell.getLibrary() == lib) continue; // subcell: make sure that cell is setup for(int cI = 0; cI<nodeProtoCount; cI++) { if (nodeProtoList[cI] != subCell) continue; if (xLibRefSatisfied[cI]) break; // make sure that cell is properly built if (!recursiveSetupFlag.contains(subCell)) { LibraryFiles reader = getReaderForLib(subCell.getLibrary()); if (reader != null) reader.realizeCellsRecursively(subCell, recursiveSetupFlag, null, 0); } int startPort = firstPortIndex[cI]; int endPort = startPort + portCounts[cI]; for(int j=startPort; j<endPort; j++) { Object obj = exportList[j]; Export pp = null; Cell otherCell = null; if (obj instanceof Cell) { otherCell = (Cell)obj; pp = (Export)findPortProto(otherCell, exportNameList[j]); // pp = otherCell.findExport(exportNameList[j]); if (pp != null) { exportList[j] = pp; } } } xLibRefSatisfied[cI] = true; break; } } // recursively scan the nodes to the bottom and only proceed when everything below is built scanNodesForRecursion(cell, recursiveSetupFlag, nodeInstList.protoType, startNode, endNode); // report progress if (LibraryFiles.VERBOSE) { if (scaledCellName == null) { System.out.println("Binary: Doing contents of " + cell + " in " + lib); } else { System.out.println("Binary: Scaling (by " + scale + ") contents of " + cell + " in " + lib); } } cellsConstructed++; setProgressValue(cellsConstructed * 100 / totalCells); // if (progress != null) progress.setProgress(cellsConstructed * 100 / totalCells); double lambda = cellLambda[cellIndex]; // if scaling, actually construct the cell if (scaledCellName != null) { Cell oldCell = cell; cell = Cell.newInstance(cell.getLibrary(), scaledCellName); cell.setTempInt(cellIndex); recursiveSetupFlag.add(cell); cell.joinGroup(oldCell); scaledCells.add(cell); lambda /= scale; } else scale = 1; // finish initializing the NodeInsts in the cell: start with the cell-center int xoff = 0, yoff = 0; for(int i=startNode; i<endNode; i++) { NodeProto np = nodeInstList.protoType[i]; if (np == Generic.tech().cellCenterNode) { realizeNode(nodeInstList, i, xoff, yoff, lambda, cell, np); xoff = (nodeInstList.lowX[i] + nodeInstList.highX[i]) / 2; yoff = (nodeInstList.lowY[i] + nodeInstList.highY[i]) / 2; break; } } cellXOff[cellIndex] = xoff; cellYOff[cellIndex] = yoff; // finish creating the rest of the NodeInsts for(int i=startNode; i<endNode; i++) { NodeProto np = nodeInstList.protoType[i]; if (np == Generic.tech().cellCenterNode) continue; if (np instanceof Cell) np = scaleCell(i, lambda, cell, recursiveSetupFlag); realizeNode(nodeInstList, i, xoff, yoff, lambda, cell, np); } // do the exports now realizeExports(cell, cellIndex, scaledCellName); // do the arcs now realizeArcs(cell, cellIndex, scaledCellName, scale); // // restore the node pointers if this was a scaled cell construction // if (scaledCellName != null) // { // int j = 0; // for(int i=startNode; i<endNode; i++) // nodeInstList.theNode[i] = oldNodes[j++]; // } // cell.loadExpandStatus(); } protected boolean spreadLambda(Cell cell, int cellIndex) { boolean changed = false; int startNode = firstNodeIndex[cellIndex]; int endNode = firstNodeIndex[cellIndex+1]; double thisLambda = cellLambda[cellIndex]; for(int i=startNode; i<endNode; i++) { NodeProto np = nodeInstList.protoType[i]; if (np instanceof PrimitiveNode) continue; Cell subCell = (Cell)np; // ignore dummy cells, they are created in the default lambda if (subCell.getVar(IO_DUMMY_OBJECT) != null) continue; LibraryFiles reader = this; if (subCell.getLibrary() != lib) { reader = getReaderForLib(subCell.getLibrary()); if (reader == null) continue; } int subCellIndex = subCell.getTempInt(); // if (subCellIndex < 0 || subCellIndex >= reader.cellLambda.length) // { // System.out.println("Index is "+subCellIndex+" but limit is "+reader.cellLambda.length); // continue; // } double subLambda = reader.cellLambda[subCellIndex]; if (subLambda < thisLambda && cell.isSchematic() && subCell.isIcon()) { reader.cellLambda[subCellIndex] = thisLambda; changed = true; } } return changed; } protected void computeTech(Cell cell, Set uncomputedCells) { uncomputedCells.remove(cell); int cellIndex = 0; for(; cellIndex<nodeProtoCount && nodeProtoList[cellIndex] != cell; cellIndex++); if (cellIndex >= nodeProtoCount) return; int startNode = firstNodeIndex[cellIndex]; int endNode = firstNodeIndex[cellIndex+1]; // recursively ensure that subcells's technologies are computed for(int i=startNode; i<endNode; i++) { NodeProto np = convertNodeProto(nodeTypeList[i]); nodeInstList.protoType[i] = np; if (!uncomputedCells.contains(np)) continue; Cell subCell = (Cell)np; LibraryFiles reader = getReaderForLib(subCell.getLibrary()); if (reader != null) reader.computeTech(subCell, uncomputedCells); } int startArc = firstArcIndex[cellIndex]; int endArc = firstArcIndex[cellIndex+1]; ArcProto[] arcTypes = new ArcProto[endArc - startArc]; for (int i = 0; i < arcTypes.length; i++) arcTypes[i] = convertArcProto(arcTypeList[i]); Technology cellTech = Technology.whatTechnology(cell, nodeInstList.protoType, startNode, endNode, arcTypes); cell.setTechnology(cellTech); } protected double computeLambda(Cell cell, int cellIndex) { // double lambda = 1.0; // int startNode = firstNodeIndex[cellIndex]; // int endNode = firstNodeIndex[cellIndex+1]; // int startArc = firstArcIndex[cellIndex]; // int endArc = firstArcIndex[cellIndex+1]; // Technology cellTech = Technology.whatTechnology(cell, nodeInstList.protoType, startNode, endNode, arcTypeList, startArc, endArc); // cell.setTechnology(cellTech); Technology cellTech = cell.getTechnology(); return cellTech != null ? getScale(cellTech) : 1.0; } private double getScale(Technology tech) { Double scale = techScale.get(tech); return scale != null ? scale : tech.getScale(); } protected boolean canScale() { return true; } private void realizeExports(Cell cell, int cellIndex, String scaledCellName) { // finish initializing the Exports in the cell int startPort = firstPortIndex[cellIndex]; int endPort = startPort + portCounts[cellIndex]; CellId cellId = cell.getId(); // Try to create ExportIds in alphanumeric order TreeSet<String> exportNames = new TreeSet<String>(TextUtils.STRING_NUMBER_ORDER); for (int i = startPort; i < endPort; i++) exportNames.add(exportNameList[i]); for (String exportName: exportNames) cellId.newPortId(exportName); for(int i=startPort; i<endPort; i++) { // if (exportList[i] instanceof Cell) // { // Cell otherCell = (Cell)exportList[i]; // Export pp = otherCell.findExport(exportNameList[i]); // if (pp != null) exportList[i] = pp; // } // if (!(exportList[i] instanceof Export)) // { // // could be missing because this is a dummy cell // if (cell.getVar(IO_DUMMY_OBJECT) != null) // continue; // don't issue error message // // not on a dummy cell, issue error message // System.out.println("ERROR: Cell "+cell.describe() + ": export " + exportNameList[i] + " is unresolved"); // continue; // } String exportName = exportNameList[i]; int nodeIndex = exportSubNodeList[i]; if (nodeIndex < 0) { System.out.println("ERROR: " + cell + ": cannot find the node on which export " + exportName + " resides"); continue; } NodeInst subNodeInst = nodeInstList.theNode[nodeIndex]; PortProto subPortProto = convertPortProto(exportSubPortList[i]); // Object o = exportSubPortList[i]; // if (exportSubPortList[i] instanceof Integer) // { // // this was an external reference that couldn't be resolved yet. Do it now // int index = ((Integer)exportSubPortList[i]).intValue(); // exportSubPortList[i] = convertPortProto(index); // } // PortProto subPortProto = (PortProto)exportSubPortList[i]; // null entries happen when there are external cell references if (subNodeInst == null || subPortProto == null || subNodeInst.getParent() != cell || subNodeInst.getProto() != subPortProto.getParent()) { String msg = "ERROR: " + cell + ": export " + exportNameList[i] + " could not be created"; System.out.println(msg); Input.errorLogger.logError(msg, cell, 1); continue; } if (subNodeInst.getProto() == null) { String msg = "ERROR: "+cell + ": export " + exportNameList[i] + " could not be created...proto bad!"; System.out.println(msg); Input.errorLogger.logError(msg, cell, 1); continue; } // convert portproto to portinst PortInst pi = subNodeInst.findPortInst(subPortProto.getName()); boolean alwaysDrawn = ImmutableExport.alwaysDrawnFromElib(exportUserbits[i]); boolean bodyOnly = ImmutableExport.bodyOnlyFromElib(exportUserbits[i]); PortCharacteristic characteristic = ImmutableExport.portCharacteristicFromElib(exportUserbits[i]); ExportId exportId = cellId.newPortId(Name.findName(exportName).toString()); Export pp = Export.newInstance(cell, exportId, null, exportNameDescriptors[i], pi, alwaysDrawn, bodyOnly, characteristic, errorLogger); exportList[i] = pp; if (pp == null) continue; realizeVariables(pp, exportVariables[i]); } // // convert "ATTRP_" variables on NodeInsts to be on PortInsts // int startNode = firstNodeIndex[cellIndex]; // int endNode = firstNodeIndex[cellIndex+1]; // for(int i=startNode; i<endNode; i++) // { // NodeInst ni = nodeInstList.theNode[i]; // boolean found = true; // while (found) // { // found = false; // for(Iterator<Variable> it = ni.getVariables(); it.hasNext(); ) // { // Variable origVar = it.next(); // Variable.Key origVarKey = origVar.getKey(); // String origVarName = origVarKey.getName(); // if (origVarName.startsWith("ATTRP_")) // { // // the form is "ATTRP_portName_variableName" with "\" escapes // StringBuffer portName = new StringBuffer(); // String varName = null; // int len = origVarName.length(); // for(int j=6; j<len; j++) // { // char ch = origVarName.charAt(j); // if (ch == '\\') // { // j++; // portName.append(origVarName.charAt(j)); // continue; // } // if (ch == '_') // { // varName = origVarName.substring(j+1); // break; // } // portName.append(ch); // } // if (varName != null) // { // String thePortName = portName.toString(); // PortInst pi = ni.findPortInst(thePortName); // if (pi != null) // { // Variable var = pi.newVar(Variable.newKey(varName), origVar.getObject(), origVar.getTextDescriptor()); //// if (var != null) //// { //// if (origVar.isDisplay()) var.setDisplay(true); //// var.setCode(origVar.getCode()); //// var.setTextDescriptor(origVar.getTextDescriptor()); //// } // ni.delVar(origVarKey); // found = true; // break; // } // } // } // } // } // } } /** * Method to create the ArcInsts in a given cell and it's index in the global lists. */ private void realizeArcs(Cell cell, int cellIndex, String scaledCellName, double scale) { double lambda = cellLambda[cellIndex] / scale; int xoff = cellXOff[cellIndex]; int yoff = cellYOff[cellIndex]; // boolean arcInfoError = false; int startArc = firstArcIndex[cellIndex]; int endArc = firstArcIndex[cellIndex+1]; for(int i=startArc; i<endArc; i++) { ArcProto ap = convertArcProto(arcTypeList[i]); String name = arcNameList[i]; long gridExtendOverMin = getSizeCorrector(ap.getTechnology()).getExtendFromDisk(ap, arcWidthList[i] / lambda); double headX = (arcHeadXPosList[i] - xoff) / lambda; double headY = (arcHeadYPosList[i] - yoff) / lambda; double tailX = (arcTailXPosList[i] - xoff) / lambda; double tailY = (arcTailYPosList[i] - yoff) / lambda; if (arcHeadNodeList[i] < 0) { System.out.println("ERROR: head of " + ap+ " not known"); continue; } NodeInst headNode = nodeInstList.theNode[arcHeadNodeList[i]]; int headPortIntValue = arcHeadPortList[i]; PortProto headPort = convertPortProto(headPortIntValue); // Object headPort = arcHeadPortList[i]; // int headPortIntValue = -1; String headname = "Port name not found"; // if (headPort instanceof Integer) // { // // this was an external reference that couldn't be resolved yet. Do it now // headPortIntValue = ((Integer)headPort).intValue(); // headPort = convertPortProto(headPortIntValue); // } if (headPort != null) { headname = headPort.getName(); } else { if (headPortIntValue >= 0 && headPortIntValue < exportNameList.length) headname = exportNameList[headPortIntValue]; } if (arcTailNodeList[i] < 0) { System.out.println("ERROR: tail of " + ap + " not known"); continue; } NodeInst tailNode = nodeInstList.theNode[arcTailNodeList[i]]; int tailPortIntValue = arcTailPortList[i]; PortProto tailPort = convertPortProto(tailPortIntValue); // Object tailPort = arcTailPortList[i]; // int tailPortIntValue = -1; String tailname = "Port name not found"; // if (tailPort instanceof Integer) // { // // this was an external reference that couldn't be resolved yet. Do it now // tailPortIntValue = ((Integer)tailPort).intValue(); // tailPort = convertPortProto(tailPortIntValue); // if (tailPortIntValue > 0 && tailPortIntValue < exportNameList.length) // tailname = exportNameList[tailPortIntValue]; // } if (tailPort != null) { tailname = tailPort.getName(); } else { if (tailPortIntValue >= 0 && tailPortIntValue < exportNameList.length) tailname = exportNameList[tailPortIntValue]; } /* if (headNode == null || headPort == null || tailNode == null || tailPort == null) { if (!arcInfoError) { System.out.println("ERROR: Missing arc information in cell " + cell.noLibDescribe() + " in library " + lib.getName() + " ..."); if (headNode == null) System.out.println(" Head node not found"); if (headPort == null) System.out.println(" Head port "+headname+" not found (was "+headPortIntValue+", node="+headNode+")"); if (tailNode == null) System.out.println(" Tail node not found"); if (tailPort == null) System.out.println(" Tail port "+tailname+" not found (was "+tailPortIntValue+", node="+tailNode+")"); arcInfoError = true; } continue; }*/ //PortInst headPortInst = headNode.findPortInst(((PortProto)headPort).getName()); //PortInst tailPortInst = tailNode.findPortInst(((PortProto)tailPort).getName()); PortInst headPortInst = getArcEnd(ap, headNode, headname, headX, headY, cell); PortInst tailPortInst = getArcEnd(ap, tailNode, tailname, tailX, tailY, cell); if (headPortInst == null || tailPortInst == null) { System.out.println("Cannot create arc of type " + ap.getName() + " in cell " + cell.getName() + " because ends are unknown"); continue; } ArcInst ai = ArcInst.newInstance(cell, ap, name, arcNameDescriptorList[i], headPortInst, tailPortInst, new EPoint(headX, headY), new EPoint(tailX, tailY), gridExtendOverMin, ImmutableArcInst.angleFromElib(arcUserBits[i]), ImmutableArcInst.flagsFromElib(arcUserBits[i])); arcList[i] = ai; if (ai == null) { String msg = "ERROR: "+cell + ": arc " + name + " could not be created"; System.out.println(msg); Input.errorLogger.logError(msg, cell, 1); continue; } // if (gridExtendOverMin < 0) { // String msg = "WARNING: "+cell + ": arc " + ai.getName() + " width is less than minimum by " + DBMath.gridToLambda(-2*gridExtendOverMin); // System.out.println(msg); // Input.errorLogger.logWarning(msg, ai, cell, null, 2); // } realizeVariables(ai, arcVariables[i]); } } /** * Method to build a NodeInst. */ private Cell scaleCell(int i, double lambda, Cell cell, HashSet<Cell> recursiveSetupFlag) { Cell subCell = (Cell)nodeInstList.protoType[i]; Rectangle2D bounds = subCell.getBounds(); double width = (nodeInstList.highX[i] - nodeInstList.lowX[i]) / lambda; double height = (nodeInstList.highY[i] - nodeInstList.lowY[i]) / lambda; if (Math.abs(bounds.getWidth() - width) <= 0.5 && Math.abs(bounds.getHeight() - height) <= 0.5) return subCell; LibraryFiles reader = this; if (subCell.getLibrary() != lib) { reader = getReaderForLib(subCell.getLibrary()); } if (reader == null || !reader.canScale() || !cell.isSchematic() || !subCell.isIcon()) return subCell; // see if uniform scaling can be done double scaleX = width / bounds.getWidth(); double scaleY = height / bounds.getHeight(); // don't scale, most likely the size changed, and this is not a lambda problem if (!GenMath.doublesClose(scaleX, scaleY)) return subCell; double scale = Math.sqrt(scaleX * scaleY); String scaledCellName = subCell.getName() + "-SCALED-BY-" + scale + subCell.getView().getAbbreviationExtension(); Cell scaledCell = subCell.getLibrary().findNodeProto(scaledCellName); if (scaledCell == null) { // create a scaled version of the cell if (reader != null) reader.realizeCellsRecursively(subCell, recursiveSetupFlag, scaledCellName, scale); scaledCell = subCell.getLibrary().findNodeProto(scaledCellName); if (scaledCell == null) { System.out.println("Error scaling " + subCell + " by " + scale); } } return scaledCell != null ? scaledCell : subCell; } // node is node we expect to have port 'portname' at location x,y. protected PortInst getArcEnd(ArcProto ap, NodeInst node, String portname, double x, double y, Cell cell) { PortInst pi = null; String whatHappenedToPort = "not found"; String nodeName = "missing node"; if (node != null) { pi = node.findPortInst(portname); nodeName = node.getName(); if (pi != null) return pi; // check to make sure location is correct // Poly portLocation = pi.getPoly(); // String extra = ""; // // // Forcing rounding here instead of PolyBase.calcBounds() //// portLocation.roundPoints(); // if (portLocation.contains(x, y) || portLocation.polyDistance(x, y) < TINYDISTANCE) { // return pi; // } // // give extra info to user if didn't contain port // Rectangle2D box = portLocation.getBox(); // if (box != null) { // extra = "...arc end at ("+x+","+y+"), but port runs "+box.getMinX()+"<=X<="+box.getMaxX()+" and "+box.getMinY()+"<=Y<="+box.getMaxY(); // } else // { // extra = "...expected ("+x+","+y+"), polyDistance=" + portLocation.polyDistance(x, y); // } // whatHappenedToPort = "has moved"+extra; // pi = null; // } else { // name not found, see if any ports exist at location that we can connect to for (Iterator<PortInst> it = node.getPortInsts(); it.hasNext(); ) { pi = it.next(); Poly portLocation = pi.getPoly(); if (portLocation.contains(x, y)) { if (pi.getPortProto().connectsTo(ap)) { // connect to this port String msg = cell+": Port '"+portname+"' on '"+nodeName+"' not found, connecting to port '"+ pi.getPortProto().getName()+"' at the same location"; System.out.println("ERROR: "+msg); Input.errorLogger.logError(msg, cell, 0); return pi; } } pi = null; } whatHappenedToPort = "is missing"; // } // if this was a dummy cell, create the export in cell Cell c = null; if (node.getProto() != null && node.isCellInstance()) if (((Cell)node.getProto()).getVar(IO_DUMMY_OBJECT) != null) c = (Cell)node.getProto(); if (c != null) { double anchorX = node.getAnchorCenterX(); double anchorY = node.getAnchorCenterY(); Point2D expected = new Point2D.Double(x, y); AffineTransform trans = node.rotateIn(); expected = trans.transform(expected, expected); Point2D center = new Point2D.Double(expected.getX() - anchorX, expected.getY() - anchorY); PrimitiveNode pn = Generic.tech().universalPinNode; NodeInst ni = NodeInst.newInstance(pn, center, 0, 0, c, Orientation.IDENT, ""); Export ex = Export.newInstance(c, ni.getOnlyPortInst(), portname, null, false, iconParameters); if (ex != null) { return node.findPortInst(portname); } } } // create pin as new end point of arc String msg = cell+": Port '"+portname+"' on "+node+" "+whatHappenedToPort+": leaving arc disconnected"; System.out.println("ERROR: "+msg); PrimitiveNode pn = ap.findOverridablePinProto(ep); node = NodeInst.newInstance(pn, new Point2D.Double(x, y), pn.getDefWidth(), pn.getDefHeight(), cell); Input.errorLogger.logError(msg, node, cell, null, 0); return node.getOnlyPortInst(); } // --------------------------------- HIGH-LEVEL OBJECTS --------------------------------- /** * Method to read the header information of an "elib" file. * The header consists of the "magic" number and the size of various pieces of data. * Returns true on error. */ private Header readHeader() throws IOException { ByteOrder byteOrder = ByteOrder.LITTLE_ENDIAN; byte byte1 = readByte(); byte byte2 = readByte(); byte byte3 = readByte(); byte byte4 = readByte(); int magic = ((byte4&0xFF) << 24) | ((byte3&0xFF) << 16) | ((byte2&0xFF) << 8) | (byte1&0xFF); if (magic != ELIBConstants.MAGIC1 && magic != ELIBConstants.MAGIC2 && magic != ELIBConstants.MAGIC3 && magic != ELIBConstants.MAGIC4 && magic != ELIBConstants.MAGIC5 && magic != ELIBConstants.MAGIC6 && magic != ELIBConstants.MAGIC7 && magic != ELIBConstants.MAGIC8 && magic != ELIBConstants.MAGIC9 && magic != ELIBConstants.MAGIC10 && magic != ELIBConstants.MAGIC11 && magic != ELIBConstants.MAGIC12 && magic != ELIBConstants.MAGIC13) { magic = ((byte1&0xFF) << 24) | ((byte2&0xFF) << 16) | ((byte3&0xFF) << 8) | (byte4&0xFF); if (magic != ELIBConstants.MAGIC1 && magic != ELIBConstants.MAGIC2 && magic != ELIBConstants.MAGIC3 && magic != ELIBConstants.MAGIC4 && magic != ELIBConstants.MAGIC5 && magic != ELIBConstants.MAGIC6 && magic != ELIBConstants.MAGIC7 && magic != ELIBConstants.MAGIC8 && magic != ELIBConstants.MAGIC9 && magic != ELIBConstants.MAGIC10 && magic != ELIBConstants.MAGIC11 && magic != ELIBConstants.MAGIC12 && magic != ELIBConstants.MAGIC13) { System.out.println("Bad file format: does not start with proper magic number"); return null; } byteOrder = ByteOrder.BIG_ENDIAN; } // determine the size of "big" and "small" integers as well as characters on disk int sizeOfBig = 4; int sizeOfSmall = 2; int sizeOfChar = 1; if (magic <= ELIBConstants.MAGIC10) { sizeOfSmall = readByte(); sizeOfBig = readByte(); } if (magic <= ELIBConstants.MAGIC11) { sizeOfChar = readByte(); } return new Header(magic, byteOrder, sizeOfBig, sizeOfSmall, sizeOfChar); } /** * Method to read a cell. returns true upon error */ private boolean readNodeProto(int cellIndex) throws IOException { // read the cell name String theProtoName; if (header.magic <= ELIBConstants.MAGIC9) { int nextInCell = -1; // read the cell information (version 9 and later) if (header.magic >= ELIBConstants.MAGIC11) { // only versions 9 to 11 int k = readBigInteger(); theProtoName = fakeCellList[k].cellName; } else { // version 12 or later theProtoName = convertCellName(readString()); int k = readBigInteger(); // fix for new cell version library corruption bug if (k == -1) { k = cellIndex; // // find self in list // for (int i=0; i<nodeProtoList.length; i++) { // if (cell == nodeProtoList[i]) { k = i; break; } // } } nextInCell = k; // the "next in cell group" circular pointer k = readBigInteger(); // cell->nextcont = nodeProtoList[k]; // the "next in cell continuation" circular pointer } View v = getView(readBigInteger()); if (v == null) v = View.UNKNOWN; int version = readBigInteger(); theProtoName += ";" + version + v.getAbbreviationExtension(); cellNextInCellGroup[cellIndex] = nextInCell; cellCreationDate[cellIndex] = readBigInteger(); cellRevisionDate[cellIndex] = readBigInteger(); } else { // versions 8 and earlier read a cell name theProtoName = readString(); } cellProtoName[cellIndex] = theProtoName; // ignore the cell bounding box readBigInteger(); // lowX readBigInteger(); // highX readBigInteger(); // lowY readBigInteger(); // highY // ignore the linked list pointers (versions 5 or older) if (header.magic >= ELIBConstants.MAGIC5) { readBigInteger(); // ignore "prev index" readBigInteger(); // ignore "next index" } // read the exports on this nodeproto firstPortIndex[cellIndex] = exportIndex; int portCount = readBigInteger(); if (portCount != portCounts[cellIndex]) System.out.println("Error! Cell header lists " + portCounts[cellIndex] + " exports, but body lists " + portCount); for(int j=0; j<portCount; j++) { // read the sub-NodeInst for this Export exportSubNodeList[exportIndex] = -1; int whichNode = readBigInteger(); if (whichNode >= 0 && whichNode < nodeCount) exportSubNodeList[exportIndex] = whichNode; // read the sub-PortProto on the sub-NodeInst exportSubPortList[exportIndex] = readBigInteger(); // exportSubPortList[exportIndex] = null; // int whichPort = readBigInteger(); // if (whichPort < 0 || exportList[whichPort] != null) // exportSubPortList[exportIndex] = convertPortProto(whichPort); // if (exportSubPortList[exportIndex] == null) // { // exportSubPortList[exportIndex] = new Integer(whichPort); // } // read the Export name String exportName = readString(); exportNameList[exportIndex] = exportName; if (exportSubNodeList[exportIndex] == -1) { System.out.println("Error: Export '" + exportName + "' of cell " + theProtoName + " cannot be read properly"); } // read the portproto text descriptor int descript0 = 0, descript1 = 0; if (header.magic <= ELIBConstants.MAGIC9) { if (convertTextDescriptors) { // conversion is done later descript0 = readBigInteger(); descript1 = 0; } else { descript0 = readBigInteger(); descript1 = readBigInteger(); } } exportNameDescriptors[exportIndex] = makeDescriptor(descript0, descript1); // ignore the "seen" bits (versions 8 and older) if (header.magic > ELIBConstants.MAGIC9) readBigInteger(); // read the portproto's "user bits" exportUserbits[exportIndex] = 0; if (header.magic <= ELIBConstants.MAGIC7) { // version 7 and later simply read the relevant data exportUserbits[exportIndex] = readBigInteger(); // versions 7 and 8 ignore net number if (header.magic >= ELIBConstants.MAGIC8) readBigInteger(); } else { // version 6 and earlier must sift through the information if (toolBCount >= 1) exportUserbits[exportIndex] = readBigInteger(); for(int i=1; i<toolBCount; i++) readBigInteger(); } // read the export variables exportVariables[exportIndex] = readVariables(); exportIndex++; } // ignore the cell's geometry information if (header.magic > ELIBConstants.MAGIC5) { // versions 4 and older have geometry module pointers (ignore it) readBigInteger(); readBigInteger(); readBigInteger(); readBigInteger(); readBigInteger(); } // read tool information readBigInteger(); // ignore "dirty" // read the "user bits" int userBits = 0; if (header.magic <= ELIBConstants.MAGIC7) { // version 7 and later simply read the relevant data userBits = readBigInteger(); // versions 7 and 8 ignore net number if (header.magic >= ELIBConstants.MAGIC8) readBigInteger(); } else { // version 6 and earlier must sift through the information if (toolBCount >= 1) userBits = readBigInteger(); for(int i=1; i<toolBCount; i++) readBigInteger(); } cellUserBits[cellIndex] = userBits; // read variable information cellVars[cellIndex] = readVariables(); // cell read successfully return false; } /** * Method to realize a cell. returns true upon error */ private void realizeNodeProto(int cellIndex, Map<Cell,Variable[]> originalVars) { String theProtoName = cellProtoName[cellIndex]; Cell cell = Cell.newInstance(lib, theProtoName); if (header.magic <= ELIBConstants.MAGIC9) { cell.lowLevelSetCreationDate(ELIBConstants.secondsToDate(cellCreationDate[cellIndex])); cell.lowLevelSetRevisionDate(ELIBConstants.secondsToDate(cellRevisionDate[cellIndex])); } nodeProtoList[cellIndex] = cell; assert cell.getCellName() != null; cell.lowLevelSetUserbits(cellUserBits[cellIndex]); originalVars.put(cell, cellVars[cellIndex]); } /** Method to read node prototype for external references */ private boolean readExternalNodeProto(int cellIndex) throws IOException { // read the cell information (version 9 and later) String theProtoName; if (header.magic >= ELIBConstants.MAGIC11) { // only versions 9 to 11 int k = readBigInteger(); theProtoName = fakeCellList[k].cellName; } else { // version 12 or later theProtoName = convertCellName(readString()); readBigInteger(); readBigInteger(); } View v = getView(readBigInteger()); if (v == null) v = View.UNKNOWN; int version = readBigInteger(); String fullCellName = theProtoName + ";" + version + v.getAbbreviationExtension(); if (version <= 1) fullCellName = theProtoName + v.getAbbreviationExtension(); cellProtoName[cellIndex] = fullCellName; cellCreationDate[cellIndex] = readBigInteger(); cellRevisionDate[cellIndex] = readBigInteger(); // read the nodeproto bounding box cellLowX[cellIndex] = readBigInteger(); cellHighX[cellIndex] = readBigInteger(); cellLowY[cellIndex] = readBigInteger(); cellHighY[cellIndex] = readBigInteger(); // get the external library cellLibraryPath[cellIndex] = readString(); // read the portproto names on this nodeproto int portCount = readBigInteger(); String [] localPortNames = new String[portCount]; for(int j=0; j<portCount; j++) localPortNames[j] = readString(); // read the portprotos on this Cell firstPortIndex[cellIndex] = exportIndex; if (portCount != portCounts[cellIndex]) System.out.println("Error! Cell header lists " + portCounts[cellIndex] + " exports, but body lists " + portCount); for(int j=0; j<portCount; j++) { // read the portproto name String protoName = localPortNames[j]; exportNameList[exportIndex] = protoName; exportIndex++; } return false; } /** Method to read node prototype for external references */ private boolean realizeExternalNodeProto(Library lib, int cellIndex) { // read the cell information (version 9 and later) String fullCellName = cellProtoName[cellIndex]; Date creationDate = ELIBConstants.secondsToDate(cellCreationDate[cellIndex]); Date revisionDate = ELIBConstants.secondsToDate(cellRevisionDate[cellIndex]); // read the nodeproto bounding box int lowX = cellLowX[cellIndex]; int highX = cellHighX[cellIndex]; int lowY = cellLowY[cellIndex]; int highY = cellHighY[cellIndex]; // get the external library Library elib = readExternalLibraryFromFilename(cellLibraryPath[cellIndex], FileType.ELIB, iconParameters); // find this cell in the external library Cell c = elib.findNodeProto(fullCellName); // if can't find, look for dummy version //String dummyName = "DUMMY" + fullCellName; String dummyName = fullCellName; if (c == null) { c = elib.findNodeProto(dummyName); } if (c == null) { // cell not found in library: issue warning System.out.println("ERROR: Cannot find cell " + fullCellName + " in " + elib); } // if cell found, check that size is unchanged (size is unknown at this point) // if (c != null) // { // Rectangle2D bounds = c.getBounds(); // double lambda = 1; // Technology cellTech = Technology.whatTechnology(c); // if (cellTech != null) lambda = techScale[cellTech.getIndex()]; // double cellWidth = (highX - lowX) / lambda; // double cellHeight = (highY - lowY) / lambda; // if (!DBMath.doublesEqual(bounds.getWidth(), cellWidth) || !DBMath.doublesEqual(bounds.getHeight(), cellHeight)) // { // // bounds differ, but lambda scaling is inaccurate: see if aspect ratio changed // if (!DBMath.doublesEqual(bounds.getWidth() * cellHeight, bounds.getHeight() * cellWidth)) // { // System.out.println("Error: cell " + c.noLibDescribe() + " in library " + elib.getName() + // " has changed size since its use in library " + lib.getName()); // System.out.println(" The cell is " + bounds.getWidth() + "x" + bounds.getHeight() + // " but the instances in library " + lib.getName() + " are " + cellWidth + "x" + cellHeight); // c = null; // } // } // } // if cell found, check that ports match /* if (c != null) { for(int j=0; j<portCount; j++) { PortProto pp = c.findExport(localPortNames[j]); if (pp == null) { LibraryFiles reader = getReaderForLib(elib); if (reader != null) { if (reader.readerHasExport(c, localPortNames[j])) continue; } System.out.println("Error: cell " + c.noLibDescribe() + " in library " + elib.getName() + " is missing export '" + localPortNames[j] + "'"); // for (Iterator<PortProto> it = c.getPorts(); it.hasNext(); ) // { // PortProto ppo = it.next(); // System.out.println("\t"+ppo.getName()); // } c = null; break; } } } */ // if cell found, warn if minor modification was made if (c != null) { if (revisionDate.compareTo(c.getRevisionDate()) != 0) { System.out.println("Warning: cell " + c.noLibDescribe() + " in " + elib + " has changed since its use in " + lib); } } // make new cell if needed // NodeInst fakeNodeInst = null; if (c == null) { // create a cell that meets these specs /* String dummyCellName = null; for(int index=0; ; index++) { dummyCellName = theProtoName + "FROM" + elib.getName(); if (index > 0) dummyCellName += "." + index; dummyCellName += "{" + v.getAbbreviation() + "}"; if (lib.findNodeProto(dummyCellName) == null) break; } c = Cell.newInstance(lib, dummyCellName); */ c = Cell.newInstance(elib, dummyName); if (c == null) return true; c.lowLevelSetCreationDate(creationDate); c.lowLevelSetRevisionDate(revisionDate); // create an artwork "Crossed box" to define the cell size Technology tech = Technology.getMocmosTechnology(); if (c.isIcon()) tech = Artwork.tech(); else if (c.isSchematic()) tech = Schematics.tech(); double lambda = getScale(tech); int cX = (lowX + highX) / 2; int cY = (lowY + highY) / 2; double width = (highX - lowX) / lambda; double height = (highY - lowY) / lambda; Point2D center = new Point2D.Double(cX / lambda, cY / lambda); NodeInst.newInstance(Generic.tech().drcNode, center, width, height, c); //PrimitiveNode cellCenter = Generic.tech.cellCenterNode; //NodeInst.newInstance(cellCenter, new Point2D.Double(0,0), cellCenter.getDefWidth(), // cellCenter.getDefHeight(), 0, c, null); //fakeNodeInst = NodeInst.newInstance(Generic.tech.universalPinNode, center, width, height, 0, c, null); // note that exports get created in getArcEnd. If it tries to connect to a missing export // on a dummy cell, it creates the export site. System.out.println("...Creating dummy cell '"+dummyName+"' in " + elib + ". Instances will be logged as Errors."); c.newVar(IO_TRUE_LIBRARY, elib.getName()); c.newVar(IO_DUMMY_OBJECT, fullCellName); } nodeProtoList[cellIndex] = c; // realize the portprotos on this Cell int portCount = portCounts[cellIndex]; for(int j=0; j<portCount; j++) { // realize the portproto name exportList[firstPortIndex[cellIndex] + j] = c; } return false; } /** * Method to read a node instance. returns true upon error */ private boolean readNodeInst(int nodeIndex, int cellIndex) throws IOException { // read the nodeproto index int protoIndex = readBigInteger(); // read the descriptive information nodeTypeList[nodeIndex] = protoIndex; nodeInstList.lowX[nodeIndex] = readBigInteger(); nodeInstList.lowY[nodeIndex] = readBigInteger(); nodeInstList.highX[nodeIndex] = readBigInteger(); nodeInstList.highY[nodeIndex] = readBigInteger(); if (header.magic <= ELIBConstants.MAGIC13) { // read anchor point for cell references if (protoIndex >= 0) { nodeInstList.anchorX[nodeIndex] = readBigInteger(); nodeInstList.anchorY[nodeIndex] = readBigInteger(); } } nodeInstList.transpose[nodeIndex] = readBigInteger(); nodeInstList.rotation[nodeIndex] = (short)readBigInteger(); nodeInstList.name[nodeIndex] = null; // versions 9 and later get text descriptor for cell name int descript0 = 0, descript1 = 0; if (header.magic <= ELIBConstants.MAGIC9) { if (convertTextDescriptors) { // conversion is done later descript0 = readBigInteger(); } else { descript0 = readBigInteger(); descript1 = readBigInteger(); } } nodeInstList.protoTextDescriptor[nodeIndex] = makeDescriptor(descript0, descript1); // mtd.setCBits(descript0, descript1); // ni.setTextDescriptor(NodeInst.NODE_PROTO_TD, mtd); // mtd.setCBits(descript0, descript1); // ni.setTextDescriptor(NodeInst.NODE_PROTO_TD, mtd); // read the nodeinst name (versions 1, 2, or 3 only) if (header.magic >= ELIBConstants.MAGIC3) { String instName = readString(); if (instName.length() > 0) nodeInstList.name[nodeIndex] = instName; } // ignore the geometry index (versions 4 or older) if (header.magic > ELIBConstants.MAGIC5) readBigInteger(); // read the arc ports int numPorts = readBigInteger(); for(int j=0; j<numPorts; j++) { // read the arcinst information (and the particular end on the arc) int k = readBigInteger(); int arcIndex = k >> 1; if (k < 0 || arcIndex >= arcCount) return true; // read the port information int portIndex = readBigInteger(); if ((k&1) == 0) arcTailPortList[arcIndex] = portIndex; else arcHeadPortList[arcIndex] = portIndex; // ignore variables on port instance readVariables(); } // ignore the exports int numExports = readBigInteger(); for(int j=0; j<numExports; j++) { readBigInteger(); readBigInteger(); readVariables(); } // ignore the "seen" bits (versions 8 and older) if (header.magic > ELIBConstants.MAGIC9) readBigInteger(); // read the tool information int userBits = 0; if (header.magic <= ELIBConstants.MAGIC7) { // version 7 and later simply read the relevant data userBits = readBigInteger(); } else { // version 6 and earlier must sift through the information if (toolBCount >= 1) userBits = readBigInteger(); for(int i=1; i<toolBCount; i++) readBigInteger(); } nodeInstList.userBits[nodeIndex] = userBits; // read variable information Variable[] vars = readVariables(); for (int j = 0; j < vars.length; j++) { Variable var = vars[j]; if (var == null || var.getKey() != NodeInst.NODE_NAME) continue; Object value = var.getObject(); if (!(value instanceof String)) continue; nodeInstList.name[nodeIndex] = convertGeomName(value, var.isDisplay()); nodeInstList.nameTextDescriptor[nodeIndex] = var.getTextDescriptor(); vars[j] = null; } nodeInstList.vars[nodeIndex] = vars; // node read successfully return false; } /** * Method to read an arc instance. returns true upon error */ private boolean readArcInst(int arcIndex) throws IOException { // read the arcproto pointer arcTypeList[arcIndex] = readBigInteger(); // read the arc length (versions 5 or older) if (header.magic >= ELIBConstants.MAGIC5) readBigInteger(); // read the arc width arcWidthList[arcIndex] = readBigInteger(); // ignore the signals value (versions 6, 7, or 8) if (header.magic <= ELIBConstants.MAGIC6 && header.magic >= ELIBConstants.MAGIC8) readBigInteger(); // read the arcinst name (versions 3 or older) if (header.magic >= ELIBConstants.MAGIC3) { String instName = readString(); if (instName.length() > 0) arcNameList[arcIndex] = instName; } // read the tail information arcTailXPosList[arcIndex] = readBigInteger(); arcTailYPosList[arcIndex] = readBigInteger(); int tailNodeIndex = readBigInteger(); if (tailNodeIndex >= 0 && tailNodeIndex < nodeCount) arcTailNodeList[arcIndex] = tailNodeIndex; // read the head information arcHeadXPosList[arcIndex] = readBigInteger(); arcHeadYPosList[arcIndex] = readBigInteger(); int headNodeIndex = readBigInteger(); if (headNodeIndex >= 0 && headNodeIndex < nodeCount) arcHeadNodeList[arcIndex] = headNodeIndex; // ignore the geometry index (versions 4 or older) if (header.magic > ELIBConstants.MAGIC5) readBigInteger(); // ignore the "seen" bits (versions 8 and older) if (header.magic > ELIBConstants.MAGIC9) readBigInteger(); // read the arcinst's tool information int userBits = 0; if (header.magic <= ELIBConstants.MAGIC7) { // version 7 and later simply read the relevant data userBits = readBigInteger(); // versions 7 and 8 ignore net number if (header.magic >= ELIBConstants.MAGIC8) readBigInteger(); } else { // version 6 and earlier must sift through the information if (toolBCount >= 1) userBits = readBigInteger(); for(int i=1; i<toolBCount; i++) readBigInteger(); } arcUserBits[arcIndex] = userBits; // read variable information Variable[] vars = readVariables(); for (int i = 0; i < vars.length; i++) { Variable var = vars[i]; if (var == null || var.getKey() != ArcInst.ARC_NAME) continue; Object value = var.getObject(); if (!(value instanceof String)) continue; arcNameList[arcIndex] = convertGeomName(value, var.isDisplay()); arcNameDescriptorList[arcIndex] = var.getTextDescriptor(); vars[i] = null; } arcVariables[arcIndex] = vars; // arc read successfully return false; } /** * Method to read (and mostly ignore) a geometry module */ private void readGeom(boolean [] isNode, int [] moreup, int index) throws IOException { int type = readBigInteger(); // read entrytype if (type != 0) isNode[index] = true; else isNode[index] = false; if (isNode[index]) readBigInteger();// skip entryaddr readBigInteger(); // skip lowx readBigInteger(); // skip highx readBigInteger(); // skip lowy readBigInteger(); // skip highy readBigInteger(); // skip moreleft readBigInteger(); // skip ll readBigInteger(); // skip moreright readBigInteger(); // skip lr moreup[index] = readBigInteger(); // read moreup readBigInteger(); // skip lu readBigInteger(); // skip moredown readBigInteger(); // skip ld readVariables(); // skip variables } // --------------------------------- VARIABLES --------------------------------- /** * Method to read the global namespace. returns true upon error */ private void readNameSpace() throws IOException { int nameCount = readBigInteger(); varNames = new String[nameCount]; varKeys = new Variable.Key[nameCount]; for(int i=0; i<nameCount; i++) varNames[i] = readString(); } /** * Method to read a set of variables onto a given object. * @return the array of variables read. */ private Variable[] readVariables() throws IOException { int count = readBigInteger(); if (count == 0) return Variable.NULL_ARRAY; Variable[] vars = new Variable[count]; for(int i=0; i<count; i++) { short key = readSmallInteger(); if (key < 0 || key >= varKeys.length) { String msg = "Bad variable index (" + key + ", limit is " + varKeys.length + ")"; System.out.println(msg); throw new IOException(msg); } if (varKeys[key] == null) varKeys[key] = Variable.newKey(varNames[key]); int newtype = readBigInteger(); // version 9 and later reads text description on displayable variables int descript0 = 0; int descript1 = 0; if (header.magic <= ELIBConstants.MAGIC9) { if (alwaysTextDescriptors) { descript0 = readBigInteger(); descript1 = readBigInteger(); } else { if ((newtype&ELIBConstants.VDISPLAY) != 0) { if (convertTextDescriptors) { // conversion is done later descript0 = readBigInteger(); } else { descript0 = readBigInteger(); descript1 = readBigInteger(); } } } } TextDescriptor td = makeDescriptor(descript0, descript1, newtype); CodeExpression.Code code = CodeExpression.Code.getByCBits(newtype); Object newAddr; if ((newtype&ELIBConstants.VISARRAY) != 0) { int len = readBigInteger(); int cou = len; // if ((newtype&ELIBConstants.VLENGTH) == 0) cou++; Object [] newAddrArray = null; switch (newtype&ELIBConstants.VTYPE) { case ELIBConstants.VADDRESS: case ELIBConstants.VINTEGER: newAddrArray = new Integer[cou]; break; case ELIBConstants.VFRACT: case ELIBConstants.VFLOAT: newAddrArray = new Float[cou]; break; case ELIBConstants.VDOUBLE: newAddrArray = new Double[cou]; break; case ELIBConstants.VSHORT: newAddrArray = new Short[cou]; break; case ELIBConstants.VBOOLEAN: newAddrArray = new Boolean[cou]; break; case ELIBConstants.VCHAR: newAddrArray = new Byte[cou]; break; case ELIBConstants.VSTRING: newAddrArray = new String[cou]; break; case ELIBConstants.VNODEPROTO: newAddrArray = new NodeProtoId[cou]; break; case ELIBConstants.VARCPROTO: newAddrArray = new ArcProtoId[cou]; break; case ELIBConstants.VPORTPROTO: newAddrArray = new ExportId[cou]; break; case ELIBConstants.VTECHNOLOGY: newAddrArray = new TechId[cou]; break; case ELIBConstants.VLIBRARY: newAddrArray = new LibId[cou]; break; case ELIBConstants.VTOOL: newAddrArray = new Tool[cou]; break; } newAddr = newAddrArray; if ((newtype&ELIBConstants.VTYPE) == ELIBConstants.VGENERAL) { for(int j=0; j<len; j += 2) { readBigInteger(); // ignore type readBigInteger(); // ignore address if (newAddrArray != null) newAddrArray[j] = null; } } else { for(int j=0; j<len; j++) { Object ret = getInVar(newtype); if (newAddrArray != null) newAddrArray[j] = ret; } } if (newAddrArray == null) { String msg = "Cannot figure out the type for code "+(newtype&ELIBConstants.VTYPE); System.out.println(msg); continue; } if (newAddrArray instanceof NodeProtoId[]) { int numCells = 0, numPrims = 0; for (int j = 0; j < newAddrArray.length; j++) { if (newAddrArray[j] == null) continue; if (newAddrArray[j] instanceof CellId) numCells++; if (newAddrArray[j] instanceof PrimitiveNodeId) numPrims++; } if (numCells >= numPrims) { CellId[] cellArray = new CellId[newAddrArray.length]; for (int j = 0; j < cellArray.length; j++) if (newAddrArray[j] instanceof CellId) cellArray[j] = (CellId)newAddrArray[j]; newAddr = cellArray; } else { PrimitiveNodeId[] primArray = new PrimitiveNodeId[newAddrArray.length]; for (int j = 0; j < primArray.length; j++) if (newAddrArray[j] instanceof PrimitiveNodeId) primArray[j] = (PrimitiveNodeId)newAddrArray[j]; newAddr = primArray; } } } else { newAddr = getInVar(newtype); } if (newAddr == null) { System.out.println("Error reading variable " + varNames[key] + " type " + newtype); continue; } newAddr = Variable.withCode(newAddr, code); vars[i] = Variable.newInstance(varKeys[key], newAddr, td); } return vars; } /** * Helper method to read a variable at address "addr" of type "ty". * Returns zero if OK, negative on memory error, positive if there were * correctable problems in the read. */ private Object getInVar(int ty) throws IOException { int i; if ((ty&(ELIBConstants.VCODE1|ELIBConstants.VCODE2)) != 0) ty = ELIBConstants.VSTRING; switch (ty&ELIBConstants.VTYPE) { case ELIBConstants.VADDRESS: case ELIBConstants.VINTEGER: return Integer.valueOf(readBigInteger()); case ELIBConstants.VFRACT: return Float.valueOf(readBigInteger() / 120.0f); case ELIBConstants.VFLOAT: return Float.valueOf(readFloat()); case ELIBConstants.VDOUBLE: return Double.valueOf(readDouble()); case ELIBConstants.VSHORT: return Short.valueOf(readSmallInteger()); case ELIBConstants.VBOOLEAN: return Boolean.valueOf(readByte() != 0); case ELIBConstants.VCHAR: return Byte.valueOf(readByte()); case ELIBConstants.VSTRING: return readString(); case ELIBConstants.VNODEINST: i = readBigInteger(); System.out.println("Cannot read variable of type NodeInst"); return null; case ELIBConstants.VNODEPROTO: i = readBigInteger(); NodeProto np = convertNodeProto(i); if (np == null) return np; return (np instanceof Cell ? ((Cell)np).getId() : ((PrimitiveNode)np).getId()); case ELIBConstants.VARCPROTO: i = readBigInteger(); if (i == -1) { System.out.println("Variable of type ArcProto has negative index"); return null; } return convertArcProto(i).getId(); case ELIBConstants.VPORTPROTO: i = readBigInteger(); PortProto pp = convertPortProto(i); if (!(pp instanceof Export)) return null; return ((Export)pp).getId(); case ELIBConstants.VARCINST: i = readBigInteger(); System.out.println("Cannot read variable of type ArcInst"); return null; case ELIBConstants.VGEOM: readBigInteger(); readBigInteger(); System.out.println("Cannot read variable of type Geometric"); return null; case ELIBConstants.VTECHNOLOGY: i = readBigInteger(); if (i == -1) { System.out.println("Variable of type Technology has negative index"); return null; } return getTechList(i).getId(); case ELIBConstants.VPORTARCINST: readBigInteger(); System.out.println("Cannot read variable of type PortArcInst"); return null; case ELIBConstants.VPORTEXPINST: readBigInteger(); System.out.println("Cannot read variable of type PortExpInst"); return null; case ELIBConstants.VLIBRARY: String libName = readString(); if (libName.length() == 0) return null; return idManager.newLibId(libName); case ELIBConstants.VTOOL: i = readBigInteger(); if (i < 0 || i >= toolCount) return null; Tool tool = toolList[i]; if (tool == null) { i = 0; if (toolError[i] != null) { System.out.println("WARNING: no tool called '" + toolError[i] + "', using 'user'"); toolError[i] = null; } } return tool; case ELIBConstants.VRTNODE: readBigInteger(); System.out.println("Cannot read variable of type RTNode"); return null; } System.out.println("Cannot read variable of type " + (ty&ELIBConstants.VTYPE)); return null; } // --------------------------------- OBJECT CONVERSION --------------------------------- /** * Method to convert the nodeproto index "i" to a true nodeproto pointer. */ private NodeProto convertNodeProto(int i) { if (i == -1) return null; if (i < 0) { // negative values are primitives int nindex = -i - 2; if (nindex >= primNodeProtoCount) { System.out.println("Error: want primitive node index " + nindex + " when limit is " + primNodeProtoCount); return null; } return getPrimNodeProtoList(nindex); } // see if the cell value is valid if (i >= nodeProtoCount) { System.out.println("Error: want cell index " + i + " when limit is " + nodeProtoCount); return null; } return nodeProtoList[i]; } /** * Method to convert the arcproto index "i" to a true arcproto pointer. */ private ArcProto convertArcProto(int i) { int aindex = -i - 2; if (aindex >= arcProtoCount || aindex < 0) { System.out.println("Want primitive arc index " + aindex + " when range is 0 to " + arcProtoCount); aindex = 0; } return getArcProtoList(aindex); } /** * Method to convert the PortProto index "i" to a true PortProto pointer. */ private PortProto convertPortProto(int i) { if (i == -1) return null; if (i < 0) { int pindex = -i - 2; if (pindex >= primPortProtoCount) { System.out.println("Error: want primitive port index " + pindex + " when limit is " + primPortProtoCount); pindex = 0; } return getPrimPortProtoList(pindex); } if (i >= exportCount) { System.out.println("Error: want port index " + i + " when limit is " + exportCount); i = 0; } if (exportList[i] instanceof Cell) return null; return (Export)exportList[i]; } private NodeProto getPrimNodeProtoList(int i) { getTechList(primNodeProtoTech[i]); if (primNodeProtoError[i]) { System.out.println("Cannot find primitive '" + primNodeProtoOrig[i] + "', using " + primNodeProtoList[i].getName()); primNodeProtoError[i] = false; } return(primNodeProtoList[i]); } private ArcProto getArcProtoList(int i) { if (arcProtoError[i] != null) { System.out.println("Cannot find arc '" + arcProtoError[i] + "', using " + arcProtoList[i].getName()); arcProtoError[i] = null; } return(arcProtoList[i]); } private PortProto getPrimPortProtoList(int i) { if (primPortProtoError[i] != null) { System.out.println("WARNING: port " + primPortProtoError[i] + " not found, using " + primPortProtoList[i].getName()); primPortProtoError[i] = null; } return(primPortProtoList[i]); } /** * Method to return the Technology associated with index "i". */ private Technology getTechList(int i) { if (techError[i] != null) { System.out.println("WARNING: technology '" + techError[i] + "' does not exist, using '" + techList[i].getTechName() + "'"); techError[i] = null; } return(techList[i]); } /** * Method to return the View associated with index "i". */ private View getView(int i) { View v = viewMapping.get(new Integer(i)); return v; } // --------------------------------- LOW-LEVEL INPUT --------------------------------- /** * Method to read a single byte from the input stream and return it. */ private byte readByte() throws IOException { int value = dataInputStream.read(); if (value == -1) throw new IOException(); updateProgressDialog(1); return (byte)value; } static private ByteBuffer bb = ByteBuffer.allocateDirect(8); static private byte [] rawData = new byte[8]; /** * Method to read an integer (4 bytes) from the input stream and return it. */ private int readBigInteger() throws IOException { if (header.sizeOfBig == 4) { updateProgressDialog(4); int data = dataInputStream.readInt(); if (!header.bytesSwapped) data = ((data >> 24) & 0xFF) | ((data >> 8) & 0xFF00) | ((data & 0xFF00) << 8) | ((data & 0xFF) << 24); return data; } readBytes(rawData, header.sizeOfBig, 4, true); if (header.bytesSwapped) { bb.put(0, rawData[0]); bb.put(1, rawData[1]); bb.put(2, rawData[2]); bb.put(3, rawData[3]); } else { bb.put(0, rawData[3]); bb.put(1, rawData[2]); bb.put(2, rawData[1]); bb.put(3, rawData[0]); } return bb.getInt(0); } /** * Method to read a float (4 bytes) from the input stream and return it. */ private float readFloat() throws IOException { if (header.bytesSwapped) { updateProgressDialog(4); return dataInputStream.readFloat(); } readBytes(rawData, header.sizeOfBig, 4, true); bb.put(0, rawData[3]); bb.put(1, rawData[2]); bb.put(2, rawData[1]); bb.put(3, rawData[0]); return bb.getFloat(0); } /** * Method to read a double (8 bytes) from the input stream and return it. */ private double readDouble() throws IOException { if (header.bytesSwapped) { updateProgressDialog(8); return dataInputStream.readDouble(); } readBytes(rawData, header.sizeOfBig, 8, true); bb.put(0, rawData[7]); bb.put(1, rawData[2]); bb.put(2, rawData[3]); bb.put(3, rawData[4]); bb.put(4, rawData[3]); bb.put(5, rawData[2]); bb.put(6, rawData[1]); bb.put(7, rawData[0]); return bb.getDouble(0); } /** * Method to read an short (2 bytes) from the input stream and return it. */ private short readSmallInteger() throws IOException { if (header.sizeOfSmall == 2) { updateProgressDialog(2); int data = dataInputStream.readShort(); if (!header.bytesSwapped) data = ((data >> 8) & 0xFF) | ((data & 0xFF) << 8); return (short)data; } readBytes(rawData, header.sizeOfSmall, 2, true); if (header.bytesSwapped) { bb.put(0, rawData[0]); bb.put(1, rawData[1]); } else { bb.put(0, rawData[1]); bb.put(1, rawData[0]); } return bb.getShort(0); } /** * Method to read a string from the input stream and return it. */ private String readString() throws IOException { if (header.sizeOfChar != 1) { // disk and memory don't match: read into temporary string System.out.println("Cannot handle library files with unicode strings"); // tempstr = io_gettempstring(); // if (allocstring(&name, tempstr, cluster)) return(0); return null; } // disk and memory match: read the data int len = readBigInteger(); if (len <= 0) return ""; if (len > fileLength - byteCount) { System.out.println("Corrupt ELIB file requests string that is " + len + " long"); throw new IOException(); } byte [] stringBytes = new byte[len]; int ret = dataInputStream.read(stringBytes, 0, len); if (ret != len) throw new IOException(); updateProgressDialog(len); String theString = new String(stringBytes); return theString; } /** * Method to read a number of bytes from the input stream and return it. */ private void readBytes(byte [] data, int diskSize, int memorySize, boolean signExtend) throws IOException { // check for direct transfer if (diskSize == memorySize) { // just peel it off the disk int ret = dataInputStream.read(data, 0, diskSize); if (ret != diskSize) throw new IOException(); } else { // not a simple read, use a buffer int ret = dataInputStream.read(rawData, 0, diskSize); if (ret != diskSize) throw new IOException(); if (diskSize > memorySize) { // trouble! disk has more bits than memory. check for clipping for(int i=0; i<memorySize; i++) data[i] = rawData[i]; for(int i=memorySize; i<diskSize; i++) if (rawData[i] != 0 && rawData[i] != 0xFF) clippedIntegers++; } else { // disk has smaller integer if (!signExtend || (rawData[diskSize-1] & 0x80) == 0) { for(int i=diskSize; i<memorySize; i++) rawData[i] = 0; } else { for(int i=diskSize; i<memorySize; i++) rawData[i] = (byte)0xFF; } for(int i=0; i<memorySize; i++) data[i] = rawData[i]; } } updateProgressDialog(diskSize); } }