Presentation
The Spice format was developped at the University of California, Berkeley. This parser/driver consists in a subset of SPICE3 netlist format. (see http://en.wikipedia.org/wiki/SPICE for more informations).
Author
Damien Dupuis: damien.dupuis(at)lip6(.)fr
Stand alone database structure
The database consists in several objects:
Using the parser
Simply load an Spice netlist file using the static function SPICE::Circuit::readFromFile().
Using the driver
Using the driver is very simple, user has to create a SPICE::Circuit object and simply add others Spice objects like SPICE::Subckt or SPICE::Instance to it. Includes, libraries and parameters can also be added to SPICE::Circuit. Finally use the SPICE::Circuit::writeToFile() method to dump the database to file.
Examples
As said is the global presentation, VLSI SAPD project provides C++ libraries and Python modules for each supported format. In this section we present simple code examples to parse and drive a SPICE file using C++ or Python. The SPICE file considered describes a simple Miller OTA: OTA_miller.spi
* Single-ended two-stage amplifier
.PARAM CC_VALUE=2.8794pF
.PARAM L_VALUE=0.340e-6
.SUBCKT currentMirrorPMOS d1 d2 s1 s2 param: l_val=0.0 w_val=0.0 nf_val=1 aeq_val=100e-6 temp_val=27
MP3 d1 d1 s1 s1 psvt l=l_val wf={w_val/nf_val} nf=nf_val aeq=aeq_val tempsimu=temp_val
MP4 d2 d1 s2 s2 psvt l=l_val wf={w_val/nf_val} nf=nf_val aeq=aeq_val tempsimu=temp_val
.ENDS currentMirrorPMOS
.SUBCKT diffPairNMOS d1 d2 g1 g2 s b param: l_val=0.0 w_val=0.0 nf_val=1 aeq_val=100e-6 temp_val=27
MN1 d1 g1 s b nsvt l=l_val wf={w_val/nf_val} nf=nf_val aeq=aeq_val tempsimu=temp_val
MN2 d2 g2 s b nsvt l=l_val wf={w_val/nf_val} nf=nf_val aeq=aeq_val tempsimu=temp_val
.ENDS diffPairNMOS
XCM 1 2 vdd vdd currentMirrorPMOS l_val=L_VALUE w_val=3.889618e-06 nf_val=2
XDP 1 2 vim vip 3 vss diffPairNMOS l_val=L_VALUE w_val=7.683346e-07 nf_val=4
MP6 vout 2 vdd vdd psvt l_val=L_VALUE w_val=3.558995e-05 nf_val=20
MN5 3 4 vss vss nsvt l_val=L_VALUE w_val=2.536703e-06 nf_val=4
MN7 vout 4 vss vss nsvt l_val=L_VALUE w_val=1.069083e-05 nf_val=16
MN8 4 4 vss vss nsvt l_val=L_VALUE w_val=2.536703e-06 nf_val=4
CC1 vout 2 CC_VALUE
.END
All source codes are available in the examples
directory.
C++
Parser
The following code (parseSpice.cpp
) is an example of how to parse a SPICE file using C++ library.
#include <cstdlib>
#include <iostream>
#include <string>
#include <map>
#include <vector>
using namespace std;
#include "vlsisapd/spice/Circuit.h"
#include "vlsisapd/spice/SpiceException.h"
#include "vlsisapd/spice/Sources.h"
#include "vlsisapd/spice/Subckt.h"
#include "vlsisapd/spice/Instances.h"
int main(int argc, char * argv[]) {
string file = "";
if (argc == 1)
file = "./OTA.cir";
else if (argc == 2)
file = argv[1];
else {
cerr << "Usage: parseSpice [filename]" << endl;
exit(1);
}
try {
circuit = SPICE::Circuit::readFromFile(file);
cerr << e.what() << endl;
exit(48);
}
cerr <<
"+ " << circuit->
getTitle() << endl;
if (includes.size()) {
cerr << "| + includes" << endl;
for (size_t i = 0 ; i < includes.size() ; i++)
cerr << "| | " << includes[i] << endl;
}
vector<pair<string, string> > libs = circuit->
getLibraries();
if (libs.size()) {
cerr << "| + libraries" << endl;
for (size_t i = 0 ; i < libs.size() ; i++)
cerr << "| | " << libs[i].first << " " << libs[i].second << endl;
}
if (params.size()) {
cerr << "| + parameters" << endl;
for (map<string, string>::const_iterator it = params.begin() ; it != params.end() ; ++it)
cerr << "| | " << (*it).first << " = " << (*it).second << endl;
}
if (opts.size()) {
cerr << "| + options" << endl;
for (map<string, string>::const_iterator it = opts.begin() ; it != opts.end() ; ++it)
cerr << "| | " << (*it).first << " = " << (*it).second << endl;
}
vector<SPICE::Source*> sources = circuit->
getSources();
if (sources.size()) {
cerr << "| + sources" << endl;
for (size_t i = 0 ; i < sources.size() ; i++) {
}
}
vector<SPICE::Subckt*> subs = circuit->
getSubckts();
if (subs.size()) {
cerr << "| + subckts" << endl;
for (size_t i = 0 ; i < subs.size() ; i++) {
cerr <<
"| | + " << sub->
getName();
cerr << " param:";
cerr << " " << (*it).first << "=" << (*it).second;
}
cerr << endl;
cerr <<
"| | | + " << inst->
getName();
if (dynamic_cast<SPICE::Mosfet*>(inst)) {
int k = 0;
if (k%6 == 0)
cerr << endl << "| | | | +";
cerr << " " << (*it).first << "=" << (*it).second;
}
} else if (dynamic_cast<SPICE::Resistor*>(inst)) {
} else if (dynamic_cast<SPICE::Capacitor*>(inst)) {
} else {
int l = 0;
if (l%6 == 0)
cerr << endl << "| | | | +";
cerr << " " << (*it).first << "=" << (*it).second;
}
}
cerr << endl;
}
}
}
if (insts.size()) {
cerr << "| + instances" << endl;
for (size_t i = 0 ; i < insts.size() ; i++) {
cerr <<
"| | + " << inst->
getName();
if (dynamic_cast<SPICE::Mosfet*>(inst)) {
int j = 0;
if (j%6 == 0)
cerr << endl << "| | | | +";
cerr << " " << (*it).first << "=" << (*it).second;
}
} else if (dynamic_cast<SPICE::Resistor*>(inst)) {
} else if (dynamic_cast<SPICE::Capacitor*>(inst)) {
} else {
int l = 0;
if (l%6 == 0)
cerr << endl << "| | | +";
cerr << " " << (*it).first << "=" << (*it).second;
}
}
cerr << endl;
}
}
return 0;
}
Driver
This C++ code (driveSpice.cpp
) generates an myOTA.spi file equivalent to the included one.
#include <string>
using namespace std;
#include "vlsisapd/spice/Circuit.h"
#include "vlsisapd/spice/Subckt.h"
#include "vlsisapd/spice/Instances.h"
int main(int argc, char * argv[]) {
circuit->
setTitle(
"* Single-ended two-stage amplifier");
circuit->writeToFile("./myOTA.spi");
return 0;
}
- Note
- In order to compile these codes, a CMakeLists.txt file is provided. User must set the $VLSISAPD_TOP variable before running these commands in the directory containing the CMakeLists.txt file:
%> mkdir build; cd build
%> cmake ..
%> make
Python
Parser
The following python script (parseSpice.py
) is an example of how to parse a SPICE file using python module.
5 def printContents(circuit):
6 print "+", circuit.title
8 if len(circuit.getIncludes()):
10 for include
in circuit.getIncludes():
13 if len(circuit.getLibraries()):
15 for (lib, typ)
in circuit.getLibraries():
18 if len(circuit.getParameters()):
19 print "| + parameters"
20 for (name, value)
in circuit.getParameters().items():
21 print "| | %s=%s"%(name, value)
23 if len(circuit.getOptions()):
25 for (name, value)
in circuit.getOptions().items():
26 print "| | %s=%s"%(name, value)
28 if len(circuit.getSources()):
30 for source
in circuit.getSources():
31 print "| |", source.getName(), source.getPositive(), source.getNegative(), source.getValue()
33 if len(circuit.getSubckts()):
35 for sub
in circuit.getSubckts():
36 print "| | +", sub.getName(),
37 for interf
in sub.getInterfaces():
39 if len(sub.getParameters()):
41 for (name, value)
in sub.getParameters().items():
42 print "%s=%s"%(name,value),
44 for inst
in sub.getInstances():
45 print "| | | +", inst.getName(),
46 if isinstance(inst, Mosfet):
47 print inst.getDrain(), inst.getGrid(), inst.getSource(), inst.getBulk(), inst.getModel(),
49 for (name, value)
in inst.getParameters().items():
53 print "%s=%s"%(name, value),
55 elif isinstance(inst, Resistor):
56 print inst.getFirst(), inst.getSecond(), inst.getValue(),
57 elif isinstance(inst, Capacitor):
58 print inst.getPositive(), inst.getNegative(), inst.getValue(),
60 for conn
in inst.getConnectors():
62 print inst.getModel(),
64 for (name, value)
in inst.getParameters().items():
68 print "%s=%s"%(name, value),
72 if len(circuit.getInstances()):
74 for inst
in circuit.getInstances():
75 print "| | | +", inst.getName(),
76 if isinstance(inst, Mosfet):
77 print inst.getDrain(), inst.getGrid(), inst.getSource(), inst.getBulk(), inst.getModel(),
79 for (name, value)
in inst.getParameters().items():
83 print "%s=%s"%(name, value),
85 elif isinstance(inst, Resistor):
86 print inst.getFirst(), inst.getSecond(), inst.getValue(),
87 elif isinstance(inst, Capacitor):
88 print inst.getPositive(), inst.getNegative(), inst.getValue(),
90 for conn
in inst.getConnectors():
92 print inst.getModel(),
94 for (name, value)
in inst.getParameters().items():
98 print "%s=%s"%(name, value),
103 print "usage:", sys.argv[0],
"[filename]"
107 if len(sys.argv) == 1:
108 filename =
"./OTA_miller.spi"
109 elif len(sys.argv) == 2:
110 filename = sys.argv[1]
114 circuit = Circuit.readFromFile(filename)
115 printContents(circuit)
118 if __name__ ==
"__main__":
Driver
This python script (driveSpice.py
) generates an myOTA.spi file equivalent to the included one.
5 circuit.title =
'* Single-ended two-stage amplifier'
8 circuit.addParameter(
"CC_VALUE",
"2.8794pF");
9 circuit.addParameter(
"L_VALUE" ,
"0.340e-6");
13 CM = circuit.addSubckt(
"currentMirrorPMOS");
14 CM.addInterface(
"d1");
15 CM.addInterface(
"d2");
16 CM.addInterface(
"s1");
17 CM.addInterface(
"s2");
18 CM.addParameter(
"l_val" ,
"0.0" );
19 CM.addParameter(
"w_val" ,
"0.0" );
20 CM.addParameter(
"nf_val" ,
"1" );
21 CM.addParameter(
"aeq_val" ,
"100e-6");
22 CM.addParameter(
"temp_val",
"27" );
24 cmP3 = Mosfet(
"P3",
"d1",
"d1",
"s1",
"s1",
"psvt");
25 cmP3.addParameter(
"l" ,
"l_val" );
26 cmP3.addParameter(
"wf" ,
"{w_val/nf_val}");
27 cmP3.addParameter(
"nf" ,
"nf_val" );
28 cmP3.addParameter(
"aeq" ,
"aeq_val" );
29 cmP3.addParameter(
"tempsimu",
"temp_val" );
32 cmP4 = Mosfet(
"P4",
"d2",
"d1",
"s2",
"s2",
"psvt");
33 cmP4.addParameter(
"l" ,
"l_val" );
34 cmP4.addParameter(
"wf" ,
"{w_val/nf_val}");
35 cmP4.addParameter(
"nf" ,
"nf_val" );
36 cmP4.addParameter(
"aeq" ,
"aeq_val" );
37 cmP4.addParameter(
"tempsimu",
"temp_val" );
41 DP = circuit.addSubckt(
"diffPairNMOS");
42 DP.addInterface(
"d1");
43 DP.addInterface(
"d2");
44 DP.addInterface(
"g1");
45 DP.addInterface(
"g2");
48 DP.addParameter(
"l_val" ,
"0.0" );
49 DP.addParameter(
"w_val" ,
"0.0" );
50 DP.addParameter(
"nf_val" ,
"1" );
51 DP.addParameter(
"aeq_val" ,
"100e-6");
52 DP.addParameter(
"temp_val",
"27" );
54 dpN1 = Mosfet(
"N1",
"d1",
"g1",
"s",
"b",
"nsvt");
55 dpN1.addParameter(
"l" ,
"l_val" );
56 dpN1.addParameter(
"wf" ,
"{w_val/nf_val}");
57 dpN1.addParameter(
"nf" ,
"nf_val" );
58 dpN1.addParameter(
"aeq" ,
"aeq_val" );
59 dpN1.addParameter(
"tempsimu",
"temp_val" );
62 dpN2 = Mosfet(
"N2",
"d2",
"g2",
"s",
"b",
"nsvt");
63 dpN2.addParameter(
"l" ,
"l_val" );
64 dpN2.addParameter(
"wf" ,
"{w_val/nf_val}");
65 dpN2.addParameter(
"nf" ,
"nf_val" );
66 dpN2.addParameter(
"aeq" ,
"aeq_val" );
67 dpN2.addParameter(
"tempsimu",
"temp_val" );
71 iCM = Instance(
"CM",
"currentMirrorPMOS");
72 iCM.addConnector(
"1");
73 iCM.addConnector(
"2");
74 iCM.addConnector(
"vdd");
75 iCM.addConnector(
"vdd");
76 iCM.addParameter(
"l_val" ,
"L_VALUE" );
77 iCM.addParameter(
"w_val" ,
"3.889618e-06");
78 iCM.addParameter(
"nf_val",
"2" );
79 circuit.addInstance(iCM);
81 iDP = Instance(
"DP",
"diffPairNMOS");
82 iDP.addConnector(
"1");
83 iDP.addConnector(
"2");
84 iDP.addConnector(
"vim");
85 iDP.addConnector(
"vip");
86 iDP.addConnector(
"3");
87 iDP.addConnector(
"vss");
88 iDP.addParameter(
"l_val" ,
"L_VALUE" );
89 iDP.addParameter(
"w_val" ,
"7.683346e-07");
90 iDP.addParameter(
"nf_val",
"4" );
91 circuit.addInstance(iDP);
93 iP6 = Mosfet(
"P6",
"vout",
"2",
"vdd",
"vdd",
"psvt");
94 iP6.addParameter(
"l_val" ,
"L_VALUE" );
95 iP6.addParameter(
"w_val" ,
"3.558995e-05");
96 iP6.addParameter(
"nf_val",
"20" );
97 circuit.addInstance(iP6);
99 iN5 = Mosfet(
"N5",
"3",
"4",
"vss",
"vss",
"nsvt");
100 iN5.addParameter(
"l_val" ,
"L_VALUE" );
101 iN5.addParameter(
"w_val" ,
"2.536703e-06");
102 iN5.addParameter(
"nf_val",
"4" );
103 circuit.addInstance(iN5);
105 iN7 = Mosfet(
"N7",
"vout",
"4",
"vss",
"vss",
"nsvt");
106 iN7.addParameter(
"l_val" ,
"L_VALUE" );
107 iN7.addParameter(
"w_val" ,
"1.069083e-05");
108 iN7.addParameter(
"nf_val",
"16" );
109 circuit.addInstance(iN7);
111 iN8 = Mosfet(
"N8",
"4",
"4",
"vss",
"vss",
"nsvt");
112 iN8.addParameter(
"l_val" ,
"L_VALUE" );
113 iN8.addParameter(
"w_val" ,
"2.536703e-06");
114 iN8.addParameter(
"nf_val",
"4" );
115 circuit.addInstance(iN8);
117 capa = Capacitor(
"C1",
"vout",
"2",
"CC_VALUE")
118 circuit.addInstance(capa);
120 circuit.writeToFile(
"./myOTA.spi");
- Note
- In order to run these two scripts (
parseSpice.py
& driveSpice.py), user must ensure that $PYTHONPATH variable points to the directory containing SPICE.so module.