Fixed #565 (SPICE global nets must not produce pins if not present) (#567)

* Fixed #565 (SPICE global nets must not produce pins if not present)

* Fixed unit tests.
This commit is contained in:
Matthias Köfferlein 2020-05-26 23:47:59 +02:00 committed by GitHub
parent 757cef91fb
commit 3246e0d36f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 163 additions and 52 deletions

View File

@ -256,6 +256,7 @@ void NetlistSpiceReader::read (tl::InputStream &stream, db::Netlist &netlist)
mp_stream.reset (new tl::TextInputStream (stream)); mp_stream.reset (new tl::TextInputStream (stream));
mp_netlist = &netlist; mp_netlist = &netlist;
mp_circuit = 0; mp_circuit = 0;
mp_anonymous_top_circuit = 0;
mp_nets_by_name.reset (0); mp_nets_by_name.reset (0);
m_global_nets.clear (); m_global_nets.clear ();
m_circuits_read.clear (); m_circuits_read.clear ();
@ -268,6 +269,8 @@ void NetlistSpiceReader::read (tl::InputStream &stream, db::Netlist &netlist)
read_card (); read_card ();
} }
build_global_nets ();
mp_delegate->finish (&netlist); mp_delegate->finish (&netlist);
finish (); finish ();
@ -287,6 +290,48 @@ void NetlistSpiceReader::read (tl::InputStream &stream, db::Netlist &netlist)
} }
} }
void NetlistSpiceReader::build_global_nets ()
{
for (std::vector<std::string>::const_iterator gn = m_global_nets.begin (); gn != m_global_nets.end (); ++gn) {
for (db::Netlist::bottom_up_circuit_iterator c = mp_netlist->begin_bottom_up (); c != mp_netlist->end_bottom_up (); ++c) {
if (c.operator-> () == mp_anonymous_top_circuit) {
// no pins for the anonymous top circuit
continue;
}
db::Net *net = c->net_by_name (*gn);
if (! net || net->pin_count () > 0) {
// only add a pin for a global net if there is a net with this name
// don't add a pin if it already has one
continue;
}
const db::Pin &pin = c->add_pin (*gn);
c->connect_pin (pin.id (), net);
for (db::Circuit::refs_iterator r = c->begin_refs (); r != c->end_refs (); ++r) {
db::SubCircuit &sc = *r;
db::Net *pnet = sc.circuit ()->net_by_name (*gn);
if (! pnet) {
pnet = new db::Net ();
pnet->set_name (*gn);
sc.circuit ()->add_net (pnet);
}
sc.connect_pin (pin.id (), pnet);
}
}
}
}
void NetlistSpiceReader::finish () void NetlistSpiceReader::finish ()
{ {
while (! m_streams.empty ()) { while (! m_streams.empty ()) {
@ -577,12 +622,9 @@ void NetlistSpiceReader::ensure_circuit ()
mp_circuit = new db::Circuit (); mp_circuit = new db::Circuit ();
// TODO: make top name configurable // TODO: make top name configurable
mp_circuit->set_name (".TOP"); mp_circuit->set_name (".TOP");
mp_anonymous_top_circuit = mp_circuit;
mp_netlist->add_circuit (mp_circuit); 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);
}
} }
} }
@ -828,13 +870,10 @@ 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) { for (std::vector<db::Net *>::const_iterator i = nets.begin (); i != nets.end (); ++i) {
cc->add_pin (std::string ()); 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 { } else {
if (cc->pin_count () != nets.size () + m_global_nets.size ()) { if (cc->pin_count () != 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 ()))); 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 ())));
} }
@ -846,11 +885,6 @@ 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) { for (std::vector<db::Net *>::const_iterator i = nets.begin (); i != nets.end (); ++i) {
sc->connect_pin (i - nets.begin (), *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*/) void NetlistSpiceReader::skip_circuit (tl::Extractor & /*ex*/)
@ -892,13 +926,10 @@ void NetlistSpiceReader::read_circuit (tl::Extractor &ex, const std::string &nc)
for (std::vector<std::string>::const_iterator i = nn.begin (); i != nn.end (); ++i) { for (std::vector<std::string>::const_iterator i = nn.begin (); i != nn.end (); ++i) {
cc->add_pin (std::string ()); 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 { } else {
if (cc->pin_count () != nn.size () + m_global_nets.size ()) { if (cc->pin_count () != nn.size ()) {
error (tl::sprintf (tl::to_string (tr ("Pin count mismatch between implicit (through call) and explicit circuit definition: %d expected, got %d in circuit %s")), int (cc->pin_count ()), int (nn.size ()), nc)); error (tl::sprintf (tl::to_string (tr ("Pin count mismatch between implicit (through call) and explicit circuit definition: %d expected, got %d in circuit %s")), int (cc->pin_count ()), int (nn.size ()), nc));
} }
@ -925,14 +956,6 @@ void NetlistSpiceReader::read_circuit (tl::Extractor &ex, const std::string &nc)
mp_circuit->connect_pin (pin_id, 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 ()) { while (! at_end ()) {
if (read_card ()) { if (read_card ()) {
break; break;

View File

@ -124,6 +124,7 @@ public:
private: private:
db::Netlist *mp_netlist; db::Netlist *mp_netlist;
db::Circuit *mp_circuit; db::Circuit *mp_circuit;
db::Circuit *mp_anonymous_top_circuit;
std::auto_ptr<tl::TextInputStream> mp_stream; std::auto_ptr<tl::TextInputStream> mp_stream;
tl::weak_ptr<NetlistSpiceReaderDelegate> mp_delegate; tl::weak_ptr<NetlistSpiceReaderDelegate> mp_delegate;
std::vector<std::pair<tl::InputStream *, tl::TextInputStream *> > m_streams; std::vector<std::pair<tl::InputStream *, tl::TextInputStream *> > m_streams;
@ -157,6 +158,7 @@ private:
db::Net *make_net (const std::string &name); db::Net *make_net (const std::string &name);
void ensure_circuit (); void ensure_circuit ();
bool subcircuit_captured (const std::string &nc_name); bool subcircuit_captured (const std::string &nc_name);
void build_global_nets ();
}; };
} }

View File

@ -443,3 +443,47 @@ TEST(12_IgnoreDuplicateGlobals)
); );
} }
TEST(13_NoGlobalNetsIfNotUsed)
{
db::Netlist nl;
std::string path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nreader13.cir");
db::NetlistSpiceReader reader;
tl::InputStream is (path);
reader.read (is, nl);
EXPECT_EQ (nl.to_string (),
"circuit .TOP ();\n"
" device RES $1 (A=VDD,B=NC) (R=1000,L=0,W=0,A=0,P=0);\n"
" subcircuit C10 '1' (VDD=VDD,GND=GND);\n"
"end;\n"
"circuit C10 (VDD=VDD,GND=GND);\n"
" subcircuit C1 '1' (VDD=VDD,GND=GND);\n"
" subcircuit C2 '2' ();\n"
" subcircuit C3 '3' (VDD=VDD,GND=GND);\n"
" subcircuit C4 '4' (VDD=VDD,GND=GND);\n"
"end;\n"
"circuit FILLER_CAP (VDD=VDD,GND=GND);\n"
" device NMOS '1' (S=GND,G=VDD,D=GND,B=GND) (L=10,W=10,AS=0,AD=0,PS=0,PD=0);\n"
"end;\n"
"circuit DUMMY ();\n"
" device NMOS '1' (S=A,G=A,D=A,B=B) (L=1,W=1,AS=0,AD=0,PS=0,PD=0);\n"
"end;\n"
"circuit C1 (VDD=VDD,GND=GND);\n"
" subcircuit FILLER_CAP '1' (VDD=VDD,GND=GND);\n"
" subcircuit DUMMY '2' ();\n"
"end;\n"
"circuit C2 ();\n"
" subcircuit DUMMY '1' ();\n"
"end;\n"
"circuit C3 (VDD=VDD,GND=GND);\n"
" device NMOS '1' (S=GND,G=VDD,D=GND,B=GND) (L=10,W=10,AS=0,AD=0,PS=0,PD=0);\n"
" subcircuit FILLER_CAP '1' (VDD=VDD,GND=GND);\n"
"end;\n"
"circuit C4 (VDD=VDD,GND=GND);\n"
" subcircuit C1 '3' (VDD=VDD,GND=GND);\n"
"end;\n"
);
}

42
testdata/algo/nreader13.cir vendored Normal file
View File

@ -0,0 +1,42 @@
.global vdd gnd
X1 C10
R$1 vdd nc 1k
.subckt FILLER_CAP
M1 gnd vdd gnd gnd NMOS W=10u L=10u
.ends FILLER_CAP
.subckt DUMMY
M1 a a a b NMOS W=1u L=1u
.ends DUMMY
.subckt C10
X1 C1
X2 C2
X3 C3
X4 C4
.ends C10
.subckt C4
X3 C1
.ends C4
.subckt C1
* generates gnd and vdd
X1 FILLER_CAP
X2 DUMMY
.ends C1
.subckt C2
* does not generate gnd or vdd
X1 DUMMY
.ends C2
.subckt C3
* generates gnd and vdd too
X1 FILLER_CAP
M1 gnd vdd gnd gnd NMOS W=10u L=10u
.ends C3

View File

@ -266,14 +266,14 @@ reference(
# Nets # Nets
net(1 name(A)) net(1 name(A))
net(2 name(Z)) net(2 name(Z))
net(3 name(VDD)) net(3 name(VSS))
net(4 name(VSS)) net(4 name(VDD))
# Outgoing pins and their connections to nets # Outgoing pins and their connections to nets
pin(1 name(A)) pin(1 name(A))
pin(2 name(Z)) pin(2 name(Z))
pin(3 name(VDD)) pin(4 name(VDD))
pin(4 name(VSS)) pin(3 name(VSS))
# Devices and their connections # Devices and their connections
device(1 NMOS device(1 NMOS
@ -286,8 +286,8 @@ reference(
param(PD 0) param(PD 0)
terminal(S 2) terminal(S 2)
terminal(G 1) terminal(G 1)
terminal(D 4) terminal(D 3)
terminal(B 4) terminal(B 3)
) )
device(2 PMOS device(2 PMOS
name('1') name('1')
@ -299,8 +299,8 @@ reference(
param(PD 0) param(PD 0)
terminal(S 2) terminal(S 2)
terminal(G 1) terminal(G 1)
terminal(D 3) terminal(D 4)
terminal(B 3) terminal(B 4)
) )
) )
@ -343,32 +343,32 @@ reference(
net(1 name(A)) net(1 name(A))
net(2 name(C)) net(2 name(C))
net(3 name(D)) net(3 name(D))
net(4 name(VDD)) net(4 name(B))
net(5 name(VSS)) net(5 name(E))
net(6 name(B)) net(6 name(VDD))
net(7 name(E)) net(7 name(VSS))
# Outgoing pins and their connections to nets # Outgoing pins and their connections to nets
pin(1 name(A)) pin(1 name(A))
pin(2 name(C)) pin(2 name(C))
pin(3 name(D)) pin(3 name(D))
pin(4 name(VDD)) pin(6 name(VDD))
pin(5 name(VSS)) pin(7 name(VSS))
# Subcircuits and their connections # Subcircuits and their connections
circuit(1 DINV name('0') circuit(1 DINV name('0')
pin(0 1) pin(0 1)
pin(1 2) pin(1 2)
pin(2 6)
pin(3 7)
pin(4 4)
pin(5 5)
)
circuit(2 INVX1 name('1')
pin(0 7)
pin(1 3)
pin(2 4) pin(2 4)
pin(3 5) pin(3 5)
pin(4 6)
pin(5 7)
)
circuit(2 INVX1 name('1')
pin(0 5)
pin(1 3)
pin(2 6)
pin(3 7)
) )
) )
@ -398,8 +398,8 @@ xref(
xref( xref(
net(3 1 match) net(3 1 match)
net(1 2 match) net(1 2 match)
net(2 3 match) net(2 4 match)
net(4 4 match) net(4 3 match)
pin(2 0 match) pin(2 0 match)
pin(0 1 match) pin(0 1 match)
pin(1 2 match) pin(1 2 match)
@ -411,11 +411,11 @@ xref(
circuit(TOP TOP match circuit(TOP TOP match
xref( xref(
net(5 3 match) net(5 3 match)
net(1 7 match) net(1 5 match)
net(6 4 match) net(6 6 match)
net(2 1 match) net(2 1 match)
net(3 2 match) net(3 2 match)
net(4 5 match) net(4 7 match)
pin(() 2 match) pin(() 2 match)
pin(() 3 match) pin(() 3 match)
pin(0 0 match) pin(0 0 match)