/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: LEF.java
* Input/output tool: LEF (Library Exchange Format) reader
* Written by Steven M. Rubin, Sun Microsystems.
*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Electric(tm) is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Electric(tm) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.tool.io.input;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.Export;
import com.sun.electric.database.hierarchy.Library;
import com.sun.electric.database.id.CellId;
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.topology.ArcInst;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.topology.PortInst;
import com.sun.electric.database.topology.RTBounds;
import com.sun.electric.technology.ArcProto;
import com.sun.electric.technology.Layer;
import com.sun.electric.technology.PrimitiveNode;
import com.sun.electric.technology.Technology;
import com.sun.electric.technology.technologies.Generic;
import com.sun.electric.tool.Job;
import com.sun.electric.util.TextUtils;
import com.sun.electric.util.math.DBMath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.net.URL;
import java.util.BitSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* This class reads files in LEF files.
* <BR>
* Note that this reader was built by examining LEF files and reverse-engineering them.
* It does not claim to be compliant with the LEF specification, but it also does not
* claim to define a new specification. It is merely incomplete.
*/
public class LEF extends LEFDEF
{
/*************** LEF PATHS ***************/
private static class LEFPath
{
private Point2D [] pt;
private NodeInst [] ni;
private double width;
private ArcProto arc;
private LEFPath nextLEFPath;
private LEFPath()
{
pt = new Point2D[2];
ni = new NodeInst[2];
}
}
private LEFPreferences localPrefs;
private Technology curTech;
public static class LEFPreferences extends InputPreferences
{
public LEFPreferences(boolean factory)
{
super(factory);
}
@Override
public Library doInput(URL fileURL, Library lib, Technology tech, Map<Library,Cell> currentCells, Map<CellId,BitSet> nodesToExpand, Job job)
{
LEF in = new LEF(this);
if (in.openTextInput(fileURL)) return null;
lib = in.importALibrary(lib, tech, currentCells);
in.closeInput();
return lib;
}
}
/**
* Creates a new instance of LEF.
*/
LEF(LEFPreferences ap) { localPrefs = ap; }
/**
* Method to import a library from disk.
* @param lib the library to fill
* @param currentCells this map will be filled with currentCells in Libraries found in library file
* @return the created library (null on error).
*/
@Override
protected Library importALibrary(Library lib, Technology tech, Map<Library,Cell> currentCells)
{
// remove any vias in the globals
curTech = tech;
firstViaDefFromLEF = null;
widthsFromLEF = new HashMap<ArcProto,Double>();
knownLayers = new HashMap<String,GetLayerInformation>();
initKeywordParsing();
try
{
if (readFile(lib)) return null; // error during reading
} catch (IOException e)
{
System.out.println("ERROR reading LEF libraries");
}
return lib;
}
/**
* Helper method for keyword processing which removes comments.
* @param line a line of text just read.
* @return the line after comments have been removed.
*/
protected String preprocessLine(String line)
{
int sharpPos = line.indexOf('#');
if (sharpPos >= 0) return line.substring(0, sharpPos);
return line;
}
/**
* Method to read the LEF file.
* @return true on error.
*/
private boolean readFile(Library lib)
throws IOException
{
for(;;)
{
// get the next keyword
String key = getAKeyword();
if (key == null) break;
if (key.equalsIgnoreCase("LAYER"))
{
if (readLayer(lib)) return true;
}
if (key.equalsIgnoreCase("MACRO"))
{
if (readMacro(lib)) return true;
}
if (key.equalsIgnoreCase("VIA"))
{
if (readVia(lib)) return true;
}
if (key.equalsIgnoreCase("VIARULE") || key.equalsIgnoreCase("SITE") ||
key.equalsIgnoreCase("ARRAY"))
{
String name = getAKeyword();
ignoreToEnd(name);
continue;
}
if (key.equalsIgnoreCase("SPACING"))
{
ignoreToEnd(key);
continue;
}
if (key.equalsIgnoreCase("MINFEATURE"))
{
ignoreToSemicolon(key);
continue;
}
}
return false;
}
private boolean readVia(Library lib)
throws IOException
{
// get the via name
String viaName = getAKeyword();
if (viaName == null) return true;
// create a new via definition
ViaDef vd = new ViaDef();
vd.viaName = viaName;
vd.sX = vd.sY = 0;
vd.via = null;
vd.lay1 = vd.lay2 = null;
vd.nextViaDef = firstViaDefFromLEF;
firstViaDefFromLEF = vd;
boolean ignoreDefault = true;
for(;;)
{
// get the next keyword
String key = getAKeyword();
if (key == null) return true;
if (ignoreDefault)
{
ignoreDefault = false;
if (key.equalsIgnoreCase("DEFAULT")) continue;
}
if (key.equalsIgnoreCase("END"))
{
key = getAKeyword();
break;
}
if (key.equalsIgnoreCase("RESISTANCE"))
{
if (ignoreToSemicolon(key)) return true;
continue;
}
if (key.equalsIgnoreCase("LAYER"))
{
key = getAKeyword();
if (key == null) return true;
GetLayerInformation li = getLayerInformation(key);
if (li.arc != null)
{
if (vd.lay1 == null) vd.lay1 = li.arc; else
vd.lay2 = li.arc;
}
if (ignoreToSemicolon("LAYER")) return true;
continue;
}
if (key.equalsIgnoreCase("RECT"))
{
// handle definition of a via rectangle
key = getAKeyword();
if (key == null) return true;
double lX = convertLEFString(key);
key = getAKeyword();
if (key == null) return true;
double lY = convertLEFString(key);
key = getAKeyword();
if (key == null) return true;
double hX = convertLEFString(key);
key = getAKeyword();
if (key == null) return true;
double hY = convertLEFString(key);
// accumulate largest layer size
if (hX-lX > vd.sX) vd.sX = hX - lX;
if (hY-lY > vd.sY) vd.sY = hY - lY;
if (ignoreToSemicolon("RECT")) return true;
continue;
}
}
if (vd.lay1 != null && vd.lay2 != null)
{
for(Iterator<PrimitiveNode> it = curTech.getNodes(); it.hasNext(); )
{
PrimitiveNode np = it.next();
if (!np.getFunction().isContact()) continue;
PortProto pp = np.getPort(0);
if (pp.connectsTo(vd.lay1) && pp.connectsTo(vd.lay2))
{
vd.via = np;
break;
}
}
}
return false;
}
private boolean readMacro(Library lib)
throws IOException
{
String cellName = getAKeyword();
if (cellName == null)
{
System.out.println("EOF parsing MACRO header");
return true;
}
cellName = cellName + "{lay.sk}";
Cell cell = Cell.makeInstance(lib, cellName);
if (cell == null)
{
System.out.println("Cannot create cell '" + cellName + "'");
return true;
}
for(;;)
{
// get the next keyword
String key = getAKeyword();
if (key == null)
{
System.out.println("EOF parsing MACRO");
return true;
}
if (key.equalsIgnoreCase("END"))
{
key = getAKeyword();
break;
}
if (key.equalsIgnoreCase("SOURCE") || key.equalsIgnoreCase("FOREIGN") ||
key.equalsIgnoreCase("SYMMETRY") || key.equalsIgnoreCase("SITE") ||
key.equalsIgnoreCase("CLASS") || key.equalsIgnoreCase("LEQ") ||
key.equalsIgnoreCase("POWER"))
{
if (ignoreToSemicolon(key)) return true;
continue;
}
if (key.equalsIgnoreCase("ORIGIN"))
{
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading ORIGIN X");
return true;
}
double oX = convertLEFString(key);
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading ORIGIN Y");
return true;
}
double oY = convertLEFString(key);
if (ignoreToSemicolon("ORIGIN")) return true;
// create or move the cell-center node
NodeInst ccNi = null;
for(Iterator<NodeInst> it = cell.getNodes(); it.hasNext(); )
{
NodeInst ni = it.next();
if (ni.getProto() == Generic.tech().cellCenterNode) { ccNi = ni; break; }
}
if (ccNi == null)
{
double sX = Generic.tech().cellCenterNode.getDefWidth();
double sY = Generic.tech().cellCenterNode.getDefHeight();
ccNi = NodeInst.makeInstance(Generic.tech().cellCenterNode, new Point2D.Double(oX, oY), sX, sY, cell);
if (ccNi == null)
{
System.out.println("Line " + lineReader.getLineNumber() + ": Cannot create cell center node");
return true;
}
ccNi.setHardSelect();
ccNi.setVisInside();
} else
{
double dX = oX - ccNi.getTrueCenterX();
double dY = oY - ccNi.getTrueCenterY();
ccNi.move(dX, dY);
}
continue;
}
if (key.equalsIgnoreCase("SIZE"))
{
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading SIZE X");
return true;
}
double wid = convertLEFString(key); // get width
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading SIZE 'BY'");
return true;
}
if (!key.equalsIgnoreCase("BY"))
{
System.out.println("Line " + lineReader.getLineNumber() + ": Expected 'by' in SIZE");
return true;
}
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading SIZE Y");
return true;
}
double hei = convertLEFString(key); // get height
cell.newVar(prXkey, new Double(wid));
cell.newVar(prYkey, new Double(hei));
if (ignoreToSemicolon("SIZE")) return true;
if (!PLACELEFGEOMETRY)
{
Point2D ctr = new Point2D.Double(wid/2, hei/2);
NodeInst.makeInstance(Generic.tech().invisiblePinNode, ctr, wid, hei, cell);
}
continue;
}
if (key.equalsIgnoreCase("PIN"))
{
if (readPin(cell)) return true;
continue;
}
if (key.equalsIgnoreCase("OBS"))
{
if (readObs(cell)) return true;
continue;
}
System.out.println("Line " + lineReader.getLineNumber() + ": Unknown MACRO keyword (" + key + ")");
return true;
}
return false;
}
private boolean readObs(Cell cell)
throws IOException
{
NodeProto np = null;
for(;;)
{
String key = getAKeyword();
if (key == null)
{
System.out.println("EOF parsing OBS");
return true;
}
if (key.equalsIgnoreCase("END")) break;
if (key.equalsIgnoreCase("LAYER"))
{
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading LAYER clause");
return true;
}
GetLayerInformation li = getLayerInformation(key);
np = li.pure;
if (li.layerFun == Layer.Function.UNKNOWN || np == null)
{
System.out.println("Line " + lineReader.getLineNumber() + ": Unknown layer name (" + key + ")");
return true;
}
if (ignoreToSemicolon("LAYER")) return true;
continue;
}
if (key.equalsIgnoreCase("RECT"))
{
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading RECT low X");
return true;
}
double lX = convertLEFString(key);
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading RECT low Y");
return true;
}
double lY = convertLEFString(key);
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading RECT high X");
return true;
}
double hX = convertLEFString(key);
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading RECT high Y");
return true;
}
double hY = convertLEFString(key);
if (ignoreToSemicolon("RECT")) return true;
// make the obstruction
if (PLACELEFGEOMETRY)
{
if (np == null)
{
System.out.println("Line " + lineReader.getLineNumber() + ": No layers for RECT");
return true;
}
Point2D ctr = new Point2D.Double((lX+hX)/2, (lY+hY)/2);
double sX = Math.abs(hX - lX);
double sY = Math.abs(hY - lY);
NodeInst ni = NodeInst.makeInstance(np, ctr, sX, sY, cell);
if (ni == null)
{
System.out.println("Line " + lineReader.getLineNumber() + ": Cannot create node for RECT");
return true;
}
}
continue;
}
}
return false;
}
private boolean readPin(Cell cell)
throws IOException
{
// get the pin name
String key = getAKeyword();
if (key == null)
{
System.out.println("EOF parsing PIN name");
return true;
}
String pinName = key.replace('<', '[').replace('>', ']');
PortCharacteristic useCharacteristics = PortCharacteristic.UNKNOWN;
PortCharacteristic portCharacteristics = PortCharacteristic.UNKNOWN;
for(;;)
{
key = getAKeyword();
if (key == null)
{
System.out.println("EOF parsing PIN");
return true;
}
if (key.equalsIgnoreCase("END"))
{
key = getAKeyword();
break;
}
if (key.equalsIgnoreCase("SHAPE") || key.equalsIgnoreCase("CAPACITANCE") ||
key.equalsIgnoreCase("ANTENNASIZE") || key.equalsIgnoreCase("ANTENNADIFFAREA") ||
key.equalsIgnoreCase("ANTENNAMODEL") || key.equalsIgnoreCase("ANTENNAGATEAREA"))
{
if (ignoreToSemicolon(key)) return true;
continue;
}
if (key.equalsIgnoreCase("USE"))
{
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading USE clause");
return true;
}
if (key.equalsIgnoreCase("POWER")) useCharacteristics = PortCharacteristic.PWR; else
if (key.equalsIgnoreCase("GROUND")) useCharacteristics = PortCharacteristic.GND; else
if (key.equalsIgnoreCase("CLOCK")) useCharacteristics = PortCharacteristic.CLK; else
if (!key.equalsIgnoreCase("SIGNAL") && !key.equalsIgnoreCase("DATA"))
{
System.out.println("Line " + lineReader.getLineNumber() + ": Unknown USE keyword (" + key + ")");
}
if (ignoreToSemicolon("USE")) return true;
continue;
}
if (key.equalsIgnoreCase("DIRECTION"))
{
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading DIRECTION clause");
return true;
}
if (key.equalsIgnoreCase("INPUT")) portCharacteristics = PortCharacteristic.IN; else
if (key.equalsIgnoreCase("OUTPUT")) portCharacteristics = PortCharacteristic.OUT; else
if (key.equalsIgnoreCase("INOUT")) portCharacteristics = PortCharacteristic.BIDIR; else
{
System.out.println("Line " + lineReader.getLineNumber() + ": Unknown DIRECTION keyword (" + key + ")");
}
if (ignoreToSemicolon("DIRECTION")) return true;
continue;
}
if (key.equalsIgnoreCase("PORT"))
{
if (useCharacteristics != PortCharacteristic.UNKNOWN) portCharacteristics = useCharacteristics;
if (readPort(cell, pinName, portCharacteristics)) return true;
continue;
}
System.out.println("Line " + lineReader.getLineNumber() + ": Unknown PIN keyword (" + key + ")");
return true;
}
return false;
}
private boolean readPort(Cell cell, String portname, PortCharacteristic portCharacteristics)
throws IOException
{
ArcProto ap = null;
NodeProto pureNp = null;
LEFPath lefPaths = null;
boolean first = true;
double intWidth = 0;
double lastIntX = 0, lastIntY = 0;
Point2D singlePathPoint = null;
for(;;)
{
String key = getAKeyword();
if (key == null)
{
System.out.println("EOF parsing PORT");
return true;
}
if (key.equalsIgnoreCase("END"))
{
break;
}
if (key.equalsIgnoreCase("CLASS"))
{
if (ignoreToSemicolon("LAYER")) return true;
continue;
}
if (key.equalsIgnoreCase("LAYER"))
{
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading LAYER clause");
return true;
}
GetLayerInformation li = getLayerInformation(key);
ap = li.arc;
pureNp = li.pure;
if (ignoreToSemicolon("LAYER")) return true;
continue;
}
if (key.equalsIgnoreCase("WIDTH"))
{
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading WIDTH clause");
return true;
}
intWidth = convertLEFString(key);
if (ignoreToSemicolon("WIDTH")) return true;
continue;
}
if (key.equalsIgnoreCase("RECT"))
{
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading RECT low X");
return true;
}
double lX = convertLEFString(key);
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading RECT low Y");
return true;
}
double lY = convertLEFString(key);
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading RECT high X");
return true;
}
double hX = convertLEFString(key);
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading RECT high Y");
return true;
}
double hY = convertLEFString(key);
if (ignoreToSemicolon("RECT")) return true;
// make the pin
if (PLACELEFEXPORTS)
{
if (pureNp == null)
{
System.out.println("Line " + lineReader.getLineNumber() + ": No layers for RECT");
return true;
}
Point2D ctr = new Point2D.Double((lX+hX)/2, (lY+hY)/2);
double sX = Math.abs(hX - lX);
double sY = Math.abs(hY - lY);
NodeInst ni = NodeInst.makeInstance(pureNp, ctr, sX, sY, cell);
if (ni == null)
{
System.out.println("Line " + lineReader.getLineNumber() + ": Cannot create pin for RECT");
return true;
}
if (first)
{
// create the port on the first pin
first = false;
Export pp = newPort(cell, ni, pureNp.getPort(0), portname);
if (pp != null) pp.setCharacteristic(portCharacteristics);
}
}
continue;
}
if (key.equalsIgnoreCase("PATH"))
{
if (ap == null)
{
System.out.println("Line " + lineReader.getLineNumber() + ": No layers for PATH");
return true;
}
for(int i=0; ; i++)
{
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading PATH clause");
return true;
}
if (key.equals(";")) break;
double intx = convertLEFString(key);
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading PATH clause");
return true;
}
double inty = convertLEFString(key);
// plot this point
if (i == 0) singlePathPoint = new Point2D.Double(intx, inty); else
{
// queue path
LEFPath lp = new LEFPath();
lp.pt[0] = new Point2D.Double(lastIntX, lastIntY);
lp.pt[1] = new Point2D.Double(intx, inty);
lp.ni[0] = null; lp.ni[1] = null;
lp.width = intWidth;
lp.arc = ap;
lp.nextLEFPath = lefPaths;
lefPaths = lp;
}
lastIntX = intx; lastIntY = inty;
}
continue;
}
if (key.equalsIgnoreCase("VIA"))
{
// get the coordinates
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading VIA clause");
return true;
}
double intX = convertLEFString(key);
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading VIA clause");
return true;
}
double intY = convertLEFString(key);
// find the proper via
key = getAKeyword();
GetLayerInformation li = getLayerInformation(key);
if (li.pin == null)
{
System.out.println("Line " + lineReader.getLineNumber() + ": No Via in current technology for '" + key + "'");
return true;
}
if (ignoreToSemicolon("VIA")) return true;
// create the via
if (PLACELEFGEOMETRY)
{
double sX = li.pin.getDefWidth();
double sY = li.pin.getDefHeight();
NodeInst ni = NodeInst.makeInstance(li.pin, new Point2D.Double(intX, intY), sX, sY, cell);
if (ni == null)
{
System.out.println("Line " + lineReader.getLineNumber() + ": Cannot create VIA for PATH");
return true;
}
}
continue;
}
System.out.println("Line " + lineReader.getLineNumber() + ": Unknown PORT keyword (" + key + ")");
return true;
}
if (!PLACELEFGEOMETRY) return false;
// look for paths that end at vias
for(LEFPath lp = lefPaths; lp != null; lp = lp.nextLEFPath)
{
for(int i=0; i<2; i++)
{
if (lp.ni[i] != null) continue;
Rectangle2D bounds = new Rectangle2D.Double(lp.pt[i].getX(), lp.pt[i].getY(), 0, 0);
for(Iterator<RTBounds> sea = cell.searchIterator(bounds); sea.hasNext(); )
{
RTBounds geom = sea.next();
if (!(geom instanceof NodeInst)) continue;
NodeInst ni = (NodeInst)geom;
if (!DBMath.areEquals(ni.getTrueCenter(), lp.pt[i])) continue;
lp.ni[i] = ni;
break;
}
if (lp.ni[i] == null) continue;
// use this via at other paths which meet here
for(LEFPath oLp = lefPaths; oLp != null; oLp = oLp.nextLEFPath)
{
for(int j=0; j<2; j++)
{
if (oLp.ni[j] != null) continue;
if (!DBMath.areEquals(oLp.pt[j], lp.pt[i])) continue;
oLp.ni[j] = lp.ni[i];
}
}
}
}
// create pins at all other path ends
for(LEFPath lp = lefPaths; lp != null; lp = lp.nextLEFPath)
{
for(int i=0; i<2; i++)
{
if (lp.ni[i] != null) continue;
NodeProto pin = lp.arc.findPinProto();
if (pin == null) continue;
double sX = pin.getDefWidth();
double sY = pin.getDefHeight();
lp.ni[i] = NodeInst.makeInstance(pin, lp.pt[i], sX, sY, cell);
if (lp.ni[i] == null)
{
System.out.println("Line " + lineReader.getLineNumber() + ": Cannot create pin for PATH");
return true;
}
if (first)
{
// create the port on the first pin
first = false;
Export pp = newPort(cell, lp.ni[i], pin.getPort(0), portname);
if (pp != null) pp.setCharacteristic(portCharacteristics);
}
// use this pin at other paths which meet here
for(LEFPath oLp = lefPaths; oLp != null; oLp = oLp.nextLEFPath)
{
for(int j=0; j<2; j++)
{
if (oLp.ni[j] != null) continue;
if (!DBMath.areEquals(oLp.pt[j], lp.pt[i])) continue;
oLp.ni[j] = lp.ni[i];
}
}
}
}
// now instantiate the paths
for(LEFPath lp = lefPaths; lp != null; lp = lp.nextLEFPath)
{
PortInst head = lp.ni[0].getPortInst(0);
PortInst tail = lp.ni[1].getPortInst(0);
Point2D headPt = lp.pt[0];
Point2D tailPt = lp.pt[1];
ArcInst ai = ArcInst.makeInstanceBase(lp.arc, lp.width, head, tail, headPt, tailPt, null);
if (ai == null)
{
System.out.println("Line " + lineReader.getLineNumber() + ": Cannot create arc for PATH");
return true;
}
}
if (lefPaths == null && singlePathPoint != null && ap != null && first)
{
// path was a single point: plot it
NodeProto pin = ap.findPinProto();
if (pin != null)
{
double sX = pin.getDefWidth();
double sY = pin.getDefHeight();
NodeInst ni = NodeInst.makeInstance(pin, singlePathPoint, sX, sY, cell);
if (ni == null)
{
System.out.println("Line " + lineReader.getLineNumber() + ": Cannot create pin for PATH");
return true;
}
// create the port on the pin
Export pp = newPort(cell, ni, pin.getPort(0), portname);
if (pp != null) pp.setCharacteristic(portCharacteristics);
}
}
return false;
}
/**
* Method to create an Export.
* @param cell the cell in which to create the export.
* @param ni the NodeInst to export.
* @param pp the PortProto on the NodeInst to export.
* @param thename the name of the export.
* @return the new Export.
* The name is modified if it already exists.
*/
private Export newPort(Cell cell, NodeInst ni, PortProto pp, String thename)
{
String portName = thename;
String newName = null;
for(int i=0; ; i++)
{
Export e = (Export)cell.findPortProto(portName);
if (e == null)
{
PortInst pi = ni.findPortInstFromProto(pp);
Export ex = Export.newInstance(cell, pi, portName);
return ex;
}
// make space for modified name
int sqPos = thename.indexOf('[');
if (sqPos < 0) newName = thename + "-" + i; else
newName = thename.substring(0, sqPos) + "-" + i + thename.substring(sqPos);
portName = newName;
}
}
private boolean readLayer(Library lib)
throws IOException
{
String layerName = getAKeyword();
if (layerName == null)
{
System.out.println("EOF parsing LAYER header");
return true;
}
String layerType = null;
double defWidth = -1;
for(;;)
{
// get the next keyword
String key = getAKeyword();
if (key == null)
{
System.out.println("EOF parsing LAYER");
return true;
}
if (key.equalsIgnoreCase("END"))
{
key = getAKeyword();
break;
}
if (key.equalsIgnoreCase("WIDTH"))
{
key = getAKeyword();
if (key == null)
{
System.out.println("EOF reading WIDTH");
return true;
}
defWidth = convertLEFString(key);
if (ignoreToSemicolon("WIDTH")) return true;
continue;
}
if (key.equalsIgnoreCase("TYPE"))
{
layerType = getAKeyword();
if (ignoreToSemicolon("TYPE")) return true;
continue;
}
if (key.equalsIgnoreCase("SPACING") || key.equalsIgnoreCase("PITCH") ||
key.equalsIgnoreCase("DIRECTION") || key.equalsIgnoreCase("CAPACITANCE") ||
key.equalsIgnoreCase("RESISTANCE"))
{
if (ignoreToSemicolon(key)) return true;
continue;
}
}
GetLayerInformation li = new GetLayerInformation(layerName, layerType);
knownLayers.put(layerName, li);
ArcProto ap = li.arc;
if (ap != null && defWidth > 0)
widthsFromLEF.put(ap, new Double(defWidth));
return false;
}
private boolean ignoreToSemicolon(String command)
throws IOException
{
// ignore up to the next semicolon
for(;;)
{
String key = getAKeyword();
if (key == null)
{
System.out.println("EOF parsing " + command);
return true;
}
if (key.equals(";")) break;
}
return false;
}
private boolean ignoreToEnd(String endName)
throws IOException
{
// ignore up to "END endName"
boolean findEnd = true;
for(;;)
{
String key = getAKeyword();
if (key == null)
{
System.out.println("EOF parsing " + endName);
return true;
}
if (findEnd && key.equalsIgnoreCase("END"))
{
key = getAKeyword();
if (key == null)
{
System.out.println("EOF parsing " + endName);
return true;
}
if (key.equals(endName)) break;
continue;
}
if (key.equals(";")) findEnd = true; else findEnd = false;
}
return false;
}
private double convertLEFString(String key)
{
double v = TextUtils.atof(key) * OVERALLSCALE;
return TextUtils.convertFromDistance(v, curTech, TextUtils.UnitScale.MICRO);
}
}