/* -*- 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; } }