/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: MOSSIM.java
* Input/output tool: MOSSIM net list generator
* 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.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.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 java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* This is the netlister for MOSSIM.
*
* A circuit can be augmented in a number of ways for MOSSIM output:
* The variable "SIM_mossim_strength" may be placed on any node or arc.
* On transistor nodes, it specifies the strength field to use for that
* transistor declaration. On arcs, it specifies the strength field to
* use for that network node (only works for internal nodes of a cell).
*/
public class MOSSIM extends Topology
{
/** key of Variable holding node or arc strength. */ public static final Variable.Key MOSSIM_STRENGTH_KEY = Variable.newKey("SIM_mossim_strength");
// private MOSSIMPreferences localPrefs;
public static class MOSSIMPreferences extends OutputPreferences
{
public MOSSIMPreferences(boolean factory) { super(factory); }
public Output doOutput(Cell cell, VarContext context, String filePath)
{
MOSSIM out = new MOSSIM(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 MOSSIM netlister.
*/
MOSSIM(MOSSIMPreferences mp) { /* localPrefs = mp; */ }
protected void start() {}
protected void done() {}
/**
* Method to write cellGeom
*/
protected void writeCellTopology(Cell cell, String cellName, CellNetInfo cni, VarContext context, Topology.MyCellInfo info)
{
if (cell == topCell)
{
// declare power and ground nodes if this is top cell
printWriter.println("| Top-level cell " + cell.describe(false) + " ;");
printWriter.println("i VDD ;");
printWriter.println("i GND ;");
} else
{
// write ports if this cell is sub-cell
printWriter.println("| Cell " + cell.describe(false) + " ;");
printWriter.print("c " + cell.getName());
for(Iterator<CellSignal> it = cni.getCellSignals(); it.hasNext(); )
{
CellSignal cs = it.next();
if (cs.isExported()) printWriter.print(" " + cs.getName());
}
printWriter.println(" ;");
}
// gather strength information
Netlist netList = cni.getNetList();
Map<Network,String> strengthMap = new HashMap<Network,String>();
for(Iterator<ArcInst> it = cell.getArcs(); it.hasNext(); )
{
ArcInst ai = it.next();
Variable var = ai.getVar(MOSSIM_STRENGTH_KEY);
if (var == null) continue;
Network net = netList.getNetwork(ai, 0);
strengthMap.put(net, var.getPureValue(-1));
}
// mark all ports that are equivalent
for(Iterator<CellSignal> it = cni.getCellSignals(); it.hasNext(); )
{
CellSignal cs = it.next();
if (cs.isPower())
{
if (!cs.getName().equalsIgnoreCase("vdd"))
printWriter.println("e VDD " + cs.getName() + " ;");
continue;
}
if (cs.isGround())
{
if (!cs.getName().equalsIgnoreCase("gnd"))
printWriter.println("e GND " + cs.getName() + " ;");
continue;
}
if (cs.isExported())
{
if (cell == topCell)
{
Export e = cs.getExport();
if (e.getCharacteristic() == PortCharacteristic.IN)
{
printWriter.println("i " + cs.getName() + " ;");
} else
{
printWriter.println("s 1 " + cs.getName() + " ;");
}
}
} else
{
String strength = strengthMap.get(cs.getNetwork());
if (strength == null) strength = "1";
printWriter.println("s " + strength + " " + cs.getName());
}
}
// now write the transistors
for(Iterator<Nodable> nIt = netList.getNodables(); nIt.hasNext(); )
{
Nodable no = nIt.next();
if (no.isCellInstance())
{
// complex node: make instance call
String nodeName = parameterizedName(no, context);
StringBuffer infstr = new StringBuffer();
infstr.append("h " + nodeName + " " + no.getName());
CellNetInfo subCni = getCellNetInfo(nodeName);
for(Iterator<CellSignal> sIt = subCni.getCellSignals(); sIt.hasNext(); )
{
CellSignal subCs = sIt.next();
if (!subCs.isExported()) continue;
PortProto pp = subCs.getExport();
Network net = netList.getNetwork(no, pp, subCs.getExportIndex());
CellSignal cs = cni.getCellSignal(net);
infstr.append(" " + cs.getName());
}
infstr.append(" ;");
printWriter.println(infstr.toString());
} else
{
// handle primitives
NodeInst ni = (NodeInst)no;
PrimitiveNode.Function type = ni.getFunction();
// if it is a transistor, write the information
if (!type.isFET()) continue;
// gate is port 0 or 2, source is port 1, drain is port 3
PortInst gate = ni.getTransistorGatePort();
PortInst source = ni.getTransistorSourcePort();
PortInst drain = ni.getTransistorDrainPort();
// write the transistor
StringBuffer infstr = new StringBuffer();
if (type.isNTypeTransistor()) infstr.append("n"); else
if (type.isPTypeTransistor()) infstr.append("p"); else
infstr.append("d");
// write the strength of the transistor
Variable var = ni.getVar(MOSSIM_STRENGTH_KEY);
if (var != null)
{
infstr.append(" " + var.getPureValue(-1));
} else
{
infstr.append(" 2");
}
// write the gate/source/drain nodes
CellSignal cs = cni.getCellSignal(netList.getNetwork(gate));
if (cs == null) reportError(ni.getParent() + " CANNOT DETERMINE GATE NETWORK ON " + ni);
infstr.append(" " + cs.getName());
cs = cni.getCellSignal(netList.getNetwork(source));
if (cs == null) reportError(ni.getParent() + " CANNOT DETERMINE SOURCE NETWORK ON " + ni);
infstr.append(" " + cs.getName());
cs = cni.getCellSignal(netList.getNetwork(drain));
if (cs == null) reportError(ni.getParent() + " CANNOT DETERMINE DRAIN NETWORK ON " + ni);
infstr.append(" " + cs.getName());
infstr.append(" ; | " + ni.getName() + ";");
printWriter.println(infstr.toString());
}
}
// finish up
printWriter.println(".");
}
/****************************** SUBCLASSED METHODS FOR THE TOPOLOGY ANALYZER ******************************/
/**
* Method to adjust a cell name to be safe for MOSSIM output.
* @param name the cell name.
* @return the name, adjusted for MOSSIM 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 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 MOSSIM 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; }
}