From 02e9f605d9377d062ffc3985c3df561b6477d245 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 24 Mar 2023 14:31:49 +0100 Subject: [PATCH] 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 +