/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: Silos.java * Input/output tool: Silos netlist output * 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.output; import com.sun.electric.database.hierarchy.Cell; import com.sun.electric.database.hierarchy.Nodable; import com.sun.electric.database.network.Global; import com.sun.electric.database.network.Netlist; import com.sun.electric.database.network.Network; import com.sun.electric.database.prototype.PortCharacteristic; import com.sun.electric.database.prototype.PortProto; import com.sun.electric.database.text.TextUtils; 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.PrimitiveNode; import com.sun.electric.technology.technologies.Schematics; import com.sun.electric.tool.simulation.Simulation; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.Date; import java.util.Iterator; /** * This is the netlister for Silos. */ public class Silos extends Topology { /** split lines into 80 characters. */ private static final int MAXSTR = 79; /** Maximum macro name length. */ private static final int MAXNAME = 12; /** key of Variable holding node name. */ public static final Variable.Key SILOS_NODE_NAME_KEY = Variable.newKey("SIM_silos_node_name"); /** key of Variable holding global names. */ public static final Variable.Key SILOS_GLOBAL_NAME_KEY = Variable.newKey("SIM_silos_global_name"); /** key of Variable holding behavior file. */ public static final Variable.Key SILOS_BEHAVIOR_FILE_KEY = Variable.newKey("SIM_silos_behavior_file"); /** key of Variable holding model. */ public static final Variable.Key SILOS_MODEL_KEY = Variable.newKey("SC_silos"); private SilosPreferences localPrefs; public static class SilosPreferences extends OutputPreferences { public SilosPreferences(boolean factory) { super(factory); } public Output doOutput(Cell cell, VarContext context, String filePath) { Silos out = new Silos(this); if (out.openTextOutputStream(filePath)) return out.finishWrite(); if (out.writeCell(cell, context)) return out.finishWrite(); if (out.closeTextOutputStream()) return out.finishWrite(); System.out.println(filePath + " written"); return out.finishWrite(); } } /** * Creates a new instance of the Silos netlister. */ Silos(SilosPreferences sp) { localPrefs = sp; } protected void start() { // parameters to the output-line-length limit and how to break long lines setOutputWidth(MAXSTR, true); setContinuationString("+"); // write header information writeWidthLimited("\n$ CELL " + topCell.describe(false) + " FROM LIBRARY " + topCell.getLibrary().getName() + "\n"); emitCopyright("$ ", ""); if (localPrefs.includeDateAndVersionInOutput) { writeWidthLimited("$ CELL CREATED ON " + TextUtils.formatDate(topCell.getCreationDate()) + "\n"); writeWidthLimited("$ VERSION " + topCell.getVersion() + "\n"); writeWidthLimited("$ LAST REVISED " + TextUtils.formatDate(topCell.getRevisionDate()) + "\n"); writeWidthLimited("$ SILOS netlist written by Electric VLSI Design System, version " + Version.getVersion() + "\n"); writeWidthLimited("$ WRITTEN ON " + TextUtils.formatDate(new Date()) + "\n"); } else { writeWidthLimited("$ SILOS netlist written by Electric VLSI Design System\n"); } // First look for any global sources for(Iterator<NodeInst> it = topCell.getNodes(); it.hasNext(); ) { NodeInst ni = it.next(); if (ni.isCellInstance()) continue; // only real sources PrimitiveNode.Function nodetype = ni.getFunction(); if (nodetype != PrimitiveNode.Function.SOURCE) continue; Variable var = ni.getVar(SILOS_GLOBAL_NAME_KEY); String name = ""; if (var != null) // is this a global source ? { name = var.getObject().toString(); writeWidthLimited(".GLOBAL " + convertSpecialNames(name) + "\n"); } // Get the source type var = ni.getVar(Spice.SPICE_MODEL_KEY); if (var == null) { reportError("Unspecified source:"); writeWidthLimited("$$$$$ Unspecified source: \n"); } else // There is more { boolean clktype = false; // Extra data required if variable there String msg = var.getObject().toString(); String line = ""; char lastChr = 0; for(int i=0; i<msg.length(); i++) { lastChr = msg.charAt(i); if (lastChr == '/') break; switch (lastChr) { case 'g': // a global clock (THIS IS WRONG!!!) line = name + " .CLK "; clktype = true; break; case 'h': // a fixed high source (THIS IS WRONG!!!) line = name + " .CLK 0 S1 $ HIGH LEVEL"; break; case 'l': // a fixed low source (THIS IS WRONG!!!) line = name + " .CLK 0 S0 $ LOW LEVEL"; break; } } if (lastChr == '/' && clktype) line += msg.substring(msg.indexOf('/')+1); writeWidthLimited(line + "\n"); } } } protected void done() { } /** * Method to write cellGeom */ protected void writeCellTopology(Cell cell, String cellName, CellNetInfo cni, VarContext context, Topology.MyCellInfo info) { // Read a behavior file if it is available for(Iterator<Cell> it = cell.getCellGroup().getCells(); it.hasNext(); ) { Cell oCell = it.next(); Variable var = oCell.getVar(SILOS_BEHAVIOR_FILE_KEY); if (var != null) { String headerPath = TextUtils.getFilePath(cell.getLibrary().getLibFile()); String fileName = headerPath + var.getObject().toString(); File test = new File(fileName); if (!test.exists()) { reportError("Cannot find SILOS behavior file " + fileName + " on " + cell); } else { try { FileReader fr = new FileReader(test); BufferedReader br = new BufferedReader(fr); for(;;) { String line = br.readLine(); if (line == null) break; writeWidthLimited(line + "\n"); } br.close(); fr.close(); } catch (IOException e) {} return; } } } // There was no behavior file, get the SILOS model from the library if it exists for(Iterator<Cell> it = cell.getCellGroup().getCells(); it.hasNext(); ) { Cell oCell = it.next(); Variable var = oCell.getVar(SILOS_MODEL_KEY); if (var != null && var.getObject() instanceof String[]) { String [] model = (String [])var.getObject(); for(int i = 0; i < model.length; i++) writeWidthLimited(model[i] + "\n"); writeWidthLimited("\n"); return; } } // gather networks in the cell Netlist netList = cni.getNetList(); // write the module header if (cell != topCell) { writeWidthLimited("\n"); String name = cni.getParameterizedName(); if (name.length() > MAXNAME) { String msg = ".MACRO name " + name + " is too long;"; name = name.substring(0, MAXNAME); msg += " truncated to " + name; reportWarning(msg); } writeWidthLimited(".MACRO " + convertName(name)); for(Iterator<CellAggregateSignal> it = cni.getCellAggregateSignals(); it.hasNext(); ) { CellAggregateSignal cas = it.next(); if (cas.getExport() == null) continue; if (cas.isSupply()) continue; writeWidthLimited(" " + convertSubscripts(cas.getNameWithIndices())); } writeWidthLimited("\n"); } else writeWidthLimited("\n"); // write the cell instances for(Iterator<Nodable> nIt = netList.getNodables(); nIt.hasNext(); ) { Nodable no = nIt.next(); if (no.isCellInstance()) { String nodeName = parameterizedName(no, context); CellNetInfo subCni = getCellNetInfo(nodeName); writeWidthLimited("(" + no.getName() + " " + convertName(nodeName)); for(Iterator<CellAggregateSignal> sIt = subCni.getCellAggregateSignals(); sIt.hasNext(); ) { CellAggregateSignal cas = sIt.next(); if (cas.isSupply()) continue; // ignore networks that aren't exported PortProto pp = cas.getExport(); if (pp == null) continue; int low = cas.getLowIndex(), high = cas.getHighIndex(); if (low > high) { // single signal Network net = netList.getNetwork(no, pp, cas.getExportIndex()); CellSignal cs = cni.getCellSignal(net); writeWidthLimited(" " + cs.getName()); } else { int total = high - low + 1; CellSignal [] outerSignalList = new CellSignal[total]; for(int j=low; j<=high; j++) { CellSignal cInnerSig = cas.getSignal(j-low); Network net = netList.getNetwork(no, cas.getExport(), cInnerSig.getExportIndex()); outerSignalList[j-low] = cni.getCellSignal(net); } writeBus(outerSignalList, low, high, cas.isDescending(), cas.getName(), cni.getPowerNet(), cni.getGroundNet()); } } writeWidthLimited("\n"); } } // write the primitives for(Iterator<Nodable> nIt = netList.getNodables(); nIt.hasNext(); ) { Nodable no = nIt.next(); // not interested in passive nodes (ports electrically connected) if (!no.isCellInstance()) { NodeInst ni = (NodeInst)no; PrimitiveNode.Function nodeType = getPrimitiveType(ni); if (nodeType == PrimitiveNode.Function.UNKNOWN) continue; if (nodeType.isFET()) { // Transistors need a part number writeWidthLimited(getNodeInstName(ni)); writeWidthLimited(" "); writeWidthLimited(getPrimitiveName(ni, false)); // write the names of the port(s) for(Iterator<PortProto> pIt = ni.getProto().getPorts(); pIt.hasNext(); ) { PortProto pp = pIt.next(); writeWidthLimited(getPortProtoName(cell == topCell, null, ni, pp, cell, netList, cni)); } writeWidthLimited("\n"); continue; } if (nodeType.isFlipFlop()) { // flip-flops need a part number writeWidthLimited(getNodeInstName(ni)); writeWidthLimited(" "); writeWidthLimited(getPrimitiveName(ni, false)); // write the names of the port(s) writeFlipFlop(cell == topCell, ni, cell, nodeType, netList, cni); continue; } if (nodeType == PrimitiveNode.Function.METER || nodeType == PrimitiveNode.Function.SOURCE) { if (cell != topCell) reportWarning("WARNING: Global Clock in a sub-cell"); continue; } if (nodeType == PrimitiveNode.Function.GATEAND || nodeType == PrimitiveNode.Function.GATEOR || nodeType == PrimitiveNode.Function.GATEXOR || nodeType == PrimitiveNode.Function.BUFFER) { // Gates use their output port as a name PortProto outPP = null; for(Iterator<PortProto> pIt = ni.getProto().getPorts(); pIt.hasNext(); ) { PortProto pp = pIt.next(); if (pp.getCharacteristic() == PortCharacteristic.OUT) { // find the name of the output port writeWidthLimited(getPortProtoName(cell == topCell, null, ni, pp, cell, netList, cni)); // record that we used it outPP = pp; // determine if this proto is negated Connection con = null; for(Iterator<Connection> aIt = ni.getConnections(); aIt.hasNext(); ) { Connection c = aIt.next(); if (c.getPortInst().getPortProto() == pp) { con = c; break; } } boolean negated = false; if (con != null && con.isNegated()) negated = true; writeWidthLimited(" " + getPrimitiveName(ni, negated)); break; } } if (outPP == null) reportError("Could not find an output connection on " + ni.getProto().getName()); // get the fall and rise times writeWidthLimited(getRiseTime(ni)); writeWidthLimited(getFallTime(ni)); // write the rest of the ports only if they're connected for(Iterator<Connection> aIt = ni.getConnections(); aIt.hasNext(); ) { Connection con = aIt.next(); PortProto pp = con.getPortInst().getPortProto(); if (pp == outPP) continue; writeWidthLimited(getPortProtoName(cell == topCell, con, ni, pp, cell, netList, cni)); } writeWidthLimited("\n"); continue; } if (nodeType == PrimitiveNode.Function.CAPAC) { // find a connected port for the node name for(Iterator<Connection> aIt = ni.getConnections(); aIt.hasNext(); ) { Connection con = aIt.next(); // write port name as output PortProto pp = con.getPortInst().getPortProto(); writeWidthLimited(getPortProtoName(cell == topCell, null, ni, pp, cell, netList, cni)); writeWidthLimited(" " + getPrimitiveName(ni, false)); double j = getCapacitanceInMicroFarads(ni, context); if (j >= 0) { writeWidthLimited(" " + TextUtils.formatDouble(j, 0)); } else { reportWarning("Warning: capacitor with no value on " + ni); } writeWidthLimited("\n"); break; } continue; } if (nodeType == PrimitiveNode.Function.RESIST) { // sorry! can't handle the resistive gate yet continue; } } } if (cell != topCell) writeWidthLimited(".EOM\n"); } /** * Method to add a bus of signals named "name" to the infinite string "infstr". If "name" is zero, * do not include the ".NAME()" wrapper. The signals are in "outerSignalList" and range in index from * "lowindex" to "highindex". They are described by a bus with characteristic "tempval" * (low bit is on if the bus descends). Any unconnected networks can be numbered starting at * "*unconnectednet". The power and grounds nets are "pwrnet" and "gndnet". */ private void writeBus(CellSignal [] outerSignalList, int lowIndex, int highIndex, boolean descending, String name, Network pwrNet, Network gndNet) { // presume writing the bus as a whole boolean breakBus = false; // see if all of the nets on this bus are distinct int j = lowIndex+1; for( ; j<=highIndex; j++) { CellSignal cs = outerSignalList[j-lowIndex]; int k = lowIndex; for( ; k<j; k++) { CellSignal oCs = outerSignalList[k-lowIndex]; if (cs == oCs) break; } if (k < j) break; } if (j <= highIndex) { breakBus = true; } else { // bus entries must have the same root name and go in order String lastnetname = null; for(j=lowIndex; j<=highIndex; j++) { CellSignal wl = outerSignalList[j-lowIndex]; String thisnetname = wl.getName(); if (wl.getExport() != null) { if (wl.isDescending()) { if (!descending) break; } else { if (descending) break; } } int openSquare = thisnetname.indexOf('['); if (openSquare < 0) break; if (j > lowIndex) { int li = 0; for( ; li < lastnetname.length(); li++) { if (thisnetname.charAt(li) != lastnetname.charAt(li)) break; if (lastnetname.charAt(li) == '[') break; } if (lastnetname.charAt(li) != '[' || thisnetname.charAt(li) != '[') break; int thisIndex = TextUtils.atoi(thisnetname.substring(li+1)); int lastIndex = TextUtils.atoi(lastnetname.substring(li+1)); if (thisIndex != lastIndex + 1) break; } lastnetname = thisnetname; } if (j <= highIndex) breakBus = true; } writeWidthLimited(" "); if (breakBus) { int start = lowIndex, end = highIndex; int order = 1; if (descending) { start = highIndex; end = lowIndex; order = -1; } for(int k=start; ; k += order) { if (k != start) writeWidthLimited("-"); CellSignal cs = outerSignalList[k-lowIndex]; writeWidthLimited(cs.getName()); if (k == end) break; } } else { CellSignal lastCs = outerSignalList[0]; String lastNetName = lastCs.getName(); int openSquare = lastNetName.indexOf('['); CellSignal cs = outerSignalList[highIndex-lowIndex]; String netName = cs.getName(); int i = netName.indexOf('['); if (i < 0) writeWidthLimited(netName); else { writeWidthLimited(netName.substring(0, i)); if (descending) { int first = TextUtils.atoi(netName.substring(i+1)); int second = TextUtils.atoi(lastNetName.substring(openSquare+1)); writeWidthLimited("[" + first + ":" + second + "]"); } else { int first = TextUtils.atoi(netName.substring(i+1)); int second = TextUtils.atoi(lastNetName.substring(openSquare+1)); writeWidthLimited("[" + second + ":" + first + "]"); } } } } /** * Method to return a string describing the SILOS type of nodeinst "ni" * if 'neg' is true, then the negated version is needed */ private String getPrimitiveName(NodeInst ni, boolean neg) { PrimitiveNode.Function f = getPrimitiveType(ni); if (f.isNTypeTransistor()) return ".NMOS"; if (f.isPTypeTransistor()) return ".PMOS"; if (f == PrimitiveNode.Function.BUFFER) { if (neg) return ".INV"; return ".BUF"; } if (f == PrimitiveNode.Function.GATEXOR) { if (neg) return ".XNOR"; return ".XOR"; } if (f == PrimitiveNode.Function.GATEAND) { if (neg) return ".NAND"; return ".NAND"; } if (f == PrimitiveNode.Function.GATEOR) { if (neg) return ".NOR"; return ".OR"; } if (f == PrimitiveNode.Function.RESIST) return ".RES"; if (f == PrimitiveNode.Function.CAPAC) return ".CAP"; if (f == PrimitiveNode.Function.FLIPFLOPRSMS || f == PrimitiveNode.Function.FLIPFLOPRSP) return ".SRPEFF"; if (f == PrimitiveNode.Function.FLIPFLOPRSN) return ".SRNEFF"; if (f == PrimitiveNode.Function.FLIPFLOPJKMS || f == PrimitiveNode.Function.FLIPFLOPJKP) return ".JKPEFF"; if (f == PrimitiveNode.Function.FLIPFLOPJKN) return ".JKNEFF"; if (f == PrimitiveNode.Function.FLIPFLOPDMS || f == PrimitiveNode.Function.FLIPFLOPDP) return ".DPEFF"; if (f == PrimitiveNode.Function.FLIPFLOPDN) return ".DNEFF"; if (f == PrimitiveNode.Function.FLIPFLOPTMS || f == PrimitiveNode.Function.FLIPFLOPTP) return ".TPEFF"; if (f == PrimitiveNode.Function.FLIPFLOPTN) return ".TNEFF"; return convertName(ni.getProto().getName()); } /** * Method to return the SILOS type of a node * Read the contents of the added string, make it available to * the caller */ private PrimitiveNode.Function getPrimitiveType(NodeInst ni) { if (ni.isCellInstance()) return null; PrimitiveNode.Function func = ni.getFunction(); if (func.isPTypeTransistor()) return PrimitiveNode.Function.TRAPMOS; if (func.isNTypeTransistor()) return PrimitiveNode.Function.TRANMOS; if (func == PrimitiveNode.Function.GATEAND || func == PrimitiveNode.Function.GATEOR || func == PrimitiveNode.Function.GATEXOR || func == PrimitiveNode.Function.BUFFER || func == PrimitiveNode.Function.RESIST || func == PrimitiveNode.Function.CAPAC || func == PrimitiveNode.Function.SOURCE || func == PrimitiveNode.Function.METER || func == PrimitiveNode.Function.FLIPFLOPRSMS || func == PrimitiveNode.Function.FLIPFLOPRSP || func == PrimitiveNode.Function.FLIPFLOPRSN || func == PrimitiveNode.Function.FLIPFLOPJKMS || func == PrimitiveNode.Function.FLIPFLOPJKP || func == PrimitiveNode.Function.FLIPFLOPJKN || func == PrimitiveNode.Function.FLIPFLOPDMS || func == PrimitiveNode.Function.FLIPFLOPDP || func == PrimitiveNode.Function.FLIPFLOPDN || func == PrimitiveNode.Function.FLIPFLOPTMS || func == PrimitiveNode.Function.FLIPFLOPTP || func == PrimitiveNode.Function.FLIPFLOPTN) return func; return(PrimitiveNode.Function.UNKNOWN); } /** * Method to return a string describing the SILOS part name of nodeinst * "ni" */ private String getNodeInstName(NodeInst ni) { Variable var = ni.getVar(SILOS_NODE_NAME_KEY); if (var != null) return var.describe(-1); String name = ni.getName(); if (name.length() > 0) { if (Character.isLetter(name.charAt(0))) return name; if (name.charAt(0) == '[') return convertSubscripts(name); } return "U" + name; } /** * Find a name to write for the port prototype, pp, on the node instance, ni * The node instance is located within the prototype, np * If there is an arc connected to the port, use the net name, or NETn. * If there are more than one arc (that are not electrically connected) * on the port, concatenate the names (with spaces between them). * If there is no arc, but the port is an export, use the exported name. * If the port is a power or ground port, ignore it * If this is not the top level cell (ie. a .macro) remove [] notation. */ private String getPortProtoName(boolean top, Connection con, NodeInst ni, PortProto pp, Cell np, Netlist netList, CellNetInfo cni) { if (pp.isPower() || pp.isGround()) return ""; if (con == null) { for(Iterator<Connection> it = ni.getConnections(); it.hasNext(); ) { Connection c = it.next(); PortInst pi = c.getPortInst(); if (pi.getPortProto() != pp) continue; con = c; } } boolean negated = false; if (con != null && con.isNegated() && pp.getCharacteristic() == PortCharacteristic.IN) negated = true; Network net = null; if (con != null) { net = netList.getNetwork(con.getArc(), 0); } else { PortInst pi = ni.findPortInstFromProto(pp); net = netList.getNetwork(pi); } if (net != null) { CellSignal cs = cni.getCellSignal(net); StringBuffer infstr = new StringBuffer(); infstr.append(" "); if (negated) infstr.append("-"); infstr.append(cs.getName()); return infstr.toString(); } // nothing connected to this port...leave a position return " .SKIP"; } /** * Method returns a string containing the rise time, as stored in * the variable SIM_rise_delay on node instance ni. * SIM_rise_delay can be multiple numbers (e.g. "rise_time,fanout") * This function returns a string. * A space is inserted as the first character in the string. * Returns an empty string if no variable found. */ private String getRiseTime(NodeInst ni) { Variable var = ni.getVar(Simulation.RISE_DELAY_KEY); if (var != null) return var.describe(-1); return ""; } /** * Method returns a string containing the fall time, as stored in * the variable SIM_fall_delay on node instance ni. * SIM_fall_delay can be either an integer or a string * (e.g. "fall_time,fanout") * This function returns a string. * A space is inserted as the first character in the string. * Returns an empty string if no variable found. */ private String getFallTime(NodeInst ni) { Variable var = ni.getVar(Simulation.FALL_DELAY_KEY); if (var != null) return var.describe(-1); return ""; } /** * Method to return an integer as the capacitance defined * by "SCHEM_capacitance" variable on an instance of a capacitor. * The returned units are in microfarads (is this right?). * Return -1 if nothing found. */ private double getCapacitanceInMicroFarads(NodeInst ni, VarContext context) { Variable var = ni.getVar(Schematics.SCHEM_CAPACITANCE); if (var != null) { String cap = context.evalVar(var).toString(); char lastChar = 0; int len = cap.length(); if (len > 0) lastChar = cap.charAt(len-1); if (lastChar == 'f' || lastChar == 'F') cap = cap.substring(0, len-1); double farads = VarContext.objectToDouble(cap, 0.0); double microFarads = farads * 1000000.0; return microFarads; } return -1; } /** * Method to write the ports of a flip-flop; * get them in the Electric order, then rewrite them * 'ni' is the current NODEINST, found in 'np' cell */ private static final int JORD = 0; private static final int K = 1; private static final int Q = 2; private static final int QB = 3; private static final int CK = 4; private static final int PRE = 5; private static final int CLR = 6; private void writeFlipFlop(boolean top, NodeInst ni, Cell np, PrimitiveNode.Function type, Netlist netList, CellNetInfo cni) { String [] portNames = new String[7]; Iterator<PortProto> it = ni.getProto().getPorts(); for(int i=0; i<7; i++) { if (!it.hasNext()) break; PortProto pp = it.next(); portNames[i] = getPortProtoName(top, null, ni, pp, np, netList, cni); } if (portNames[PRE].equals(" .SKIP") && portNames[CLR].equals(" .SKIP")) { portNames[CLR] = ""; // If neither on, don't print portNames[PRE] = ""; } if (type == PrimitiveNode.Function.FLIPFLOPDMS) { writeWidthLimited(portNames[CK] + portNames[JORD] + portNames[PRE] + portNames[CLR] + " /" + portNames[Q]+ portNames[QB]); } else { writeWidthLimited(portNames[CK] + portNames[JORD] + portNames[K] + portNames[PRE] + portNames[CLR] + " /" + portNames[Q] + portNames[QB]); } } /** * Method to convert special names to SILOS format */ private String convertSpecialNames(String str) { if (str.equals("vdd")) return ".VDD"; if (str.equals("vss")) return ".VSS"; if (str.equals("vcc")) return ".VCC"; if (str.equals("gnd")) return ".GND"; if (str.equals("low")) return ".GND"; if (str.equals("hig")) return ".VDD"; return str; } /** * replace subscripted name with __ format */ private String convertSubscripts(String string) { StringBuffer sb = new StringBuffer(); for(int i=0; i<string.length(); i++) { char chr = string.charAt(i); if (chr == '[') { sb.append("__"); continue; } if (chr == ']') continue; sb.append(chr); } return sb.toString(); } /** * routine to replace all non-printing characters * in the string "p" with the letter "X" and return the string * We will not permit a digit in the first location; replace it * with '_' */ private String convertName(String p) { int len = p.length(); if (len <= 0) return p; boolean defined = true; for(int i=0; i<len; i++) if (!Character.isDefined(p.charAt(i))) { defined = false; break; } if (defined && !TextUtils.isDigit(p.charAt(0))) return p; StringBuffer sb = new StringBuffer(); if (TextUtils.isDigit(p.charAt(0))) sb.append("_"); for(int i=0; i<len; i++) { char t = p.charAt(i); if (Character.isDefined(t)) sb.append(t); else sb.append("_"); } return sb.toString(); } /****************************** SUBCLASSED METHODS FOR THE TOPOLOGY ANALYZER ******************************/ /** * Method to adjust a cell name to be safe for Silos output. * @param name the cell name. * @return the name, adjusted for Silos output. */ protected String getSafeCellName(String name) { return name; } /** Method to return the proper name of Power */ protected String getPowerName(Network net) { return ".VDD"; } /** Method to return the proper name of Ground */ protected String getGroundName(Network net) { return ".GND"; } /** Method to return the proper name of a Global signal */ protected String getGlobalName(Global glob) { return glob.getName(); } /** Method to report that export names DO take precedence over * arc names when determining the name of the network. */ protected boolean isNetworksUseExportedNames() { return true; } /** Method to report that library names ARE always prepended to cell names. */ protected boolean isLibraryNameAlwaysAddedToCellName() { return false; } /** Method to report that aggregate names (busses) ARE used. */ protected boolean isAggregateNamesSupported() { return true; } /** Abstract method to decide whether aggregate names (busses) can have gaps in their ranges. */ protected boolean isAggregateNameGapsSupported() { return false; } /** Method to report whether input and output names are separated. */ protected boolean isSeparateInputAndOutput() { return true; } /** Abstract method to decide whether netlister is case-sensitive (Verilog) or not (Spice). */ protected boolean isCaseSensitive() { return true; } /** * Method to adjust a network name to be safe for Silos output. */ protected String getSafeNetName(String name, boolean bus) { return name; } /** Tell the Hierarchy enumerator how to short resistors */ @Override protected Netlist.ShortResistors getShortResistors() { return Netlist.ShortResistors.ALL; } /** * Method to tell whether the topological analysis should mangle cell names that are parameterized. */ protected boolean canParameterizeNames() { return true; } }