/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: JELIB.java * Input/output tool: JELIB Library input * Written by Steven M. Rubin, Sun Microsystems. * * Copyright (c) 2004 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.geometry.EPoint; 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.id.ArcProtoId; import com.sun.electric.database.id.CellId; 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.TechId; import com.sun.electric.database.prototype.NodeProto; import com.sun.electric.database.prototype.PortProto; import com.sun.electric.database.text.CellName; import com.sun.electric.database.text.Setting; import com.sun.electric.database.text.TextUtils; import com.sun.electric.database.topology.ArcInst; import com.sun.electric.database.topology.Geometric; import com.sun.electric.database.topology.NodeInst; import com.sun.electric.database.topology.PortInst; import com.sun.electric.database.variable.Variable; import com.sun.electric.technology.ArcProto; import com.sun.electric.technology.PrimitiveNode; import com.sun.electric.technology.TechPool; import com.sun.electric.technology.Technology; import com.sun.electric.technology.technologies.Generic; import com.sun.electric.tool.Tool; import com.sun.electric.tool.io.FileType; import com.sun.electric.tool.user.ErrorLogger; import com.sun.electric.tool.user.IconParameters; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.net.URL; import java.util.*; /** * This class reads files in new library file (.jelib) format. */ public class JELIB extends LibraryFiles { private final FileType fileType; private final JelibParser parser; private final IconParameters iconParameters; JELIB(LibId libId, URL fileURL, FileType type, IconParameters iconParams) throws IOException { fileType = type; parser = JelibParser.parse(libId, fileURL, fileType, false, Input.errorLogger); iconParameters = iconParams; } public static Map<Setting,Object> readProjectSettings(URL fileURL, FileType fileType, TechPool techPool, ErrorLogger errorLogger) { JelibParser parser; try { parser = parse(techPool.idManager, fileURL, fileType, true, errorLogger); } catch (IOException e) { errorLogger.logError("Error reading " + fileURL + ": " + e.getMessage(), -1); return null; } HashMap<Setting,Object> projectSettings = new HashMap<Setting,Object>(); for (Map.Entry<TechId,Variable[]> e: parser.techIds.entrySet()) { TechId techId = e.getKey(); Variable[] vars = e.getValue(); Technology tech = techPool.getTech(techId); if (tech == null && techId.techName.equals("tsmc90")) tech = techPool.getTech(techPool.idManager.newTechId("cmos90")); if (tech == null) { Input.errorLogger.logError(fileURL + ", Cannot identify technology " + techId.techName, -1); continue; } realizeMeaningPrefs(projectSettings, tech, vars); } for (Map.Entry<String,Variable[]> e: parser.tools.entrySet()) { String toolName = e.getKey(); Variable[] vars = e.getValue(); Tool tool = Tool.findTool(toolName); if (tool == null) { Input.errorLogger.logError(fileURL + ", Cannot identify tool " + toolName, -1); continue; } realizeMeaningPrefs(projectSettings, tool, vars); } return projectSettings; } public static JelibParser parse(IdManager idManager, URL fileURL, FileType fileType, boolean onlyProjectSettings, ErrorLogger errorLogger) throws IOException { LibId libId = idManager.newLibId(TextUtils.getFileNameWithoutExtension(fileURL)); return JelibParser.parse(libId, fileURL, fileType, onlyProjectSettings, errorLogger); } /** * Method to read a Library in new library file (.jelib) format. * @return true on error. */ @Override boolean readTheLibrary(boolean onlyProjectSettings, LibraryStatistics.FileContents fc) { return false; } @Override Map<Cell,Variable[]> createLibraryCells(boolean onlyProjectSettings) { lib.erase(); realizeVariables(lib, parser.libVars); lib.setVersion(parser.version); // Project preferences for (Map.Entry<TechId,Variable[]> e: parser.techIds.entrySet()) { TechId techId = e.getKey(); Variable[] vars = e.getValue(); Technology tech = findTechnology(techId); if (tech == null) { Input.errorLogger.logError(filePath + ", Cannot identify technology " + techId.techName, -1); continue; } realizeMeaningPrefs(tech, vars); } for (Map.Entry<String,Variable[]> e: parser.tools.entrySet()) { String toolName = e.getKey(); Variable[] vars = e.getValue(); Tool tool = Tool.findTool(toolName); if (tool == null) { Input.errorLogger.logError(parser.fileURL + ", Cannot identify tool " + toolName, -1); continue; } realizeMeaningPrefs(tool, vars); } for (Map.Entry<LibId,String> e: parser.externalLibIds.entrySet()) { LibId libId = e.getKey(); String libFileName = e.getValue(); if (Library.findLibrary(libId.libName) == null) readExternalLibraryFromFilename(libFileName, fileType, iconParameters); } nodeProtoCount = parser.allCells.size(); nodeProtoList = new Cell[nodeProtoCount]; cellLambda = new double[nodeProtoCount]; HashMap<Cell,Variable[]> originalVars = new HashMap<Cell,Variable[]>(); HashMap<CellName,Cell> cellGroupExamples = new HashMap<CellName,Cell>(); int cellNum = 0; for (JelibParser.CellContents cc: parser.allCells.values()) { CellId cellId = cc.cellId; Cell cell = Cell.newInstance(lib, cellId.cellName.toString()); Technology tech = findTechnology(cc.techId); cell.setTechnology(tech); cell.lowLevelSetCreationDate(new Date(cc.creationDate)); cell.lowLevelSetRevisionDate(new Date(cc.revisionDate)); if (cc.expanded) cell.setWantExpanded(); if (cc.allLocked) cell.setAllLocked(); if (cc.instLocked) cell.setInstancesLocked(); if (cc.cellLib) cell.setInCellLibrary(); if (cc.techLib) cell.setInTechnologyLibrary(); originalVars.put(cell, cc.vars); nodeProtoList[cellNum++] = cell; Cell otherCell = cellGroupExamples.get(cc.groupName); if (otherCell == null) cellGroupExamples.put(cc.groupName, cell); else cell.joinGroup(otherCell); } lib.setFromDisk(); lib.setDelibCells(); // lib.setDelibCellFiles(parser.delibCellFiles); return originalVars; } @Override Variable[] findVarsOnExampleIcon(Cell parentCell, Cell iconCell) { JelibParser.CellContents cc = parser.allCells.get(parentCell.getId()); if (cc == null) return null; for (JelibParser.NodeContents nc: cc.nodes) { if (nc.protoId == iconCell.getId()) return nc.vars; } return null; } /** * Method to recursively create the contents of each cell in the library. */ @Override protected void realizeCellsRecursively(Cell cell, HashSet<Cell> recursiveSetupFlag, String scaledCellName, double scale) { if (scaledCellName != null) return; JelibParser.CellContents cc = parser.allCells.get(cell.getId()); if (cc == null || cc.filledIn) return; instantiateCellContent(cell, cc, recursiveSetupFlag); cellsConstructed++; setProgressValue(cellsConstructed * 100 / totalCells); recursiveSetupFlag.add(cell); // cell.loadExpandStatus(); } /** * Method called after all libraries have been read to instantiate a single Cell. * @param cell the Cell to instantiate. * @param cc the contents of that cell (the strings from the file). */ private void instantiateCellContent(Cell cell, JelibParser.CellContents cc, HashSet<Cell> recursiveSetupFlag) { HashMap<Technology,Technology.SizeCorrector> sizeCorrectors = new HashMap<Technology,Technology.SizeCorrector>(); // boolean immutableInstantiateOK = true; // for (int nodeId = 0; nodeId < cc.nodes.size(); nodeId++) { // JelibParser.NodeContents n = cc.nodes.get(nodeId); // try { // n.n = ImmutableNodeInst.newInstance(nodeId, n.protoId, Name.findName(n.nodeName), n.nameTextDescriptor, // n.orient, n.anchor, n.size, n.flags, n.techBits, n.protoTextDescriptor); // } catch (Exception e) { // immutableInstantiateOK = false; // System.out.println("Exception in immutable instantiate " + cell); // break; // } // } // place all nodes for (JelibParser.NodeContents n: cc.nodes) { int line = n.line; String prefixName = lib.getName(); NodeProto np = null; NodeProtoId protoId = n.protoId; if (protoId instanceof CellId) np = database.getCell((CellId)protoId); else { PrimitiveNodeId pnId = (PrimitiveNodeId)protoId; np = findPrimitiveNode(pnId); if (np == null) { Input.errorLogger.logError(cc.fileName + ", line " + line + ", Cannot find primitive node " + pnId, cell, -1); Set<PrimitiveNodeId> primSet = undefinedTechsAndPrimitives.get(pnId.techId); if (primSet == null) { primSet = new HashSet<PrimitiveNodeId>(); undefinedTechsAndPrimitives.put(pnId.techId, primSet); } primSet.add(pnId); CellName cellName = CellName.parseName(pnId.name); if (cellName.getVersion() <= 0) cellName = CellName.newName(cellName.getName(), cellName.getView(), 1); protoId = lib.getId().newCellId(cellName); } } // make sure the subcell has been instantiated if (np != null && np instanceof Cell) { Cell subCell = (Cell)np; // subcell: make sure that cell is setup if (!recursiveSetupFlag.contains(subCell)) { LibraryFiles reader = this; if (subCell.getLibrary() != cell.getLibrary()) reader = getReaderForLib(subCell.getLibrary()); // subcell: make sure that cell is setup if (reader != null) reader.realizeCellsRecursively(subCell, recursiveSetupFlag, null, 0); } } EPoint size = n.size; if (np instanceof PrimitiveNode) { PrimitiveNode pn = (PrimitiveNode)np; Technology tech = pn.getTechnology(); Technology.SizeCorrector sizeCorrector = sizeCorrectors.get(tech); if (sizeCorrector == null) { sizeCorrector = tech.getSizeCorrector(cc.version, projectSettings, true, false); sizeCorrectors.put(tech, sizeCorrector); } size = sizeCorrector.getSizeFromDisk(pn, size.getLambdaX(), size.getLambdaY()); } if (np == null) { CellId dummyCellId = (CellId)protoId; String protoName = dummyCellId.cellName.toString(); Library cellLib = database.getLib(dummyCellId.libId); if (cellLib == null) { Input.errorLogger.logError(cc.fileName + ", line " + line + ", Creating dummy library " + prefixName, cell, -1); cellLib = Library.newInstance(prefixName, null); } Cell dummyCell = cellLib.findNodeProto(protoName); if (dummyCell != null && dummyCell.getVar(IO_DUMMY_OBJECT) == null) dummyCell = null; if (dummyCell == null) { dummyCell = Cell.makeInstance(cellLib, protoName); if (dummyCell == null) { Input.errorLogger.logError(cc.fileName + ", line " + line + ", Unable to create dummy cell " + protoName + " in " + cellLib, cell, -1); continue; } Input.errorLogger.logError(cc.fileName + ", line " + line + ", Creating dummy cell " + protoName + " in " + cellLib, cell, -1); } Rectangle2D bounds = parser.externalCells.get(dummyCellId.toString()); if (bounds == null) { Input.errorLogger.logError(cc.fileName + ", line " + line + ", Warning: cannot find information about external cell " + dummyCellId, cell, -1); NodeInst.newInstance(Generic.tech().invisiblePinNode, new Point2D.Double(0,0), 0, 0, dummyCell); } else { NodeInst.newInstance(Generic.tech().invisiblePinNode, new Point2D.Double(bounds.getCenterX(), bounds.getCenterY()), bounds.getWidth(), bounds.getHeight(), dummyCell); } // mark this as a dummy cell dummyCell.newVar(IO_TRUE_LIBRARY, prefixName); dummyCell.newVar(IO_DUMMY_OBJECT, protoName); np = dummyCell; } // create the node NodeInst ni = NodeInst.newInstance(cell, np, n.nodeName, n.nameTextDescriptor, n.anchor, size, n.orient, n.flags, n.techBits, n.protoTextDescriptor, Input.errorLogger); if (ni == null) { Input.errorLogger.logError(cc.fileName + ", line " + (cc.lineNumber + line) + " (" + cell + ") cannot create node " + n.protoId, cell, -1); continue; } // if (immutableInstantiateOK && !ni.getD().equalsExceptVariables(n.n)) { // System.out.println("Difference between immutable and mutable nodes in " + cell); // immutableInstantiateOK = false; // } // add variables realizeVariables(ni, n.vars); // insert into map of disk names n.ni = ni; } // place all exports for (JelibParser.ExportContents e: cc.exports) { int line = e.line; PortInst pi = figureOutPortInst(cell, e.originalPort.externalId, e.originalNode, e.pos, cc.fileName, line); if (pi == null) continue; // create the export Export pp = Export.newInstance(cell, e.exportId, e.exportUserName, e.nameTextDescriptor, pi, e.alwaysDrawn, e.bodyOnly, e.ch, errorLogger); if (pp == null) { Input.errorLogger.logError(cc.fileName + ", line " + (cc.lineNumber + line) + " (" + cell + ") cannot create export " + e.exportUserName, pi.getNodeInst(), cell, null, -1); continue; } // add variables in tail fields realizeVariables(pp, e.vars); } // next place all arcs for(JelibParser.ArcContents a: cc.arcs) { int line = a.line; ArcProto ap = findArcProto(a.arcProtoId); if (ap == null) { if (ap == null) ap = cell.getTechnology().convertOldArcName(a.arcProtoId.name); if (ap == null) { Input.errorLogger.logError(cc.fileName + ", line " + line + " (" + cell + ") cannot find arc " + a.arcProtoId, cell, -1); continue; } } Technology tech = ap.getTechnology(); Technology.SizeCorrector sizeCorrector = sizeCorrectors.get(tech); if (sizeCorrector == null) { sizeCorrector = tech.getSizeCorrector(cc.version, projectSettings, true, false); sizeCorrectors.put(tech, sizeCorrector); } long gridExtendOverMin = sizeCorrector.getExtendFromDisk(ap, a.diskWidth); PortInst headPI = figureOutPortInst(cell, a.headPort.externalId, a.headNode, a.headPoint, cc.fileName, line); if (headPI == null) continue; PortInst tailPI = figureOutPortInst(cell, a.tailPort.externalId, a.tailNode, a.tailPoint, cc.fileName, line); if (tailPI == null) continue; ArcInst ai = ArcInst.newInstance(cell, ap, a.arcName, a.nameTextDescriptor, headPI, tailPI, a.headPoint, a.tailPoint, gridExtendOverMin, a.angle, a.flags); if (ai == null) { List<Geometric> geomList = new ArrayList<Geometric>(); geomList.add(headPI.getNodeInst()); geomList.add(tailPI.getNodeInst()); Input.errorLogger.logMessage(cc.fileName + ", line " + line + " (" + cell + ") cannot create arc " + a.arcProtoId, geomList, cell, 2, true); continue; } realizeVariables(ai, a.vars); } cc.filledIn = true; } /** * Method to find the proper PortInst for a specified port on a node, at a given position. * @param cell the cell in which this all resides. * @param portName the name of the port (may be an empty string if there is only 1 port). * @param n the node. * @param pos the position of the port on the node. * @param lineNumber the line number in the file being read (for error reporting). * @return the PortInst specified (null if none can be found). */ private PortInst figureOutPortInst(Cell cell, String portName, JelibParser.NodeContents n, Point2D pos, String fileName, int lineNumber) { NodeInst ni = n != null ? n.ni : null; if (ni == null) { Input.errorLogger.logError(fileName + ", line " + lineNumber + " (" + cell + ") cannot find node " + n.nodeName, cell, -1); return null; } PortInst pi = null; PortProto pp = findPortProto(ni.getProto(), portName); if (pp != null) pi = ni.findPortInstFromProto(pp); // primitives use the name match // if (!ni.isCellInstance()) return pi; // // make sure the port can handle the position // if (pi != null && pos != null) // { // Poly poly = pi.getPoly(); // if (!(poly.isInside(pos) || poly.polyDistance(pos.getX(), pos.getY()) < TINYDISTANCE)) // { // NodeProto np = ni.getProto(); // Input.errorLogger.logError(fileName + ", line " + lineNumber + // " (" + cell + ") point (" + pos.getX() + "," + pos.getY() + ") does not fit in " + // pi + " which is centered at (" + poly.getCenterX() + "," + poly.getCenterY() + ")", new EPoint(pos.getX(), pos.getY()), cell, -1); // if (np instanceof Cell) // pi = null; // } // } if (pi != null) return pi; // see if this is a dummy cell Variable var = null; Cell subCell = null; if (ni.isCellInstance()) { subCell = (Cell)ni.getProto(); var = subCell.getVar(IO_TRUE_LIBRARY); if (pos == null) pos = parser.externalExports.get(subCell.getId().newPortId(portName)); } if (pos == null) pos = ni.getAnchorCenter(); if (var == null) { // not a dummy cell: create a pin at the top level NodeInst portNI = NodeInst.newInstance(Generic.tech().universalPinNode, pos, 0, 0, cell); if (portNI == null) { Input.errorLogger.logError(fileName + ", line " + lineNumber + ", Unable to create dummy node in " + cell + " (cannot create source node)", cell, -1); return null; } Input.errorLogger.logError(fileName + ", line " + lineNumber + ", Port "+portName+" on "+ni.getProto() + " renamed or deleted, still used on node "+n.nodeName+" in " + cell, portNI, cell, null, -1); return portNI.getOnlyPortInst(); } // a dummy cell: create a dummy export on it to fit this String name = portName; if (name.length() == 0) name = "X"; Point2D.Double tpos = new Point2D.Double(); ni.transformIn().transform(pos, tpos); NodeInst portNI = NodeInst.newInstance(Generic.tech().universalPinNode, tpos, 0, 0, subCell); if (portNI == null) { Input.errorLogger.logError(fileName + ", line " + lineNumber + ", Unable to create export " + name + " on dummy " + subCell + " (cannot create source node)", cell, -1); return null; } PortInst portPI = portNI.getOnlyPortInst(); Export export = Export.newInstance(subCell, portPI, name, null, false, iconParameters); if (export == null) { Input.errorLogger.logError(fileName + ", line " + lineNumber + ", Unable to create export " + name + " on dummy " + subCell, cell, -1); return null; } pi = ni.findPortInstFromProto(export); Input.errorLogger.logError(fileName + ", line " + lineNumber + ", Creating export " + name + " on dummy " + subCell, cell, -1); return pi; } Technology findTechnology(TechId techId) { TechPool techPool = database.getTechPool(); Technology tech = techPool.getTech(techId); if (tech == null && techId.techName.equals("tsmc90")) tech = techPool.getTech(idManager.newTechId("cmos90")); return tech; } PrimitiveNode findPrimitiveNode(PrimitiveNodeId primitiveNodeId) { TechPool techPool = database.getTechPool(); PrimitiveNode pn = techPool.getPrimitiveNode(primitiveNodeId); if (pn == null && primitiveNodeId.techId.techName.equals("tsmc90")) pn = findPrimitiveNode(idManager.newTechId("cmos90").newPrimitiveNodeId(primitiveNodeId.name)); if (pn == null) { Technology tech = findTechnology(primitiveNodeId.techId); if (tech != null) pn = tech.convertOldNodeName(primitiveNodeId.name); } return pn; } ArcProto findArcProto(ArcProtoId arcProtoId) { TechPool techPool = database.getTechPool(); ArcProto ap = techPool.getArcProto(arcProtoId); if (ap == null && arcProtoId.techId.techName.equals("tsmc90")) ap = findArcProto(idManager.newTechId("cmos90").newArcProtoId(arcProtoId.name)); return ap; } }