Implemented .lib for Spice reader - issue #1320

This commit is contained in:
Matthias Koefferlein 2023-03-24 14:31:49 +01:00
parent a39441cdbd
commit 02e9f605d9
6 changed files with 118 additions and 5 deletions

View File

@ -75,6 +75,7 @@ class SpiceReaderStream
{ {
public: public:
SpiceReaderStream (); SpiceReaderStream ();
SpiceReaderStream (const std::string &lib);
~SpiceReaderStream (); ~SpiceReaderStream ();
void set_stream (tl::InputStream &stream); void set_stream (tl::InputStream &stream);
@ -85,9 +86,11 @@ public:
int line_number () const; int line_number () const;
std::string source () const; std::string source () const;
bool at_end () const; bool at_end () const;
const std::string &lib () const { return m_lib; }
void swap (SpiceReaderStream &other) void swap (SpiceReaderStream &other)
{ {
std::swap (m_lib, other.m_lib);
std::swap (mp_stream, other.mp_stream); std::swap (mp_stream, other.mp_stream);
std::swap (m_owns_stream, other.m_owns_stream); std::swap (m_owns_stream, other.m_owns_stream);
std::swap (mp_text_stream, other.mp_text_stream); std::swap (mp_text_stream, other.mp_text_stream);
@ -103,6 +106,7 @@ private:
int m_line_number; int m_line_number;
std::string m_stored_line; std::string m_stored_line;
bool m_has_stored_line; bool m_has_stored_line;
std::string m_lib;
}; };
@ -112,6 +116,12 @@ SpiceReaderStream::SpiceReaderStream ()
// .. nothing yet .. // .. 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 () SpiceReaderStream::~SpiceReaderStream ()
{ {
close (); close ();
@ -372,6 +382,7 @@ private:
std::vector<std::string> m_paths; std::vector<std::string> m_paths;
std::map<std::string, int> m_file_id_per_path; std::map<std::string, int> m_file_id_per_path;
std::list<SpiceReaderStream> m_streams; std::list<SpiceReaderStream> m_streams;
std::list<std::string> m_in_lib;
SpiceReaderStream m_stream; SpiceReaderStream m_stream;
int m_file_id; int m_file_id;
std::map<std::string, SpiceCachedCircuit *> m_cached_circuits; std::map<std::string, SpiceCachedCircuit *> m_cached_circuits;
@ -382,7 +393,7 @@ private:
std::set<std::string> m_global_net_names; std::set<std::string> m_global_net_names;
std::vector<std::string> m_global_nets; std::vector<std::string> 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 (); void pop_stream ();
bool at_end (); bool at_end ();
void read_subcircuit (const std::string &sc_name, const std::string &nc_name, const std::vector<db::Net *> &nets); void read_subcircuit (const std::string &sc_name, const std::string &nc_name, const std::vector<db::Net *> &nets);
@ -489,7 +500,7 @@ SpiceCircuitDict::read (tl::InputStream &stream)
} }
void 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 current_uri (m_stream.source ());
tl::URI new_uri (path); 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 ()); 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_streams.back ().swap (m_stream);
m_stream.set_stream (istream); m_stream.set_stream (istream);
@ -557,24 +568,73 @@ SpiceCircuitDict::get_line ()
if (m_streams.empty ()) { if (m_streams.empty ()) {
break; break;
} else { } else {
if (! m_stream.lib ().empty ()) {
m_in_lib.pop_back ();
}
pop_stream (); pop_stream ();
} }
} else { } 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 ()); tl::Extractor ex (lp.first.c_str ());
if (ex.test_without_case (".include") || ex.test_without_case (".inc")) { if (ex.test_without_case (".include") || ex.test_without_case (".inc")) {
std::string path; std::string path;
ex.read_word_or_quoted (path, allowed_name_chars); 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 ("*")) { } else if (ex.at_end () || ex.test ("*")) {
// skip empty and comment lines // skip empty and comment lines
} else { } else if (consider_line) {
break; break;
} }

View File

@ -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) TEST(100_ExpressionParser)
{ {
std::map<std::string, tl::Variant> vars; std::map<std::string, tl::Variant> vars;

6
testdata/algo/nreader21.cir vendored Normal file
View File

@ -0,0 +1,6 @@
.lib nreader21_lib1.cir lib1
.lib nreader21_lib1.cir lib2
C100 1 2 15p

4
testdata/algo/nreader21_inc.cir vendored Normal file
View File

@ -0,0 +1,4 @@
C2a 1 2 101p
C2b 1 2 102p

10
testdata/algo/nreader21_lib1.cir vendored Normal file
View File

@ -0,0 +1,10 @@
.lib lib1
.lib nreader21_lib2.cir lib3
C1 1 2 100p
.endl
.lib lib2
.include nreader21_inc.cir
.endl

11
testdata/algo/nreader21_lib2.cir vendored Normal file
View File

@ -0,0 +1,11 @@
.lib lib3
C10 1 2 1p
.endl
C11 1 2 1.5p
.lib lib4
C12 1 2 42p
.endl