From 6f63fa09bf5a796bfb0ce7fe2074a6b992665ab8 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 2 Jul 2021 00:44:17 +0200 Subject: [PATCH 01/19] Fixed #856 --- src/db/db/dbNetlistDeviceClasses.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/db/db/dbNetlistDeviceClasses.h b/src/db/db/dbNetlistDeviceClasses.h index 0c7153889..e54f518e5 100644 --- a/src/db/db/dbNetlistDeviceClasses.h +++ b/src/db/db/dbNetlistDeviceClasses.h @@ -72,9 +72,9 @@ public: virtual void parallel (Device *a, Device *b) const; virtual void serial (Device *a, Device *b) const; - virtual size_t normalize_terminal_id (size_t) const + virtual size_t normalize_terminal_id (size_t id) const { - return terminal_id_A; + return id == terminal_id_B ? terminal_id_A : id; } }; From fd5efe9f920711a3dd4c7f00f2af884e8d580045 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 2 Jul 2021 00:46:22 +0200 Subject: [PATCH 02/19] Fixed #854 --- src/db/db/dbNetlistDeviceExtractorClasses.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/db/db/dbNetlistDeviceExtractorClasses.cc b/src/db/db/dbNetlistDeviceExtractorClasses.cc index 2eb1d5c2a..81b0c4d0b 100644 --- a/src/db/db/dbNetlistDeviceExtractorClasses.cc +++ b/src/db/db/dbNetlistDeviceExtractorClasses.cc @@ -454,17 +454,17 @@ void NetlistDeviceExtractorResistor::extract_devices (const std::vectorset_parameter_value (db::DeviceClassResistor::param_id_R, m_sheet_rho * double (length) / double (width)); - device->set_parameter_value (db::DeviceClassResistor::param_id_L, sdbu () * length); - device->set_parameter_value (db::DeviceClassResistor::param_id_W, sdbu () * width); + device->set_parameter_value (db::DeviceClassResistor::param_id_R, m_sheet_rho * double (length2) / double (width2)); + device->set_parameter_value (db::DeviceClassResistor::param_id_L, sdbu () * 0.5 * length2); + device->set_parameter_value (db::DeviceClassResistor::param_id_W, sdbu () * 0.5 * width2); device->set_parameter_value (db::DeviceClassResistor::param_id_A, sdbu () * sdbu () * p->area ()); device->set_parameter_value (db::DeviceClassResistor::param_id_P, sdbu () * p->perimeter ()); From 79c552b300fd2e24586c7c82ac6270e854d7517b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 2 Jul 2021 23:31:54 +0200 Subject: [PATCH 03/19] Fixed #858 (+ line continuation after blanks in Spice reader) --- src/db/db/dbNetlistSpiceReader.cc | 209 +++++++++++++++------- src/db/db/dbNetlistSpiceReader.h | 41 ++++- src/db/unit_tests/dbNetlistReaderTests.cc | 40 +++++ testdata/algo/nreader14.cir | 3 + testdata/algo/nreader14a.cir | 4 + testdata/algo/nreader14x.cir | 4 + testdata/algo/nreader15.cir | 18 ++ 7 files changed, 254 insertions(+), 65 deletions(-) create mode 100644 testdata/algo/nreader14.cir create mode 100644 testdata/algo/nreader14a.cir create mode 100644 testdata/algo/nreader14x.cir create mode 100644 testdata/algo/nreader15.cir diff --git a/src/db/db/dbNetlistSpiceReader.cc b/src/db/db/dbNetlistSpiceReader.cc index bfa207d13..0f0fe8312 100644 --- a/src/db/db/dbNetlistSpiceReader.cc +++ b/src/db/db/dbNetlistSpiceReader.cc @@ -635,8 +635,108 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin // ------------------------------------------------------------------------------------------------------ +NetlistSpiceReader::SpiceReaderStream::SpiceReaderStream () + : mp_stream (0), m_owns_stream (false), mp_text_stream (0), m_line_number (0), m_stored_line (), m_has_stored_line (false) +{ + // .. nothing yet .. +} + +NetlistSpiceReader::SpiceReaderStream::~SpiceReaderStream () +{ + close (); +} + +void +NetlistSpiceReader::SpiceReaderStream::close () +{ + delete mp_text_stream; + mp_text_stream = 0; + + if (m_owns_stream) { + delete mp_stream; + mp_stream = 0; + m_owns_stream = false; + } +} + +std::pair +NetlistSpiceReader::SpiceReaderStream::get_line () +{ + if (mp_text_stream->at_end ()) { + return std::make_pair (std::string (), false); + } + + ++m_line_number; + + std::string l = m_has_stored_line ? m_stored_line : mp_text_stream->get_line (); + + m_has_stored_line = false; + m_stored_line.clear (); + + while (! mp_text_stream->at_end ()) { + + std::string ll = mp_text_stream->get_line (); + + tl::Extractor ex (ll.c_str ()); + if (! ex.test ("+")) { + m_stored_line = ll; + m_has_stored_line = true; + break; + } else { + ++m_line_number; + l += " "; + l += ex.get (); + } + + } + + return std::make_pair (l, true); +} + +int +NetlistSpiceReader::SpiceReaderStream::line_number () const +{ + return m_line_number; +} + +std::string +NetlistSpiceReader::SpiceReaderStream::source () const +{ + return mp_stream->source (); +} + +bool +NetlistSpiceReader::SpiceReaderStream::at_end () const +{ + return mp_text_stream->at_end (); +} + +void +NetlistSpiceReader::SpiceReaderStream::set_stream (tl::InputStream &stream) +{ + close (); + mp_stream = &stream; + mp_text_stream = new tl::TextInputStream (stream); + m_owns_stream = false; + m_has_stored_line = false; + m_line_number = 0; +} + +void +NetlistSpiceReader::SpiceReaderStream::set_stream (tl::InputStream *stream) +{ + close (); + mp_stream = stream; + mp_text_stream = new tl::TextInputStream (*stream); + m_owns_stream = true; + m_has_stored_line = false; + m_line_number = 0; +} + +// ------------------------------------------------------------------------------------------------------ + NetlistSpiceReader::NetlistSpiceReader (NetlistSpiceReaderDelegate *delegate) - : mp_netlist (0), mp_stream (), mp_delegate (delegate) + : mp_netlist (0), mp_delegate (delegate), m_stream () { static NetlistSpiceReaderDelegate std_delegate; if (! delegate) { @@ -653,7 +753,8 @@ void NetlistSpiceReader::read (tl::InputStream &stream, db::Netlist &netlist) { tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading netlist ")) + stream.source ()); - mp_stream.reset (new tl::TextInputStream (stream)); + m_stream.set_stream (stream); + mp_netlist = &netlist; mp_circuit = 0; mp_anonymous_top_circuit = 0; @@ -681,7 +782,7 @@ void NetlistSpiceReader::read (tl::InputStream &stream, db::Netlist &netlist) // NOTE: because we do a peek to capture the "+" line continuation character, we're // one line ahead. - std::string fmt_msg = tl::sprintf ("%s in %s, line %d", ex.msg (), mp_stream->source (), mp_stream->line_number () - 1); + std::string fmt_msg = tl::sprintf ("%s in %s, line %d", ex.msg (), m_stream.source (), m_stream.line_number ()); finish (); throw tl::Exception (fmt_msg); @@ -737,11 +838,9 @@ void NetlistSpiceReader::build_global_nets () void NetlistSpiceReader::finish () { - while (! m_streams.empty ()) { - pop_stream (); - } + m_streams.clear (); + m_stream.close (); - mp_stream.reset (0); mp_netlist = 0; mp_circuit = 0; mp_nets_by_name.reset (0); @@ -749,7 +848,7 @@ void NetlistSpiceReader::finish () void NetlistSpiceReader::push_stream (const std::string &path) { - tl::URI current_uri (mp_stream->source ()); + tl::URI current_uri (m_stream.source ()); tl::URI new_uri (path); tl::InputStream *istream; @@ -757,80 +856,68 @@ void NetlistSpiceReader::push_stream (const std::string &path) if (tl::is_absolute (path)) { istream = new tl::InputStream (path); } else { - istream = new tl::InputStream (tl::combine_path (tl::dirname (mp_stream->source ()), path)); + istream = new tl::InputStream (tl::combine_path (tl::dirname (m_stream.source ()), path)); } } else { istream = new tl::InputStream (current_uri.resolved (new_uri).to_abstract_path ()); } - m_streams.push_back (std::make_pair (istream, mp_stream.release ())); - mp_stream.reset (new tl::TextInputStream (*istream)); + m_streams.push_back (SpiceReaderStream ()); + m_streams.back ().swap (m_stream); + m_stream.set_stream (istream); } void NetlistSpiceReader::pop_stream () { if (! m_streams.empty ()) { - - mp_stream.reset (m_streams.back ().second); - delete m_streams.back ().first; - + m_stream.swap (m_streams.back ()); m_streams.pop_back (); - } } bool NetlistSpiceReader::at_end () { - return mp_stream->at_end () && m_streams.empty (); + return m_stream.at_end () && m_streams.empty (); } std::string NetlistSpiceReader::get_line () { - if (! m_stored_line.empty ()) { - std::string l; - l.swap (m_stored_line); - return l; + std::pair lp; + + while (true) { + + lp = m_stream.get_line (); + if (! lp.second) { + + if (m_streams.empty ()) { + break; + } else { + pop_stream (); + } + + } else { + + 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); + + } else if (ex.at_end () || ex.test ("*")) { + + // skip empty and comment lines + + } else { + break; + } + + } + } - std::string l; - - do { - - while (mp_stream->at_end ()) { - if (m_streams.empty ()) { - return std::string (); - } - pop_stream (); - } - - l = mp_stream->get_line (); - while (! mp_stream->at_end () && mp_stream->peek_char () == '+') { - mp_stream->get_char (); - l += mp_stream->get_line (); - } - - tl::Extractor ex (l.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); - - l.clear (); - - } else if (ex.at_end () || ex.test ("*")) { - l.clear (); - } - - } while (l.empty ()); - - return l; -} - -void NetlistSpiceReader::unget_line (const std::string &l) -{ - m_stored_line = l; + return lp.first; } bool NetlistSpiceReader::subcircuit_captured (const std::string &nc_name) @@ -928,7 +1015,7 @@ void NetlistSpiceReader::error (const std::string &msg) void NetlistSpiceReader::warn (const std::string &msg) { - std::string fmt_msg = tl::sprintf ("%s in %s, line %d", msg, mp_stream->source (), mp_stream->line_number () - 1); + std::string fmt_msg = tl::sprintf ("%s in %s, line %d", msg, m_stream.source (), m_stream.line_number ()); tl::warn << fmt_msg; } diff --git a/src/db/db/dbNetlistSpiceReader.h b/src/db/db/dbNetlistSpiceReader.h index 24dd6f111..01491e6c9 100644 --- a/src/db/db/dbNetlistSpiceReader.h +++ b/src/db/db/dbNetlistSpiceReader.h @@ -168,14 +168,48 @@ public: virtual void read (tl::InputStream &stream, db::Netlist &netlist); private: + + class SpiceReaderStream + { + public: + SpiceReaderStream (); + ~SpiceReaderStream (); + + void set_stream (tl::InputStream &stream); + void set_stream (tl::InputStream *stream); + void close (); + + std::pair get_line(); + int line_number () const; + std::string source () const; + bool at_end () const; + + void swap (SpiceReaderStream &other) + { + 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); + std::swap (m_line_number, other.m_line_number); + std::swap (m_stored_line, other.m_stored_line); + std::swap (m_has_stored_line, other.m_has_stored_line); + } + + private: + tl::InputStream *mp_stream; + bool m_owns_stream; + tl::TextInputStream *mp_text_stream; + int m_line_number; + std::string m_stored_line; + bool m_has_stored_line; + }; + db::Netlist *mp_netlist; db::Circuit *mp_circuit; db::Circuit *mp_anonymous_top_circuit; - std::unique_ptr mp_stream; tl::weak_ptr mp_delegate; - std::vector > m_streams; + std::list m_streams; + SpiceReaderStream m_stream; std::unique_ptr > mp_nets_by_name; - std::string m_stored_line; std::map m_captured; std::vector m_global_nets; std::set m_global_net_names; @@ -191,7 +225,6 @@ private: bool read_card (); std::string read_name (tl::Extractor &ex); std::string get_line (); - void unget_line (const std::string &l); void error (const std::string &msg); void warn (const std::string &msg); void finish (); diff --git a/src/db/unit_tests/dbNetlistReaderTests.cc b/src/db/unit_tests/dbNetlistReaderTests.cc index 1dd39a5c1..987c432af 100644 --- a/src/db/unit_tests/dbNetlistReaderTests.cc +++ b/src/db/unit_tests/dbNetlistReaderTests.cc @@ -550,3 +550,43 @@ TEST(13_NoGlobalNetsIfNotUsed) ); } +TEST(14_IncludeWithError) +{ + db::Netlist nl; + + std::string path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nreader14.cir"); + + try { + db::NetlistSpiceReader reader; + tl::InputStream is (path); + reader.read (is, nl); + EXPECT_EQ (true, false); // must not happen + } catch (tl::Exception &ex) { + EXPECT_EQ (ex.msg (), "'M' element must have four nodes in " + std::string (tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nreader14x.cir")) + ", line 3"); + } +} + +TEST(15_ContinuationWithBlanks) +{ + db::Netlist nl; + + std::string path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nreader15.cir"); + + db::NetlistSpiceReader reader; + tl::InputStream is (path); + reader.read (is, nl); + + EXPECT_EQ (nl.to_string (), + "circuit SUBCKT ($1=$1,'A[5]<1>'='A[5]<1>','V42(%)'='V42(%)',Z=Z,GND=GND,GND$1=GND$1);\n" + " subcircuit HVPMOS D_$1 ($1='V42(%)',$2=$3,$3=Z,$4=$1);\n" + " subcircuit HVPMOS D_$2 ($1='V42(%)',$2='A[5]<1>',$3=$3,$4=$1);\n" + " subcircuit HVNMOS D_$3 ($1=GND,$2=$3,$3=GND,$4=GND$1);\n" + " subcircuit HVNMOS D_$4 ($1=GND,$2=$3,$3=Z,$4=GND$1);\n" + " subcircuit HVNMOS D_$5 ($1=GND,$2='A[5]<1>',$3=$3,$4=GND$1);\n" + "end;\n" + "circuit HVPMOS ($1=(null),$2=(null),$3=(null),$4=(null));\n" + "end;\n" + "circuit HVNMOS ($1=(null),$2=(null),$3=(null),$4=(null));\n" + "end;\n" + ); +} diff --git a/testdata/algo/nreader14.cir b/testdata/algo/nreader14.cir new file mode 100644 index 000000000..20a308b46 --- /dev/null +++ b/testdata/algo/nreader14.cir @@ -0,0 +1,3 @@ + +.include "nreader14a.cir" + diff --git a/testdata/algo/nreader14a.cir b/testdata/algo/nreader14a.cir new file mode 100644 index 000000000..08414862b --- /dev/null +++ b/testdata/algo/nreader14a.cir @@ -0,0 +1,4 @@ +.subckt INVX1 1 2 3 4 5 6 + .include nreader14x.cir +.ends + diff --git a/testdata/algo/nreader14x.cir b/testdata/algo/nreader14x.cir new file mode 100644 index 000000000..74e02ef7f --- /dev/null +++ b/testdata/algo/nreader14x.cir @@ -0,0 +1,4 @@ +m$1 1 5 2 4 mlvpmos w=1.5um l=0.25um +m$2 3 5 2 6 mlvnmos w=0.95um l=0.25um +m1 1 *an error + diff --git a/testdata/algo/nreader15.cir b/testdata/algo/nreader15.cir new file mode 100644 index 000000000..3ff574f5e --- /dev/null +++ b/testdata/algo/nreader15.cir @@ -0,0 +1,18 @@ +.SUBCKT SUBCKT + + \$1 A[5]<1> V42\x28\x25\x29 Z gnd gnd$1 +* device instance $1 r0 *1 0,0 HVPMOS +XD_$1 V42\x28\x25\x29 \$3 Z \$1 + + HVPMOS PARAMS: L=0.2 W=1 AS=0.18 AD=0.18 + + PS=2.16 PD=2.16 +XD_$2 + + V42\x28\x25\x29 A[5]<1> \$3 \$1 + + HVPMOS PARAMS: L=0.2 W=1 AS=0.18 AD=0.18 + + PS=2.16 PD=2.16 +XD_$3 gnd \$3 gnd gnd$1 HVNMOS PARAMS: L=1.13 W=2.12 PS=6 PD=6 AS=0 AD=0 + + + +XD_$4 gnd \$3 Z gnd$1 HVNMOS PARAMS: L=0.4 W=0.4 PS=1.16 PD=1.16 AS=0.19 AD=0.19 +XD_$5 gnd A[5]<1> \$3 gnd$1 HVNMOS + + PARAMS: L=0.4 W=0.4 PS=1.76 PD=1.76 AS=0.19 AD=0.19 + +.ENDS SUBCKT From 1a0b05e6633a4c6dd3096a260d537731ee877e7d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 2 Jul 2021 23:38:38 +0200 Subject: [PATCH 04/19] Updated test data --- src/db/unit_tests/dbNetlistExtractorTests.cc | 8 ++++---- testdata/lvs/custom_compare.lvsdb | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/db/unit_tests/dbNetlistExtractorTests.cc b/src/db/unit_tests/dbNetlistExtractorTests.cc index 6324c42ea..7dea4307b 100644 --- a/src/db/unit_tests/dbNetlistExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistExtractorTests.cc @@ -1301,8 +1301,8 @@ TEST(4_ResAndCapExtraction) " device PMOS $2 (S=VDD,G=IN,D=$3) (L=0.4,W=2.3,AS=1.38,AD=1.38,PS=5.8,PD=5.8);\n" " device NMOS $3 (S=VSS,G=$4,D=OUT) (L=0.4,W=4.6,AS=2.185,AD=2.185,PS=8.8,PD=8.8);\n" " device MIM_CAP $5 (A=$4,B=VSS) (C=2.622e-14,A=26.22,P=29.8);\n" - " device POLY_RES $7 (A=$3,B=$4) (R=750,L=12,W=0.8,A=2.4,P=13.6);\n" - " device POLY_RES $9 (A=$4,B=VSS) (R=1825,L=29.2,W=0.8,A=5.84,P=30);\n" + " device POLY_RES $7 (A=$3,B=$4) (R=750,L=6,W=0.4,A=2.4,P=13.6);\n" + " device POLY_RES $9 (A=$4,B=VSS) (R=1825,L=14.6,W=0.4,A=5.84,P=30);\n" " device NMOS $10 (S=VSS,G=IN,D=$3) (L=0.4,W=3.1,AS=1.86,AD=1.86,PS=7.4,PD=7.4);\n" "end;\n", true /*exact parameter compare*/ @@ -1576,8 +1576,8 @@ TEST(5_ResAndCapWithBulkExtraction) " device NMOS $3 (S=VSS,G=$4,D=OUT,B=BULK) (L=0.4,W=4.6,AS=2.185,AD=2.185,PS=8.8,PD=8.8);\n" " device MIM_CAP_SUBSTRATE $5 (A=$4,B=VSS,W=BULK) (C=1.334e-14,A=13.34,P=15);\n" " device MIM_CAP_NWELL $6 (A=$4,B=VSS,W=NWELL) (C=1.288e-14,A=12.88,P=14.8);\n" - " device POLY_RES_NWELL $7 (A=$3,B=$4,W=NWELL) (R=750,L=12,W=0.8,A=2.4,P=13.6);\n" - " device POLY_RES_SUBSTRATE $9 (A=$4,B=VSS,W=BULK) (R=1825,L=29.2,W=0.8,A=5.84,P=30);\n" + " device POLY_RES_NWELL $7 (A=$3,B=$4,W=NWELL) (R=750,L=6,W=0.4,A=2.4,P=13.6);\n" + " device POLY_RES_SUBSTRATE $9 (A=$4,B=VSS,W=BULK) (R=1825,L=14.6,W=0.4,A=5.84,P=30);\n" " device NMOS $10 (S=VSS,G=IN,D=$3,B=BULK) (L=0.4,W=3.1,AS=1.86,AD=1.86,PS=7.4,PD=7.4);\n" "end;\n", true /*exact parameter compare*/ diff --git a/testdata/lvs/custom_compare.lvsdb b/testdata/lvs/custom_compare.lvsdb index c54b0fb98..69358e767 100644 --- a/testdata/lvs/custom_compare.lvsdb +++ b/testdata/lvs/custom_compare.lvsdb @@ -53,8 +53,8 @@ layout( device(1 D$RES location(7520 4175) param(R 51) - param(L 25.5) - param(W 0.5) + param(L 12.75) + param(W 0.25) param(A 3.1875) param(P 26) terminal(A 2) From ce61145f1c01c5adb51cb7e74e272b6e0958fbd7 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 4 Jul 2021 17:05:17 +0200 Subject: [PATCH 05/19] More control over primary/secondary flag of parameters in device extraction - Spice reader will set primary flag for all (known) parameters read from a Spice netlist - "extract_devices" will return the device class object - primary/secondary flag can be set on device class objects through "enable_devices" --- src/db/db/dbDeviceClass.cc | 9 ++++ src/db/db/dbDeviceClass.h | 5 ++ src/db/db/dbNetlistDeviceExtractor.cc | 8 +-- src/db/db/dbNetlistDeviceExtractor.h | 12 ++++- src/db/db/dbNetlistSpiceReader.cc | 2 + src/db/db/gsiDeclDbNetlist.cc | 57 ++++++++++++++++++++ src/db/db/gsiDeclDbNetlistDeviceExtractor.cc | 13 ++++- src/drc/drc/built-in-macros/_drc_netter.rb | 5 ++ 8 files changed, 105 insertions(+), 6 deletions(-) diff --git a/src/db/db/dbDeviceClass.cc b/src/db/db/dbDeviceClass.cc index 389e81677..4ccf27c98 100644 --- a/src/db/db/dbDeviceClass.cc +++ b/src/db/db/dbDeviceClass.cc @@ -179,6 +179,15 @@ const DeviceParameterDefinition *DeviceClass::parameter_definition (size_t id) c } } +DeviceParameterDefinition *DeviceClass::parameter_definition_non_const (size_t id) +{ + if (id < m_parameter_definitions.size ()) { + return & m_parameter_definitions [id]; + } else { + return 0; + } +} + bool DeviceClass::has_parameter_with_name (const std::string &name) const { const std::vector &pd = parameter_definitions (); diff --git a/src/db/db/dbDeviceClass.h b/src/db/db/dbDeviceClass.h index 396a03fe4..01e8dc06e 100644 --- a/src/db/db/dbDeviceClass.h +++ b/src/db/db/dbDeviceClass.h @@ -508,6 +508,11 @@ public: */ const DeviceParameterDefinition *parameter_definition (size_t id) const; + /** + * @brief Gets the parameter definition from the ID (non-const version) + */ + DeviceParameterDefinition *parameter_definition_non_const (size_t id); + /** * @brief Returns true, if the device has a parameter with the given name */ diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc index 7c97d1782..03129ea62 100644 --- a/src/db/db/dbNetlistDeviceExtractor.cc +++ b/src/db/db/dbNetlistDeviceExtractor.cc @@ -391,7 +391,7 @@ void NetlistDeviceExtractor::push_new_devices (const db::Vector &disp_cache) std::string cell_name = "D$" + mp_device_class->name (); db::Cell &device_cell = mp_layout->cell (mp_layout->add_cell (cell_name.c_str ())); - db::DeviceAbstract *dm = new db::DeviceAbstract (mp_device_class, mp_layout->cell_name (device_cell.cell_index ())); + db::DeviceAbstract *dm = new db::DeviceAbstract (mp_device_class.get (), mp_layout->cell_name (device_cell.cell_index ())); m_netlist->add_device_abstract (dm); dm->set_cell_index (device_cell.cell_index ()); @@ -487,7 +487,7 @@ void NetlistDeviceExtractor::register_device_class (DeviceClass *device_class) tl_assert (device_class != 0); tl_assert (m_netlist.get () != 0); - if (mp_device_class != 0) { + if (mp_device_class.get () != 0) { throw tl::Exception (tl::to_string (tr ("Device class already set"))); } if (m_name.empty ()) { @@ -526,12 +526,12 @@ const db::NetlistDeviceExtractorLayerDefinition &NetlistDeviceExtractor::define_ Device *NetlistDeviceExtractor::create_device () { - if (mp_device_class == 0) { + if (mp_device_class.get () == 0) { throw tl::Exception (tl::to_string (tr ("No device class registered"))); } tl_assert (mp_circuit != 0); - Device *device = new Device (mp_device_class); + Device *device = new Device (mp_device_class.get ()); mp_circuit->add_device (device); return device; } diff --git a/src/db/db/dbNetlistDeviceExtractor.h b/src/db/db/dbNetlistDeviceExtractor.h index c6cab89ae..7ee6d9f90 100644 --- a/src/db/db/dbNetlistDeviceExtractor.h +++ b/src/db/db/dbNetlistDeviceExtractor.h @@ -387,6 +387,16 @@ public: */ Device *create_device (); + /** + * @brief Gets the device class used during extraction + * + * This member is set in 'extract_devices' and holds the device class object used during extraction. + */ + DeviceClass *device_class () + { + return mp_device_class.get (); + } + /** * @brief Defines a device terminal in the layout (a region) */ @@ -535,7 +545,7 @@ private: const std::set *mp_breakout_cells; double m_device_scaling; db::Circuit *mp_circuit; - db::DeviceClass *mp_device_class; + tl::weak_ptr mp_device_class; std::string m_name; layer_definitions m_layer_definitions; std::vector m_layers; diff --git a/src/db/db/dbNetlistSpiceReader.cc b/src/db/db/dbNetlistSpiceReader.cc index 0f0fe8312..33b9f9202 100644 --- a/src/db/db/dbNetlistSpiceReader.cc +++ b/src/db/db/dbNetlistSpiceReader.cc @@ -625,6 +625,8 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin std::map::const_iterator v = params.find (i->name ()); if (v != params.end ()) { device->set_parameter_value (i->id (), v->second / i->si_scaling ()); + // parameters read from the netlist are made primary so they are shown in the netlist browser + cls->parameter_definition_non_const (i->id ())->set_is_primary (true); } else if (i->id () == defp) { device->set_parameter_value (i->id (), value / i->si_scaling ()); } diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index be85f137f..7d677e5f2 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -927,6 +927,36 @@ static db::EqualDeviceParameters *get_equal_parameters (db::DeviceClass *cls) return dynamic_cast (cls->parameter_compare_delegate ()); } +static void enable_parameter (db::DeviceClass *cls, size_t id, bool en) +{ + db::DeviceParameterDefinition *pd = cls->parameter_definition_non_const (id); + if (pd) { + pd->set_is_primary (en); + } +} + +static void enable_parameter2 (db::DeviceClass *cls, const std::string &name, bool en) +{ + if (! cls->has_parameter_with_name (name)) { + return; + } + + size_t id = cls->parameter_id_for_name (name); + db::DeviceParameterDefinition *pd = cls->parameter_definition_non_const (id); + if (pd) { + pd->set_is_primary (en); + } +} + +static const db::DeviceParameterDefinition *parameter_definition2 (const db::DeviceClass *cls, const std::string &name) +{ + if (! cls->has_parameter_with_name (name)) { + return 0; + } else { + return cls->parameter_definition (cls->parameter_id_for_name (name)); + } +} + Class decl_dbDeviceClass ("db", "DeviceClass", gsi::method ("name", &db::DeviceClass::name, "@brief Gets the name of the device class." @@ -981,6 +1011,33 @@ Class decl_dbDeviceClass ("db", "DeviceClass", "Parameter definition IDs are used in some places to reference a specific parameter of a device. " "This method obtains the corresponding definition object." ) + + gsi::method_ext ("parameter_definition", ¶meter_definition2, gsi::arg ("parameter_name"), + "@brief Gets the parameter definition object for a given ID.\n" + "Parameter definition IDs are used in some places to reference a specific parameter of a device. " + "This method obtains the corresponding definition object." + "\n" + "This version accepts a parameter name.\n" + "\n" + "This method has been introduced in version 0.27.3.\n" + ) + + gsi::method_ext ("enable_parameter", &enable_parameter, gsi::arg ("parameter_id"), gsi::arg ("enable"), + "@brief Enables or disables a parameter.\n" + "Some parameters are 'secondary' parameters which are extracted but not handled in device compare and are not shown in the netlist browser. " + "For example, the 'W' parameter of the resistor is such a secondary parameter. This method allows turning a parameter in a primary one ('enable') or " + "into a secondary one ('disable').\n" + "\n" + "This method has been introduced in version 0.27.3.\n" + ) + + gsi::method_ext ("enable_parameter", &enable_parameter2, gsi::arg ("parameter_name"), gsi::arg ("enable"), + "@brief Enables or disables a parameter.\n" + "Some parameters are 'secondary' parameters which are extracted but not handled in device compare and are not shown in the netlist browser. " + "For example, the 'W' parameter of the resistor is such a secondary parameter. This method allows turning a parameter in a primary one ('enable') or " + "into a secondary one ('disable').\n" + "\n" + "This version accepts a parameter name.\n" + "\n" + "This method has been introduced in version 0.27.3.\n" + ) + gsi::method ("has_parameter?", &db::DeviceClass::has_parameter_with_name, gsi::arg ("name"), "@brief Returns true, if the device class has a parameter with the given name.\n" ) + diff --git a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc index 8ab83f4cf..24dc1fe2c 100644 --- a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc +++ b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc @@ -214,6 +214,13 @@ Class decl_dbNetlistDeviceExtractor ("db", "DeviceEx gsi::method ("name", &db::NetlistDeviceExtractor::name, "@brief Gets the name of the device extractor and the device class." ) + + gsi::method ("device_class", &db::NetlistDeviceExtractor::device_class, + "@brief Gets the device class used during extraction\n" + "The attribute will hold the actual device class used in the device extraction. It " + "is valid only after 'extract_devices'.\n" + "\n" + "This method has been added in version 0.27.3.\n" + ) + gsi::iterator ("each_layer_definition", &db::NetlistDeviceExtractor::begin_layer_definitions, &db::NetlistDeviceExtractor::end_layer_definitions, "@brief Iterates over all layer definitions." ) + @@ -251,9 +258,13 @@ Class decl_GenericDeviceExtractor (decl_dbNetlistDeviceE "This method shall raise an error, if the input layer are not properly defined (e.g.\n" "too few etc.)\n" "\n" + "This is not a connectivity definition in the electrical sense, but defines the cluster of shapes " + "which generates a specific device. In this case, 'connectivity' means 'definition of shapes that need to touch to form the device'.\n" + "\n" "The 'layers' argument specifies the actual layer layouts for the logical device layers (see \\define_layer). " "The list of layers corresponds to the number of layers defined. Use the layer indexes from this list " - "to build the connectivity with \\Connectivity#connect." + "to build the connectivity with \\Connectivity#connect. Note, that in order to capture a connected cluster of shapes on the " + "same layer you'll need to include a self-connection like 'connectivity.connect(layers[0], layers[0])'." ) + gsi::callback ("extract_devices", &GenericDeviceExtractor::extract_devices, &GenericDeviceExtractor::cb_extract_devices, gsi::arg ("layer_geometry"), diff --git a/src/drc/drc/built-in-macros/_drc_netter.rb b/src/drc/drc/built-in-macros/_drc_netter.rb index 978e6c723..fe87ee25a 100644 --- a/src/drc/drc/built-in-macros/_drc_netter.rb +++ b/src/drc/drc/built-in-macros/_drc_netter.rb @@ -192,6 +192,9 @@ module DRC # # extract_devices(mos4("NMOS4"), { :SD => nsd, :G => gate, :P => poly, :W => bulk }) # @/code + # + # The return value of this method will be the device class of the devices + # generated in the extraction step (see \DeviceClass). def extract_devices(devex, layer_selection) @@ -215,6 +218,8 @@ module DRC end + devex.device_class + end # %DRC% From 45152dad00a95064c39c17fdfd148d11b460313b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 4 Jul 2021 19:13:42 +0200 Subject: [PATCH 06/19] Fixed a linker issue --- src/tl/tl/tlMath.h | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/tl/tl/tlMath.h b/src/tl/tl/tlMath.h index 0b174fc35..7a93726ba 100644 --- a/src/tl/tl/tlMath.h +++ b/src/tl/tl/tlMath.h @@ -35,7 +35,7 @@ namespace tl * @brief A generic less operator */ template -bool less (T a, T b) +inline bool less (T a, T b) { return a < b; } @@ -44,7 +44,7 @@ bool less (T a, T b) * @brief A generic equal operator */ template -bool equal (T a, T b) +inline bool equal (T a, T b) { return a == b; } @@ -53,7 +53,7 @@ bool equal (T a, T b) * @brief A generalization of the modulo operator */ template -T modulo (T a, T b) +inline T modulo (T a, T b) { return a % b; } @@ -68,7 +68,7 @@ const double epsilon = 1e-10; /** * @brief A specialization for double values */ -bool less (double a, double b) +inline bool less (double a, double b) { return a < b - tl::epsilon; } @@ -76,7 +76,7 @@ bool less (double a, double b) /** * @brief A specialization for double values */ -bool equal (double a, double b) +inline bool equal (double a, double b) { return fabs (a - b) < tl::epsilon; } @@ -85,7 +85,7 @@ bool equal (double a, double b) * @brief A specialization of the modulo operator for doubles * a % b == a - b * floor (a / b) */ -double modulo (double a, double b) +inline double modulo (double a, double b) { return a - b * floor (a / b + tl::epsilon); } @@ -94,6 +94,7 @@ double modulo (double a, double b) * @brief Compute the greatest common divider of two numbers using the euclidian method */ template +inline T gcd (T a, T b) { while (! equal (b, T (0))) { @@ -108,6 +109,7 @@ T gcd (T a, T b) * @brief Compute the lowest common multiple of two numbers using the euclidian method */ template +inline T lcm (T a, T b) { return a * (b / gcd (a, b)); @@ -116,7 +118,7 @@ T lcm (T a, T b) /** * @brief Rounding down to the closest multiple of g */ -double round_down (double x, double g) +inline double round_down (double x, double g) { return g * floor (x / g + tl::epsilon); } @@ -124,7 +126,7 @@ double round_down (double x, double g) /** * @brief Rounding up to the closest multiple of g */ -double round_up (double x, double g) +inline double round_up (double x, double g) { return g * ceil (x / g - tl::epsilon); } @@ -133,7 +135,7 @@ double round_up (double x, double g) * @brief Rounding to the closest multiple of g * A value of (n+1/2)*g is rounded down. */ -double round (double x, double g) +inline double round (double x, double g) { return g * floor (0.5 + x / g - tl::epsilon); } From 3220bdf60d7fefac3510317a9443ba57b98853e6 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 4 Jul 2021 19:14:11 +0200 Subject: [PATCH 07/19] Added device class templates for CapWithBulk and ResWithBulk --- src/db/db/dbNetlistDeviceClasses.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/db/db/dbNetlistDeviceClasses.cc b/src/db/db/dbNetlistDeviceClasses.cc index 915f03f27..ad1fae98f 100644 --- a/src/db/db/dbNetlistDeviceClasses.cc +++ b/src/db/db/dbNetlistDeviceClasses.cc @@ -30,7 +30,9 @@ namespace db // The built-in device class templates static tl::RegisteredClass dct_cap (new db::device_class_template ("CAP")); +static tl::RegisteredClass dct_cap_with_bulk (new db::device_class_template ("CAP3")); static tl::RegisteredClass dct_res (new db::device_class_template ("RES")); +static tl::RegisteredClass dct_res_with_bulk (new db::device_class_template ("RES3")); static tl::RegisteredClass dct_ind (new db::device_class_template ("IND")); static tl::RegisteredClass dct_diode (new db::device_class_template ("DIODE")); static tl::RegisteredClass dct_mos3 (new db::device_class_template ("MOS3")); From ae6f77f45fa9f443b37457f987930040e7046115 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 4 Jul 2021 19:14:37 +0200 Subject: [PATCH 08/19] Serialization of custom device classes --- src/db/db/dbLayoutToNetlistFormatDefs.h | 12 +++++- src/db/db/dbLayoutToNetlistReader.cc | 49 +++++++++++++++++++++++- src/db/db/dbLayoutToNetlistWriter.cc | 50 ++++++++++++++++++++++++- src/db/db/dbLayoutToNetlistWriter.h | 2 + 4 files changed, 108 insertions(+), 5 deletions(-) diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.h b/src/db/db/dbLayoutToNetlistFormatDefs.h index 66cc393e1..5f261e467 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.h +++ b/src/db/db/dbLayoutToNetlistFormatDefs.h @@ -58,7 +58,7 @@ namespace db * - connects the shapes of the layer with the given global * nets [short key: G] * circuit( [circuit-def]) - circuit (cell) [short key: X] - * class(