From a39441cdbd7f4eb9ab3f416c5664060b39f19efc Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 24 Mar 2023 13:29:14 +0100 Subject: [PATCH 1/2] Some alignment of Spice reader details with ngspice (not all possible ways of specifying R, L or C elements are supported currently) --- src/db/db/dbNetlistSpiceReaderDelegate.cc | 98 ++++++++++++++----- src/db/db/dbNetlistSpiceReaderDelegate.h | 5 + .../dbNetlistSpiceReaderExpressionParser.cc | 30 ++++-- .../db/dbNetlistSpiceReaderExpressionParser.h | 3 +- src/db/unit_tests/dbNetlistReaderTests.cc | 62 ++++++++++++ testdata/algo/nreader19b.cir | 29 ++++++ testdata/algo/nreader20.cir | 37 +++++++ 7 files changed, 228 insertions(+), 36 deletions(-) create mode 100644 testdata/algo/nreader19b.cir create mode 100644 testdata/algo/nreader20.cir diff --git a/src/db/db/dbNetlistSpiceReaderDelegate.cc b/src/db/db/dbNetlistSpiceReaderDelegate.cc index 326d920aa..905360073 100644 --- a/src/db/db/dbNetlistSpiceReaderDelegate.cc +++ b/src/db/db/dbNetlistSpiceReaderDelegate.cc @@ -225,7 +225,7 @@ void NetlistSpiceReaderDelegate::parse_element_components (const std::string &s, // a parameter std::string pn = mp_netlist ? mp_netlist->normalize_name (n) : tl::to_upper_case (n); - pv [pn] = read_value (ex, variables); + pv [pn] = read_value (ex, variables, pv); } else { @@ -304,44 +304,81 @@ void NetlistSpiceReaderDelegate::parse_element (const std::string &s, const std: // (same for C, L instead of R) if (nn.size () < 2) { - error (tl::to_string (tr ("Not enough specs for a R, C or L device"))); + error (tl::to_string (tr ("Not enough specs (nodes, value, model) for a R, C or L device"))); + } else if (nn.size () > 5) { + error (tl::to_string (tr ("Too many specs (nodes, value, model) for a R, C or L device"))); } + // Variations are (here for "C" element): + // (1) Cname n1 n2 C=value [other params] + // (2) Cname n1 n2 value [params] + // (3) Cname n1 n2 model C=value [other params] + // Cname n1 n2 n3 C=value [other params] -> not supported, cannot tell from (3) without further analysis + // (4) Cname n1 n2 model value [params] + // Cname n1 n2 n3 value [params] -> not supported, cannot tell from (4) without further analysis + // (5) Cname n1 n2 n3 model C=value [other params] + // (6) Cname n1 n2 value model [params] + // (7) Cname n1 n2 n3 model value [params] + // (8) Cname n1 n2 n3 value model [params] + auto rv = pv.find (element); - if (rv != pv.end ()) { - // value given by parameter - value = rv->second.to_double (); - - if (nn.size () >= 3) { - // Rname n1 n2 model [params] - // Rname n1 n2 n3 model [params] - model = nn.back (); - nn.pop_back (); + bool has_value = false; + if (nn.size () == 2) { + if (rv != pv.end ()) { + value = rv->second.to_double (); // (1) + has_value = true; } - - } else if (nn.size () >= 3) { - + } else if (nn.size () == 3) { if (try_read_value (nn.back (), value, variables)) { - - // Rname n1 n2 value - // Rname n1 n2 n3 value + has_value = true; // (2) nn.pop_back (); - } else { - - // Rname n1 n2 value model [params] - // Rname n1 n2 n3 value model [params] + model = nn.back (); // (3) + nn.pop_back (); + if (rv != pv.end ()) { + value = rv->second.to_double (); + has_value = true; + } + } + } else if (nn.size () == 4) { + if (try_read_value (nn.back (), value, variables)) { + has_value = true; // (4) + nn.pop_back (); + } else if (rv != pv.end ()) { + value = rv->second.to_double (); // (5) + has_value = true; model = nn.back (); nn.pop_back (); - if (! try_read_value (nn.back (), value, variables)) { - error (tl::to_string (tr ("Can't find a value for a R, C or L device"))); - } else { - nn.pop_back (); - } - + } else if (try_read_value (nn[2], value, variables)) { + has_value = true; // (6) + model = nn.back (); + nn.pop_back (); + nn.pop_back (); + } else { + model = nn.back (); // fall back to (5) + nn.pop_back (); } + } else { + if (try_read_value (nn.back (), value, variables)) { + has_value = true; // (7) + nn.pop_back (); + model = nn.back (); + nn.pop_back (); + } else if (try_read_value (nn[3], value, variables)) { + has_value = true; // (8) + model = nn.back (); + nn.pop_back (); + nn.pop_back (); + } + } + if (rv != pv.end ()) { + pv.erase (rv); + } + + if (! has_value) { + error (tl::to_string (tr ("Can't find a value for a R, C or L device"))); } } else { @@ -653,6 +690,13 @@ NetlistSpiceReaderDelegate::read_value (tl::Extractor &ex, const std::map &variables1, const std::map &variables2) +{ + NetlistSpiceReaderExpressionParser parser (&variables1, &variables2); + return parser.read (ex); +} + bool NetlistSpiceReaderDelegate::try_read_value (const std::string &s, double &v, const std::map &variables) { diff --git a/src/db/db/dbNetlistSpiceReaderDelegate.h b/src/db/db/dbNetlistSpiceReaderDelegate.h index 6e304ed80..75e47824f 100644 --- a/src/db/db/dbNetlistSpiceReaderDelegate.h +++ b/src/db/db/dbNetlistSpiceReaderDelegate.h @@ -154,6 +154,11 @@ public: */ static tl::Variant read_value(tl::Extractor &ex, const std::map &variables); + /** + * @brief Reads a value from the extractor (with formula evaluation and two levels of variables) + */ + static tl::Variant read_value(tl::Extractor &ex, const std::map &variables1, const std::map &variables2); + /** * @brief Tries to read a value from the extractor (with formula evaluation) */ diff --git a/src/db/db/dbNetlistSpiceReaderExpressionParser.cc b/src/db/db/dbNetlistSpiceReaderExpressionParser.cc index ef2ad63d4..dcfd46332 100644 --- a/src/db/db/dbNetlistSpiceReaderExpressionParser.cc +++ b/src/db/db/dbNetlistSpiceReaderExpressionParser.cc @@ -47,8 +47,15 @@ static bool to_bool (const tl::Variant &v) NetlistSpiceReaderExpressionParser::NetlistSpiceReaderExpressionParser (const variables_type *vars, double def_scale) : m_def_scale (def_scale) { - static variables_type empty_variables; - mp_variables = vars ? vars : &empty_variables; + mp_variables1 = vars; + mp_variables2 = 0; +} + +NetlistSpiceReaderExpressionParser::NetlistSpiceReaderExpressionParser (const variables_type *vars1, const variables_type *vars2, double def_scale) + : m_def_scale (def_scale) +{ + mp_variables1 = vars1; + mp_variables2 = vars2; } // expression syntax taken from ngspice: @@ -264,13 +271,20 @@ NetlistSpiceReaderExpressionParser::read_atomic_value (tl::Extractor &ex, bool * } else { - auto vi = mp_variables->find (var); - if (vi != mp_variables->end ()) { - return vi->second; - } else { - // keep word as string value - return tl::Variant (var); + if (mp_variables1) { + auto vi = mp_variables1->find (var); + if (vi != mp_variables1->end ()) { + return vi->second; + } } + if (mp_variables2) { + auto vi = mp_variables2->find (var); + if (vi != mp_variables2->end ()) { + return vi->second; + } + } + // keep word as string value + return tl::Variant (var); } diff --git a/src/db/db/dbNetlistSpiceReaderExpressionParser.h b/src/db/db/dbNetlistSpiceReaderExpressionParser.h index 06684e124..822788587 100644 --- a/src/db/db/dbNetlistSpiceReaderExpressionParser.h +++ b/src/db/db/dbNetlistSpiceReaderExpressionParser.h @@ -46,6 +46,7 @@ public: typedef std::map variables_type; NetlistSpiceReaderExpressionParser (const variables_type *vars, double def_scale = 1.0); + NetlistSpiceReaderExpressionParser (const variables_type *vars1, const variables_type *vars2, double def_scale = 1.0); tl::Variant read (tl::Extractor &ex) const; tl::Variant read (const std::string &s) const; @@ -53,7 +54,7 @@ public: bool try_read (const std::string &s, tl::Variant &v) const; private: - const variables_type *mp_variables; + const variables_type *mp_variables1, *mp_variables2; double m_def_scale; tl::Variant read_atomic_value (tl::Extractor &ex, bool *status) const; diff --git a/src/db/unit_tests/dbNetlistReaderTests.cc b/src/db/unit_tests/dbNetlistReaderTests.cc index d82d3b02e..927859725 100644 --- a/src/db/unit_tests/dbNetlistReaderTests.cc +++ b/src/db/unit_tests/dbNetlistReaderTests.cc @@ -752,6 +752,68 @@ TEST(19_ngspice_ref) ); } +// using parameters evaluated before inside formulas +TEST(19b_ngspice_ref) +{ + db::Netlist nl; + + std::string path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nreader19b.cir"); + + db::NetlistSpiceReader reader; + tl::InputStream is (path); + reader.read (is, nl); + + EXPECT_EQ (nl.to_string (), + "circuit .TOP ();\n" + " subcircuit 'PMOS4_STANDARD(L=0.15,NF=4,V=1.5)' XPMOS (D=Q,G=I,S=VDD,B=VDD);\n" + " subcircuit 'NMOS4_STANDARD(L=0.15,NF=4,V=1.5)' XNMOS (D=Q,G=I,S=VSS,B=VSS);\n" + " subcircuit 'NMOS4_STANDARD(L=0.15,NF=2,V=1.5)' XDUMMY0 (D=VSS,G=VSS,S=VSS,B=VSS);\n" + " subcircuit 'NMOS4_STANDARD(L=0.15,NF=2,V=1.5)' XDUMMY1 (D=VSS,G=VSS,S=VSS,B=VSS);\n" + " subcircuit 'PMOS4_STANDARD(L=0.15,NF=2,V=1.5)' XDUMMY2 (D=VDD,G=VDD,S=VDD,B=VDD);\n" + " subcircuit 'PMOS4_STANDARD(L=0.15,NF=2,V=1.5)' XDUMMY3 (D=VDD,G=VDD,S=VDD,B=VDD);\n" + "end;\n" + "circuit 'PMOS4_STANDARD(L=0.15,NF=4,V=1.5)' (D=D,G=G,S=S,B=B);\n" + " device SKY130_FD_PR__PFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=6,AS=0.32625,AD=0.2175,PS=3.99,PD=2.66);\n" + "end;\n" + "circuit 'NMOS4_STANDARD(L=0.15,NF=4,V=1.5)' (D=D,G=G,S=S,B=B);\n" + " device SKY130_FD_PR__NFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=6,AS=0.32625,AD=0.2175,PS=3.99,PD=2.66);\n" + "end;\n" + "circuit 'NMOS4_STANDARD(L=0.15,NF=2,V=1.5)' (D=D,G=G,S=S,B=B);\n" + " device SKY130_FD_PR__NFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=3,AS=0.435,AD=0.2175,PS=4.16,PD=2.08);\n" + "end;\n" + "circuit 'PMOS4_STANDARD(L=0.15,NF=2,V=1.5)' (D=D,G=G,S=S,B=B);\n" + " device SKY130_FD_PR__PFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=3,AS=0.435,AD=0.2175,PS=4.16,PD=2.08);\n" + "end;\n" + ); +} + +// issue #1319, clarification +TEST(20_precendence) +{ + db::Netlist nl; + + std::string path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nreader20.cir"); + + db::NetlistSpiceReader reader; + tl::InputStream is (path); + reader.read (is, nl); + + EXPECT_EQ (nl.to_string (), + "circuit TEST ();\n" + " device CAP '1' (A=A,B=B) (C=5e-12,A=0,P=0);\n" + " device CAP '2A' (A=A,B=B) (C=2.5e-12,A=0,P=0);\n" + " device CAP '2B' (A=A,B=B) (C=2.5e-12,A=0,P=0);\n" + " device CAP_MODEL1 '3' (A=A,B=B) (C=5e-12,A=0,P=0);\n" + " device CAP3 '4' (A=A,B=B,W=CAP_MODEL1) (C=2.5e-12,A=0,P=0);\n" + " device CAP_MODEL2 '5' (A=A,B=B,W=C) (C=5e-12,A=0,P=0);\n" + " device CAP_MODEL1 '6' (A=A,B=B) (C=2.5e-12,A=0,P=0);\n" + " device CAP_MODEL2 '7A' (A=A,B=B,W=C) (C=2.5e-12,A=0,P=0);\n" + " device CAP_MODEL2 '7B' (A=A,B=B,W=C) (C=2.5e-12,A=0,P=0);\n" + " device CAP_MODEL2 '8' (A=A,B=B,W=C) (C=2.5e-12,A=0,P=0);\n" + "end;\n" + ); +} + TEST(100_ExpressionParser) { std::map vars; diff --git a/testdata/algo/nreader19b.cir b/testdata/algo/nreader19b.cir new file mode 100644 index 000000000..5e2585fe8 --- /dev/null +++ b/testdata/algo/nreader19b.cir @@ -0,0 +1,29 @@ +* Test + +.options scale=1e-6 + +.model sky130_fd_pr__pfet_01v8 NMOS level=8 version=3.3.0 +.model sky130_fd_pr__nfet_01v8 NMOS level=8 version=3.3.0 + +XXpmos Q I VDD VDD pmos4_standard v=1.5 l=0.15 nf=4 +XXnmos Q I VSS VSS nmos4_standard v=1.5 l=0.15 nf=4 +XXDUMMY0 VSS VSS VSS VSS nmos4_standard v=1.5 l=0.15 nf=2 +XXDUMMY1 VSS VSS VSS VSS nmos4_standard v=1.5 l=0.15 nf=2 +XXDUMMY2 VDD VDD VDD VDD pmos4_standard v=1.5 l=0.15 nf=2 +XXDUMMY3 VDD VDD VDD VDD pmos4_standard v=1.5 l=0.15 nf=2 + +* NOTE: "W" in the "ad" formula uses the previously computed parameter "W" +.subckt pmos4_standard D G S B v=0.1 l=0.018 nf=4 +MM1 D G S B sky130_fd_pr__pfet_01v8 L=l W='v * nf ' ad='int((nf+1)/2) * W/nf**2 * 0.29' as='int((nf+2)/2) * W/nf**2 * 0.29' ++ pd='2*int((nf+1)/2) * (W/nf**2 + 0.29)' ps='2*int((nf+2)/2) * (W/nf**2 + 0.29)' nrd='0.29 / W' nrs='0.29 / W' ++ m=1 +.ends + +* NOTE: "W" in the "ad" formula uses the previously computed parameter "W" +.subckt nmos4_standard D G S B v=0.1 l=0.018 nf=4 +MM1 D G S B sky130_fd_pr__nfet_01v8 L=l W='v * nf ' ad='int((nf+1)/2) * W/nf**2 * 0.29' as='int((nf+2)/2) * W/nf**2 * 0.29' ++ pd='2*int((nf+1)/2) * (W/nf**2 + 0.29)' ps='2*int((nf+2)/2) * (W/nf**2 + 0.29)' nrd='0.29 / W' nrs='0.29 / W' ++ m=1 +.ends + +.end diff --git a/testdata/algo/nreader20.cir b/testdata/algo/nreader20.cir new file mode 100644 index 000000000..7680c8468 --- /dev/null +++ b/testdata/algo/nreader20.cir @@ -0,0 +1,37 @@ + +.subckt test + +* Variations are: +* (1) Cname n1 n2 C=value [other params] +* (2) Cname n1 n2 value [params] +* (3) Cname n1 n2 model C=value [other params] +* Cname n1 n2 n3 C=value [other params] -> not supported, cannot tell from (3) without further analysis +* (4) Cname n1 n2 model value [params] +* Cname n1 n2 n3 value [params] -> not supported, cannot tell from (4) without further analysis +* (5) Cname n1 n2 n3 model C=value [other params] +* (6) Cname n1 n2 value model [params] +* (7) Cname n1 n2 n3 model value [params] +* (8) Cname n1 n2 n3 value model [params] + +* ngspice takes second C parameter (5p) +c1 a b M=1 l=50.000u w=50.000u c=2.5p c=5p +* ngspice ignores C parameter and uses 2.5p +c2a a b M=1 l=50.000u w=50.000u 2.5p c=5p +* ngspice ignores C parameter and uses 2.5p +c2b a b 2.5p M=1 l=50.000u w=50.000u c=5p +* ngspice ignores first C parameter and uses 5p +c3 a b cap_model1 c=2.5p M=1 l=50.000u w=50.000u c=5p +* ngspice ignores C parameter and uses 2.5p +c4 a b cap_model1 2.5p M=1 l=50.000u w=50.000u c=5p +* ngspice ignores first C parameter and uses 5p +c5 a b c cap_model2 M=1 l=50.000u w=50.000u c=2.5p c=5p +* C parameter must not be present for this to be recognized as value +c6 a b 2.5p cap_model1 M=1 l=50.000u w=50.000u +* ngspice ignores C parameter and uses 2.5p +c7a a b c cap_model2 2.5p M=1 l=50.000u w=50.000u c=5p +* ngspice ignores C parameter and uses 2.5p +c7b a b c cap_model2 M=1 l=50.000u w=50.000u 2.5p c=5p +* ngspice ignores C parameter and uses 2.5p +c8 a b c 2.5p cap_model2 M=1 l=50.000u w=50.000u c=5p +.ends + From 02e9f605d9377d062ffc3985c3df561b6477d245 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 24 Mar 2023 14:31:49 +0100 Subject: [PATCH 2/2] Implemented .lib for Spice reader - issue #1320 --- src/db/db/dbNetlistSpiceReader.cc | 70 +++++++++++++++++++++-- src/db/unit_tests/dbNetlistReaderTests.cc | 22 +++++++ testdata/algo/nreader21.cir | 6 ++ testdata/algo/nreader21_inc.cir | 4 ++ testdata/algo/nreader21_lib1.cir | 10 ++++ testdata/algo/nreader21_lib2.cir | 11 ++++ 6 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 testdata/algo/nreader21.cir create mode 100644 testdata/algo/nreader21_inc.cir create mode 100644 testdata/algo/nreader21_lib1.cir create mode 100644 testdata/algo/nreader21_lib2.cir diff --git a/src/db/db/dbNetlistSpiceReader.cc b/src/db/db/dbNetlistSpiceReader.cc index 55bc8388a..913fc43e8 100644 --- a/src/db/db/dbNetlistSpiceReader.cc +++ b/src/db/db/dbNetlistSpiceReader.cc @@ -75,6 +75,7 @@ class SpiceReaderStream { public: SpiceReaderStream (); + SpiceReaderStream (const std::string &lib); ~SpiceReaderStream (); void set_stream (tl::InputStream &stream); @@ -85,9 +86,11 @@ public: int line_number () const; std::string source () const; bool at_end () const; + const std::string &lib () const { return m_lib; } void swap (SpiceReaderStream &other) { + std::swap (m_lib, other.m_lib); std::swap (mp_stream, other.mp_stream); std::swap (m_owns_stream, other.m_owns_stream); std::swap (mp_text_stream, other.mp_text_stream); @@ -103,6 +106,7 @@ private: int m_line_number; std::string m_stored_line; bool m_has_stored_line; + std::string m_lib; }; @@ -112,6 +116,12 @@ SpiceReaderStream::SpiceReaderStream () // .. nothing yet .. } +SpiceReaderStream::SpiceReaderStream (const std::string &lib) + : mp_stream (0), m_owns_stream (false), mp_text_stream (0), m_line_number (0), m_stored_line (), m_has_stored_line (false), m_lib (lib) +{ + // .. nothing yet .. +} + SpiceReaderStream::~SpiceReaderStream () { close (); @@ -372,6 +382,7 @@ private: std::vector m_paths; std::map m_file_id_per_path; std::list m_streams; + std::list m_in_lib; SpiceReaderStream m_stream; int m_file_id; std::map m_cached_circuits; @@ -382,7 +393,7 @@ private: std::set m_global_net_names; std::vector m_global_nets; - void push_stream (const std::string &path); + void push_stream (const std::string &path, const std::string &lib = std::string ()); void pop_stream (); bool at_end (); void read_subcircuit (const std::string &sc_name, const std::string &nc_name, const std::vector &nets); @@ -489,7 +500,7 @@ SpiceCircuitDict::read (tl::InputStream &stream) } void -SpiceCircuitDict::push_stream (const std::string &path) +SpiceCircuitDict::push_stream (const std::string &path, const std::string &lib) { tl::URI current_uri (m_stream.source ()); tl::URI new_uri (path); @@ -505,7 +516,7 @@ SpiceCircuitDict::push_stream (const std::string &path) istream = new tl::InputStream (current_uri.resolved (new_uri).to_abstract_path ()); } - m_streams.push_back (SpiceReaderStream ()); + m_streams.push_back (SpiceReaderStream (lib)); m_streams.back ().swap (m_stream); m_stream.set_stream (istream); @@ -557,24 +568,73 @@ SpiceCircuitDict::get_line () if (m_streams.empty ()) { break; } else { + if (! m_stream.lib ().empty ()) { + m_in_lib.pop_back (); + } pop_stream (); } } else { + bool consider_line = m_in_lib.empty () || (! m_stream.lib ().empty () && m_stream.lib () == m_in_lib.back ()); + tl::Extractor ex (lp.first.c_str ()); if (ex.test_without_case (".include") || ex.test_without_case (".inc")) { std::string path; ex.read_word_or_quoted (path, allowed_name_chars); - push_stream (path); + if (consider_line) { + std::string libname = m_stream.lib (); + push_stream (path, libname); + if (! libname.empty ()) { + m_in_lib.push_back (libname); + } + } + + ex.expect_end (); + + } else if (ex.test_without_case (".lib")) { + + std::string path_or_libname; + + ex.read_word_or_quoted (path_or_libname, allowed_name_chars); + if (! ex.at_end ()) { + + std::string libname; + ex.read_word_or_quoted (libname, allowed_name_chars); + + if (consider_line) { + libname = mp_netlist->normalize_name (libname); + push_stream (path_or_libname, libname); + if (! libname.empty ()) { + m_in_lib.push_back (std::string ()); + } + } + + } else { + + std::string libname = mp_netlist->normalize_name (path_or_libname); + m_in_lib.push_back (libname); + ex.expect_end (); + + } + + } else if (ex.test_without_case (".endl")) { + + if (! m_in_lib.empty ()) { + m_in_lib.pop_back (); + } else { + warn (tl::to_string (tr ("Ignoring .endl without .lib"))); + } + + ex.expect_end (); } else if (ex.at_end () || ex.test ("*")) { // skip empty and comment lines - } else { + } else if (consider_line) { break; } diff --git a/src/db/unit_tests/dbNetlistReaderTests.cc b/src/db/unit_tests/dbNetlistReaderTests.cc index 927859725..78902c8a0 100644 --- a/src/db/unit_tests/dbNetlistReaderTests.cc +++ b/src/db/unit_tests/dbNetlistReaderTests.cc @@ -814,6 +814,28 @@ TEST(20_precendence) ); } +// issue #1320, .lib support +TEST(21_lib) +{ + db::Netlist nl; + + std::string path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nreader21.cir"); + + db::NetlistSpiceReader reader; + tl::InputStream is (path); + reader.read (is, nl); + + EXPECT_EQ (nl.to_string (), + "circuit .TOP ();\n" + " device CAP '10' (A='1',B='2') (C=1e-12,A=0,P=0);\n" + " device CAP '1' (A='1',B='2') (C=1e-10,A=0,P=0);\n" + " device CAP '2A' (A='1',B='2') (C=1.01e-10,A=0,P=0);\n" + " device CAP '2B' (A='1',B='2') (C=1.02e-10,A=0,P=0);\n" + " device CAP '100' (A='1',B='2') (C=1.5e-11,A=0,P=0);\n" + "end;\n" + ); +} + TEST(100_ExpressionParser) { std::map vars; diff --git a/testdata/algo/nreader21.cir b/testdata/algo/nreader21.cir new file mode 100644 index 000000000..21e6d198b --- /dev/null +++ b/testdata/algo/nreader21.cir @@ -0,0 +1,6 @@ + +.lib nreader21_lib1.cir lib1 +.lib nreader21_lib1.cir lib2 + +C100 1 2 15p + diff --git a/testdata/algo/nreader21_inc.cir b/testdata/algo/nreader21_inc.cir new file mode 100644 index 000000000..4dc60c6b2 --- /dev/null +++ b/testdata/algo/nreader21_inc.cir @@ -0,0 +1,4 @@ + +C2a 1 2 101p +C2b 1 2 102p + diff --git a/testdata/algo/nreader21_lib1.cir b/testdata/algo/nreader21_lib1.cir new file mode 100644 index 000000000..9240aa460 --- /dev/null +++ b/testdata/algo/nreader21_lib1.cir @@ -0,0 +1,10 @@ + +.lib lib1 +.lib nreader21_lib2.cir lib3 +C1 1 2 100p +.endl + +.lib lib2 +.include nreader21_inc.cir +.endl + diff --git a/testdata/algo/nreader21_lib2.cir b/testdata/algo/nreader21_lib2.cir new file mode 100644 index 000000000..b2d48e21d --- /dev/null +++ b/testdata/algo/nreader21_lib2.cir @@ -0,0 +1,11 @@ + +.lib lib3 +C10 1 2 1p +.endl + +C11 1 2 1.5p + +.lib lib4 +C12 1 2 42p +.endl +