/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: LEFDEF.java
* Input/output tool: LEF and DEF helpers
* 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.prototype.NodeProto;
import com.sun.electric.database.prototype.PortProto;
import com.sun.electric.database.variable.Variable;
import com.sun.electric.technology.ArcProto;
import com.sun.electric.technology.Layer;
import com.sun.electric.technology.PrimitiveNode;
import com.sun.electric.technology.Technology;
import com.sun.electric.util.TextUtils;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* This class defines supporting structures and methods for reading of LEF and DEF files.
*/
public class LEFDEF extends Input<Object>
{
// special controls to ignore LEF/DEF data (set false to eliminate data)
protected static final boolean PLACELEFGEOMETRY = true;
protected static final boolean PLACELEFEXPORTS = true;
protected static final boolean PLACEDEFNETS = true;
protected static ViaDef firstViaDefFromLEF = null;
protected static HashMap<ArcProto,Double> widthsFromLEF = new HashMap<ArcProto,Double>();
protected static Map<String,GetLayerInformation> knownLayers;
protected static final double OVERALLSCALE = 1;
protected static Variable.Key prXkey = Variable.newKey("ATTR_LEFwidth");
protected static Variable.Key prYkey = Variable.newKey("ATTR_LEFheight");
/**
* Class to define Via information for LEF and DEF reading.
*/
protected static class ViaDef
{
protected String viaName;
protected NodeProto via;
protected ArcProto lay1, lay2;
protected double sX, sY;
protected ViaDef nextViaDef;
};
/**
* Method to find a layer from its name.
* Uses a map of known layers, and analyzes the name if none is found.
* @param name the layer name.
* @return the layer information object.
*/
protected GetLayerInformation getLayerInformation(String name)
{
if (knownLayers != null)
{
GetLayerInformation li = knownLayers.get(name);
if (li != null) return li;
}
GetLayerInformation li = new GetLayerInformation(name);
return li;
}
/**
* Class to define layer information for LEF and DEF reading.
*/
protected static class GetLayerInformation
{
NodeProto pin;
NodeProto pure;
ArcProto arc;
ArcProto.Function arcFun;
Layer.Function layerFun;
ArcProto viaArc1, viaArc2;
private NodeProto getPureLayerNode()
{
// find the pure layer node with this function
for(Iterator<Layer> it = Technology.getCurrent().getLayers(); it.hasNext(); )
{
Layer lay = it.next();
if (lay.getFunction() == layerFun)
{
return lay.getPureLayerNode();
}
}
return null;
}
GetLayerInformation(String name)
{
initialize(name, null);
}
GetLayerInformation(String name, String type)
{
initialize(name, type);
}
private void initialize(String name, String type)
{
// initialize
pin = null;
pure = null;
arc = null;
arcFun = ArcProto.Function.UNKNOWN;
layerFun = Layer.Function.UNKNOWN;
viaArc1 = viaArc2 = null;
name = name.toUpperCase();
// first handle known layer names
if (name.startsWith("POLY"))
{
setupPolyLayer(name.substring(4));
return;
}
if (name.equals("PDIFF"))
{
arcFun = ArcProto.Function.DIFFP;
layerFun = Layer.Function.DIFFP;
pure = getPureLayerNode();
return;
}
if (name.equals("NDIFF"))
{
arcFun = ArcProto.Function.DIFFN;
layerFun = Layer.Function.DIFFN;
pure = getPureLayerNode();
return;
}
if (name.equals("DIFF"))
{
arcFun = ArcProto.Function.DIFF;
layerFun = Layer.Function.DIFF;
pure = getPureLayerNode();
return;
}
if (name.equals("CONT") || name.equals("CON"))
{
layerFun = Layer.Function.CONTACT1;
pure = getPureLayerNode();
return;
}
// handle via layers
int j = 0;
if (name.startsWith("VIA")) j = 3; else
if (name.startsWith("V")) j = 1;
if (j != 0)
{
setupViaLayer(name.substring(j));
return;
}
// handle metal layers
j = 0;
if (name.startsWith("METAL")) j = 5; else
if (name.startsWith("MET")) j = 3; else
if (name.startsWith("M")) j = 1;
if (j != 0)
{
setupMetalLayer(name.substring(j));
return;
}
// if type is given, use it
if (type != null)
{
if (type.equalsIgnoreCase("masterslice"))
{
// masterslice layers are typically polysilicon
j = 0;
name = name.toUpperCase();
if (name.startsWith("POLY")) j = 4; else
if (name.startsWith("P")) j = 1;
setupPolyLayer(name.substring(j));
return;
}
if (type.equalsIgnoreCase("cut"))
{
j = 0;
name = name.toUpperCase();
if (name.startsWith("VIA")) j = 3; else
if (name.startsWith("V")) j = 1;
setupViaLayer(name.substring(j));
return;
}
if (type.equalsIgnoreCase("routing"))
{
j = 0;
if (name.startsWith("METAL")) j = 5; else
if (name.startsWith("MET")) j = 3; else
if (name.startsWith("M")) j = 1;
name = name.substring(j);
while (name.length() > 0 && !Character.isDigit(name.charAt(0)))
name = name.substring(1);
setupMetalLayer(name);
return;
}
}
}
private void setupMetalLayer(String name)
{
int layNum = TextUtils.atoi(name);
arcFun = ArcProto.Function.getMetal(layNum);
layerFun = Layer.Function.getMetal(layNum);
if (arcFun == null || layerFun == null) return;
// find the arc with this function
for(Iterator<ArcProto> it = Technology.getCurrent().getArcs(); it.hasNext(); )
{
ArcProto ap = it.next();
if (ap.getFunction() == arcFun)
{
arc = ap;
pin = ap.findPinProto();
break;
}
}
// find the pure layer node with this function
pure = getPureLayerNode();
}
private void setupPolyLayer(String name)
{
int layNum = TextUtils.atoi(name);
if (layNum == 0) layNum = 1;
arcFun = ArcProto.Function.getPoly(layNum);
layerFun = Layer.Function.getPoly(layNum);
if (arcFun == null || layerFun == null) return;
// find the arc with this function
for(Iterator<ArcProto> it = Technology.getCurrent().getArcs(); it.hasNext(); )
{
ArcProto ap = it.next();
if (ap.getFunction() == arcFun)
{
arc = ap;
pin = ap.findPinProto();
break;
}
}
// find the pure layer node with this function
pure = getPureLayerNode();
}
private void setupViaLayer(String name)
{
// find the two layer functions
ArcProto.Function aFunc1 = ArcProto.Function.UNKNOWN;
ArcProto.Function aFunc2 = ArcProto.Function.UNKNOWN;
if (name.length() <= 0)
{
aFunc1 = ArcProto.Function.METAL1;
aFunc2 = ArcProto.Function.METAL2;
} else if (name.length() <= 1)
{
int level = name.charAt(0) - '0';
if (level == 0) aFunc1 = ArcProto.Function.getPoly(1); else
aFunc1 = ArcProto.Function.getMetal(level);
aFunc2 = ArcProto.Function.getMetal(level + 1);
} else
{
int level1 = name.charAt(0) - '0';
if (level1 == 0) aFunc1 = ArcProto.Function.getPoly(1); else
aFunc1 = ArcProto.Function.getMetal(level1);
int level2 = name.charAt(1) - '0';
aFunc2 = ArcProto.Function.getMetal(level2);
}
// find the arcprotos that embody these layers
for(Iterator<ArcProto> it = Technology.getCurrent().getArcs(); it.hasNext(); )
{
ArcProto apTry = it.next();
if (apTry.getFunction() == aFunc1) viaArc1 = apTry;
if (apTry.getFunction() == aFunc2) viaArc2 = apTry;
}
if (viaArc1 == null || viaArc2 == null) return;
// find the via that connects these two arcs
for(Iterator<PrimitiveNode> it = Technology.getCurrent().getNodes(); it.hasNext(); )
{
PrimitiveNode np = it.next();
// must have just one port
if (np.getNumPorts() != 1) continue;
// port must connect to both arcs
PortProto pp = np.getPort(0);
boolean ap1Found = pp.connectsTo(viaArc1);
boolean ap2Found = pp.connectsTo(viaArc2);
if (ap1Found && ap2Found) { pin = np; break; }
}
// find the pure layer node that is the via contact
if (pin != null)
{
// find the layer on this node that is of type "contact"
PrimitiveNode pNp = (PrimitiveNode)pin;
Technology.NodeLayer [] nl = pNp.getNodeLayers();
Layer viaLayer = null;
for(int i=0; i<nl.length; i++)
{
Technology.NodeLayer nLay = nl[i];
Layer lay = nLay.getLayer();
Layer.Function fun = lay.getFunction();
if (fun.isContact()) { viaLayer = lay; layerFun = fun; break; }
}
if (viaLayer == null) return;
pure = viaLayer.getPureLayerNode();
}
}
}
}