/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: Spice.java * Input/output tool: reader for Spice netlists (.spi) * Inspired by Graham Petley, written by Steven M. Rubin, Sun Microsystems. * * Copyright (c) 2009 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.input; import com.sun.electric.database.geometry.EPoint; import com.sun.electric.database.geometry.Orientation; import com.sun.electric.database.geometry.Poly; import com.sun.electric.database.hierarchy.Cell; import com.sun.electric.database.hierarchy.Export; import com.sun.electric.database.hierarchy.Library; import com.sun.electric.database.id.CellId; 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.topology.ArcInst; import com.sun.electric.database.topology.NodeInst; import com.sun.electric.database.topology.PortInst; import com.sun.electric.database.variable.TextDescriptor; import com.sun.electric.technology.ArcProto; import com.sun.electric.technology.PrimitiveNode; import com.sun.electric.technology.Technology; import com.sun.electric.technology.technologies.Artwork; import com.sun.electric.technology.technologies.Schematics; import com.sun.electric.tool.Job; import com.sun.electric.tool.user.IconParameters; import com.sun.electric.tool.placement.Placement; import com.sun.electric.tool.placement.PlacementFrame; import com.sun.electric.tool.placement.Placement.PlacementPreferences; import com.sun.electric.tool.placement.PlacementFrame.PlacementExport; import com.sun.electric.tool.placement.PlacementFrame.PlacementNetwork; import com.sun.electric.tool.placement.PlacementFrame.PlacementNode; import com.sun.electric.tool.placement.PlacementFrame.PlacementPort; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.BitSet; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; /** * Class for reading and displaying Spice decks (.spi files). */ public class Spice extends Input { private Map<String,SubcktDef> allCells = new HashMap<String,SubcktDef>(); private SpicePreferences localPrefs; public static class SpicePreferences extends InputPreferences { public String placementAlgorithm; public IconParameters iconParameters = IconParameters.makeInstance(false); public SpicePreferences(boolean factory) { super(factory); } public void initFromUserDefaults() { placementAlgorithm = Placement.getAlgorithmName(); iconParameters.initFromUserDefaults(); } @Override public Library doInput(URL fileURL, Library lib, Technology tech, Map<Library,Cell> currentCells, Map<CellId,BitSet> nodesToExpand, Job job) { Spice in = new Spice(this); in.readDirectory(fileURL, lib); return lib; } } /** * Creates a new instance of Spice. */ Spice(SpicePreferences ap) { localPrefs = ap; } /** * Method to import a library from disk. * @param lib the library to fill */ public void readDirectory(URL dirURL, Library lib) { try { String dirName = dirURL.getPath(); File dir = new File(dirName); if (dir == null) { System.out.println("Unable to find files in directory " + dirName); return; } String [] filesInDir = dir.list(); for(int i=0; i<filesInDir.length; i++) { String fileName = filesInDir[i]; int lastDotPos = fileName.lastIndexOf('.'); if (lastDotPos < 0) continue; String ext = fileName.substring(lastDotPos+1).toLowerCase(); if (ext.equals("spi") || ext.equals("sp")) { URL url = TextUtils.makeURLToFile(dirName + fileName); if (url == null) continue; if (openTextInput(url)) continue; System.out.println("Reading " + fileName); readSimFile(); closeInput(); } } } catch (IOException e) {} // file read, now create all circuitry placeCells(lib); } private void readSimFile() throws IOException { SubcktDef current = null; for(;;) { String line = getNextLine(); if (line == null) break; line = line.trim(); if (line.length() == 0) continue; if (line.charAt(0) == '*') continue; // handle ".subckt" header String lineLC = line.toLowerCase(); if (lineLC.startsWith(".subckt")) { String[] expPieces = line.split(" "); current = new SubcktDef(); allCells.put(expPieces[1], current); for(int i=2; i<expPieces.length; i++) current.exports.add(expPieces[i]); continue; } if (lineLC.startsWith(".ends")) current = null; // handle transistors if (lineLC.charAt(0) == 'm' && current != null) { TransistorDef td = new TransistorDef(); current.transistors.add(td); String[] traPieces = line.split(" "); if (traPieces.length < 6) { System.out.println("Error on Transistor line: " + line); continue; } td.name = traPieces[0].substring(1); td.drain = traPieces[1]; td.gate = traPieces[2]; td.source = traPieces[3]; td.bias = traPieces[4]; td.type = traPieces[5].toLowerCase(); for(int i=6; i<traPieces.length; i++) { if (traPieces[i].toLowerCase().startsWith("w=")) td.width = traPieces[i].substring(2); if (traPieces[i].toLowerCase().startsWith("l=")) td.length = traPieces[i].substring(2); } continue; } // handle resistors if (lineLC.charAt(0) == 'r' && current != null) { ResistorDef rd = new ResistorDef(); current.resistors.add(rd); String[] resPieces = line.split(" "); if (resPieces.length < 3) { System.out.println("Error on Resistor line: " + line); continue; } rd.name = resPieces[0].substring(1); rd.left = resPieces[1]; rd.right = resPieces[2]; if (resPieces.length >= 4) rd.resistance = resPieces[3]; continue; } // handle capacitors if (lineLC.charAt(0) == 'c' && current != null) { CapacitorDef cd = new CapacitorDef(); current.capacitors.add(cd); String[] capPieces = line.split(" "); if (capPieces.length < 3) { System.out.println("Error on Capacitor line: " + line); continue; } cd.name = capPieces[0].substring(1); cd.top = capPieces[1]; cd.bottom = capPieces[2]; if (capPieces.length >= 4) cd.capacitance = capPieces[3]; continue; } // handle instances if (lineLC.charAt(0) == 'x' && current != null) { InstanceDef id = new InstanceDef(); current.instances.add(id); String[] iPieces = line.split(" "); if (iPieces.length < 2) { System.out.println("Error on Instance line: " + line); continue; } id.name = iPieces[0].substring(1); id.instName = iPieces[iPieces.length-1]; for(int i=1; i<iPieces.length-1; i++) id.signals.add(iPieces[i]); continue; } } } private void placeCells(Library lib) { PlacementPreferences prefs = new PlacementPreferences(false); prefs.placementAlgorithm = localPrefs.placementAlgorithm; PlacementFrame pla = Placement.getCurrentPlacementAlgorithm(prefs); System.out.println("Placing cells using the " + pla.getAlgorithmName() + " algorithm"); // make icons for(String name : allCells.keySet()) { SubcktDef sd = allCells.get(name); Cell cell = Cell.makeInstance(lib, name + "{ic}"); sd.iconCell = cell; double yPos = 1; double lowY = yPos; for(String export : sd.exports) { PrimitiveNode np = Schematics.tech().wirePinNode; EPoint center1 = new EPoint(0, yPos); EPoint center2 = new EPoint(2, yPos); NodeInst ni1 = NodeInst.makeInstance(np, center1, np.getDefWidth(), np.getDefHeight(), cell); PortInst pi1 = ni1.getOnlyPortInst(); NodeInst ni2 = NodeInst.makeInstance(np, center2, np.getDefWidth(), np.getDefHeight(), cell); PortInst pi2 = ni2.getOnlyPortInst(); ArcProto ap = Schematics.tech().wire_arc; ArcInst.makeInstance(ap, pi1, pi2); Export e = Export.newInstance(cell, pi1, export, PortCharacteristic.UNKNOWN, localPrefs.iconParameters); TextDescriptor newTD = e.getTextDescriptor(Export.EXPORT_NAME).withPos(TextDescriptor.Position.LEFT); e.setTextDescriptor(Export.EXPORT_NAME, newTD); yPos += 2; } if (yPos == lowY) yPos += 2; double width = 10; double height = yPos-lowY; EPoint center = new EPoint(7, (yPos-2+lowY)/2); PrimitiveNode np = Artwork.tech().boxNode; NodeInst ni = NodeInst.makeInstance(np, center, width, height, cell); ni.setName(name.replaceAll("@", "_")); TextDescriptor newTD = ni.getTextDescriptor(NodeInst.NODE_NAME).withRelSize(2); ni.setTextDescriptor(NodeInst.NODE_NAME, newTD); } // now make the schematic cells for(String name : allCells.keySet()) { SubcktDef sd = allCells.get(name); // use the placement tool to situate the objects List<PlacementNode> nodesToPlace = new ArrayList<PlacementNode>(); Map<String,PlacementNetwork> allNetworks = new HashMap<String,PlacementNetwork>(); List<PlacementExport> exportsToPlace = new ArrayList<PlacementExport>(); // make PlacementNodes for the transistors for(TransistorDef td : sd.transistors) { int bits = 0; if (td.type.equals("p")) bits = Schematics.getPrimitiveFunctionBits(PrimitiveNode.Function.TRAPMOS); else bits = Schematics.getPrimitiveFunctionBits(PrimitiveNode.Function.TRANMOS); PrimitiveNode np = Schematics.tech().transistorNode; NodeInst niDummy = NodeInst.makeDummyInstance(np); List<PlacementPort> ports = new ArrayList<PlacementPort>(); PortInst piSource = niDummy.getTransistorSourcePort(); ports.add(addPlacementPort(niDummy, piSource, td.source, allNetworks, sd.exports, sd.usedExports, exportsToPlace)); PortInst piGate = niDummy.getTransistorGatePort(); ports.add(addPlacementPort(niDummy, piGate, td.gate, allNetworks, sd.exports, sd.usedExports, exportsToPlace)); PortInst piDrain = niDummy.getTransistorDrainPort(); ports.add(addPlacementPort(niDummy, piDrain, td.drain, allNetworks, sd.exports, sd.usedExports, exportsToPlace)); PlacementNode plNode = new PlacementNode(np, "m" + td.name, bits, np.getDefWidth(), np.getDefHeight(), ports); nodesToPlace.add(plNode); for(PlacementPort plPort : ports) plPort.setPlacementNode(plNode); plNode.setOrientation(Orientation.IDENT); if (td.width != null) plNode.addVariable(Schematics.ATTR_WIDTH, td.width); if (td.length != null) plNode.addVariable(Schematics.ATTR_LENGTH, td.length); } // place resistors and capacitors for(ResistorDef rd : sd.resistors) { PrimitiveNode np = Schematics.tech().resistorNode; NodeInst niDummy = NodeInst.makeDummyInstance(np); List<PlacementPort> ports = new ArrayList<PlacementPort>(); PortInst piSource = niDummy.getPortInst(0); ports.add(addPlacementPort(niDummy, piSource, rd.left, allNetworks, sd.exports, sd.usedExports, exportsToPlace)); PortInst piGate = niDummy.getPortInst(1); ports.add(addPlacementPort(niDummy, piGate, rd.right, allNetworks, sd.exports, sd.usedExports, exportsToPlace)); PlacementNode plNode = new PlacementNode(np, "r" + rd.name, 0, np.getDefWidth(), np.getDefHeight(), ports); nodesToPlace.add(plNode); for(PlacementPort plPort : ports) plPort.setPlacementNode(plNode); plNode.setOrientation(Orientation.IDENT); if (rd.resistance != null) plNode.addVariable(Schematics.SCHEM_RESISTANCE, rd.resistance); } for(CapacitorDef cd : sd.capacitors) { PrimitiveNode np = Schematics.tech().capacitorNode; NodeInst niDummy = NodeInst.makeDummyInstance(np); List<PlacementPort> ports = new ArrayList<PlacementPort>(); PortInst piSource = niDummy.getPortInst(0); ports.add(addPlacementPort(niDummy, piSource, cd.top, allNetworks, sd.exports, sd.usedExports, exportsToPlace)); PortInst piGate = niDummy.getPortInst(1); ports.add(addPlacementPort(niDummy, piGate, cd.bottom, allNetworks, sd.exports, sd.usedExports, exportsToPlace)); PlacementNode plNode = new PlacementNode(np, "c" + cd.name, 0, np.getDefWidth(), np.getDefHeight(), ports); nodesToPlace.add(plNode); for(PlacementPort plPort : ports) plPort.setPlacementNode(plNode); plNode.setOrientation(Orientation.IDENT); if (cd.capacitance != null) plNode.addVariable(Schematics.SCHEM_CAPACITANCE, cd.capacitance); } // place instances for(InstanceDef id : sd.instances) { SubcktDef subSD = allCells.get(id.instName); if (subSD == null) { System.out.println("Cannot find subcircuit "+id.instName); continue; } Cell np = subSD.iconCell; NodeInst niDummy = NodeInst.makeDummyInstance(np); if (subSD.exports.size() != id.signals.size()) { System.out.println("Error: Subcircuit " + id.instName + " has " + subSD.exports.size() + " exports but instance " + id.name + " of it in cell " + name + "{sch}" + " has " + id.signals.size() + " signals on it"); continue; } List<PlacementPort> ports = new ArrayList<PlacementPort>(); for(int i=0; i<subSD.exports.size(); i++) { PortProto pp = subSD.iconCell.findPortProto(subSD.exports.get(i)); if (pp == null) continue; PortInst pi = niDummy.findPortInstFromProto(pp); String sigName = id.signals.get(i); ports.add(addPlacementPort(niDummy, pi, sigName, allNetworks, sd.exports, sd.usedExports, exportsToPlace)); } PlacementNode plNode = new PlacementNode(np, id.name.replace('@', '_'), 0, np.getDefWidth(), np.getDefHeight(), ports); nodesToPlace.add(plNode); for(PlacementPort plPort : ports) plPort.setPlacementNode(plNode); plNode.setOrientation(Orientation.IDENT); } // add dummy pins for unused exports for(String export : sd.exports) { if (sd.usedExports.contains(export)) continue; PrimitiveNode np = Schematics.tech().wirePinNode; NodeInst niDummy = NodeInst.makeDummyInstance(np); List<PlacementPort> ports = new ArrayList<PlacementPort>(); PortInst pi = niDummy.getPortInst(0); ports.add(addPlacementPort(niDummy, pi, export, allNetworks, sd.exports, sd.usedExports, exportsToPlace)); PlacementNode plNode = new PlacementNode(np, null, 0, np.getDefWidth(), np.getDefHeight(), ports); nodesToPlace.add(plNode); for(PlacementPort plPort : ports) plPort.setPlacementNode(plNode); plNode.setOrientation(Orientation.IDENT); } // make a list of PlacementNetworks List<PlacementNetwork> nets = new ArrayList<PlacementNetwork>(); for(String netName : allNetworks.keySet()) { PlacementNetwork net = allNetworks.get(netName); for(PlacementPort port : net.getPortsOnNet()) port.setPlacementNetwork(net); if (net.getPortsOnNet() == null || net.getPortsOnNet().size() <= 1) continue; nets.add(net); } // run placement pla.doPlacement(lib, name + "{sch}", nodesToPlace, nets, exportsToPlace, sd.iconCell, localPrefs.iconParameters); // the old way... // Cell cell = Cell.makeInstance(lib, name + "{sch}"); // if (sd.iconCell != null) // { // EPoint center = new EPoint(0, 15); // NodeInst.makeInstance(sd.iconCell, center, sd.iconCell.getDefWidth(), sd.iconCell.getDefHeight(), cell); // } // // // place transistors // double pPos = 0, nPos = 0; // for(TransistorDef td : sd.transistors) // { // EPoint center = null; // PrimitiveNode.Function func = null; // if (td.type.equals("p")) // { // center = new EPoint(pPos, 5); // pPos += 10; // func = PrimitiveNode.Function.TRAPMOS; // } else // { // center = new EPoint(nPos, -5); // nPos += 10; // func = PrimitiveNode.Function.TRANMOS; // } // PrimitiveNode np = Schematics.tech().transistorNode; // Orientation o = Orientation.R; // NodeInst ni = NodeInst.makeInstance(np, center, np.getDefWidth(), np.getDefHeight(), // cell, o, "m" + td.name, func); // TextDescriptor tdesc = TextDescriptor.newTextDescriptor(MutableTextDescriptor.getNodeTextDescriptor()); // TextDescriptor.Rotation r = TextDescriptor.Rotation.getRotation(270); // ni.setTextDescriptor(NodeInst.NODE_NAME, tdesc.withRotation(r).withPos(TextDescriptor.Position.DOWNLEFT)); // if (td.width != null) // { // Variable var = ni.newDisplayVar(Schematics.ATTR_WIDTH, td.width); // TextDescriptor newTD = var.getTextDescriptor(). // withRotation(r).withOff(0.5, -0.5).withRelSize(1).withPos(TextDescriptor.Position.DOWN); // ni.setTextDescriptor(Schematics.ATTR_WIDTH, newTD); // } // if (td.length != null) // { // Variable var = ni.newDisplayVar(Schematics.ATTR_LENGTH, td.length); // TextDescriptor newTD = var.getTextDescriptor(). // withRotation(r).withOff(-0.5, -0.75).withRelSize(0.5).withPos(TextDescriptor.Position.DOWN); // ni.setTextDescriptor(Schematics.ATTR_LENGTH, newTD); // } // PortInst piSource = ni.getTransistorSourcePort(); // addLead(piSource, 0, -2, cell, td.source, sd.exports, sd.usedExports); // PortInst piGate = ni.getTransistorGatePort(); // addLead(piGate, -2, 0, cell, td.gate, sd.exports, sd.usedExports); // PortInst piDrain = ni.getTransistorDrainPort(); // addLead(piDrain, 0, 2, cell, td.drain, sd.exports, sd.usedExports); // } // // // place resistors and capacitors // for(ResistorDef rd : sd.resistors) // { // EPoint center = new EPoint(pPos, 5); // pPos += 10; // PrimitiveNode np = Schematics.tech().resistorNode; // NodeInst ni = NodeInst.makeInstance(np, center, np.getDefWidth(), np.getDefHeight(), // cell, Orientation.IDENT, "r" + rd.name); // if (rd.resistance != null) // { // Variable var = ni.newDisplayVar(Schematics.SCHEM_RESISTANCE, rd.resistance); // TextDescriptor newTD = var.getTextDescriptor(). // withOff(0, 0.5).withPos(TextDescriptor.Position.UP); // ni.setTextDescriptor(Schematics.SCHEM_RESISTANCE, newTD); // } // PortInst piSource = ni.getPortInst(0); // addLead(piSource, -2, 0, cell, rd.left, sd.exports, sd.usedExports); // PortInst piGate = ni.getPortInst(1); // addLead(piGate, 2, 0, cell, rd.right, sd.exports, sd.usedExports); // } // for(CapacitorDef cd : sd.capacitors) // { // EPoint center = new EPoint(nPos, -5); // nPos += 10; // PrimitiveNode np = Schematics.tech().capacitorNode; // NodeInst ni = NodeInst.makeInstance(np, center, np.getDefWidth(), np.getDefHeight(), // cell, Orientation.IDENT, "c" + cd.name); // if (cd.capacitance != null) // ni.newDisplayVar(Schematics.SCHEM_CAPACITANCE, cd.capacitance); // PortInst piSource = ni.getPortInst(0); // addLead(piSource, 0, 2, cell, cd.top, sd.exports, sd.usedExports); // PortInst piGate = ni.getPortInst(1); // addLead(piGate, 0, -2, cell, cd.bottom, sd.exports, sd.usedExports); // } // // // place instances // double iPos = 0; // for(InstanceDef id : sd.instances) // { // SubcktDef subSD = allCells.get(id.instName); // if (subSD == null) // { // System.out.println("Cannot find subcircuit "+id.instName); // continue; // } // Cell np = subSD.iconCell; // EPoint center = new EPoint(iPos, -10-np.getDefHeight()); // iPos += 30; // NodeInst ni = NodeInst.makeInstance(np, center, np.getDefWidth(), np.getDefHeight(), cell); // ni.setName(id.name.replace('@', '_')); // TextDescriptor newTD = ni.getTextDescriptor(NodeInst.NODE_NAME). // withOff(1, -1).withPos(TextDescriptor.Position.DOWN); // ni.setTextDescriptor(NodeInst.NODE_NAME, newTD); // if (subSD.exports.size() != id.signals.size()) // { // System.out.println("Error: Subcircuit " + id.instName + " has " + subSD.exports.size() + // " exports but instance " + id.name + " of it in cell " + cell.describe(false) + // " has " + id.signals.size() + " signals on it"); // continue; // } // for(int i=0; i<subSD.exports.size(); i++) // { // PortProto pp = subSD.iconCell.findPortProto(subSD.exports.get(i)); // if (pp == null) continue; // PortInst pi = ni.findPortInstFromProto(pp); // String sigName = id.signals.get(i); // addLead(pi, -2, 0, cell, sigName, sd.exports, sd.usedExports); // } // } // // // add dummy pins for unused exports // double dummyPos = 30; // for(String export : sd.exports) // { // if (sd.usedExports.contains(export)) continue; // EPoint ctr = new EPoint(dummyPos, 15); // dummyPos += 10; // PrimitiveNode np = Schematics.tech().wirePinNode; // NodeInst ni = NodeInst.makeInstance(np, ctr, np.getDefWidth(), np.getDefHeight(), cell); // Export.newInstance(cell, ni.getOnlyPortInst(), export, PortCharacteristic.UNKNOWN); // } } } private PlacementPort addPlacementPort(NodeInst ni, PortInst pi, String name, Map<String,PlacementNetwork> allNetworks, List<String> exports, Set<String> usedExports, List<PlacementExport> exportsToPlace) { PlacementNetwork net = allNetworks.get(name); if (net == null) allNetworks.put(name, net = new PlacementNetwork(new ArrayList<PlacementPort>())); List<PlacementPort> portsOnNet = net.getPortsOnNet(); Poly poly = pi.getPoly(); double offX = poly.getCenterX() - ni.getTrueCenterX(); double offY = poly.getCenterY() - ni.getTrueCenterY(); PlacementPort plPort = new PlacementPort(offX, offY, pi.getPortProto()); portsOnNet.add(plPort); // see if this port is exported if (exports.contains(name) && !usedExports.contains(name)) { usedExports.add(name); PlacementExport plExport = new PlacementExport(plPort, name, PortCharacteristic.UNKNOWN); exportsToPlace.add(plExport); } return plPort; } // private void addLead(PortInst pi, double dX, double dY, Cell cell, String name, List<String> exports, Set<String> usedExports) // { // EPoint ctr1 = pi.getCenter(); // EPoint ctr2 = new EPoint(ctr1.getX()+dX, ctr1.getY()+dY); // // PrimitiveNode np = Schematics.tech().wirePinNode; // NodeInst ni = NodeInst.makeInstance(np, ctr2, np.getDefWidth(), np.getDefHeight(), cell); // ArcProto ap = Schematics.tech().wire_arc; // PortInst pi2 = ni.getOnlyPortInst(); // ArcInst ai = ArcInst.makeInstance(ap, pi, pi2); // // name = name.replace('@', '_'); // if (exports.contains(name) && !usedExports.contains(name)) // { // usedExports.add(name); // Export.newInstance(cell, pi2, name, PortCharacteristic.UNKNOWN); // } else // { // ai.setName(name); // TextDescriptor.Position p = (dX == 0) ? TextDescriptor.Position.LEFT : TextDescriptor.Position.DOWN; // TextDescriptor newTD = ai.getTextDescriptor(ArcInst.ARC_NAME).withPos(p); // ai.setTextDescriptor(ArcInst.ARC_NAME, newTD); // } // } private String lastLine = null; private String getNextLine() throws IOException { String line = lastLine; if (line == null) line = getLine(); if (line != null) { lastLine = getLine(); while (lastLine != null && lastLine.startsWith("+")) { line += lastLine.substring(1); lastLine = getLine(); } } return line; } private static class SubcktDef { List<String> exports; List<TransistorDef> transistors; List<ResistorDef> resistors; List<CapacitorDef> capacitors; List<InstanceDef> instances; Set<String> usedExports; Cell iconCell; public SubcktDef() { exports = new ArrayList<String>(); transistors = new ArrayList<TransistorDef>(); resistors = new ArrayList<ResistorDef>(); capacitors = new ArrayList<CapacitorDef>(); instances = new ArrayList<InstanceDef>(); usedExports = new HashSet<String>(); } } private static class InstanceDef { String name; String instName; List<String> signals; public InstanceDef() { signals = new ArrayList<String>(); } } private static class TransistorDef { String name; String source, gate, drain; String bias; String type; String width, length; } private static class ResistorDef { String name; String left, right; String resistance; } private static class CapacitorDef { String name; String top, bottom; String capacitance; } }