Added .global to Spice reader.

This commit is contained in:
Matthias Koefferlein 2019-07-22 23:02:31 +02:00
parent 9d250d6df9
commit 14d9689498
4 changed files with 116 additions and 4 deletions

View File

@ -195,6 +195,7 @@ void NetlistSpiceReader::read (tl::InputStream &stream, db::Netlist &netlist)
mp_netlist = &netlist;
mp_circuit = 0;
mp_nets_by_name.reset (0);
m_global_nets.clear ();
try {
@ -343,6 +344,11 @@ bool NetlistSpiceReader::read_card ()
// ignore model statements
} else if (ex.test_without_case ("global")) {
std::string n = read_name (ex);
m_global_nets.push_back (n);
} else if (ex.test_without_case ("subckt")) {
std::string nc = read_name (ex);
@ -497,6 +503,10 @@ void NetlistSpiceReader::ensure_circuit ()
mp_circuit->set_name (".TOP");
mp_netlist->add_circuit (mp_circuit);
for (std::vector<std::string>::const_iterator gn = m_global_nets.begin (); gn != m_global_nets.end (); ++gn) {
make_net (*gn);
}
}
}
@ -737,16 +747,25 @@ void NetlistSpiceReader::read_subcircuit (const std::string &sc_name, const std:
db::Circuit *cc = mp_netlist->circuit_by_name (nc_name);
if (! cc) {
cc = new db::Circuit ();
mp_netlist->add_circuit (cc);
cc->set_name (nc_name);
// we'll make the names later ...
for (std::vector<db::Net *>::const_iterator i = nets.begin (); i != nets.end (); ++i) {
cc->add_pin (std::string ());
}
for (std::vector<std::string>::const_iterator gn = m_global_nets.begin (); gn != m_global_nets.end (); ++gn) {
cc->add_pin (std::string ());
}
} else {
if (cc->pin_count () != nets.size ()) {
if (cc->pin_count () != nets.size () + m_global_nets.size ()) {
error (tl::sprintf (tl::to_string (tr ("Pin count mismatch between circuit definition and circuit call: %d expected, got %d")), int (cc->pin_count ()), int (nets.size ())));
}
}
db::SubCircuit *sc = new db::SubCircuit (cc, sc_name);
@ -755,6 +774,11 @@ void NetlistSpiceReader::read_subcircuit (const std::string &sc_name, const std:
for (std::vector<db::Net *>::const_iterator i = nets.begin (); i != nets.end (); ++i) {
sc->connect_pin (i - nets.begin (), *i);
}
for (std::vector<std::string>::const_iterator gn = m_global_nets.begin (); gn != m_global_nets.end (); ++gn) {
db::Net *net = make_net (*gn);
sc->connect_pin (gn - m_global_nets.begin () + nets.size (), net);
}
}
void NetlistSpiceReader::skip_circuit (tl::Extractor & /*ex*/)
@ -789,16 +813,23 @@ void NetlistSpiceReader::read_circuit (tl::Extractor &ex, const std::string &nc)
db::Circuit *cc = mp_netlist->circuit_by_name (nc);
if (! cc) {
cc = new db::Circuit ();
mp_netlist->add_circuit (cc);
cc->set_name (nc);
for (std::vector<std::string>::const_iterator i = nn.begin (); i != nn.end (); ++i) {
cc->add_pin (std::string ());
}
for (std::vector<std::string>::const_iterator gn = m_global_nets.begin (); gn != m_global_nets.end (); ++gn) {
cc->add_pin (std::string ());
}
} else {
if (cc->pin_count () != nn.size ()) {
if (cc->pin_count () != nn.size () + m_global_nets.size ()) {
error (tl::sprintf (tl::to_string (tr ("Pin count mismatch between implicit (through call) and explicit circuit definition: %d expected, got %d")), int (cc->pin_count ()), int (nn.size ())));
}
}
std::auto_ptr<std::map<std::string, db::Net *> > n2n (mp_nets_by_name.release ());
@ -806,13 +837,23 @@ void NetlistSpiceReader::read_circuit (tl::Extractor &ex, const std::string &nc)
std::swap (cc, mp_circuit);
// produce the explicit pins
for (std::vector<std::string>::const_iterator i = nn.begin (); i != nn.end (); ++i) {
db::Net *net = make_net (*i);
// use the net name to name the pin (otherwise SPICE pins are always unnamed)
size_t pin_id = i - nn.begin ();
if (! i->empty ()) {
mp_circuit->rename_pin (i - nn.begin (), net->name ());
mp_circuit->rename_pin (pin_id, net->name ());
}
mp_circuit->connect_pin (i - nn.begin (), net);
mp_circuit->connect_pin (pin_id, net);
}
// produce pins for the global nets
for (std::vector<std::string>::const_iterator gn = m_global_nets.begin (); gn != m_global_nets.end (); ++gn) {
db::Net *net = make_net (*gn);
size_t pin_id = gn - m_global_nets.begin () + nn.size ();
mp_circuit->rename_pin (pin_id, net->name ());
mp_circuit->connect_pin (pin_id, net);
}
while (! at_end ()) {

View File

@ -128,6 +128,7 @@ private:
std::auto_ptr<std::map<std::string, db::Net *> > mp_nets_by_name;
std::string m_stored_line;
std::map<std::string, bool> m_captured;
std::vector<std::string> m_global_nets;
void push_stream (const std::string &path);
void pop_stream ();

View File

@ -255,3 +255,42 @@ TEST(6_ReaderWithDelegate)
"end;\n"
);
}
TEST(7_GlobalNets)
{
db::Netlist nl;
std::string path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nreader7.cir");
MyNetlistReaderDelegate delegate;
db::NetlistSpiceReader reader (&delegate);
tl::InputStream is (path);
reader.read (is, nl);
EXPECT_EQ (nl.to_string (),
"circuit RINGO (FB=FB,OUT=OUT,ENABLE=ENABLE,VDD=VDD,VSS=VSS);\n"
" subcircuit ND2X1 $1 (OUT='1',B=FB,A=ENABLE,VDD=VDD,VSS=VSS);\n"
" subcircuit INVX1 $2 (OUT='2',IN='1',VDD=VDD,VSS=VSS);\n"
" subcircuit INVX1 $3 (OUT='3',IN='2',VDD=VDD,VSS=VSS);\n"
" subcircuit INVX1 $4 (OUT='4',IN='3',VDD=VDD,VSS=VSS);\n"
" subcircuit INVX1 $5 (OUT='5',IN='4',VDD=VDD,VSS=VSS);\n"
" subcircuit INVX1 $6 (OUT='6',IN='5',VDD=VDD,VSS=VSS);\n"
" subcircuit INVX1 $7 (OUT='7',IN='6',VDD=VDD,VSS=VSS);\n"
" subcircuit INVX1 $8 (OUT='8',IN='7',VDD=VDD,VSS=VSS);\n"
" subcircuit INVX1 $9 (OUT='9',IN='8',VDD=VDD,VSS=VSS);\n"
" subcircuit INVX1 $10 (OUT='10',IN='9',VDD=VDD,VSS=VSS);\n"
" subcircuit INVX1 $11 (OUT=FB,IN='10',VDD=VDD,VSS=VSS);\n"
" subcircuit INVX1 $12 (OUT=OUT,IN=FB,VDD=VDD,VSS=VSS);\n"
"end;\n"
"circuit ND2X1 (OUT=OUT,B=B,A=A,VDD=VDD,VSS=VSS);\n"
" device MLVPMOS $1 (S=OUT,G=A,D=VDD,B=VDD) (L=0.25,W=1.5,AS=0.6375,AD=0.3375,PS=3.85,PD=1.95);\n"
" device MLVPMOS $2 (S=VDD,G=B,D=OUT,B=VDD) (L=0.25,W=1.5,AS=0.3375,AD=0.6375,PS=1.95,PD=3.85);\n"
" device MLVNMOS $3 (S=VSS,G=A,D=INT,B=VSS) (L=0.25,W=0.95,AS=0.40375,AD=0.21375,PS=2.75,PD=1.4);\n"
" device MLVNMOS $4 (S=INT,G=B,D=OUT,B=VSS) (L=0.25,W=0.95,AS=0.21375,AD=0.40375,PS=1.4,PD=2.75);\n"
"end;\n"
"circuit INVX1 (OUT=OUT,IN=IN,VDD=VDD,VSS=VSS);\n"
" device MLVPMOS $1 (S=VDD,G=IN,D=OUT,B=VDD) (L=0.25,W=1.5,AS=0.6375,AD=0.6375,PS=3.85,PD=3.85);\n"
" device MLVNMOS $2 (S=VSS,G=IN,D=OUT,B=VSS) (L=0.25,W=0.95,AS=0.40375,AD=0.40375,PS=2.75,PD=2.75);\n"
"end;\n"
);
}

31
testdata/algo/nreader7.cir vendored Normal file
View File

@ -0,0 +1,31 @@
* RINGO netlist with global nets
.GLOBAL VDD
.GLOBAL VSS
.SUBCKT RINGO FB OUT ENABLE
X$1 1 FB ENABLE ND2X1
X$2 2 1 INVX1
X$3 3 2 INVX1
X$4 4 3 INVX1
X$5 5 4 INVX1
X$6 6 5 INVX1
X$7 7 6 INVX1
X$8 8 7 INVX1
X$9 9 8 INVX1
X$10 10 9 INVX1
X$11 FB 10 INVX1
X$12 OUT FB INVX1
.ENDS RINGO
.SUBCKT ND2X1 OUT B A
M$1 OUT A VDD VDD MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.3375P PS=3.85U PD=1.95U
M$2 VDD B OUT VDD MLVPMOS L=0.25U W=1.5U AS=0.3375P AD=0.6375P PS=1.95U PD=3.85U
M$3 VSS A INT VSS MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.21375P PS=2.75U PD=1.4U
M$4 INT B OUT VSS MLVNMOS L=0.25U W=0.95U AS=0.21375P AD=0.40375P PS=1.4U PD=2.75U
.ENDS ND2X1
.SUBCKT INVX1 OUT IN
M$1 VDD IN OUT VDD MLVPMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U
M$2 VSS IN OUT VSS MLVNMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U
.ENDS INVX1