/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: IRSIM.java
* Input/output tool: IRSIM Netlist output
* 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.output;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.network.Netlist;
import com.sun.electric.database.network.Network;
import com.sun.electric.database.text.Version;
import com.sun.electric.database.topology.Connection;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.topology.PortInst;
import com.sun.electric.database.variable.VarContext;
import com.sun.electric.database.variable.Variable;
import com.sun.electric.technology.Layer;
import com.sun.electric.technology.PrimitiveNode;
import com.sun.electric.technology.Technology;
import com.sun.electric.technology.TransistorSize;
import com.sun.electric.technology.technologies.Schematics;
import com.sun.electric.tool.extract.ExtractedPBucket;
import com.sun.electric.tool.extract.ParasiticGenerator;
import com.sun.electric.tool.extract.ParasiticTool;
import com.sun.electric.tool.extract.RCPBucket;
import com.sun.electric.tool.extract.TransistorPBucket;
import com.sun.electric.tool.simulation.SimulationTool;
import com.sun.electric.tool.user.User;
import com.sun.electric.util.TextUtils;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
/**
* Class to write IRSIM netlists.
*/
public class IRSIM extends Output implements ParasiticGenerator
{
private VarContext context;
private List<Object> components;
private Technology technology;
private IRSIMPreferences localPrefs;
public static class IRSIMPreferences extends OutputPreferences
{
// From Settings
Technology layoutTech = Schematics.getDefaultSchematicTechnology();
Technology schematicTech = User.getSchematicTechnology();
// run preferences
public int irDebug = SimulationTool.getIRSIMDebugging();
public String steppingModel = SimulationTool.getIRSIMStepModel();
public String parameterFile = SimulationTool.getIRSIMParameterFile();
public IRSIMPreferences(boolean factory) { super(factory); }
@Override
public Output doOutput(Cell cell, VarContext context, String filePath)
{
IRSIM out = new IRSIM(this);
out.technology = cell.getTechnology();
if (out.technology == Schematics.tech()) out.technology = schematicTech;
out.writeNetlist(cell, context, layoutTech, filePath);
return out.finishWrite();
}
}
/**
* Creates a new instance of IRSIM
*/
private IRSIM(IRSIMPreferences ip)
{
localPrefs = ip;
context = null;
}
/**
* The main entry point for IRSIM extraction.
* @param cell the top-level cell to extract.
* @param context the hierarchical context to the cell.
* @return a List of ComponentInfoOLD objects that describes the circuit.
*/
public static List<Object> getIRSIMComponents(Cell cell, VarContext context, IRSIMPreferences ip)
{
// gather all components
IRSIM out = new IRSIM(ip);
out.technology = cell.getTechnology();
if (out.technology == Schematics.tech()) out.technology = ip.schematicTech;
return out.getNetlist(cell, context);
}
private List<Object> getNetlist(Cell cell, VarContext context)
{
this.context = context;
if (context == null) this.context = VarContext.globalContext;
components = ParasiticTool.calculateParasistic(this, cell, context);
return components;
}
private void writeNetlist(Cell cell, VarContext context, Technology layoutTech, String filePath)
{
// gather all components
List<Object> parasitics = getNetlist(cell, context);
// write them
if (openTextOutputStream(filePath)) return;
// write the header
double scale = technology.getScale() / 10;
printWriter.println("| units: " + scale + " tech: " + technology.getTechName() + " format: SU");
printWriter.println("| IRSIM file for cell " + cell.noLibDescribe() +
" from library " + cell.getLibrary().getName());
emitCopyright("| ", "");
if (localPrefs.includeDateAndVersionInOutput)
{
printWriter.println("| Created on " + TextUtils.formatDate(cell.getCreationDate()));
printWriter.println("| Last revised on " + TextUtils.formatDate(cell.getRevisionDate()));
printWriter.println("| Written on " + TextUtils.formatDate(new Date()) +
" by Electric VLSI Design System, version " + Version.getVersion());
} else
{
printWriter.println("| Written by Electric VLSI Design System");
}
// write the components
for(Object obj : parasitics)
{
ExtractedPBucket ci = (ExtractedPBucket)obj;
String info = ci.getInfo(layoutTech);
if (info != null && !info.equals("")) printWriter.println(info);
}
if (closeTextOutputStream()) return;
System.out.println(filePath + " written");
ParasiticTool.getParasiticErrorLogger().sortLogs();
ParasiticTool.getParasiticErrorLogger().termLogging(true);
}
//---------------------------- ParasiticGenerator interface --------------------
public ExtractedPBucket createBucket(NodeInst ni, ParasiticTool.ParasiticCellInfo info)
{
ExtractedPBucket bucket = null;
Netlist netlist = info.getNetlist();
int numRemoveParents = context.getNumLevels();
// Depending on primitive node
if (ni.isPrimitiveTransistor())
{
PortInst g = ni.getTransistorGatePort();
PortInst d = ni.getTransistorDrainPort();
PortInst s = ni.getTransistorSourcePort();
if (g == null || d == null || s == null)
{
reportError("PortInst for " + ni + " null!");
return null;
}
Network gnet = netlist.getNetwork(g);
Network dnet = netlist.getNetwork(d);
Network snet = netlist.getNetwork(s);
if (gnet == null || dnet == null || snet == null)
{
reportWarning("Warning, ignoring unconnected transistor " + ni + " in cell " + info.getCell());
return null;
}
TransistorSize dim = ni.getTransistorSize(info.getContext());
if (dim != null && (dim.getDoubleLength() == 0 || dim.getDoubleWidth() == 0))
{
if (ni.getFunction().isFET())
{
double len = dim.getDoubleLength();
double wid = dim.getDoubleWidth();
if (len == 0) len = 2;
if (wid == 0) wid = 2;
dim = new TransistorSize(new Double(wid), new Double(len), dim.getActiveLength(), null, true);
reportWarning("Warning, cannot evaluate size of transistor " + ni +
" in cell " + info.getCell() + ", using default sizes");
} else dim = null;
}
if (dim == null)
{
reportWarning("Warning, ignoring non fet transistor " + ni + " in cell " + info.getCell());
return null;
}
// print out transistor
String gName = info.getUniqueNetNameProxy(gnet, "/").toString(numRemoveParents);
String sName = info.getUniqueNetNameProxy(snet, "/").toString(numRemoveParents);
String dName = info.getUniqueNetNameProxy(dnet, "/").toString(numRemoveParents);
bucket = new TransistorPBucket(ni, dim, gName, sName, dName, info.getMFactor());
}
else
{
// handle resistors and capacitors
PrimitiveNode.Function fun = ni.getFunction();
double rcValue = 0;
char type = 0;
Network net1 = null, net2 = null;
String net1Name = null, net2Name = null;
Technology tech = info.getCell().getTechnology();
if (fun.isContact())
{
for (Iterator<Connection> it = ni.getConnections(); it.hasNext();)
{
Connection c = it.next();
Network net = netlist.getNetwork(c.getArc(), 0);
if (net1 == null)
{
net1 = net;
net1Name = info.getUniqueNetNameProxy(net1, "/").toString(numRemoveParents) + "_" + c.getArc().getName();
}
else if (net2 == null)
{
net2 = net;
net2Name = info.getUniqueNetNameProxy(net2, "/").toString(numRemoveParents) + "_" + c.getArc().getName();
}
else
reportWarning("Warning: contact " + ni.describe(true) + " has more than 2 connections, RC estimation may be wrong");
}
// RC value will be via resistance divided by number of cuts of this contact
// Searching for via layer
PrimitiveNode pn = (PrimitiveNode)ni.getProto();
Technology.MultiCutData mcd = new Technology.MultiCutData(ni.getD(), ni.getTechPool());
int cuts = mcd.numCuts();
Technology.NodeLayer[] layers = pn.getNodeLayers();
Layer thisLayer = null;
for (int i = 0; i < layers.length; i++)
{
if (layers[i].getLayer().getFunction().isContact())
{
thisLayer = layers[i].getLayer();
break;
}
}
if (thisLayer != null)
rcValue = thisLayer.getResistance()/cuts;
type = 'r';
// Only valid for layout
if ((rcValue < tech.getMinResistance()))
return null;
}
else if (fun.isResistor() || fun.isCapacitor())
{
PortInst end1 = ni.getPortInst(0);
PortInst end2 = ni.getPortInst(1);
if (end1 == null || end2 == null)
{
reportError("PortInst for " + ni + " null!");
return null;
}
net1 = netlist.getNetwork(end1);
net2 = netlist.getNetwork(end2);
if (net1 == null || net2 == null)
{
reportWarning("Warning, ignoring unconnected component " + ni + " in cell " + info.getCell());
return null;
}
net1Name = info.getUniqueNetNameProxy(net1, "/").toString(numRemoveParents);
net2Name = info.getUniqueNetNameProxy(net2, "/").toString(numRemoveParents);
Variable.Key varKey = Schematics.SCHEM_CAPACITANCE;
if (fun.isResistor())
{
varKey = Schematics.SCHEM_RESISTANCE;
}
Variable valueVar = ni.getVar(varKey);
String extra = "";
if (valueVar != null)
{
extra = valueVar.describe(info.getContext(), ni);
if (TextUtils.isANumber(extra))
{
double pureValue = TextUtils.atof(extra);
extra = TextUtils.formatDoublePostFix(pureValue); // displayedUnits(pureValue, unit, TextUtils.UnitScale.NONE);
}
}
rcValue = 0;
if (extra.length() > 0) rcValue = TextUtils.parsePostFixNumber(extra, null).doubleValue();
if (fun.isResistor())
{
type = 'r';
} else
{
type = 'C';
rcValue = Math.rint((rcValue/ 1e-15) * 1000) / 1000;
}
}
if (type == 0) return null;
if ((type == 'C' && rcValue < tech.getMinCapacitance()))
return null;
bucket = new RCPBucket(type, net1Name, net2Name, rcValue);
}
return bucket;
}
}