From 1bc03c3b79049cec4fddd6395066dd2b0d26e6a2 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 19 Aug 2019 22:51:22 +0200 Subject: [PATCH] Implement "M" parameter for Spice This implementation is pretty simplistic and applies "M" the following way: * R: R(final) = R/M * L: L(final) = L/M * C: C(final) = C*M * M: W(final) = W*M * D: A(final) = A*M * Q: AE(final) = AE*M The other parameters (specifically the other geometry parameters) are not scaled yet. --- src/db/db/dbNetlistSpiceReader.cc | 58 ++++++++++++++++++++++- src/db/unit_tests/dbNetlistReaderTests.cc | 26 ++++++++++ testdata/algo/nreader9.cir | 12 +++++ 3 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 testdata/algo/nreader9.cir diff --git a/src/db/db/dbNetlistSpiceReader.cc b/src/db/db/dbNetlistSpiceReader.cc index 38773716b..ce4477c7d 100644 --- a/src/db/db/dbNetlistSpiceReader.cc +++ b/src/db/db/dbNetlistSpiceReader.cc @@ -85,34 +85,73 @@ static db::DeviceClass *make_device_class (db::Circuit *circuit, const std::stri return cls; } -bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::string &element, const std::string &name, const std::string &model, double value, const std::vector &nets, const std::map ¶ms) +bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::string &element, const std::string &name, const std::string &model, double value, const std::vector &nets, const std::map &pv) { + std::map params = pv; + + double mult = 1.0; + std::map::const_iterator mp = params.find ("M"); + if (mp != params.end ()) { + mult = mp->second; + } + + if (mult < 1e-10) { + error (tl::sprintf (tl::to_string (tr ("Invalid multiplier value (M=%.12g) - must not be zero or negative")), mult)); + } + std::string cn = model; db::DeviceClass *cls = circuit->netlist ()->device_class_by_name (cn); if (cls) { + // use given class + } else if (element == "R") { + if (cn.empty ()) { cn = "RES"; } cls = make_device_class (circuit, cn); + + // Apply multiplier + value /= mult; + } else if (element == "L") { + if (cn.empty ()) { cn = "IND"; } cls = make_device_class (circuit, cn); + + // Apply multiplier + value /= mult; + } else if (element == "C") { + if (cn.empty ()) { cn = "CAP"; } cls = make_device_class (circuit, cn); + + // Apply multiplier + value *= mult; + } else if (element == "D") { + if (cn.empty ()) { cn = "DIODE"; } cls = make_device_class (circuit, cn); + + // Apply multiplier to "A" + std::map::iterator p; + p = params.find ("A"); + if (p != params.end ()) { + p->second *= mult; + } + } else if (element == "Q") { + if (nets.size () == 3) { if (cn.empty ()) { cn = "BJT3"; @@ -126,12 +165,29 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin } else { error (tl::to_string (tr ("'Q' element needs to have 3 or 4 terminals"))); } + + // Apply multiplier to "AE" + std::map::iterator p; + p = params.find ("AE"); + if (p != params.end ()) { + p->second *= mult; + } + } else if (element == "M") { + if (nets.size () == 4) { if (cn.empty ()) { cn = "MOS4"; } cls = make_device_class (circuit, cn); + + // Apply multiplier to "W" + std::map::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"))); } diff --git a/src/db/unit_tests/dbNetlistReaderTests.cc b/src/db/unit_tests/dbNetlistReaderTests.cc index 3a66a4468..664373d22 100644 --- a/src/db/unit_tests/dbNetlistReaderTests.cc +++ b/src/db/unit_tests/dbNetlistReaderTests.cc @@ -333,3 +333,29 @@ TEST(8_Include) ); } +TEST(9_DeviceMultipliers) +{ + db::Netlist nl; + + 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); + + EXPECT_EQ (nl.to_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" + ); +} + diff --git a/testdata/algo/nreader9.cir b/testdata/algo/nreader9.cir new file mode 100644 index 000000000..302b7a0a2 --- /dev/null +++ b/testdata/algo/nreader9.cir @@ -0,0 +1,12 @@ + +R$1 1 2 1.7k M=2 +R$2 3 4 1.7k +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 +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 +Q$2 1 2 3 4 BIP AE=10P +