/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: Tegas.java
* Original C Code written by T.J.Goodman, University of Canterbury, N.Z.
* Translated to Java 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.hierarchy.Export;
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.topology.ArcInst;
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.PrimitivePort;
import com.sun.electric.tool.simulation.SimulationTool;
import com.sun.electric.tool.user.User;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
/**
* This is the netlister for Tegas.
*/
public class Tegas extends Topology
{
private static final int MAXLENGTH = 80;
private static final int MAXNAMECHARS = 12;
private Map<Nodable,Integer> nodeNames;
private Map<ArcInst,Integer> implicitInverters;
private Netlist netList;
private TegasPreferences localPrefs;
public static class TegasPreferences extends OutputPreferences
{
String workingDirectory = "";
public TegasPreferences(boolean factory) {
super(factory);
workingDirectory = factory ? "" : User.getWorkingDirectory();
}
public Output doOutput(Cell cell, VarContext context, String filePath)
{
Tegas out = new Tegas(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 Tegas netlister.
*/
Tegas(TegasPreferences tp) { localPrefs = tp; }
protected void start()
{
// parameters to the output-line-length limit and how to break long lines
setOutputWidth(MAXLENGTH, true);
writeWidthLimited("/* GENERATED BY THE ELECTRIC VLSI DESIGN SYSTEM */\n\n");
writeWidthLimited("COMPILE ;\n\n");
// get library name, check validity
String libname = getLibraryName(topCell);
int length = libname.length();
if (length > 12)
{
reportWarning("Library name exceeds 12 characters, The name used for the\n" +
"TDL directory will be truncated to :- " + convertName(libname));
}
// check library name
String str1 = convertName(libname);
if (isReservedWord(str1))
{
reportError(str1 + " IS A RESERVED WORD, RENAME LIBRARY AND RE-RUN");
return;
}
// write "directory line" to file
writeWidthLimited("DIRECTORY: " + str1 + " ;\n\n");
writeWidthLimited("OPTIONS: REPLACE ;\n\n");
}
protected void done()
{
writeWidthLimited(" END COMPILE;\n\n ");
}
/**
* Method to write cellGeom
*/
protected void writeCellTopology(Cell cell, String cellName, CellNetInfo cni, VarContext context, Topology.MyCellInfo info)
{
// MODULE
writeWidthLimited("MODULE: ");
writeWidthLimited(convertName(cell.describe(false)));
writeWidthLimited(";\n\n");
netList = cni.getNetList();
// INPUTS
if (cell.getNumPorts() > 0)
{
StringBuffer infstr = new StringBuffer();
infstr.append("INPUTS:\n");
for(Iterator<CellSignal> it = cni.getCellSignals(); it.hasNext(); )
{
CellSignal cs = it.next();
if (!cs.isExported()) continue;
Export e = cs.getExport();
if (e.getCharacteristic() != PortCharacteristic.IN) continue;
if (isReservedWord(convertName(e.getName())))
{
reportError("ERROR: " + convertName(e.getName()) + " IS A RESERVED WORD");
}
infstr.append(" " + convertName(e.getName()) + "\n");
}
infstr.append(";\n\n");
writeWidthLimited(infstr.toString());
// OUTPUTS
infstr = new StringBuffer();
infstr.append("OUTPUTS:\n");
for(Iterator<CellSignal> it = cni.getCellSignals(); it.hasNext(); )
{
CellSignal cs = it.next();
if (!cs.isExported()) continue;
Export e = cs.getExport();
if (e.getCharacteristic() == PortCharacteristic.OUT)
{
infstr.append(" " + convertName(e.getName()) + "\n");
} else if (e.getCharacteristic() != PortCharacteristic.IN)
{
reportError("EXPORT " + e.getName() + " MUST BE EITHER INPUT OR OUTPUT");
}
}
infstr.append(";\n\n");
writeWidthLimited(infstr.toString());
}
// USE
Set<String> instanceDeclarations = new TreeSet<String>();
Set<String> gateDeclarations = new TreeSet<String>();
for(Iterator<Nodable> it = netList.getNodables(); it.hasNext(); )
{
Nodable no = it.next();
if (no.isCellInstance())
{
// This case can either be for an existing user defined module in this
// directory or for a module from the MASTER directory
Cell subCell = (Cell)no.getProto();
String instName = getNodeProtoName(no);
instanceDeclarations.add(instName + " = " + instName + "///" + getLibraryName(subCell));
continue;
}
NodeInst ni = (NodeInst)no;
PrimitiveNode.Function fun = ni.getFunction();
if (fun == PrimitiveNode.Function.GATEAND || fun == PrimitiveNode.Function.GATEOR || fun == PrimitiveNode.Function.GATEXOR)
{
// Count number of inputs
String gateName = getGateName(ni);
int gateWidth = getGateWidth(ni);
gateDeclarations.add(gateWidth + "-" + gateName + " = " + gateName + "(" + gateWidth + ",1)");
continue;
}
if (fun == PrimitiveNode.Function.SOURCE ||
fun.isResistor() || // == PrimitiveNode.Function.RESIST ||
fun.isCapacitor() || // == PrimitiveNode.Function.CAPAC ||
fun == PrimitiveNode.Function.DIODE || fun == PrimitiveNode.Function.INDUCT || fun == PrimitiveNode.Function.METER)
{
reportError("CANNOT HANDLE " + ni.getProto().describe(true) + " NODES");
continue;
}
}
int numDecls = instanceDeclarations.size() + gateDeclarations.size();
if (numDecls > 0) writeWidthLimited("USE:\n\n");
int countDecls = 1;
for(String decl : instanceDeclarations)
{
if (countDecls < numDecls) decl += ","; else decl += ";";
countDecls++;
writeWidthLimited(" " + decl + "\n");
}
for(String decl : gateDeclarations)
{
if (countDecls < numDecls) decl += ","; else decl += ";";
countDecls++;
writeWidthLimited(" " + decl + "\n");
}
if (numDecls > 0) writeWidthLimited("\n");
// DEFINE
writeWidthLimited("DEFINE:\n");
// count no. of inverters (negated arcs not attached to logic primitives)
implicitInverters = new HashMap<ArcInst,Integer>();
int count = 1;
for(Iterator<ArcInst> it = cell.getArcs(); it.hasNext(); )
{
ArcInst ai = it.next();
for(int i=0; i<2; i++)
{
if (!ai.isNegated(i)) continue;
if (ai.getPortInst(i).getPortProto().getCharacteristic() == PortCharacteristic.OUT)
{
PrimitiveNode.Function fun = ai.getPortInst(i).getNodeInst().getFunction();
if (fun == PrimitiveNode.Function.GATEAND || fun == PrimitiveNode.Function.GATEOR ||
fun == PrimitiveNode.Function.GATEXOR || fun == PrimitiveNode.Function.BUFFER) continue;
}
implicitInverters.put(ai, new Integer(count));
count++;
}
}
// name every node
nodeNames = new HashMap<Nodable,Integer>();
for(Iterator<Nodable> it = netList.getNodables(); it.hasNext(); )
{
Nodable no = it.next();
PrimitiveNode.Function fun = getNodableFunction(no);
if (fun.isTransistor() || fun == PrimitiveNode.Function.GATEXOR ||
fun == PrimitiveNode.Function.GATEAND || fun == PrimitiveNode.Function.GATEOR ||
fun == PrimitiveNode.Function.BUFFER || fun.isFlipFlop() || no.isCellInstance())
{
nodeNames.put(no, new Integer(count++));
continue;
}
}
// write the nodes
boolean wrotePower = false, wroteGround = false;
for(Iterator<Nodable> it = netList.getNodables(); it.hasNext(); )
{
Nodable no = it.next();
PrimitiveNode.Function fun = getNodableFunction(no);
if (fun.isPin() || fun == PrimitiveNode.Function.ART) continue;
if (fun == PrimitiveNode.Function.CONPOWER)
{
if (wrotePower) continue;
wrotePower = true;
writeWidthLimited(getNameOfPower((NodeInst)no));
continue;
}
if (fun == PrimitiveNode.Function.CONGROUND)
{
if (wroteGround) continue;
wroteGround = true;
writeWidthLimited(getNameOfPower((NodeInst)no));
continue;
}
// handle nodeinst descriptions
if (fun.isTransistor() || fun == PrimitiveNode.Function.GATEXOR ||
fun == PrimitiveNode.Function.GATEAND || fun == PrimitiveNode.Function.GATEOR ||
fun == PrimitiveNode.Function.BUFFER || fun.isFlipFlop() || no.isCellInstance())
{
String str1 = getOutputSignals(no, context, cni) + " = " + getNodeProtoName(no) + getInputSignals(no, context, cni) + getGateDelay(no) + ";\n";
writeWidthLimited(str1);
continue;
}
reportWarning("NODETYPE " + no.getProto() + " NOT SUPPORTED");
}
// end module
writeWidthLimited(" END MODULE;\n\n");
}
/****************************** MAIN BLOCKS ******************************/
/**
* Method to write the output signals for a Nodable.
* @param no the Nodable to write.
* @param context the NodeInst's context down the hierarchy.
* @param cni the CellNetInfo for the node's parent cell.
* @return the output signals for the Nodable.
*/
private String getOutputSignals(Nodable no, VarContext context, CellNetInfo cni)
{
int nodeNumber = -1;
Integer nodeNum = nodeNames.get(no);
if (nodeNum != null) nodeNumber = nodeNum.intValue();
StringBuffer infstr = new StringBuffer();
infstr.append("U" + nodeNumber + "(");
PrimitiveNode.Function fun = getNodableFunction(no);
boolean needComma = false;
if (no.isCellInstance())
{
CellNetInfo subCni = getCellNetInfo(parameterizedName(no, context));
for(Iterator<CellSignal> it = subCni.getCellSignals(); it.hasNext(); )
{
CellSignal subCs = it.next();
if (!subCs.isExported()) continue;
Export e = subCs.getExport();
if (e.getCharacteristic() == PortCharacteristic.IN) continue;
if (needComma) infstr.append(","); else needComma = true;
Network net = netList.getNetwork(no, e, subCs.getExportIndex());
CellSignal cs = cni.getCellSignal(net);
infstr.append(convertName(cs.getName()));
}
} else
{
NodeInst ni = (NodeInst)no;
for(Iterator<PortProto> it = no.getProto().getPorts(); it.hasNext(); )
{
PortProto pp = it.next();
if (fun.isTransistor())
{
if (pp.getName().equals("g")) continue;
} else
{
if (pp.getCharacteristic() == PortCharacteristic.IN) continue;
}
for(Iterator<Connection> aIt = ni.getConnections(); aIt.hasNext(); )
{
Connection con = aIt.next();
PortInst pi = con.getPortInst();
if (pi.getPortProto() != pp) continue;
ArcInst ai = con.getArc();
if (needComma) infstr.append(","); else needComma = true;
String nodeName = getConnectionName(con);
infstr.append(nodeName);
// if arc on port not negated or a description for an inverter for a negated
// arc already exists simply write the source name of this port/arc inst.
if (con.isNegated() && implicitInverters.get(ai) != null)
{
// if the negation is at this end (ie nearest this node) write an inverter
// with the port name of the output as inverter input and the net name of the
// arc as inverter output. The source name is the net name of the arc
writeInverter(con, nodeName, "U" + nodeNumber + "." + convertName(pp.getName()));
}
}
}
}
infstr.append(")");
return infstr.toString();
}
/**
* Method to write the input signals for a Nodable.
* @param no the Nodable to write.
* @param context the NodeInst's context down the hierarchy.
* @param cni the CellNetInfo for the node's parent cell.
* @return the input signals for the Nodable.
*/
private String getInputSignals(Nodable no, VarContext context, CellNetInfo cni)
{
PrimitiveNode.Function fun = getNodableFunction(no);
if (fun.isFlipFlop())
return getFlipFlopInputSignals((NodeInst)no);
if (no.getProto().getNumPorts() == 0) return "";
StringBuffer infstr = new StringBuffer();
infstr.append("(");
boolean first = true;
if (no.isCellInstance())
{
CellNetInfo subCni = getCellNetInfo(parameterizedName(no, context));
for(Iterator<CellSignal> it = subCni.getCellSignals(); it.hasNext(); )
{
CellSignal subCs = it.next();
if (!subCs.isExported()) continue;
Export e = subCs.getExport();
if (e.getCharacteristic() == PortCharacteristic.OUT) continue;
if (first) first = false; else infstr.append(",");
Network net = netList.getNetwork(no, e, subCs.getExportIndex());
CellSignal cs = cni.getCellSignal(net);
infstr.append(convertName(cs.getName()));
}
} else
{
NodeInst ni = (NodeInst)no;
for(Iterator<PortProto> it = no.getProto().getPorts(); it.hasNext(); )
{
PrimitivePort pp = (PrimitivePort)it.next();
if (pp.getCharacteristic() != PortCharacteristic.IN) continue;
// The transistor "s" port is treated as an inport by electric but is used
// as an outport by TDL
if (fun.isTransistor() && pp.getName().startsWith("s")) continue;
// Buffer primitive has a "c" port not used by TDL
if (fun == PrimitiveNode.Function.BUFFER && pp.getName().equals("c")) continue;
boolean portWired = false;
for(Iterator<Connection> aIt = ni.getConnections(); aIt.hasNext(); )
{
Connection con = aIt.next();
if (con.getPortInst().getPortProto() == pp)
{
if (first) first = false; else infstr.append(",");
infstr.append(getInvertedConnectionName(con));
portWired = true;
// if port is not isolated then write one signal only
if (!pp.isIsolated()) break;
}
}
if (!portWired)
{
reportWarning("UNWIRED PORT " + pp.getName());
if (first) first = false; else infstr.append(",");
infstr.append("NC");
}
}
}
infstr.append(")");
String result = infstr.toString();
return result;
}
/**
* Method to write the input signals for flip flops.
* @param ni the flip-flop NodeInst to convert.
* @return the input signals for the flip-flop.
*/
private String getFlipFlopInputSignals(NodeInst ni)
{
String [] signals = new String[5];
int x = 0;
for(Iterator<PortProto> it = ni.getProto().getPorts(); it.hasNext(); )
{
PortProto pp = it.next();
if (pp.getCharacteristic() == PortCharacteristic.OUT) continue;
String ptr = "NC"; // if no-connection write NC
for(Iterator<Connection> pIt = ni.getConnections(); pIt.hasNext(); )
{
Connection con = pIt.next();
if (con.getPortInst().getPortProto() == pp)
{
ptr = getInvertedConnectionName(con);
break;
}
}
for(Iterator<Export> eIt = ni.getExports(); eIt.hasNext(); )
{
Export e = eIt.next();
if (e.getOriginalPort().getPortProto() == pp)
{
ptr = convertName(e.getName());
break;
}
}
if (x >= 5) break;
signals[x++] = ptr;
}
// We now have the signals in 5 arrays ready to be output in the correct
// order which is 2,0,1,3,4.If the flip flop is a D or T type don't put
// out array[1][].
StringBuffer infstr = new StringBuffer();
infstr.append("(" + signals[2] + "," + signals[0]);
// JK and SR have one input more than D or T flip flops
PrimitiveNode.Function fun = ni.getFunction();
if (fun == PrimitiveNode.Function.FLIPFLOPRSMS || fun == PrimitiveNode.Function.FLIPFLOPRSP || fun == PrimitiveNode.Function.FLIPFLOPRSN ||
fun == PrimitiveNode.Function.FLIPFLOPJKMS || fun == PrimitiveNode.Function.FLIPFLOPJKP || fun == PrimitiveNode.Function.FLIPFLOPJKN)
{
infstr.append("," + signals[1]);
}
infstr.append("," + signals[3] + "," + signals[4] + ")");
return infstr.toString();
}
/****************************** HELPER METHODS ******************************/
/**
* Method to determine whether a nodeinst has an output arc that is negated.
* @param ni the NodeInst that may be negated.
* @return true if the NodeInst is negated (its output is negated).
*/
private boolean isNegatedNode(NodeInst ni)
{
for(Iterator<Connection> it = ni.getConnections(); it.hasNext(); )
{
Connection con = it.next();
PortInst pi = con.getPortInst();
PortProto pp = pi.getPortProto();
if (pp.getCharacteristic() != PortCharacteristic.OUT) continue;
if (con.isNegated()) return true;
}
return false;
}
/**
* Method to return the TDL delay on a Nodable.
* @param no the Nodable to get delay information on.
* @return the node delay. If no delay information is on the node,
* returns the default: "/1,1/".
*/
private String getGateDelay(Nodable no)
{
if (no.isCellInstance()) return "";
NodeInst ni = (NodeInst)no;
Variable var = ni.getVar(SimulationTool.RISE_DELAY_KEY);
String str1 = "/1,";
if (var != null) str1 = "/" + var.getPureValue(-1) + ",";
var = ni.getVar(SimulationTool.FALL_DELAY_KEY);
String str2 = "/1,";
if (var != null) str2 = "/" + var.getPureValue(-1) + ",";
return str1 + str2;
}
private int getGateWidth(NodeInst ni)
{
int inputs = 0;
for(Iterator<Connection> iIt = ni.getConnections(); iIt.hasNext(); )
{
Connection con = iIt.next();
if (con.getPortInst().getPortProto().getCharacteristic() == PortCharacteristic.IN) inputs++;
}
if (inputs < 2)
reportError("MUST HAVE AT LEAST TWO INPUTS ON " + ni);
return inputs;
}
private String getGateName(NodeInst ni)
{
// Determine whether node should be NAND, NOR or NXOR
boolean negated = false;
if (isNegatedNode(ni)) negated = true;
// Write USE description for current node
PrimitiveNode.Function fun = ni.getFunction();
if (fun == PrimitiveNode.Function.GATEAND)
{
if (negated) return "NAND";
return "AND";
}
if (fun == PrimitiveNode.Function.GATEOR)
{
if (negated) return "NOR";
return "OR";
}
if (fun == PrimitiveNode.Function.GATEXOR)
{
if (negated) return "NXOR";
return "XOR";
}
return "";
}
/**
* Method to write out an inverter description for a negated Connection.
* @param con the Connection that is inverted.
* @param str1 the output signal name.
* @param str2 the input signal name.
*/
private void writeInverter(Connection con, String str1, String str2)
{
Integer index = implicitInverters.get(con.getArc());
if (index == null) return;
writeWidthLimited("I" + index + "(" + convertName(str1) + ") = NOT(" + convertName(str2) + ");\n");
implicitInverters.remove(con.getArc()); // write once only
}
/**
* Method to return the name of a Power/Ground node.
* @param ni the Power/Ground node.
* @return the node name (returns an empty string if not applicable).
*/
private String getNameOfPower(NodeInst ni)
{
// To prevent Un-connected power nodes
if (!ni.hasConnections())
{
reportWarning("PWR / GND NODE UNCONNECTED");
return "";
}
PrimitiveNode.Function fun = ni.getFunction();
if (fun == PrimitiveNode.Function.CONGROUND || fun == PrimitiveNode.Function.CONPOWER)
{
if (ni.hasConnections())
{
Connection con = ni.getConnections().next();
Network net = netList.getNetwork(con.getArc(), 0);
String decl = net.describe(false) + " = ";
if (fun == PrimitiveNode.Function.CONPOWER) decl += "PWR"; else
decl += "GRND";
return decl + ";\n";
}
}
return "";
}
/**
* Method to return the name of the network on a given Connection.
* @param con the Connection to name.
* @return the name of that network.
*/
private String getConnectionName(Connection con)
{
Network net = netList.getNetwork(con.getArc(), 0);
if (net != null) return convertName(net.describe(false));
return "???";
}
/**
* Method to return the name of the signal on a Connection.
* @param con the Connection to name.
* @return the name of the Connection network.
* Also emits an implicit inverter if there is one.
*/
private String getInvertedConnectionName(Connection con)
{
String conName = getConnectionName(con);
ArcInst ai = con.getArc();
if (!con.isNegated()) return conName;
// insert an inverter description if a negated arc attached to primitive
// other than AND,OR,XOR
Integer index = implicitInverters.get(ai);
if (index != null)
{
String str = "I" + index + ".O";
writeInverter(con, str, conName);
return str;
}
return conName;
}
private PrimitiveNode.Function getNodableFunction(Nodable no)
{
PrimitiveNode.Function fun = PrimitiveNode.Function.UNKNOWN;
if (!no.isCellInstance())
{
NodeInst ni = (NodeInst)no;
fun = ni.getFunction();
}
return fun;
}
/**
* Method to return the TDL name of a Nodable.
* @param no the Nodable to report.
* @return the name of that Nodable.
*/
private String getNodeProtoName(Nodable no)
{
if (no.isCellInstance())
{
return convertName(no.getProto().describe(false));
}
NodeInst ni = (NodeInst)no;
PrimitiveNode.Function fun = ni.getFunction();
if (fun == PrimitiveNode.Function.GATEAND || fun == PrimitiveNode.Function.GATEOR || fun == PrimitiveNode.Function.GATEXOR)
{
return getGateWidth(ni) + "-" + getGateName(ni);
}
if (fun == PrimitiveNode.Function.BUFFER)
{
if (isNegatedNode(ni)) return "NOT";
return "DELAY";
}
if (fun.isFlipFlop()) return getFlipFlopName(ni);
if (fun == PrimitiveNode.Function.TRANS) return "BDSWITCH";
return "";
}
/**
* Method to limit a string to the max 12 chars and in upper case for TDL.
* @param str a name.
* @return the name in upper case and limited to 12 characters.
*/
private String convertName(String str)
{
if (str.length() > MAXNAMECHARS) str = str.substring(0, MAXNAMECHARS);
return str.toUpperCase();
}
/**
* Method to return the library name to use, given a cell.
* @param cell the Cell whose library is desired.
* @return the library name of the cell.
*/
String getLibraryName(Cell cell)
{
return convertName(cell.getLibrary().getName());
}
/**
* Method to return the TDL primitive name of a flip-flop.
* @param ni the NodeInst that is a flip-flop.
* @return the proper TDL name for that type of flip-flop.
*/
private String getFlipFlopName(NodeInst ni)
{
PrimitiveNode.Function fun = ni.getFunction();
if (fun == PrimitiveNode.Function.FLIPFLOPRSMS) return "SRMNE";
if (fun == PrimitiveNode.Function.FLIPFLOPRSP) return "SREPE";
if (fun == PrimitiveNode.Function.FLIPFLOPRSN) return "SRENE";
if (fun == PrimitiveNode.Function.FLIPFLOPJKMS) return "JKMNE";
if (fun == PrimitiveNode.Function.FLIPFLOPJKP) return "JKEPE";
if (fun == PrimitiveNode.Function.FLIPFLOPJKN) return "JKENE";
if (fun == PrimitiveNode.Function.FLIPFLOPDMS) return "DMNE";
if (fun == PrimitiveNode.Function.FLIPFLOPDP) return "DEPE";
if (fun == PrimitiveNode.Function.FLIPFLOPDN) return "DENE";
if (fun == PrimitiveNode.Function.FLIPFLOPTP || fun == PrimitiveNode.Function.FLIPFLOPTN)
reportError("T TYPE FLIP-FLOP MUST BE MS");
return "TMNE";
}
private List<String> reservedWords = null;
/**
* Method that takes a string of max length 12 and checks to see if it is a reserved word.
* @param str the name to check.
* @return true if the word is reserved.
* Returns false if the word is not reserved.
*/
private boolean isReservedWord(String str)
{
if (reservedWords == null)
{
reservedWords = new ArrayList<String>();
try
{
File f = new File(localPrefs.workingDirectory + File.separator + "reservedwords.dat");
FileReader fr = new FileReader(f);
BufferedReader br = new BufferedReader(fr);
for(;;)
{
String line = br.readLine();
if (line == null) break;
reservedWords.add(line);
}
br.close();
fr.close();
} catch (IOException e)
{
return false;
}
}
if (str.length() < 2) return false;
for(String match : reservedWords)
{
if (match.startsWith(str)) return true;
}
return false;
}
/****************************** SUBCLASSED METHODS FOR THE TOPOLOGY ANALYZER ******************************/
/**
* Method to adjust a cell name to be safe for Tegas output.
* @param name the cell name.
* @return the name, adjusted for Tegas 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 "GRND"; }
/** 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 false; }
/** 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 Tegas 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; }
}