Fixed #652 (M scaling not working sometimes for Spice), provided test… (#653)

* Fixed #652 (M scaling not working sometimes for Spice), provided testcases

* One more patch (bugfix, Spice reader)
This commit is contained in:
Matthias Köfferlein 2020-10-10 23:16:02 +02:00 committed by GitHub
parent 051a8bdc77
commit 591d4a5c37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 154 additions and 61 deletions

View File

@ -104,46 +104,66 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
std::string cn = model;
db::DeviceClass *cls = circuit->netlist ()->device_class_by_name (cn);
if (cls) {
if (element == "R") {
// use given class
} else if (element == "R") {
if (cn.empty ()) {
cn = "RES";
if (cls) {
if (! dynamic_cast<db::DeviceClassResistor *>(cls)) {
error (tl::sprintf (tl::to_string (tr ("Class %s not a resistor device class as required by 'R' element")), cn));
}
} else {
if (cn.empty ()) {
cn = "RES";
}
cls = make_device_class<db::DeviceClassResistor> (circuit, cn);
}
cls = make_device_class<db::DeviceClassResistor> (circuit, cn);
// Apply multiplier
value /= mult;
} else if (element == "L") {
if (cn.empty ()) {
cn = "IND";
if (cls) {
if (! dynamic_cast<db::DeviceClassInductor *>(cls)) {
error (tl::sprintf (tl::to_string (tr ("Class %s not a inductor device class as required by 'L' element")), cn));
}
} else {
if (cn.empty ()) {
cn = "IND";
}
cls = make_device_class<db::DeviceClassInductor> (circuit, cn);
}
cls = make_device_class<db::DeviceClassInductor> (circuit, cn);
// Apply multiplier
value /= mult;
} else if (element == "C") {
if (cn.empty ()) {
cn = "CAP";
if (cls) {
if (! dynamic_cast<db::DeviceClassCapacitor *>(cls)) {
error (tl::sprintf (tl::to_string (tr ("Class %s not a capacitor device class as required by 'C' element")), cn));
}
} else {
if (cn.empty ()) {
cn = "CAP";
}
cls = make_device_class<db::DeviceClassCapacitor> (circuit, cn);
}
cls = make_device_class<db::DeviceClassCapacitor> (circuit, cn);
// Apply multiplier
value *= mult;
} else if (element == "D") {
if (cn.empty ()) {
cn = "DIODE";
if (cls) {
if (! dynamic_cast<db::DeviceClassDiode *>(cls)) {
error (tl::sprintf (tl::to_string (tr ("Class %s not a diode device class as required by 'D' element")), cn));
}
} else {
if (cn.empty ()) {
cn = "DIODE";
}
cls = make_device_class<db::DeviceClassDiode> (circuit, cn);
}
cls = make_device_class<db::DeviceClassDiode> (circuit, cn);
// Apply multiplier to "A"
std::map<std::string, double>::iterator p;
@ -154,18 +174,30 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
} else if (element == "Q") {
if (nets.size () == 3) {
if (cn.empty ()) {
cn = "BJT3";
}
cls = make_device_class<db::DeviceClassBJT3Transistor> (circuit, cn);
} else if (nets.size () == 4) {
if (cn.empty ()) {
cn = "BJT4";
}
cls = make_device_class<db::DeviceClassBJT4Transistor> (circuit, cn);
} else {
if (nets.size () != 3 && nets.size () != 4) {
error (tl::to_string (tr ("'Q' element needs to have 3 or 4 terminals")));
} else if (cls) {
if (nets.size () == 3) {
if (! dynamic_cast<db::DeviceClassBJT3Transistor *>(cls)) {
error (tl::sprintf (tl::to_string (tr ("Class %s not a 3-terminal BJT device class as required by 'Q' element")), cn));
}
} else {
if (! dynamic_cast<db::DeviceClassBJT4Transistor *>(cls)) {
error (tl::sprintf (tl::to_string (tr ("Class %s not a 4-terminal BJT device class as required by 'Q' element")), cn));
}
}
} else {
if (nets.size () == 3) {
if (cn.empty ()) {
cn = "BJT3";
}
cls = make_device_class<db::DeviceClassBJT3Transistor> (circuit, cn);
} else {
if (cn.empty ()) {
cn = "BJT4";
}
cls = make_device_class<db::DeviceClassBJT4Transistor> (circuit, cn);
}
}
// Apply multiplier to "AE"
@ -177,22 +209,28 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
} else if (element == "M") {
if (nets.size () == 4) {
if (cn.empty ()) {
cn = "MOS4";
if (cls) {
if (! dynamic_cast<db::DeviceClassMOS4Transistor *>(cls)) {
error (tl::sprintf (tl::to_string (tr ("Class %s not a 4-terminal MOS device class as required by 'M' element")), cn));
}
cls = make_device_class<db::DeviceClassMOS4Transistor> (circuit, cn);
// Apply multiplier to "W"
std::map<std::string, double>::iterator p;
p = params.find ("W");
if (p != params.end ()) {
p->second *= mult;
}
} else {
error (tl::to_string (tr ("'M' element needs to have 4 terminals")));
if (nets.size () == 4) {
if (cn.empty ()) {
cn = "MOS4";
}
cls = make_device_class<db::DeviceClassMOS4Transistor> (circuit, cn);
} else {
error (tl::to_string (tr ("'M' element needs to have 4 terminals")));
}
}
// Apply multiplier to "W"
std::map<std::string, double>::iterator p;
p = params.find ("W");
if (p != params.end ()) {
p->second *= mult;
}
} else {
error (tl::sprintf (tl::to_string (tr ("Not a known element type: '%s'")), element));
}

View File

@ -359,28 +359,75 @@ TEST(9_DeviceMultipliers)
std::string path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nreader9.cir");
db::NetlistSpiceReader reader;
tl::InputStream is (path);
reader.read (is, nl);
{
db::NetlistSpiceReader reader;
tl::InputStream is (path);
reader.read (is, nl);
std::string nl_string = nl.to_string ();
// normalization of exponential representation:
nl_string = tl::replaced (nl_string, "e-009", "e-09");
std::string nl_string = nl.to_string ();
// normalization of exponential representation:
nl_string = tl::replaced (nl_string, "e-009", "e-09");
EXPECT_EQ (nl_string,
"circuit .TOP ();\n"
" device RES $1 (A='1',B='2') (R=850,L=0,W=0,A=0,P=0);\n"
" device RES $2 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n"
" device NMOS $1 (S='1',G='2',D='3',B='4') (L=7,W=4,AS=0,AD=0,PS=0,PD=0);\n"
" device PMOS $2 (S='1',G='2',D='3',B='4') (L=7,W=2,AS=0,AD=0,PS=0,PD=0);\n"
" device CAP $1 (A='1',B='2') (C=2e-09,A=0,P=0);\n"
" device CAP $2 (A='3',B='4') (C=1e-09,A=0,P=0);\n"
" device DIODE $1 (A='1',C='2') (A=20,P=0);\n"
" device DIODE $2 (A='3',C='4') (A=10,P=0);\n"
" device BIP $1 (C='1',B='2',E='3',S='4') (AE=20,PE=0,AB=0,PB=0,AC=0,PC=0,NE=1);\n"
" device BIP $2 (C='1',B='2',E='3',S='4') (AE=10,PE=0,AB=0,PB=0,AC=0,PC=0,NE=1);\n"
"end;\n"
);
EXPECT_EQ (nl_string,
"circuit .TOP ();\n"
" device RES $1 (A='1',B='2') (R=850,L=0,W=0,A=0,P=0);\n"
" device RES $2 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n"
" device RMODEL $3 (A='1',B='2') (R=850,L=0,W=0,A=0,P=0);\n"
" device RMODEL $4 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n"
" device NMOS $1 (S='1',G='2',D='3',B='4') (L=7,W=4,AS=0,AD=0,PS=0,PD=0);\n"
" device PMOS $2 (S='1',G='2',D='3',B='4') (L=7,W=2,AS=0,AD=0,PS=0,PD=0);\n"
" device CAP $1 (A='1',B='2') (C=2e-09,A=0,P=0);\n"
" device CAP $2 (A='3',B='4') (C=1e-09,A=0,P=0);\n"
" device CMODEL $3 (A='1',B='2') (C=2e-09,A=0,P=0);\n"
" device CMODEL $4 (A='3',B='4') (C=1e-09,A=0,P=0);\n"
" device IND $1 (A='1',B='2') (L=5e-10);\n"
" device IND $2 (A='3',B='4') (L=1e-09);\n"
" device LMODEL $3 (A='1',B='2') (L=5e-10);\n"
" device LMODEL $4 (A='3',B='4') (L=1e-09);\n"
" device DIODE $1 (A='1',C='2') (A=20,P=0);\n"
" device DIODE $2 (A='3',C='4') (A=10,P=0);\n"
" device BIP $1 (C='1',B='2',E='3',S='4') (AE=20,PE=0,AB=0,PB=0,AC=0,PC=0,NE=1);\n"
" device BIP $2 (C='1',B='2',E='3',S='4') (AE=10,PE=0,AB=0,PB=0,AC=0,PC=0,NE=1);\n"
"end;\n"
);
}
db::Circuit *top = nl.circuit_by_name (".TOP");
nl.remove_circuit (top);
// read once again, this time with known classes (must not trigger issue-652)
{
db::NetlistSpiceReader reader;
tl::InputStream is (path);
reader.read (is, nl);
std::string nl_string = nl.to_string ();
// normalization of exponential representation:
nl_string = tl::replaced (nl_string, "e-009", "e-09");
EXPECT_EQ (nl_string,
"circuit .TOP ();\n"
" device RES $1 (A='1',B='2') (R=850,L=0,W=0,A=0,P=0);\n"
" device RES $2 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n"
" device RMODEL $3 (A='1',B='2') (R=850,L=0,W=0,A=0,P=0);\n"
" device RMODEL $4 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n"
" device NMOS $1 (S='1',G='2',D='3',B='4') (L=7,W=4,AS=0,AD=0,PS=0,PD=0);\n"
" device PMOS $2 (S='1',G='2',D='3',B='4') (L=7,W=2,AS=0,AD=0,PS=0,PD=0);\n"
" device CAP $1 (A='1',B='2') (C=2e-09,A=0,P=0);\n"
" device CAP $2 (A='3',B='4') (C=1e-09,A=0,P=0);\n"
" device CMODEL $3 (A='1',B='2') (C=2e-09,A=0,P=0);\n"
" device CMODEL $4 (A='3',B='4') (C=1e-09,A=0,P=0);\n"
" device IND $1 (A='1',B='2') (L=5e-10);\n"
" device IND $2 (A='3',B='4') (L=1e-09);\n"
" device LMODEL $3 (A='1',B='2') (L=5e-10);\n"
" device LMODEL $4 (A='3',B='4') (L=1e-09);\n"
" device DIODE $1 (A='1',C='2') (A=20,P=0);\n"
" device DIODE $2 (A='3',C='4') (A=10,P=0);\n"
" device BIP $1 (C='1',B='2',E='3',S='4') (AE=20,PE=0,AB=0,PB=0,AC=0,PC=0,NE=1);\n"
" device BIP $2 (C='1',B='2',E='3',S='4') (AE=10,PE=0,AB=0,PB=0,AC=0,PC=0,NE=1);\n"
"end;\n"
);
}
}
TEST(10_SubcircuitsNoPins)

View File

@ -1,10 +1,18 @@
R$1 1 2 1.7k M=2
R$2 3 4 1.7k
R$3 1 2 1.7k RMODEL M=2
R$4 3 4 1.7k RMODEL
M$1 1 2 3 4 NMOS W=2u L=7u M=2
M$2 1 2 3 4 PMOS W=2u L=7u
C$1 1 2 1e-9 M=2
C$2 3 4 1e-9
C$3 1 2 1e-9 CMODEL M=2
C$4 3 4 1e-9 CMODEL
L$1 1 2 1e-9 M=2
L$2 3 4 1e-9
L$3 1 2 1e-9 LMODEL M=2
L$4 3 4 1e-9 LMODEL
D$1 1 2 DIODE A=10P M=2
D$2 3 4 DIODE A=10P
Q$1 1 2 3 4 BIP AE=10P M=2