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( ) - a device class definition (template: RES,CAP,...) [short key: K]
+ * class( [template-def]) - a device class definition (template: RES,CAP,...) [short key: K]
* device( [device-abstract-def])
* - device abstract [short key: D]
*
@@ -127,8 +127,18 @@ namespace db
* ( ) - relative coordinates (reference is reset to 0,0
* for each net or terminal in device abstract)
*
+ * [template-def]:
+ *
+ * param( ? *) - defines a template parameter [short key: E]
+ * ('primary' is a value: 0 or 1)
+ * terminal() - defines a terminal [short key: T]
+ *
* [device-abstract-def]:
*
+ * [device-abstract-terminal-def]*
+ *
+ * [device-abstract-terminal-def]:
+ *
* terminal( [geometry-def]*)
* - specifies the terminal geometry [short key: T]
*
diff --git a/src/db/db/dbLayoutToNetlistReader.cc b/src/db/db/dbLayoutToNetlistReader.cc
index d809398d1..4300c0a43 100644
--- a/src/db/db/dbLayoutToNetlistReader.cc
+++ b/src/db/db/dbLayoutToNetlistReader.cc
@@ -236,10 +236,9 @@ void LayoutToNetlistStandardReader::read_netlist (db::Netlist *netlist, db::Layo
std::string class_name, templ_name;
read_word_or_quoted (class_name);
read_word_or_quoted (templ_name);
- br.done ();
if (netlist->device_class_by_name (class_name) != 0) {
- throw tl::Exception (tl::to_string (tr ("Device class must be defined before being used in device")));
+ throw tl::Exception (tl::to_string (tr ("Duplicate definition of device class: ")) + class_name);
}
db::DeviceClassTemplateBase *dct = db::DeviceClassTemplateBase::template_by_name (templ_name);
@@ -251,6 +250,52 @@ void LayoutToNetlistStandardReader::read_netlist (db::Netlist *netlist, db::Layo
dc->set_name (class_name);
netlist->add_device_class (dc);
+ while (br) {
+
+ if (test (skeys::terminal_key) || test (lkeys::terminal_key)) {
+
+ Brace br (this);
+
+ std::string terminal_name;
+ read_word_or_quoted (terminal_name);
+ if (! dc->has_terminal_with_name (terminal_name)) {
+ db::DeviceTerminalDefinition td;
+ td.set_name (terminal_name);
+ dc->add_terminal_definition (td);
+ }
+
+ br.done ();
+
+ } else if (test (skeys::param_key) || test (lkeys::param_key)) {
+
+ Brace br (this);
+
+ std::string param_name;
+ read_word_or_quoted (param_name);
+ int primary = read_int ();
+ int default_value = read_double ();
+ if (! dc->has_parameter_with_name (param_name)) {
+ db::DeviceParameterDefinition pd;
+ pd.set_name (param_name);
+ pd.set_is_primary (primary);
+ pd.set_default_value (default_value);
+ dc->add_parameter_definition (pd);
+ } else {
+ db::DeviceParameterDefinition *pd = dc->parameter_definition_non_const (dc->parameter_id_for_name (param_name));
+ pd->set_default_value (default_value);
+ pd->set_is_primary (primary);
+ }
+
+ br.done ();
+
+ } else {
+ throw tl::Exception (tl::to_string (tr ("Invalid keyword")));
+ }
+
+ }
+
+ br.done ();
+
} else if (l2n && (test (skeys::connect_key) || test (lkeys::connect_key))) {
Brace br (this);
diff --git a/src/db/db/dbLayoutToNetlistWriter.cc b/src/db/db/dbLayoutToNetlistWriter.cc
index 4dc227ae4..d7956761d 100644
--- a/src/db/db/dbLayoutToNetlistWriter.cc
+++ b/src/db/db/dbLayoutToNetlistWriter.cc
@@ -24,6 +24,7 @@
#include "dbLayoutToNetlist.h"
#include "dbLayoutToNetlistFormatDefs.h"
#include "dbPolygonTools.h"
+#include "tlMath.h"
namespace db
{
@@ -113,6 +114,47 @@ void std_writer_impl::write (const db::Netlist *netlist, const db::LayoutT
}
}
+static bool same_parameter (const DeviceParameterDefinition &a, const DeviceParameterDefinition &b)
+{
+ if (a.is_primary () != b.is_primary ()) {
+ return false;
+ }
+ if (! tl::equal (a.default_value (), b.default_value ())) {
+ return false;
+ }
+ return true;
+}
+
+template
+void std_writer_impl::write_device_class (const std::string &indent, const db::DeviceClass *cls, const std::string &temp_name, const db::DeviceClass *temp_class)
+{
+ *mp_stream << indent << Keys::class_key << "(" << tl::to_word_or_quoted_string (cls->name ()) << " " << tl::to_word_or_quoted_string (temp_name);
+
+ bool any_def = false;
+
+ const std::vector &pd = cls->parameter_definitions ();
+ for (std::vector::const_iterator p = pd.begin (); p != pd.end (); ++p) {
+ if (! temp_class->has_parameter_with_name (p->name ()) || !same_parameter (*p, *temp_class->parameter_definition (temp_class->parameter_id_for_name (p->name ())))) {
+ *mp_stream << endl << indent << indent1 << Keys::param_key << "(" << tl::to_word_or_quoted_string (p->name ()) << " " << tl::to_string (p->is_primary () ? 1 : 0) << " " << tl::to_string (p->default_value ()) << ")";
+ any_def = true;
+ }
+ }
+
+ const std::vector &td = cls->terminal_definitions ();
+ for (std::vector::const_iterator t = td.begin (); t != td.end (); ++t) {
+ if (! temp_class->has_terminal_with_name (t->name ())) {
+ *mp_stream << endl << indent << indent1 << Keys::terminal_key << "(" << tl::to_word_or_quoted_string (t->name ()) << ")";
+ any_def = true;
+ }
+ }
+
+ if (any_def) {
+ *mp_stream << endl << indent << ")" << endl;
+ } else {
+ *mp_stream << ")" << endl;
+ }
+}
+
template
void std_writer_impl::write (bool nested, std::map > *net2id_per_circuit)
{
@@ -203,9 +245,13 @@ void std_writer_impl::write (bool nested, std::mapbegin_device_classes (); c != mp_netlist->end_device_classes (); ++c) {
db::DeviceClassTemplateBase *temp = db::DeviceClassTemplateBase::is_a (c.operator-> ());
if (temp) {
- *mp_stream << indent << Keys::class_key << "(" << tl::to_word_or_quoted_string (c->name ()) << " " << tl::to_word_or_quoted_string (temp->name ()) << ")" << endl;
- m_progress.set (mp_stream->pos ());
+ std::unique_ptr temp_class (temp->create ());
+ write_device_class (indent, c.operator-> (), temp->name (), temp_class.get ());
+ } else {
+ db::DeviceClass empty;
+ write_device_class (indent, c.operator-> (), std::string (), &empty);
}
+ m_progress.set (mp_stream->pos ());
}
if (mp_netlist->begin_device_abstracts () != mp_netlist->end_device_abstracts () && ! Keys::is_short ()) {
diff --git a/src/db/db/dbLayoutToNetlistWriter.h b/src/db/db/dbLayoutToNetlistWriter.h
index 72d9b14f8..67d2b0366 100644
--- a/src/db/db/dbLayoutToNetlistWriter.h
+++ b/src/db/db/dbLayoutToNetlistWriter.h
@@ -37,6 +37,7 @@ namespace db
class Circuit;
class SubCircuit;
class Device;
+class DeviceClass;
class DeviceAbstract;
class Net;
class Netlist;
@@ -78,6 +79,7 @@ private:
void write (const db::DeviceAbstract &device_abstract, const std::string &indent);
void write (const db::NetShape *s, const db::ICplxTrans &tr, const std::string &lname, bool relative);
void write (const db::DCplxTrans &trans);
+ void write_device_class (const std::string &indent, const db::DeviceClass *cls, const std::string &name, const db::DeviceClass *temp_class);
void reset_geometry_ref ();
// implementation of CircuitCallback
From 9f3d26af2542cb2c51b36a2f158a203e6ac27bb2 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sun, 4 Jul 2021 19:23:30 +0200
Subject: [PATCH 09/19] Doc update
---
.../lay/doc/manual/lvs_device_extractors.xml | 31 +++++++++++++++++--
1 file changed, 29 insertions(+), 2 deletions(-)
diff --git a/src/lay/lay/doc/manual/lvs_device_extractors.xml b/src/lay/lay/doc/manual/lvs_device_extractors.xml
index b6fdbe30a..2c43ca6d3 100644
--- a/src/lay/lay/doc/manual/lvs_device_extractors.xml
+++ b/src/lay/lay/doc/manual/lvs_device_extractors.xml
@@ -3,9 +3,9 @@
- LVS Devices Extractors
+ LVS Device Extractors
-
+
@@ -345,5 +345,32 @@ extract_devices(bjt3(model_name), { "C" => collector, "B" => base, "E" => emitte
+ Device extractors and device classes
+
+
+ "extract_devices" will return the DeviceClass object of the devices generated.
+ This object can be useful to apply some basic modifications.
+ The most important of them is enabling or disabling certain parameters.
+
+
+
+ Most device extractors extract more parameters than they give you by default.
+ For example, the resitor extractor will not just extract the resistance, but also the length (L)
+ and width (W) of the resistor stripe and its area (A) and perimeter (P).
+ By default these additional parameters are declared "secondary" - i.e. they will not
+ show up in the netlist browser, they will not participate in the device compare and
+ will not be netlisted.
+
+
+
+ Parameters can be declared primary ones by using "enable_parameter" on the device class.
+ Hence it is possible to enable "W" and "L" on a resistor type using the following code:
+
+
+ dc = extract_devices(resistor("RES", 1), ...)
+dc.enable_parameter("W", true)
+dc.enable_parameter("L", true)
+
+
From 4303e1ab738547d3fa322e248567b4ca8a641297 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sun, 4 Jul 2021 19:58:15 +0200
Subject: [PATCH 10/19] Revert change of making spice parameters primary - will
create problems in swappable parameters such as AD and AS
---
src/db/db/dbDeviceClass.cc | 93 ++++++++++++-------
src/db/db/dbNetlistSpiceReader.cc | 2 -
.../laybasic/layNetlistBrowserModel.cc | 6 +-
3 files changed, 61 insertions(+), 40 deletions(-)
diff --git a/src/db/db/dbDeviceClass.cc b/src/db/db/dbDeviceClass.cc
index 4ccf27c98..c51933143 100644
--- a/src/db/db/dbDeviceClass.cc
+++ b/src/db/db/dbDeviceClass.cc
@@ -109,6 +109,52 @@ bool AllDeviceParametersAreEqual::less (const db::Device &a, const db::Device &b
return false;
}
+// --------------------------------------------------------------------------------
+// PrimaryDeviceParametersAreEqual class implementation
+
+class DB_PUBLIC PrimaryDeviceParametersAreEqual
+ : public DeviceParameterCompareDelegate
+{
+public:
+ PrimaryDeviceParametersAreEqual (double relative);
+
+ virtual bool less (const db::Device &a, const db::Device &b) const;
+
+ virtual DeviceParameterCompareDelegate *clone () const
+ {
+ return new PrimaryDeviceParametersAreEqual (*this);
+ }
+
+private:
+ double m_relative;
+};
+
+PrimaryDeviceParametersAreEqual::PrimaryDeviceParametersAreEqual (double relative)
+ : m_relative (relative)
+{
+ // .. nothing yet ..
+}
+
+bool PrimaryDeviceParametersAreEqual::less (const db::Device &a, const db::Device &b) const
+{
+ const std::vector &pd = a.device_class ()->parameter_definitions ();
+ for (std::vector::const_iterator p = pd.begin (); p != pd.end (); ++p) {
+ const db::DeviceParameterDefinition *pdb = b.device_class ()->parameter_definition (p->id ());
+ if (! pdb) {
+ continue;
+ }
+ if (! pdb->is_primary () && ! p->is_primary ()) {
+ continue;
+ }
+ int cmp = compare_parameters (a.parameter_value (p->id ()), b.parameter_value (p->id ()), 0.0, m_relative);
+ if (cmp != 0) {
+ return cmp < 0;
+ }
+ }
+
+ return false;
+}
+
// --------------------------------------------------------------------------------
// DeviceClass class implementation
@@ -236,6 +282,9 @@ size_t DeviceClass::terminal_id_for_name (const std::string &name) const
// a default relative tolerance.
const double relative_tolerance = 1e-6;
+// The default compare delegate
+static PrimaryDeviceParametersAreEqual default_compare (relative_tolerance);
+
bool DeviceClass::less (const db::Device &a, const db::Device &b)
{
tl_assert (a.device_class () != 0);
@@ -245,25 +294,11 @@ bool DeviceClass::less (const db::Device &a, const db::Device &b)
if (! pcd) {
pcd = b.device_class ()->mp_pc_delegate.get ();
}
-
- if (pcd != 0) {
- return pcd->less (a, b);
- } else {
-
- const std::vector &pd = a.device_class ()->parameter_definitions ();
- for (std::vector::const_iterator p = pd.begin (); p != pd.end (); ++p) {
- if (! p->is_primary ()) {
- continue;
- }
- int cmp = compare_parameters (a.parameter_value (p->id ()), b.parameter_value (p->id ()), 0.0, relative_tolerance);
- if (cmp != 0) {
- return cmp < 0;
- }
- }
-
- return false;
-
+ if (! pcd) {
+ pcd = &default_compare;
}
+
+ return pcd->less (a, b);
}
bool DeviceClass::equal (const db::Device &a, const db::Device &b)
@@ -275,25 +310,11 @@ bool DeviceClass::equal (const db::Device &a, const db::Device &b)
if (! pcd) {
pcd = b.device_class ()->mp_pc_delegate.get ();
}
-
- if (pcd != 0) {
- return ! pcd->less (a, b) && ! pcd->less (b, a);
- } else {
-
- const std::vector &pd = a.device_class ()->parameter_definitions ();
- for (std::vector::const_iterator p = pd.begin (); p != pd.end (); ++p) {
- if (! p->is_primary ()) {
- continue;
- }
- int cmp = compare_parameters (a.parameter_value (p->id ()), b.parameter_value (p->id ()), 0.0, relative_tolerance);
- if (cmp != 0) {
- return false;
- }
- }
-
- return true;
-
+ if (! pcd) {
+ pcd = &default_compare;
}
+
+ return ! pcd->less (a, b) && ! pcd->less (b, a);
}
// --------------------------------------------------------------------------------
diff --git a/src/db/db/dbNetlistSpiceReader.cc b/src/db/db/dbNetlistSpiceReader.cc
index 33b9f9202..0f0fe8312 100644
--- a/src/db/db/dbNetlistSpiceReader.cc
+++ b/src/db/db/dbNetlistSpiceReader.cc
@@ -625,8 +625,6 @@ 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/laybasic/laybasic/layNetlistBrowserModel.cc b/src/laybasic/laybasic/layNetlistBrowserModel.cc
index b160ac73a..70f94a7ed 100644
--- a/src/laybasic/laybasic/layNetlistBrowserModel.cc
+++ b/src/laybasic/laybasic/layNetlistBrowserModel.cc
@@ -25,6 +25,7 @@
#include "layIndexedNetlistModel.h"
#include "layNetlistCrossReferenceModel.h"
#include "dbNetlistDeviceClasses.h"
+#include "tlMath.h"
#include
#include
@@ -324,7 +325,8 @@ std::string device_parameter_string (const db::Device *device)
bool first = true;
const std::vector &pd = device->device_class ()->parameter_definitions ();
for (std::vector::const_iterator p = pd.begin (); p != pd.end (); ++p) {
- if (p->is_primary ()) {
+ double v = device->parameter_value (p->id ());
+ if (! tl::equal (v, p->default_value ())) {
if (first) {
s += " [";
first = false;
@@ -333,7 +335,7 @@ std::string device_parameter_string (const db::Device *device)
}
s += p->name ();
s += "=";
- s += formatted_value (device->parameter_value (p->id ()));
+ s += formatted_value (v);
}
}
if (! first) {
From 20b7ee6aca3661c75446bef8fc39867b4fbb0b73 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sun, 4 Jul 2021 20:11:53 +0200
Subject: [PATCH 11/19] Fixed some documentation bugs
---
src/lay/lay/doc/manual/lvs_device_extractors.xml | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/src/lay/lay/doc/manual/lvs_device_extractors.xml b/src/lay/lay/doc/manual/lvs_device_extractors.xml
index 2c43ca6d3..e1200800f 100644
--- a/src/lay/lay/doc/manual/lvs_device_extractors.xml
+++ b/src/lay/lay/doc/manual/lvs_device_extractors.xml
@@ -355,15 +355,14 @@ extract_devices(bjt3(model_name), { "C" => collector, "B" => base, "E" => emitte
Most device extractors extract more parameters than they give you by default.
- For example, the resitor extractor will not just extract the resistance, but also the length (L)
+ For example, the resistor extractor will not just extract the resistance, but also the length (L)
and width (W) of the resistor stripe and its area (A) and perimeter (P).
- By default these additional parameters are declared "secondary" - i.e. they will not
- show up in the netlist browser, they will not participate in the device compare and
- will not be netlisted.
+ By default these additional parameters are declared "secondary" - i.e. they will not
+ participate in the device compare and will not be netlisted.
- Parameters can be declared primary ones by using "enable_parameter" on the device class.
+ Parameters can be fully enabled by using "enable_parameter" on the device class.
Hence it is possible to enable "W" and "L" on a resistor type using the following code:
@@ -372,5 +371,10 @@ dc.enable_parameter("W", true)
dc.enable_parameter("L", true)
+
+ This will modify the parameters of the generated device class such that "W" and "L" are
+ fully enabled parameters.
+
+
From b2746958d241534a41079ec5500ba986d9979450 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sun, 4 Jul 2021 23:31:37 +0200
Subject: [PATCH 12/19] Updated tests
---
src/laybasic/unit_tests/layNetlistBrowserModelTests.cc | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc b/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc
index 57599b8af..f155df235 100644
--- a/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc
+++ b/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc
@@ -320,7 +320,7 @@ TEST (2)
// INV2, net 1 has one pin and one terminal at BULK
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Net0Index), Qt::UserRole).toString ()), "B|B|PMOS|PMOS|$1|$1");
- EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Net0Index), Qt::DisplayRole).toString ()), "B / PMOS [L=0.25, W=3.5]");
+ EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Net0Index), Qt::DisplayRole).toString ()), "B / PMOS [L=0.25, W=3.5, AS=1.4, AD=1.4, PS=6.85, PD=6.85]");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2Net0Index), Qt::DisplayRole).toString ()), "$1");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2Net0Index), Qt::DisplayRole).toString ()), "$1");
@@ -356,8 +356,8 @@ TEST (2)
// first of devices in INV2 circuit
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_devices), Qt::UserRole).toString ()), "$1|$1|PMOS|PMOS");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_devices), Qt::DisplayRole).toString ()), "PMOS");
- EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_devices), Qt::DisplayRole).toString ()), "$1 / PMOS [L=0.25, W=3.5]");
- EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, sn_devices), Qt::DisplayRole).toString ()), "$1 / PMOS [L=0.25, W=3.5]");
+ EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_devices), Qt::DisplayRole).toString ()), "$1 / PMOS [L=0.25, W=3.5, AS=1.4, AD=1.4, PS=6.85, PD=6.85]");
+ EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, sn_devices), Qt::DisplayRole).toString ()), "$1 / PMOS [L=0.25, W=3.5, AS=1.4, AD=1.4, PS=6.85, PD=6.85]");
QModelIndex inv2PairIndex = model->index (2, 0, QModelIndex ());
EXPECT_EQ (model->parent (inv2PairIndex).isValid (), false);
From c62592ede18d0b63151b388c279a184448a016a0 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Mon, 5 Jul 2021 19:55:55 +0200
Subject: [PATCH 13/19] Added test for device class factory.
---
src/db/db/dbNetlistDeviceExtractorClasses.cc | 54 +++----
src/db/db/dbNetlistDeviceExtractorClasses.h | 82 +++++++++--
src/db/db/gsiDeclDbNetlist.cc | 2 +-
src/db/db/gsiDeclDbNetlistDeviceExtractor.cc | 133 +++++++++++++-----
.../dbNetlistDeviceExtractorTests.cc | 62 ++++++++
5 files changed, 254 insertions(+), 79 deletions(-)
diff --git a/src/db/db/dbNetlistDeviceExtractorClasses.cc b/src/db/db/dbNetlistDeviceExtractorClasses.cc
index 81b0c4d0b..957c9e8bb 100644
--- a/src/db/db/dbNetlistDeviceExtractorClasses.cc
+++ b/src/db/db/dbNetlistDeviceExtractorClasses.cc
@@ -30,8 +30,8 @@ namespace db
// ---------------------------------------------------------------------------------
// NetlistDeviceExtractorMOS3Transistor implementation
-NetlistDeviceExtractorMOS3Transistor::NetlistDeviceExtractorMOS3Transistor (const std::string &name, bool strict)
- : db::NetlistDeviceExtractor (name),
+NetlistDeviceExtractorMOS3Transistor::NetlistDeviceExtractorMOS3Transistor (const std::string &name, bool strict, db::DeviceClassFactory *factory)
+ : db::NetlistDeviceExtractorImplBase (name, factory ? factory : new db::device_class_factory ()),
m_strict (strict)
{
// .. nothing yet ..
@@ -66,7 +66,7 @@ void NetlistDeviceExtractorMOS3Transistor::setup ()
}
- db::DeviceClass *cls = new db::DeviceClassMOS3Transistor ();
+ db::DeviceClass *cls = make_class ();
cls->set_strict (m_strict);
register_device_class (cls);
}
@@ -322,8 +322,8 @@ void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector ())
{
// .. nothing yet ..
}
@@ -367,7 +367,7 @@ void NetlistDeviceExtractorMOS4Transistor::setup ()
}
- db::DeviceClass *cls = new db::DeviceClassMOS4Transistor ();
+ db::DeviceClass *cls = make_class ();
cls->set_strict (is_strict ());
register_device_class (cls);
}
@@ -383,8 +383,8 @@ void NetlistDeviceExtractorMOS4Transistor::modify_device (const db::Polygon &rga
// ---------------------------------------------------------------------------------
// NetlistDeviceExtractorResistor implementation
-NetlistDeviceExtractorResistor::NetlistDeviceExtractorResistor (const std::string &name, double sheet_rho)
- : db::NetlistDeviceExtractor (name), m_sheet_rho (sheet_rho)
+NetlistDeviceExtractorResistor::NetlistDeviceExtractorResistor (const std::string &name, double sheet_rho, db::DeviceClassFactory *factory)
+ : db::NetlistDeviceExtractorImplBase (name, factory ? factory : new db::device_class_factory ()), m_sheet_rho (sheet_rho)
{
// .. nothing yet ..
}
@@ -396,7 +396,7 @@ void NetlistDeviceExtractorResistor::setup ()
define_layer ("tA", 1, "A terminal output"); // #2 -> C
define_layer ("tB", 1, "B terminal output"); // #3 -> C
- register_device_class (new db::DeviceClassResistor ());
+ register_device_class (make_class ());
}
db::Connectivity NetlistDeviceExtractorResistor::get_connectivity (const db::Layout & /*layout*/, const std::vector &layers) const
@@ -494,8 +494,8 @@ void NetlistDeviceExtractorResistor::extract_devices (const std::vector ())
{
// .. nothing yet ..
}
@@ -509,7 +509,7 @@ void NetlistDeviceExtractorResistorWithBulk::setup ()
define_layer ("W", "Well/Bulk"); // #4
define_layer ("tW", 4, "W terminal output"); // #5 -> W
- register_device_class (new db::DeviceClassResistorWithBulk ());
+ register_device_class (make_class ());
}
void NetlistDeviceExtractorResistorWithBulk::modify_device (const db::Polygon &res, const std::vector & /*layer_geometry*/, db::Device *device)
@@ -521,8 +521,8 @@ void NetlistDeviceExtractorResistorWithBulk::modify_device (const db::Polygon &r
// ---------------------------------------------------------------------------------
// NetlistDeviceExtractorCapacitor implementation
-NetlistDeviceExtractorCapacitor::NetlistDeviceExtractorCapacitor (const std::string &name, double area_cap)
- : db::NetlistDeviceExtractor (name), m_area_cap (area_cap)
+NetlistDeviceExtractorCapacitor::NetlistDeviceExtractorCapacitor (const std::string &name, double area_cap, db::DeviceClassFactory *factory)
+ : db::NetlistDeviceExtractorImplBase (name, factory ? factory : new db::device_class_factory ()), m_area_cap (area_cap)
{
// .. nothing yet ..
}
@@ -534,7 +534,7 @@ void NetlistDeviceExtractorCapacitor::setup ()
define_layer ("tA", 0, "A terminal output"); // #2 -> P1
define_layer ("tB", 1, "B terminal output"); // #3 -> P2
- register_device_class (new db::DeviceClassCapacitor ());
+ register_device_class (make_class ());
}
db::Connectivity NetlistDeviceExtractorCapacitor::get_connectivity (const db::Layout & /*layout*/, const std::vector &layers) const
@@ -596,8 +596,8 @@ void NetlistDeviceExtractorCapacitor::extract_devices (const std::vector ())
{
// .. nothing yet ..
}
@@ -611,7 +611,7 @@ void NetlistDeviceExtractorCapacitorWithBulk::setup ()
define_layer ("W", "Well/Bulk"); // #4
define_layer ("tW", 4, "W terminal output"); // #5 -> W
- register_device_class (new db::DeviceClassCapacitorWithBulk ());
+ register_device_class (make_class ());
}
void NetlistDeviceExtractorCapacitorWithBulk::modify_device (const db::Polygon &cap, const std::vector & /*layer_geometry*/, db::Device *device)
@@ -623,8 +623,8 @@ void NetlistDeviceExtractorCapacitorWithBulk::modify_device (const db::Polygon &
// ---------------------------------------------------------------------------------
// NetlistDeviceExtractorBJT3Transistor implementation
-NetlistDeviceExtractorBJT3Transistor::NetlistDeviceExtractorBJT3Transistor (const std::string &name)
- : db::NetlistDeviceExtractor (name)
+NetlistDeviceExtractorBJT3Transistor::NetlistDeviceExtractorBJT3Transistor (const std::string &name, db::DeviceClassFactory *factory)
+ : db::NetlistDeviceExtractorImplBase (name, factory ? factory : new db::device_class_factory ())
{
// .. nothing yet ..
}
@@ -640,7 +640,7 @@ void NetlistDeviceExtractorBJT3Transistor::setup ()
define_layer ("tB", 1, "Base terminal output"); // #4 -> B
define_layer ("tE", 2, "Emitter terminal output"); // #5 -> E
- register_device_class (new db::DeviceClassBJT3Transistor ());
+ register_device_class (make_class ());
}
db::Connectivity NetlistDeviceExtractorBJT3Transistor::get_connectivity (const db::Layout & /*layout*/, const std::vector &layers) const
@@ -750,8 +750,8 @@ void NetlistDeviceExtractorBJT3Transistor::extract_devices (const std::vector ())
{
// .. nothing yet ..
}
@@ -772,7 +772,7 @@ void NetlistDeviceExtractorBJT4Transistor::setup ()
define_layer ("tS", 6, "Substrate (bulk) terminal output"); // #7 -> S
- register_device_class (new db::DeviceClassBJT4Transistor ());
+ register_device_class (make_class ());
}
void NetlistDeviceExtractorBJT4Transistor::modify_device (const db::Polygon &emitter, const std::vector & /*layer_geometry*/, db::Device *device)
@@ -784,8 +784,8 @@ void NetlistDeviceExtractorBJT4Transistor::modify_device (const db::Polygon &emi
// ---------------------------------------------------------------------------------
// NetlistDeviceExtractorDiode implementation
-NetlistDeviceExtractorDiode::NetlistDeviceExtractorDiode (const std::string &name)
- : db::NetlistDeviceExtractor (name)
+NetlistDeviceExtractorDiode::NetlistDeviceExtractorDiode (const std::string &name, db::DeviceClassFactory *factory)
+ : db::NetlistDeviceExtractorImplBase (name, factory ? factory : new db::device_class_factory ())
{
// .. nothing yet ..
}
@@ -797,7 +797,7 @@ void NetlistDeviceExtractorDiode::setup ()
define_layer ("tA", 0, "A terminal output"); // #2 -> P
define_layer ("tC", 1, "C terminal output"); // #3 -> N
- register_device_class (new db::DeviceClassDiode ());
+ register_device_class (make_class ());
}
db::Connectivity NetlistDeviceExtractorDiode::get_connectivity (const db::Layout & /*layout*/, const std::vector &layers) const
diff --git a/src/db/db/dbNetlistDeviceExtractorClasses.h b/src/db/db/dbNetlistDeviceExtractorClasses.h
index 3a157b7aa..1f1f07429 100644
--- a/src/db/db/dbNetlistDeviceExtractorClasses.h
+++ b/src/db/db/dbNetlistDeviceExtractorClasses.h
@@ -24,10 +24,64 @@
#define _HDR_dbNetlistDeviceExtractorClasses
#include "dbNetlistDeviceExtractor.h"
+#include "gsiObject.h"
namespace db
{
+/**
+ * @brief A device class factory base class
+ */
+class DB_PUBLIC DeviceClassFactory
+ : public gsi::ObjectBase
+{
+public:
+ DeviceClassFactory () { }
+ ~DeviceClassFactory () { }
+ virtual db::DeviceClass *create_class () const = 0;
+};
+
+/**
+ * @brief A specific factory
+ */
+template
+class DB_PUBLIC device_class_factory
+ : public DeviceClassFactory
+{
+public:
+ virtual db::DeviceClass *create_class () const { return new C (); }
+};
+
+/**
+ * @brief A base class for the specialized device extractors
+ *
+ * The main feature of this class is to supply a device class factory
+ * which actually creates the device class object.
+ *
+ * The NetlistDeviceExtractorImplBase object will own the factory object.
+ */
+class DB_PUBLIC NetlistDeviceExtractorImplBase
+ : public db::NetlistDeviceExtractor
+{
+public:
+ NetlistDeviceExtractorImplBase (const std::string &name, DeviceClassFactory *factory)
+ : db::NetlistDeviceExtractor (name), mp_factory (factory)
+ {
+ mp_factory->keep ();
+ }
+
+ /**
+ * @brief Creates the device class object
+ */
+ db::DeviceClass *make_class ()
+ {
+ return mp_factory->create_class ();
+ }
+
+private:
+ std::unique_ptr mp_factory;
+};
+
/**
* @brief A device extractor for a three-terminal MOS transistor
*
@@ -45,10 +99,10 @@ namespace db
* the particular source or drain area.
*/
class DB_PUBLIC NetlistDeviceExtractorMOS3Transistor
- : public db::NetlistDeviceExtractor
+ : public db::NetlistDeviceExtractorImplBase
{
public:
- NetlistDeviceExtractorMOS3Transistor (const std::string &name, bool strict = false);
+ NetlistDeviceExtractorMOS3Transistor (const std::string &name, bool strict = false, DeviceClassFactory *factory = 0);
virtual void setup ();
virtual db::Connectivity get_connectivity (const db::Layout &layout, const std::vector &layers) const;
@@ -94,7 +148,7 @@ class DB_PUBLIC NetlistDeviceExtractorMOS4Transistor
: public NetlistDeviceExtractorMOS3Transistor
{
public:
- NetlistDeviceExtractorMOS4Transistor (const std::string &name, bool strict = false);
+ NetlistDeviceExtractorMOS4Transistor (const std::string &name, bool strict = false, DeviceClassFactory *factory = 0);
virtual void setup ();
@@ -121,10 +175,10 @@ private:
* terminals are produced.
*/
class DB_PUBLIC NetlistDeviceExtractorResistor
- : public db::NetlistDeviceExtractor
+ : public db::NetlistDeviceExtractorImplBase
{
public:
- NetlistDeviceExtractorResistor (const std::string &name, double sheet_rho);
+ NetlistDeviceExtractorResistor (const std::string &name, double sheet_rho, DeviceClassFactory *factory = 0);
virtual void setup ();
virtual db::Connectivity get_connectivity (const db::Layout &layout, const std::vector &layers) const;
@@ -162,7 +216,7 @@ class DB_PUBLIC NetlistDeviceExtractorResistorWithBulk
: public db::NetlistDeviceExtractorResistor
{
public:
- NetlistDeviceExtractorResistorWithBulk (const std::string &name, double sheet_rho);
+ NetlistDeviceExtractorResistorWithBulk (const std::string &name, double sheet_rho, DeviceClassFactory *factory = 0);
virtual void setup ();
virtual void modify_device (const db::Polygon &res, const std::vector & /*layer_geometry*/, db::Device *device);
@@ -186,10 +240,10 @@ public:
* the terminals for A and B are produced respectively.
*/
class DB_PUBLIC NetlistDeviceExtractorCapacitor
- : public db::NetlistDeviceExtractor
+ : public db::NetlistDeviceExtractorImplBase
{
public:
- NetlistDeviceExtractorCapacitor (const std::string &name, double area_cap);
+ NetlistDeviceExtractorCapacitor (const std::string &name, double area_cap, DeviceClassFactory *factory = 0);
virtual void setup ();
virtual db::Connectivity get_connectivity (const db::Layout &layout, const std::vector &layers) const;
@@ -227,7 +281,7 @@ class DB_PUBLIC NetlistDeviceExtractorCapacitorWithBulk
: public db::NetlistDeviceExtractorCapacitor
{
public:
- NetlistDeviceExtractorCapacitorWithBulk (const std::string &name, double cap_area);
+ NetlistDeviceExtractorCapacitorWithBulk (const std::string &name, double cap_area, DeviceClassFactory *factory = 0);
virtual void setup ();
virtual void modify_device (const db::Polygon &cap, const std::vector & /*layer_geometry*/, db::Device *device);
@@ -256,10 +310,10 @@ public:
* The terminal output layer names are 'tC' (collector), 'tB' (base) and 'tE' (emitter).
*/
class DB_PUBLIC NetlistDeviceExtractorBJT3Transistor
- : public db::NetlistDeviceExtractor
+ : public db::NetlistDeviceExtractorImplBase
{
public:
- NetlistDeviceExtractorBJT3Transistor (const std::string &name);
+ NetlistDeviceExtractorBJT3Transistor (const std::string &name, DeviceClassFactory *factory = 0);
virtual void setup ();
virtual db::Connectivity get_connectivity (const db::Layout &layout, const std::vector &layers) const;
@@ -296,7 +350,7 @@ class DB_PUBLIC NetlistDeviceExtractorBJT4Transistor
: public NetlistDeviceExtractorBJT3Transistor
{
public:
- NetlistDeviceExtractorBJT4Transistor (const std::string &name);
+ NetlistDeviceExtractorBJT4Transistor (const std::string &name, DeviceClassFactory *factory = 0);
virtual void setup ();
@@ -321,10 +375,10 @@ private:
* cathode respectively.
*/
class DB_PUBLIC NetlistDeviceExtractorDiode
- : public db::NetlistDeviceExtractor
+ : public db::NetlistDeviceExtractorImplBase
{
public:
- NetlistDeviceExtractorDiode (const std::string &name);
+ NetlistDeviceExtractorDiode (const std::string &name, DeviceClassFactory *factory = 0);
virtual void setup ();
virtual db::Connectivity get_connectivity (const db::Layout &layout, const std::vector &layers) const;
diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc
index 7d677e5f2..cfdc5a341 100644
--- a/src/db/db/gsiDeclDbNetlist.cc
+++ b/src/db/db/gsiDeclDbNetlist.cc
@@ -843,7 +843,7 @@ public:
}
}
- gsi::Callback cb_less, cb_equal;
+ gsi::Callback cb_less;
};
}
diff --git a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc
index 24dc1fe2c..0dc5f9a05 100644
--- a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc
+++ b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc
@@ -27,7 +27,7 @@
namespace {
/**
- * @brief A NetlistDeviceExtractor implementation that allows reimplementation of the virtual methods
+ * @brief A NetlistDeviceExtractor implementation that allows reimplementing the virtual methods
*/
class GenericDeviceExtractor
: public db::NetlistDeviceExtractor
@@ -110,6 +110,55 @@ template<> struct type_traits : public tl::type_traits (&db::DeviceClassFactory::create_class);
+ } else {
+ return 0;
+ }
+ }
+
+ gsi::Callback cb_create_class;
+};
+
+}
+
+Class decl_dbDeviceClassFactoryBase ("db", "DeviceClassFactory",
+ gsi::factory_callback ("create_class", &DeviceClassFactoryImpl::create_class, &DeviceClassFactoryImpl::cb_create_class,
+ "@brief Creates the DeviceClass object\n"
+ ),
+ "@brief A factory for creating specific device classes for the standard device extractors\n"
+ "Use a reimplementation of this class to provide a device class generator for built-in device extractors "
+ "such as \\DeviceExtractorMOS3Transistor. The constructor of this extractor has a 'factory' parameter "
+ "which takes an object of \\DeviceClassFactory type. If such an object is provided, this factory is used "
+ "to create the actual device class.\n"
+ "\n"
+ "@code\n"
+ "class MyFactory < RBA::DeviceClassMOS3Transistor\n"
+ " ... overrides some methods ...\n"
+ "end\n"
+ "\n"
+ "extractor = RBA::DeviceExtractorMOS3Transistor::new(\"NMOS\", false, MyFactor.new)\n"
+ "@/code\n"
+);
+
Class decl_dbNetlistDeviceExtractorError ("db", "NetlistDeviceExtractorError",
gsi::method ("message", &db::NetlistDeviceExtractorError::message,
"@brief Gets the message text.\n"
@@ -408,16 +457,18 @@ Class decl_GenericDeviceExtractor (decl_dbNetlistDeviceE
"This class has been introduced in version 0.26."
);
-static db::NetlistDeviceExtractorMOS3Transistor *make_mos3_extractor (const std::string &name, bool strict)
+static db::NetlistDeviceExtractorMOS3Transistor *make_mos3_extractor (const std::string &name, bool strict, db::DeviceClassFactory *factory)
{
- return new db::NetlistDeviceExtractorMOS3Transistor (name, strict);
+ return new db::NetlistDeviceExtractorMOS3Transistor (name, strict, factory);
}
Class decl_NetlistDeviceExtractorMOS3Transistor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorMOS3Transistor",
- gsi::constructor ("new", &make_mos3_extractor, gsi::arg ("name"), gsi::arg ("strict", false),
+ gsi::constructor ("new", &make_mos3_extractor, gsi::arg ("name"), gsi::arg ("strict", false), gsi::arg ("factory", (db::DeviceClassFactory *)0, "none"),
"@brief Creates a new device extractor with the given name.\n"
"If \\strict is true, the MOS device extraction will happen in strict mode. That is, source and drain "
- "are not interchangeable."
+ "are not interchangeable.\n"
+ "\n"
+ "For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
) +
gsi::method ("strict?", &db::NetlistDeviceExtractorMOS3Transistor::is_strict,
"@brief Returns a value indicating whether extraction happens in strict mode."
@@ -465,14 +516,15 @@ Class decl_NetlistDeviceExtractorMOS3T
"This class has been introduced in version 0.26."
);
-static db::NetlistDeviceExtractorMOS4Transistor *make_mos4_extractor (const std::string &name, bool strict)
+static db::NetlistDeviceExtractorMOS4Transistor *make_mos4_extractor (const std::string &name, bool strict, db::DeviceClassFactory *factory)
{
- return new db::NetlistDeviceExtractorMOS4Transistor (name, strict);
+ return new db::NetlistDeviceExtractorMOS4Transistor (name, strict, factory);
}
Class decl_NetlistDeviceExtractorMOS4Transistor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorMOS4Transistor",
- gsi::constructor ("new", &make_mos4_extractor, gsi::arg ("name"), gsi::arg ("strict", false),
- "@brief Creates a new device extractor with the given name."
+ gsi::constructor ("new", &make_mos4_extractor, gsi::arg ("name"), gsi::arg ("strict", false), gsi::arg ("factory", (db::DeviceClassFactory *)0, "none"),
+ "@brief Creates a new device extractor with the given name\n"
+ "For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
"@brief A device extractor for a four-terminal MOS transistor\n"
"\n"
@@ -503,14 +555,15 @@ Class decl_NetlistDeviceExtractorMOS4T
"This class has been introduced in version 0.26."
);
-db::NetlistDeviceExtractorResistor *make_res_extractor (const std::string &name, double sheet_rho)
+db::NetlistDeviceExtractorResistor *make_res_extractor (const std::string &name, double sheet_rho, db::DeviceClassFactory *factory)
{
- return new db::NetlistDeviceExtractorResistor (name, sheet_rho);
+ return new db::NetlistDeviceExtractorResistor (name, sheet_rho, factory);
}
Class decl_NetlistDeviceExtractorResistor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorResistor",
- gsi::constructor ("new", &make_res_extractor, gsi::arg ("name"), gsi::arg ("sheet_rho"),
- "@brief Creates a new device extractor with the given name."
+ gsi::constructor ("new", &make_res_extractor, gsi::arg ("name"), gsi::arg ("sheet_rho"), gsi::arg ("factory", (db::DeviceClassFactory *)0, "none"),
+ "@brief Creates a new device extractor with the given name\n"
+ "For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
"@brief A device extractor for a two-terminal resistor\n"
"\n"
@@ -553,14 +606,15 @@ Class decl_NetlistDeviceExtractorResistor (d
"This class has been introduced in version 0.26."
);
-db::NetlistDeviceExtractorResistorWithBulk *make_res_with_bulk_extractor (const std::string &name, double sheet_rho)
+db::NetlistDeviceExtractorResistorWithBulk *make_res_with_bulk_extractor (const std::string &name, double sheet_rho, db::DeviceClassFactory *factory)
{
- return new db::NetlistDeviceExtractorResistorWithBulk (name, sheet_rho);
+ return new db::NetlistDeviceExtractorResistorWithBulk (name, sheet_rho, factory);
}
Class decl_NetlistDeviceExtractorResistorWithBulk (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorResistorWithBulk",
- gsi::constructor ("new", &make_res_with_bulk_extractor, gsi::arg ("name"), gsi::arg ("sheet_rho"),
- "@brief Creates a new device extractor with the given name."
+ gsi::constructor ("new", &make_res_with_bulk_extractor, gsi::arg ("name"), gsi::arg ("sheet_rho"), gsi::arg ("factory", (db::DeviceClassFactory *)0, "none"),
+ "@brief Creates a new device extractor with the given name\n"
+ "For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
"@brief A device extractor for a resistor with a bulk terminal\n"
"\n"
@@ -598,14 +652,15 @@ Class decl_NetlistDeviceExtractorRes
"This class has been introduced in version 0.26."
);
-db::NetlistDeviceExtractorCapacitor *make_cap_extractor (const std::string &name, double area_cap)
+db::NetlistDeviceExtractorCapacitor *make_cap_extractor (const std::string &name, double area_cap, db::DeviceClassFactory *factory)
{
- return new db::NetlistDeviceExtractorCapacitor (name, area_cap);
+ return new db::NetlistDeviceExtractorCapacitor (name, area_cap, factory);
}
Class decl_NetlistDeviceExtractorCapacitor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorCapacitor",
- gsi::constructor ("new", &make_cap_extractor, gsi::arg ("name"), gsi::arg ("area_cap"),
- "@brief Creates a new device extractor with the given name."
+ gsi::constructor ("new", &make_cap_extractor, gsi::arg ("name"), gsi::arg ("area_cap"), gsi::arg ("factory", (db::DeviceClassFactory *)0, "none"),
+ "@brief Creates a new device extractor with the given name\n"
+ "For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
"@brief A device extractor for a two-terminal capacitor\n"
"\n"
@@ -643,14 +698,15 @@ Class decl_NetlistDeviceExtractorCapacitor
"This class has been introduced in version 0.26."
);
-db::NetlistDeviceExtractorCapacitorWithBulk *make_cap_with_bulk_extractor (const std::string &name, double area_cap)
+db::NetlistDeviceExtractorCapacitorWithBulk *make_cap_with_bulk_extractor (const std::string &name, double area_cap, db::DeviceClassFactory *factory)
{
- return new db::NetlistDeviceExtractorCapacitorWithBulk (name, area_cap);
+ return new db::NetlistDeviceExtractorCapacitorWithBulk (name, area_cap, factory);
}
Class decl_NetlistDeviceExtractorCapacitorWithBulk (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorCapacitorWithBulk",
- gsi::constructor ("new", &make_cap_with_bulk_extractor, gsi::arg ("name"), gsi::arg ("sheet_rho"),
- "@brief Creates a new device extractor with the given name."
+ gsi::constructor ("new", &make_cap_with_bulk_extractor, gsi::arg ("name"), gsi::arg ("sheet_rho"), gsi::arg ("factory", (db::DeviceClassFactory *)0, "none"),
+ "@brief Creates a new device extractor with the given name\n"
+ "For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
"@brief A device extractor for a capacitor with a bulk terminal\n"
"\n"
@@ -687,14 +743,15 @@ Class decl_NetlistDeviceExtractorCa
"This class has been introduced in version 0.26."
);
-db::NetlistDeviceExtractorBJT3Transistor *make_bjt3_extractor (const std::string &name)
+db::NetlistDeviceExtractorBJT3Transistor *make_bjt3_extractor (const std::string &name, db::DeviceClassFactory *factory)
{
- return new db::NetlistDeviceExtractorBJT3Transistor (name);
+ return new db::NetlistDeviceExtractorBJT3Transistor (name, factory);
}
Class decl_dbNetlistDeviceExtractorBJT3Transistor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorBJT3Transistor",
- gsi::constructor ("new", &make_bjt3_extractor, gsi::arg ("name"),
- "@brief Creates a new device extractor with the given name."
+ gsi::constructor ("new", &make_bjt3_extractor, gsi::arg ("name"), gsi::arg ("factory", (db::DeviceClassFactory *)0, "none"),
+ "@brief Creates a new device extractor with the given name\n"
+ "For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
"@brief A device extractor for a bipolar transistor (BJT)\n"
"\n"
@@ -740,14 +797,15 @@ Class decl_dbNetlistDeviceExtractorBJT
"This class has been introduced in version 0.26."
);
-db::NetlistDeviceExtractorBJT4Transistor *make_bjt4_extractor (const std::string &name)
+db::NetlistDeviceExtractorBJT4Transistor *make_bjt4_extractor (const std::string &name, db::DeviceClassFactory *factory)
{
- return new db::NetlistDeviceExtractorBJT4Transistor (name);
+ return new db::NetlistDeviceExtractorBJT4Transistor (name, factory);
}
Class decl_NetlistDeviceExtractorBJT4Transistor (decl_dbNetlistDeviceExtractorBJT3Transistor, "db", "DeviceExtractorBJT4Transistor",
- gsi::constructor ("new", &make_bjt4_extractor, gsi::arg ("name"),
- "@brief Creates a new device extractor with the given name."
+ gsi::constructor ("new", &make_bjt4_extractor, gsi::arg ("name"), gsi::arg ("factory", (db::DeviceClassFactory *)0, "none"),
+ "@brief Creates a new device extractor with the given name\n"
+ "For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
"@brief A device extractor for a four-terminal bipolar transistor (BJT)\n"
"\n"
@@ -774,14 +832,15 @@ Class decl_NetlistDeviceExtractorBJT4T
"This class has been introduced in version 0.26."
);
-db::NetlistDeviceExtractorDiode *make_diode_extractor (const std::string &name)
+db::NetlistDeviceExtractorDiode *make_diode_extractor (const std::string &name, db::DeviceClassFactory *factory)
{
- return new db::NetlistDeviceExtractorDiode (name);
+ return new db::NetlistDeviceExtractorDiode (name, factory);
}
Class decl_NetlistDeviceExtractorDiode (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorDiode",
- gsi::constructor ("new", &make_diode_extractor, gsi::arg ("name"),
- "@brief Creates a new device extractor with the given name."
+ gsi::constructor ("new", &make_diode_extractor, gsi::arg ("name"), gsi::arg ("factory", (db::DeviceClassFactory *)0, "none"),
+ "@brief Creates a new device extractor with the given name\n"
+ "For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
"@brief A device extractor for a planar diode\n"
"\n"
diff --git a/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc b/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc
index e77984177..c6077ce61 100644
--- a/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc
+++ b/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc
@@ -25,6 +25,7 @@
#include "dbReader.h"
#include "dbRecursiveShapeIterator.h"
#include "dbNetlistDeviceExtractorClasses.h"
+#include "dbNetlistDeviceClasses.h"
#include "tlUnitTest.h"
#include "tlFileUtils.h"
@@ -90,6 +91,67 @@ TEST(2_NetlistDeviceExtractorErrors)
EXPECT_EQ (error2string (errors [3]), ":cat1:desc1:(10,11;10,13;12,13;12,11):msg3");
}
+namespace {
+
+class MyDeviceClass
+ : public db::DeviceClassMOS3Transistor
+{
+public:
+ MyDeviceClass () : db::DeviceClassMOS3Transistor () { }
+};
+
+}
+
+TEST(3_ClassFactoryTest)
+{
+ db::Layout ly;
+
+ {
+ db::LoadLayoutOptions options;
+
+ std::string fn (tl::testdata ());
+ fn = tl::combine_path (fn, "algo");
+ fn = tl::combine_path (fn, "mos3_1.gds");
+
+ tl::InputStream stream (fn);
+ db::Reader reader (stream);
+ reader.read (ly, options);
+ }
+
+ db::Cell &tc = ly.cell (*ly.begin_top_down ());
+
+ db::DeepShapeStore dss;
+ dss.set_text_enlargement (1);
+ dss.set_text_property_name (tl::Variant ("LABEL"));
+
+ // original layers
+ db::Region l1 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(1, 0))), dss);
+ db::Region l2 (db::RecursiveShapeIterator (ly, tc, ly.get_layer (db::LayerProperties(2, 0))), dss);
+ db::Region o1 (dss);
+ db::Region o2 (dss);
+ db::Region o3 (dss);
+
+ // perform the extraction
+
+ db::Netlist nl;
+ db::hier_clusters cl;
+
+ db::NetlistDeviceExtractorMOS3Transistor ex ("MOS3", false, new db::device_class_factory ());
+
+ db::NetlistDeviceExtractor::input_layers dl;
+
+ dl["SD"] = &l1;
+ dl["G"] = &l2;
+ dl["tS"] = &o1;
+ dl["tD"] = &o2;
+ dl["tG"] = &o3;
+ ex.extract (dss, 0, dl, nl, cl);
+
+ // the generated objects are of MyDeviceClassType
+ EXPECT_EQ (dynamic_cast (ex.device_class ()) != 0, true);
+ EXPECT_EQ (dynamic_cast (nl.device_class_by_name ("MOS3")) != 0, true);
+}
+
TEST(10_MOS3DeviceExtractorTest)
{
db::Layout ly;
From ba35ac9bfe0e199612968bc61a09239a2958927c Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Mon, 5 Jul 2021 21:06:02 +0200
Subject: [PATCH 14/19] Doc update, some tests
---
src/db/db/dbNetlistDeviceExtractor.h | 13 ++-
src/db/db/gsiDeclDbNetlistDeviceExtractor.cc | 65 +++++++----
testdata/ruby/dbNetlistDeviceExtractors.rb | 112 +++++++++++++++++++
3 files changed, 162 insertions(+), 28 deletions(-)
diff --git a/src/db/db/dbNetlistDeviceExtractor.h b/src/db/db/dbNetlistDeviceExtractor.h
index 7ee6d9f90..9300586ea 100644
--- a/src/db/db/dbNetlistDeviceExtractor.h
+++ b/src/db/db/dbNetlistDeviceExtractor.h
@@ -503,6 +503,13 @@ public:
*/
std::string cell_name () const;
+ /**
+ * @brief Initializes the extractor
+ * This method will produce the device classes required for the device extraction.
+ * It is mainly provided for test purposes. Don't call it directly.
+ */
+ void initialize (db::Netlist *nl);
+
private:
struct DeviceCellKey
{
@@ -557,12 +564,6 @@ private:
NetlistDeviceExtractor (const NetlistDeviceExtractor &);
NetlistDeviceExtractor &operator= (const NetlistDeviceExtractor &);
- /**
- * @brief Initializes the extractor
- * This method will produce the device classes required for the device extraction.
- */
- void initialize (db::Netlist *nl);
-
void extract_without_initialize (db::Layout &layout, db::Cell &cell, hier_clusters_type &clusters, const std::vector &layers, double device_scaling, const std::set *breakout_cells);
void push_new_devices (const Vector &disp_cache);
void push_cached_devices (const tl::vector &cached_devices, const db::Vector &disp_cache, const db::Vector &new_disp);
diff --git a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc
index 0dc5f9a05..6112967b9 100644
--- a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc
+++ b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc
@@ -143,20 +143,34 @@ public:
Class decl_dbDeviceClassFactoryBase ("db", "DeviceClassFactory",
gsi::factory_callback ("create_class", &DeviceClassFactoryImpl::create_class, &DeviceClassFactoryImpl::cb_create_class,
"@brief Creates the DeviceClass object\n"
+ "Reimplement this method to create the desired device class."
),
"@brief A factory for creating specific device classes for the standard device extractors\n"
"Use a reimplementation of this class to provide a device class generator for built-in device extractors "
"such as \\DeviceExtractorMOS3Transistor. The constructor of this extractor has a 'factory' parameter "
- "which takes an object of \\DeviceClassFactory type. If such an object is provided, this factory is used "
- "to create the actual device class.\n"
+ "which takes an object of \\DeviceClassFactory type.\n"
+ "\n"
+ "If such an object is provided, this factory is used "
+ "to create the actual device class. The following code shows an example:\n"
"\n"
"@code\n"
- "class MyFactory < RBA::DeviceClassMOS3Transistor\n"
+ "class MyClass < RBA::DeviceClassMOS3Transistor\n"
" ... overrides some methods ...\n"
"end\n"
"\n"
- "extractor = RBA::DeviceExtractorMOS3Transistor::new(\"NMOS\", false, MyFactor.new)\n"
+ "class MyFactory < RBA::DeviceClassFactory\n"
+ " def create_class\n"
+ " MyClass.new\n"
+ " end\n"
+ "end\n"
+ "\n"
+ "extractor = RBA::DeviceExtractorMOS3Transistor::new(\"NMOS\", false, MyFactory.new)\n"
"@/code\n"
+ "\n"
+ "When using a factory with a device extractor, make sure it creates a corresponding device class, e.g. "
+ "for the \\DeviceExtractorMOS3Transistor extractor create a device class derived from \\DeviceClassMOS3Transistor.\n"
+ "\n"
+ "This class has been introduced in version 0.27.3.\n"
);
Class decl_dbNetlistDeviceExtractorError ("db", "NetlistDeviceExtractorError",
@@ -259,6 +273,12 @@ Class decl_dbNetlistDeviceExtractorLa
"This class has been introduced in version 0.26."
);
+// for test only
+static void test_initialize (db::NetlistDeviceExtractor *ex, db::Netlist *nl)
+{
+ ex->initialize (nl);
+}
+
Class decl_dbNetlistDeviceExtractor ("db", "DeviceExtractorBase",
gsi::method ("name", &db::NetlistDeviceExtractor::name,
"@brief Gets the name of the device extractor and the device class."
@@ -270,6 +290,7 @@ Class decl_dbNetlistDeviceExtractor ("db", "DeviceEx
"\n"
"This method has been added in version 0.27.3.\n"
) +
+ gsi::method_ext ("test_initialize", &test_initialize, gsi::arg ("netlist"), "@hide") + // for test only
gsi::iterator ("each_layer_definition", &db::NetlistDeviceExtractor::begin_layer_definitions, &db::NetlistDeviceExtractor::end_layer_definitions,
"@brief Iterates over all layer definitions."
) +
@@ -457,13 +478,13 @@ Class decl_GenericDeviceExtractor (decl_dbNetlistDeviceE
"This class has been introduced in version 0.26."
);
-static db::NetlistDeviceExtractorMOS3Transistor *make_mos3_extractor (const std::string &name, bool strict, db::DeviceClassFactory *factory)
+static db::NetlistDeviceExtractorMOS3Transistor *make_mos3_extractor (const std::string &name, bool strict, DeviceClassFactoryImpl *factory)
{
return new db::NetlistDeviceExtractorMOS3Transistor (name, strict, factory);
}
Class decl_NetlistDeviceExtractorMOS3Transistor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorMOS3Transistor",
- gsi::constructor ("new", &make_mos3_extractor, gsi::arg ("name"), gsi::arg ("strict", false), gsi::arg ("factory", (db::DeviceClassFactory *)0, "none"),
+ gsi::constructor ("new", &make_mos3_extractor, gsi::arg ("name"), gsi::arg ("strict", false), gsi::arg ("factory", (DeviceClassFactoryImpl *)0, "none"),
"@brief Creates a new device extractor with the given name.\n"
"If \\strict is true, the MOS device extraction will happen in strict mode. That is, source and drain "
"are not interchangeable.\n"
@@ -516,13 +537,13 @@ Class decl_NetlistDeviceExtractorMOS3T
"This class has been introduced in version 0.26."
);
-static db::NetlistDeviceExtractorMOS4Transistor *make_mos4_extractor (const std::string &name, bool strict, db::DeviceClassFactory *factory)
+static db::NetlistDeviceExtractorMOS4Transistor *make_mos4_extractor (const std::string &name, bool strict, DeviceClassFactoryImpl *factory)
{
return new db::NetlistDeviceExtractorMOS4Transistor (name, strict, factory);
}
Class decl_NetlistDeviceExtractorMOS4Transistor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorMOS4Transistor",
- gsi::constructor ("new", &make_mos4_extractor, gsi::arg ("name"), gsi::arg ("strict", false), gsi::arg ("factory", (db::DeviceClassFactory *)0, "none"),
+ gsi::constructor ("new", &make_mos4_extractor, gsi::arg ("name"), gsi::arg ("strict", false), gsi::arg ("factory", (DeviceClassFactoryImpl *)0, "none"),
"@brief Creates a new device extractor with the given name\n"
"For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
@@ -555,13 +576,13 @@ Class decl_NetlistDeviceExtractorMOS4T
"This class has been introduced in version 0.26."
);
-db::NetlistDeviceExtractorResistor *make_res_extractor (const std::string &name, double sheet_rho, db::DeviceClassFactory *factory)
+db::NetlistDeviceExtractorResistor *make_res_extractor (const std::string &name, double sheet_rho, DeviceClassFactoryImpl *factory)
{
return new db::NetlistDeviceExtractorResistor (name, sheet_rho, factory);
}
Class decl_NetlistDeviceExtractorResistor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorResistor",
- gsi::constructor ("new", &make_res_extractor, gsi::arg ("name"), gsi::arg ("sheet_rho"), gsi::arg ("factory", (db::DeviceClassFactory *)0, "none"),
+ gsi::constructor ("new", &make_res_extractor, gsi::arg ("name"), gsi::arg ("sheet_rho"), gsi::arg ("factory", (DeviceClassFactoryImpl *)0, "none"),
"@brief Creates a new device extractor with the given name\n"
"For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
@@ -606,13 +627,13 @@ Class decl_NetlistDeviceExtractorResistor (d
"This class has been introduced in version 0.26."
);
-db::NetlistDeviceExtractorResistorWithBulk *make_res_with_bulk_extractor (const std::string &name, double sheet_rho, db::DeviceClassFactory *factory)
+db::NetlistDeviceExtractorResistorWithBulk *make_res_with_bulk_extractor (const std::string &name, double sheet_rho, DeviceClassFactoryImpl *factory)
{
return new db::NetlistDeviceExtractorResistorWithBulk (name, sheet_rho, factory);
}
Class decl_NetlistDeviceExtractorResistorWithBulk (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorResistorWithBulk",
- gsi::constructor ("new", &make_res_with_bulk_extractor, gsi::arg ("name"), gsi::arg ("sheet_rho"), gsi::arg ("factory", (db::DeviceClassFactory *)0, "none"),
+ gsi::constructor ("new", &make_res_with_bulk_extractor, gsi::arg ("name"), gsi::arg ("sheet_rho"), gsi::arg ("factory", (DeviceClassFactoryImpl *)0, "none"),
"@brief Creates a new device extractor with the given name\n"
"For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
@@ -652,13 +673,13 @@ Class decl_NetlistDeviceExtractorRes
"This class has been introduced in version 0.26."
);
-db::NetlistDeviceExtractorCapacitor *make_cap_extractor (const std::string &name, double area_cap, db::DeviceClassFactory *factory)
+db::NetlistDeviceExtractorCapacitor *make_cap_extractor (const std::string &name, double area_cap, DeviceClassFactoryImpl *factory)
{
return new db::NetlistDeviceExtractorCapacitor (name, area_cap, factory);
}
Class decl_NetlistDeviceExtractorCapacitor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorCapacitor",
- gsi::constructor ("new", &make_cap_extractor, gsi::arg ("name"), gsi::arg ("area_cap"), gsi::arg ("factory", (db::DeviceClassFactory *)0, "none"),
+ gsi::constructor ("new", &make_cap_extractor, gsi::arg ("name"), gsi::arg ("area_cap"), gsi::arg ("factory", (DeviceClassFactoryImpl *)0, "none"),
"@brief Creates a new device extractor with the given name\n"
"For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
@@ -698,13 +719,13 @@ Class decl_NetlistDeviceExtractorCapacitor
"This class has been introduced in version 0.26."
);
-db::NetlistDeviceExtractorCapacitorWithBulk *make_cap_with_bulk_extractor (const std::string &name, double area_cap, db::DeviceClassFactory *factory)
+db::NetlistDeviceExtractorCapacitorWithBulk *make_cap_with_bulk_extractor (const std::string &name, double area_cap, DeviceClassFactoryImpl *factory)
{
return new db::NetlistDeviceExtractorCapacitorWithBulk (name, area_cap, factory);
}
Class decl_NetlistDeviceExtractorCapacitorWithBulk (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorCapacitorWithBulk",
- gsi::constructor ("new", &make_cap_with_bulk_extractor, gsi::arg ("name"), gsi::arg ("sheet_rho"), gsi::arg ("factory", (db::DeviceClassFactory *)0, "none"),
+ gsi::constructor ("new", &make_cap_with_bulk_extractor, gsi::arg ("name"), gsi::arg ("sheet_rho"), gsi::arg ("factory", (DeviceClassFactoryImpl *)0, "none"),
"@brief Creates a new device extractor with the given name\n"
"For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
@@ -743,13 +764,13 @@ Class decl_NetlistDeviceExtractorCa
"This class has been introduced in version 0.26."
);
-db::NetlistDeviceExtractorBJT3Transistor *make_bjt3_extractor (const std::string &name, db::DeviceClassFactory *factory)
+db::NetlistDeviceExtractorBJT3Transistor *make_bjt3_extractor (const std::string &name, DeviceClassFactoryImpl *factory)
{
return new db::NetlistDeviceExtractorBJT3Transistor (name, factory);
}
Class decl_dbNetlistDeviceExtractorBJT3Transistor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorBJT3Transistor",
- gsi::constructor ("new", &make_bjt3_extractor, gsi::arg ("name"), gsi::arg ("factory", (db::DeviceClassFactory *)0, "none"),
+ gsi::constructor ("new", &make_bjt3_extractor, gsi::arg ("name"), gsi::arg ("factory", (DeviceClassFactoryImpl *)0, "none"),
"@brief Creates a new device extractor with the given name\n"
"For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
@@ -797,13 +818,13 @@ Class decl_dbNetlistDeviceExtractorBJT
"This class has been introduced in version 0.26."
);
-db::NetlistDeviceExtractorBJT4Transistor *make_bjt4_extractor (const std::string &name, db::DeviceClassFactory *factory)
+db::NetlistDeviceExtractorBJT4Transistor *make_bjt4_extractor (const std::string &name, DeviceClassFactoryImpl *factory)
{
return new db::NetlistDeviceExtractorBJT4Transistor (name, factory);
}
Class decl_NetlistDeviceExtractorBJT4Transistor (decl_dbNetlistDeviceExtractorBJT3Transistor, "db", "DeviceExtractorBJT4Transistor",
- gsi::constructor ("new", &make_bjt4_extractor, gsi::arg ("name"), gsi::arg ("factory", (db::DeviceClassFactory *)0, "none"),
+ gsi::constructor ("new", &make_bjt4_extractor, gsi::arg ("name"), gsi::arg ("factory", (DeviceClassFactoryImpl *)0, "none"),
"@brief Creates a new device extractor with the given name\n"
"For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
@@ -832,13 +853,13 @@ Class decl_NetlistDeviceExtractorBJT4T
"This class has been introduced in version 0.26."
);
-db::NetlistDeviceExtractorDiode *make_diode_extractor (const std::string &name, db::DeviceClassFactory *factory)
+db::NetlistDeviceExtractorDiode *make_diode_extractor (const std::string &name, DeviceClassFactoryImpl *factory)
{
return new db::NetlistDeviceExtractorDiode (name, factory);
}
Class decl_NetlistDeviceExtractorDiode (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorDiode",
- gsi::constructor ("new", &make_diode_extractor, gsi::arg ("name"), gsi::arg ("factory", (db::DeviceClassFactory *)0, "none"),
+ gsi::constructor ("new", &make_diode_extractor, gsi::arg ("name"), gsi::arg ("factory", (DeviceClassFactoryImpl *)0, "none"),
"@brief Creates a new device extractor with the given name\n"
"For the 'factory' parameter see \\DeviceClassFactory. It has been added in version 0.27.3.\n"
),
diff --git a/testdata/ruby/dbNetlistDeviceExtractors.rb b/testdata/ruby/dbNetlistDeviceExtractors.rb
index aed9b395d..74c372263 100644
--- a/testdata/ruby/dbNetlistDeviceExtractors.rb
+++ b/testdata/ruby/dbNetlistDeviceExtractors.rb
@@ -74,6 +74,118 @@ class DBNetlistExtractorTests_TestClass < TestBase
end
+ class MyClass < RBA::DeviceClass
+ end
+
+ class MyFactory < RBA::DeviceClassFactory
+ def create_class
+ MyClass.new
+ end
+ end
+
+ def test_3_Factory
+
+ ex = RBA::DeviceExtractorMOS3Transistor::new("myclass")
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, false)
+ assert_equal(ex.device_class.class == RBA::DeviceClassMOS3Transistor, true)
+
+ ex = RBA::DeviceExtractorMOS3Transistor::new("myclass", false, MyFactory.new)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, true)
+
+ ex = RBA::DeviceExtractorMOS4Transistor::new("myclass")
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, false)
+ assert_equal(ex.device_class.class == RBA::DeviceClassMOS4Transistor, true)
+
+ ex = RBA::DeviceExtractorMOS4Transistor::new("myclass", false, MyFactory.new)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, true)
+
+ ex = RBA::DeviceExtractorBJT3Transistor::new("myclass")
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, false)
+ assert_equal(ex.device_class.class == RBA::DeviceClassBJT3Transistor, true)
+
+ ex = RBA::DeviceExtractorBJT3Transistor::new("myclass", MyFactory.new)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, true)
+
+ ex = RBA::DeviceExtractorBJT4Transistor::new("myclass")
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, false)
+ assert_equal(ex.device_class.class == RBA::DeviceClassBJT4Transistor, true)
+
+ ex = RBA::DeviceExtractorBJT4Transistor::new("myclass", MyFactory.new)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, true)
+
+ ex = RBA::DeviceExtractorDiode::new("myclass")
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, false)
+ assert_equal(ex.device_class.class == RBA::DeviceClassDiode, true)
+
+ ex = RBA::DeviceExtractorDiode::new("myclass", MyFactory.new)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, true)
+
+ ex = RBA::DeviceExtractorResistor::new("myclass", 1.0)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, false)
+ assert_equal(ex.device_class.class == RBA::DeviceClassResistor, true)
+
+ ex = RBA::DeviceExtractorResistor::new("myclass", 1.0, MyFactory.new)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, true)
+
+ ex = RBA::DeviceExtractorResistorWithBulk::new("myclass", 1.0)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, false)
+ assert_equal(ex.device_class.class == RBA::DeviceClassResistorWithBulk, true)
+
+ ex = RBA::DeviceExtractorResistorWithBulk::new("myclass", 1.0, MyFactory.new)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, true)
+
+ ex = RBA::DeviceExtractorCapacitor::new("myclass", 1.0)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, false)
+ assert_equal(ex.device_class.class == RBA::DeviceClassCapacitor, true)
+
+ ex = RBA::DeviceExtractorCapacitor::new("myclass", 1.0, MyFactory.new)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, true)
+
+ ex = RBA::DeviceExtractorCapacitorWithBulk::new("myclass", 1.0)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, false)
+ assert_equal(ex.device_class.class == RBA::DeviceClassCapacitorWithBulk, true)
+
+ ex = RBA::DeviceExtractorCapacitorWithBulk::new("myclass", 1.0, MyFactory.new)
+ ex.test_initialize(RBA::Netlist::new)
+ assert_equal(ex.device_class.name, "myclass")
+ assert_equal(ex.device_class.class == MyClass, true)
+
+ end
+
end
load("test_epilogue.rb")
From e34fc8967a49f6305fefbdff89e0d5d042bc4d7c Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Mon, 5 Jul 2021 22:22:13 +0200
Subject: [PATCH 15/19] Some enhancements
* Device#net_for_terminal with terminal name
* Spice writer now dumps all parameters for resistors and caps (also secondary)
* Enabled Spice writer delegate in LVS (spice_format(...))
* Device class factories for built-in device extractors
---
src/db/db/dbNetlistSpiceWriter.cc | 3 +
src/db/db/gsiDeclDbNetlist.cc | 30 +++++
src/drc/drc/built-in-macros/_drc_engine.rb | 103 +++++++++++----
.../lay/doc/manual/lvs_device_extractors.xml | 28 ++++
src/lvs/unit_tests/lvsSimpleTests.cc | 8 +-
testdata/lvs/enable_wl1.cir | 11 ++
testdata/lvs/enable_wl1.lvs | 52 ++++++++
testdata/lvs/enable_wl1.lvsdb | 118 +++++++++++++++++
testdata/lvs/enable_wl2.cir | 11 ++
testdata/lvs/enable_wl2.lvs | 33 +++++
testdata/lvs/enable_wl2.lvsdb | 118 +++++++++++++++++
testdata/lvs/enable_wl3.cir | 11 ++
testdata/lvs/enable_wl3.lvs | 33 +++++
testdata/lvs/enable_wl3.lvsdb | 121 ++++++++++++++++++
testdata/lvs/resistor.cir | 4 +
testdata/lvs/resistor.gds | Bin 0 -> 2048 bytes
testdata/lvs/resistor2.cir | 4 +
testdata/ruby/dbNetlist.rb | 2 +
18 files changed, 665 insertions(+), 25 deletions(-)
create mode 100644 testdata/lvs/enable_wl1.cir
create mode 100644 testdata/lvs/enable_wl1.lvs
create mode 100644 testdata/lvs/enable_wl1.lvsdb
create mode 100644 testdata/lvs/enable_wl2.cir
create mode 100644 testdata/lvs/enable_wl2.lvs
create mode 100644 testdata/lvs/enable_wl2.lvsdb
create mode 100644 testdata/lvs/enable_wl3.cir
create mode 100644 testdata/lvs/enable_wl3.lvs
create mode 100644 testdata/lvs/enable_wl3.lvsdb
create mode 100644 testdata/lvs/resistor.cir
create mode 100644 testdata/lvs/resistor.gds
create mode 100644 testdata/lvs/resistor2.cir
diff --git a/src/db/db/dbNetlistSpiceWriter.cc b/src/db/db/dbNetlistSpiceWriter.cc
index 5bf03d678..b5893bee3 100644
--- a/src/db/db/dbNetlistSpiceWriter.cc
+++ b/src/db/db/dbNetlistSpiceWriter.cc
@@ -117,6 +117,7 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const
os << " ";
os << format_name (dev.device_class ()->name ());
}
+ os << format_params (dev, db::DeviceClassCapacitor::param_id_C);
} else if (ind) {
@@ -129,6 +130,7 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const
os << " ";
os << format_name (dev.device_class ()->name ());
}
+ os << format_params (dev, db::DeviceClassInductor::param_id_L);
} else if (res || res3) {
@@ -141,6 +143,7 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const
os << " ";
os << format_name (dev.device_class ()->name ());
}
+ os << format_params (dev, db::DeviceClassResistor::param_id_R);
} else if (diode) {
diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc
index cfdc5a341..0941d63c3 100644
--- a/src/db/db/gsiDeclDbNetlist.cc
+++ b/src/db/db/gsiDeclDbNetlist.cc
@@ -251,6 +251,24 @@ static void add_other_abstracts (db::Device *device, const db::DeviceAbstractRef
device->other_abstracts ().push_back (ref);
}
+static const db::Net *net_for_terminal_by_name_const (const db::Device *device, const std::string &name)
+{
+ if (! device->device_class () || ! device->device_class ()->has_terminal_with_name (name)) {
+ return 0;
+ } else {
+ return device->net_for_terminal (device->device_class ()->terminal_id_for_name (name));
+ }
+}
+
+static const db::Net *net_for_terminal_by_name (db::Device *device, const std::string &name)
+{
+ if (! device->device_class () || ! device->device_class ()->has_terminal_with_name (name)) {
+ return 0;
+ } else {
+ return device->net_for_terminal (device->device_class ()->terminal_id_for_name (name));
+ }
+}
+
Class decl_dbDevice (decl_dbNetlistObject, "db", "Device",
gsi::method ("device_class", &db::Device::device_class,
"@brief Gets the device class the device belongs to.\n"
@@ -337,6 +355,18 @@ Class decl_dbDevice (decl_dbNetlistObject, "db", "Device",
"\n\n"
"This constness variant has been introduced in version 0.26.8"
) +
+ gsi::method_ext ("net_for_terminal", net_for_terminal_by_name_const, gsi::arg ("terminal_name"),
+ "@brief Gets the net connected to the specified terminal.\n"
+ "If the terminal is not connected, nil is returned for the net."
+ "\n\n"
+ "This convenience method has been introduced in version 0.27.3.\n"
+ ) +
+ gsi::method_ext ("net_for_terminal", net_for_terminal_by_name, gsi::arg ("terminal_name"),
+ "@brief Gets the net connected to the specified terminal (non-const version).\n"
+ "If the terminal is not connected, nil is returned for the net."
+ "\n\n"
+ "This convenience method has been introduced in version 0.27.3.\n"
+ ) +
gsi::method ("connect_terminal", &db::Device::connect_terminal, gsi::arg ("terminal_id"), gsi::arg ("net"),
"@brief Connects the given terminal to the specified net.\n"
) +
diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb
index 51f44c266..6359bff21 100644
--- a/src/drc/drc/built-in-macros/_drc_engine.rb
+++ b/src/drc/drc/built-in-macros/_drc_engine.rb
@@ -4,6 +4,15 @@ require 'pathname'
module DRC
+ class CustomDeviceClassFactory < RBA::DeviceClassFactory
+ def initialize(cls)
+ @cls = cls
+ end
+ def create_class
+ @cls.new
+ end
+ end
+
# The DRC engine
# %DRC%
@@ -308,22 +317,57 @@ module DRC
# @brief Defines SPICE output format (with options)
# @name write_spice
# @synopsis write_spice([ use_net_names [, with_comments ] ])
+ # @synopsis write_spice(writer_delegate [, use_net_names [, with_comments ] ])
# Use this option in \target_netlist for the format parameter to
# specify SPICE format.
# "use_net_names" and "with_comments" are boolean parameters indicating
# whether to use named nets (numbers if false) and whether to add
# information comments such as instance coordinates or pin names.
+ #
+ # "writer_delegate" allows using a \NetlistSpiceWriterDelegate object to
+ # control the actual writing.
+
+ def write_spice(*args)
- def write_spice(use_net_names = nil, with_comments = nil)
self._context("write_spice") do
- writer = RBA::NetlistSpiceWriter::new
+
+ delegate = nil
+ use_net_names = nil
+ with_comments = nil
+ args.each do |a|
+ if (a == false || a == true) && (use_net_names == nil || with_comments == nil)
+ if use_net_names == nil
+ use_net_names = a
+ else
+ with_comments = a
+ end
+ elsif a.is_a?(RBA::NetlistSpiceWriterDelegate)
+ delegate = a
+ else
+ raise("Too many arguments specified or argument is of wrong type: " + a.inspect)
+ end
+ end
+
+ writer = RBA::NetlistSpiceWriter::new(delegate)
if use_net_names != nil
writer.use_net_names = use_net_names
end
if with_comments != nil
writer.with_comments = with_comments
end
+
writer
+
+ end
+ end
+
+ def _make_factory(cls)
+ if !cls
+ return nil
+ elsif !cls.is_a?(Class)
+ raise("Expected a class object for the 'class' argument of device extractors")
+ else
+ CustomDeviceClassFactory::new(cls)
end
end
@@ -331,15 +375,16 @@ module DRC
# @brief Supplies the MOS3 transistor extractor class
# @name mos3
# @synopsis mos3(name)
+ # @synopsis mos3(name, class)
# Use this class with \extract_devices to specify extraction of a
# three-terminal MOS transistor.
#
# See RBA::DeviceExtractorMOS3Transistor for more details
# about this extractor (non-strict mode applies for 'mos3').
- def mos3(name)
+ def mos3(name, cls = nil)
self._context("mos3") do
- RBA::DeviceExtractorMOS3Transistor::new(name)
+ RBA::DeviceExtractorMOS3Transistor::new(name, false, _make_factory(cls))
end
end
@@ -347,15 +392,16 @@ module DRC
# @brief Supplies the MOS4 transistor extractor class
# @name mos4
# @synopsis mos4(name)
+ # @synopsis mos4(name, class)
# Use this class with \extract_devices to specify extraction of a
# four-terminal MOS transistor.
#
# See RBA::DeviceExtractorMOS4Transistor for more details
# about this extractor (non-strict mode applies for 'mos4').
- def mos4(name)
+ def mos4(name, cls = nil)
self._context("mos4") do
- RBA::DeviceExtractorMOS4Transistor::new(name)
+ RBA::DeviceExtractorMOS4Transistor::new(name, false, _make_factory(cls))
end
end
@@ -363,6 +409,7 @@ module DRC
# @brief Supplies the DMOS3 transistor extractor class
# @name dmos3
# @synopsis dmos3(name)
+ # @synopsis dmos3(name, class)
# Use this class with \extract_devices to specify extraction of a
# three-terminal DMOS transistor. A DMOS transistor is essentially
# the same than a MOS transistor, but source and drain are
@@ -371,9 +418,9 @@ module DRC
# See RBA::DeviceExtractorMOS3Transistor for more details
# about this extractor (strict mode applies for 'dmos3').
- def dmos3(name)
+ def dmos3(name, cls = nil)
self._context("dmos3") do
- RBA::DeviceExtractorMOS3Transistor::new(name, true)
+ RBA::DeviceExtractorMOS3Transistor::new(name, true, _make_factory(cls))
end
end
@@ -381,6 +428,7 @@ module DRC
# @brief Supplies the MOS4 transistor extractor class
# @name dmos4
# @synopsis dmos4(name)
+ # @synopsis dmos4(name, class)
# Use this class with \extract_devices to specify extraction of a
# four-terminal DMOS transistor. A DMOS transistor is essentially
# the same than a MOS transistor, but source and drain are
@@ -389,9 +437,9 @@ module DRC
# See RBA::DeviceExtractorMOS4Transistor for more details
# about this extractor (strict mode applies for 'dmos4').
- def dmos4(name)
+ def dmos4(name, cls = nil)
self._context("dmos4") do
- RBA::DeviceExtractorMOS4Transistor::new(name, true)
+ RBA::DeviceExtractorMOS4Transistor::new(name, true, _make_factory(cls))
end
end
@@ -399,15 +447,16 @@ module DRC
# @brief Supplies the BJT3 transistor extractor class
# @name bjt3
# @synopsis bjt3(name)
+ # @synopsis bjt3(name, class)
# Use this class with \extract_devices to specify extraction of a
# bipolar junction transistor
#
# See RBA::DeviceExtractorBJT3Transistor for more details
# about this extractor.
- def bjt3(name)
+ def bjt3(name, cls = nil)
self._context("bjt3") do
- RBA::DeviceExtractorBJT3Transistor::new(name)
+ RBA::DeviceExtractorBJT3Transistor::new(name, _make_factory(cls))
end
end
@@ -415,15 +464,16 @@ module DRC
# @brief Supplies the BJT4 transistor extractor class
# @name bjt4
# @synopsis bjt4(name)
+ # @synopsis bjt4(name, class)
# Use this class with \extract_devices to specify extraction of a
# bipolar junction transistor with a substrate terminal
#
# See RBA::DeviceExtractorBJT4Transistor for more details
# about this extractor.
- def bjt4(name)
+ def bjt4(name, cls = nil)
self._context("bjt4") do
- RBA::DeviceExtractorBJT4Transistor::new(name)
+ RBA::DeviceExtractorBJT4Transistor::new(name, _make_factory(cls))
end
end
@@ -431,15 +481,16 @@ module DRC
# @brief Supplies the diode extractor class
# @name diode
# @synopsis diode(name)
+ # @synopsis diode(name, class)
# Use this class with \extract_devices to specify extraction of a
# planar diode
#
# See RBA::DeviceExtractorDiode for more details
# about this extractor.
- def diode(name)
+ def diode(name, cls = nil)
self._context("diode") do
- RBA::DeviceExtractorDiode::new(name)
+ RBA::DeviceExtractorDiode::new(name, _make_factory(cls))
end
end
@@ -447,6 +498,7 @@ module DRC
# @brief Supplies the resistor extractor class
# @name resistor
# @synopsis resistor(name, sheet_rho)
+ # @synopsis resistor(name, sheet_rho, class)
# Use this class with \extract_devices to specify extraction of a resistor.
#
# The sheet_rho value is the sheet resistance in ohms/square. It is used
@@ -455,9 +507,9 @@ module DRC
# See RBA::DeviceExtractorResistor for more details
# about this extractor.
- def resistor(name, sheet_rho)
+ def resistor(name, sheet_rho, cls = nil)
self._context("resistor") do
- RBA::DeviceExtractorResistor::new(name, sheet_rho)
+ RBA::DeviceExtractorResistor::new(name, sheet_rho, _make_factory(cls))
end
end
@@ -465,6 +517,7 @@ module DRC
# @brief Supplies the resistor extractor class that includes a bulk terminal
# @name resistor_with_bulk
# @synopsis resistor_with_bulk(name, sheet_rho)
+ # @synopsis resistor_with_bulk(name, sheet_rho, class)
# Use this class with \extract_devices to specify extraction of a resistor
# with a bulk terminal.
# The sheet_rho value is the sheet resistance in ohms/square.
@@ -472,9 +525,9 @@ module DRC
# See RBA::DeviceExtractorResistorWithBulk for more details
# about this extractor.
- def resistor_with_bulk(name, sheet_rho)
+ def resistor_with_bulk(name, sheet_rho, cls = nil)
self._context("resistor_with_bulk") do
- RBA::DeviceExtractorResistorWithBulk::new(name, sheet_rho)
+ RBA::DeviceExtractorResistorWithBulk::new(name, sheet_rho, _make_factory(cls))
end
end
@@ -482,15 +535,16 @@ module DRC
# @brief Supplies the capacitor extractor class
# @name capacitor
# @synopsis capacitor(name, area_cap)
+ # @synopsis capacitor(name, area_cap, class)
# Use this class with \extract_devices to specify extraction of a capacitor.
# The area_cap argument is the capacitance in Farad per square micrometer.
#
# See RBA::DeviceExtractorCapacitor for more details
# about this extractor.
- def capacitor(name, area_cap)
+ def capacitor(name, area_cap, cls = nil)
self._context("capacitor") do
- RBA::DeviceExtractorCapacitor::new(name, area_cap)
+ RBA::DeviceExtractorCapacitor::new(name, area_cap, _make_factory(cls))
end
end
@@ -498,6 +552,7 @@ module DRC
# @brief Supplies the capacitor extractor class that includes a bulk terminal
# @name capacitor_with_bulk
# @synopsis capacitor_with_bulk(name, area_cap)
+ # @synopsis capacitor_with_bulk(name, area_cap, class)
# Use this class with \extract_devices to specify extraction of a capacitor
# with a bulk terminal.
# The area_cap argument is the capacitance in Farad per square micrometer.
@@ -505,9 +560,9 @@ module DRC
# See RBA::DeviceExtractorCapacitorWithBulk for more details
# about this extractor.
- def capacitor_with_bulk(name, area_cap)
+ def capacitor_with_bulk(name, area_cap, cls = nil)
self._context("capacitor_with_bulk") do
- RBA::DeviceExtractorCapacitorWithBulk::new(name, area_cap)
+ RBA::DeviceExtractorCapacitorWithBulk::new(name, area_cap, _make_factory(cls))
end
end
diff --git a/src/lay/lay/doc/manual/lvs_device_extractors.xml b/src/lay/lay/doc/manual/lvs_device_extractors.xml
index e1200800f..7cf6449e2 100644
--- a/src/lay/lay/doc/manual/lvs_device_extractors.xml
+++ b/src/lay/lay/doc/manual/lvs_device_extractors.xml
@@ -376,5 +376,33 @@ dc.enable_parameter("L", true)
fully enabled parameters.
+
+ Another way of customizing the built-in device extractors is to
+ supply a custom device class. The following code creates a new
+ resistor class which changes the preconfigured device parameter definitions
+ to enable "W" and "L".
+
+
+ class MyResistor < RBA::DeviceClassResistor
+ def initialize
+ super
+ enable_parameter("W", true)
+ enable_parameter("L", true)
+ end
+end
+
+...
+
+extract_devices(resistor("RES", 1, MyResistor), ...)
+
+
+
+ The effect of this code is the same than the first one, but using a custom
+ device class opens the option to supply additional parameters for example
+ or to implement some entirely new device while using the extraction
+ mechanics of the resistor extractor. The only requirement is compatibility of
+ the parameter and terminal definitions.
+
+
diff --git a/src/lvs/unit_tests/lvsSimpleTests.cc b/src/lvs/unit_tests/lvsSimpleTests.cc
index 6d054e461..304aa9dd5 100644
--- a/src/lvs/unit_tests/lvsSimpleTests.cc
+++ b/src/lvs/unit_tests/lvsSimpleTests.cc
@@ -206,8 +206,14 @@ TEST(23_issue709)
run_test (_this, "empty_subcells", "empty_subcells.gds");
}
-// empty gds
TEST(24_issue806)
{
run_test (_this, "custom_compare", "custom_compare.gds");
}
+
+TEST(25_enableWandL)
+{
+ run_test (_this, "enable_wl1", "resistor.gds");
+ run_test (_this, "enable_wl2", "resistor.gds");
+ run_test (_this, "enable_wl3", "resistor.gds");
+}
diff --git a/testdata/lvs/enable_wl1.cir b/testdata/lvs/enable_wl1.cir
new file mode 100644
index 000000000..2dbc8c321
--- /dev/null
+++ b/testdata/lvs/enable_wl1.cir
@@ -0,0 +1,11 @@
+* Extracted by KLayout
+
+* cell Rre
+* pin gnd!
+* pin vdd!
+.SUBCKT Rre 1 2
+* net 1 gnd!
+* net 2 vdd!
+* device instance $1 r0 *1 8.43,1.51 RR1
+R$1 1 2 RR1 10 W=0.6 L=6
+.ENDS Rre
diff --git a/testdata/lvs/enable_wl1.lvs b/testdata/lvs/enable_wl1.lvs
new file mode 100644
index 000000000..a58903723
--- /dev/null
+++ b/testdata/lvs/enable_wl1.lvs
@@ -0,0 +1,52 @@
+
+# test spice writer delegate on this occasion
+class MyWriterDelegate < RBA::NetlistSpiceWriterDelegate
+ def write_device(device)
+ if device.device_class.name == "RR1"
+ line = "R"
+ line += format_name(device.expanded_name)
+ line += " "
+ line += net_to_string(device.net_for_terminal("A"))
+ line += " "
+ line += net_to_string(device.net_for_terminal("B"))
+ line += " "
+ line += format_name(device.device_class.name)
+ line += " "
+ line += "%.12g" % device.parameter("R")
+ line += " W="
+ line += "%.12g" % device.parameter("W")
+ line += " L="
+ line += "%.12g" % device.parameter("L")
+ emit_line(line)
+ else
+ super
+ end
+ end
+end
+
+source($lvs_test_source)
+report_lvs($lvs_test_target_lvsdb, true)
+target_netlist($lvs_test_target_cir, write_spice(MyWriterDelegate::new), "Extracted by KLayout")
+
+schematic("resistor.cir")
+
+deep
+
+contact = input(15, 0)
+metal1 = input(16, 0)
+metal1_ver = input(16, 5)
+metal1_lbl = labels(16, 3)
+res = metal1 & metal1_ver
+metal1_not_res = metal1 - metal1_ver
+
+dc = extract_devices(resistor("RR1", 1), { "R" => res , "C" => metal1_not_res})
+dc.enable_parameter("W", true)
+dc.enable_parameter("L", true)
+
+connect(contact, metal1_not_res)
+connect(metal1_not_res, metal1_lbl)
+
+align
+netlist.simplify
+compare
+
diff --git a/testdata/lvs/enable_wl1.lvsdb b/testdata/lvs/enable_wl1.lvsdb
new file mode 100644
index 000000000..67695b612
--- /dev/null
+++ b/testdata/lvs/enable_wl1.lvsdb
@@ -0,0 +1,118 @@
+#%lvsdb-klayout
+
+# Layout
+layout(
+ top(Rre)
+ unit(0.001)
+
+ # Layer section
+ # This section lists the mask layers (drawing or derived) and their connections.
+
+ # Mask layers
+ layer(l3 '15/0')
+ layer(l4 '16/3')
+ layer(l1)
+
+ # Mask layer connectivity
+ connect(l3 l3 l1)
+ connect(l4 l1)
+ connect(l1 l3 l4 l1)
+
+ # Device class section
+ class(RR1 RES
+ param(L 1 0)
+ param(W 1 0)
+ )
+
+ # Device abstracts section
+ # Device abstracts list the pin shapes of the devices.
+ device(D$RR1 RR1
+ terminal(A
+ rect(l1 (-3160 -300) (160 600))
+ )
+ terminal(B
+ rect(l1 (3000 -300) (160 600))
+ )
+ )
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(Rre
+
+ # Circuit boundary
+ rect((5270 1210) (6320 600))
+
+ # Nets with their geometries
+ net(1 name('gnd!')
+ rect(l3 (5295 1230) (120 560))
+ text(l4 'gnd!' (-60 -60))
+ rect(l1 (-70 -505) (125 570))
+ rect(l1 (-140 -585) (160 600))
+ )
+ net(2 name('vdd!')
+ rect(l3 (11455 1240) (120 540))
+ text(l4 'vdd!' (-65 -60))
+ rect(l1 (-65 -495) (125 560))
+ rect(l1 (-140 -575) (160 600))
+ )
+
+ # Outgoing pins and their connections to nets
+ pin(1 name('gnd!'))
+ pin(2 name('vdd!'))
+
+ # Devices and their connections
+ device(1 D$RR1
+ location(8430 1510)
+ param(R 10)
+ param(L 6)
+ param(W 0.6)
+ param(A 3.6)
+ param(P 13.2)
+ terminal(A 1)
+ terminal(B 2)
+ )
+
+ )
+)
+
+# Reference netlist
+reference(
+
+ # Device class section
+ class(RR1 RES)
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(RRE
+
+ # Nets
+ net(1 name('VDD!'))
+ net(2 name('GND!'))
+
+ # Devices and their connections
+ device(1 RR1
+ name(R0)
+ param(R 10)
+ param(L 6)
+ param(W 0.6)
+ param(A 0)
+ param(P 0)
+ terminal(A 1)
+ terminal(B 2)
+ )
+
+ )
+)
+
+# Cross reference
+xref(
+ circuit(Rre RRE match
+ xref(
+ net(1 2 match)
+ net(2 1 match)
+ pin(0 () match)
+ pin(1 () match)
+ device(1 1 match)
+ )
+ )
+)
diff --git a/testdata/lvs/enable_wl2.cir b/testdata/lvs/enable_wl2.cir
new file mode 100644
index 000000000..5ce133250
--- /dev/null
+++ b/testdata/lvs/enable_wl2.cir
@@ -0,0 +1,11 @@
+* Extracted by KLayout
+
+* cell Rre
+* pin gnd!
+* pin vdd!
+.SUBCKT Rre 1 2
+* net 1 gnd!
+* net 2 vdd!
+* device instance $1 r0 *1 8.43,1.51 RR1
+R$1 1 2 10 RR1 L=6U W=0.6U A=3.6P P=13.2U
+.ENDS Rre
diff --git a/testdata/lvs/enable_wl2.lvs b/testdata/lvs/enable_wl2.lvs
new file mode 100644
index 000000000..945a89294
--- /dev/null
+++ b/testdata/lvs/enable_wl2.lvs
@@ -0,0 +1,33 @@
+
+source($lvs_test_source)
+report_lvs($lvs_test_target_lvsdb, true)
+target_netlist($lvs_test_target_cir, write_spice, "Extracted by KLayout")
+
+schematic("resistor.cir")
+
+deep
+
+contact = input(15, 0)
+metal1 = input(16, 0)
+metal1_ver = input(16, 5)
+metal1_lbl = labels(16, 3)
+res = metal1 & metal1_ver
+metal1_not_res = metal1 - metal1_ver
+
+class MyResistorClass < RBA::DeviceClassResistor
+ def initialize
+ super
+ enable_parameter("W", true)
+ enable_parameter("L", true)
+ end
+end
+
+extract_devices(resistor("RR1", 1, MyResistorClass), { "R" => res , "C" => metal1_not_res})
+
+connect(contact, metal1_not_res)
+connect(metal1_not_res, metal1_lbl)
+
+align
+netlist.simplify
+compare
+
diff --git a/testdata/lvs/enable_wl2.lvsdb b/testdata/lvs/enable_wl2.lvsdb
new file mode 100644
index 000000000..67695b612
--- /dev/null
+++ b/testdata/lvs/enable_wl2.lvsdb
@@ -0,0 +1,118 @@
+#%lvsdb-klayout
+
+# Layout
+layout(
+ top(Rre)
+ unit(0.001)
+
+ # Layer section
+ # This section lists the mask layers (drawing or derived) and their connections.
+
+ # Mask layers
+ layer(l3 '15/0')
+ layer(l4 '16/3')
+ layer(l1)
+
+ # Mask layer connectivity
+ connect(l3 l3 l1)
+ connect(l4 l1)
+ connect(l1 l3 l4 l1)
+
+ # Device class section
+ class(RR1 RES
+ param(L 1 0)
+ param(W 1 0)
+ )
+
+ # Device abstracts section
+ # Device abstracts list the pin shapes of the devices.
+ device(D$RR1 RR1
+ terminal(A
+ rect(l1 (-3160 -300) (160 600))
+ )
+ terminal(B
+ rect(l1 (3000 -300) (160 600))
+ )
+ )
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(Rre
+
+ # Circuit boundary
+ rect((5270 1210) (6320 600))
+
+ # Nets with their geometries
+ net(1 name('gnd!')
+ rect(l3 (5295 1230) (120 560))
+ text(l4 'gnd!' (-60 -60))
+ rect(l1 (-70 -505) (125 570))
+ rect(l1 (-140 -585) (160 600))
+ )
+ net(2 name('vdd!')
+ rect(l3 (11455 1240) (120 540))
+ text(l4 'vdd!' (-65 -60))
+ rect(l1 (-65 -495) (125 560))
+ rect(l1 (-140 -575) (160 600))
+ )
+
+ # Outgoing pins and their connections to nets
+ pin(1 name('gnd!'))
+ pin(2 name('vdd!'))
+
+ # Devices and their connections
+ device(1 D$RR1
+ location(8430 1510)
+ param(R 10)
+ param(L 6)
+ param(W 0.6)
+ param(A 3.6)
+ param(P 13.2)
+ terminal(A 1)
+ terminal(B 2)
+ )
+
+ )
+)
+
+# Reference netlist
+reference(
+
+ # Device class section
+ class(RR1 RES)
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(RRE
+
+ # Nets
+ net(1 name('VDD!'))
+ net(2 name('GND!'))
+
+ # Devices and their connections
+ device(1 RR1
+ name(R0)
+ param(R 10)
+ param(L 6)
+ param(W 0.6)
+ param(A 0)
+ param(P 0)
+ terminal(A 1)
+ terminal(B 2)
+ )
+
+ )
+)
+
+# Cross reference
+xref(
+ circuit(Rre RRE match
+ xref(
+ net(1 2 match)
+ net(2 1 match)
+ pin(0 () match)
+ pin(1 () match)
+ device(1 1 match)
+ )
+ )
+)
diff --git a/testdata/lvs/enable_wl3.cir b/testdata/lvs/enable_wl3.cir
new file mode 100644
index 000000000..5ce133250
--- /dev/null
+++ b/testdata/lvs/enable_wl3.cir
@@ -0,0 +1,11 @@
+* Extracted by KLayout
+
+* cell Rre
+* pin gnd!
+* pin vdd!
+.SUBCKT Rre 1 2
+* net 1 gnd!
+* net 2 vdd!
+* device instance $1 r0 *1 8.43,1.51 RR1
+R$1 1 2 10 RR1 L=6U W=0.6U A=3.6P P=13.2U
+.ENDS Rre
diff --git a/testdata/lvs/enable_wl3.lvs b/testdata/lvs/enable_wl3.lvs
new file mode 100644
index 000000000..8f5405307
--- /dev/null
+++ b/testdata/lvs/enable_wl3.lvs
@@ -0,0 +1,33 @@
+
+source($lvs_test_source)
+report_lvs($lvs_test_target_lvsdb, true)
+target_netlist($lvs_test_target_cir, write_spice, "Extracted by KLayout")
+
+schematic("resistor2.cir")
+
+deep
+
+contact = input(15, 0)
+metal1 = input(16, 0)
+metal1_ver = input(16, 5)
+metal1_lbl = labels(16, 3)
+res = metal1 & metal1_ver
+metal1_not_res = metal1 - metal1_ver
+
+class MyResistorClass < RBA::DeviceClassResistor
+ def initialize
+ super
+ enable_parameter("W", true)
+ enable_parameter("L", true)
+ end
+end
+
+extract_devices(resistor("RR1", 1, MyResistorClass), { "R" => res , "C" => metal1_not_res})
+
+connect(contact, metal1_not_res)
+connect(metal1_not_res, metal1_lbl)
+
+align
+netlist.simplify
+compare
+
diff --git a/testdata/lvs/enable_wl3.lvsdb b/testdata/lvs/enable_wl3.lvsdb
new file mode 100644
index 000000000..947fc54ac
--- /dev/null
+++ b/testdata/lvs/enable_wl3.lvsdb
@@ -0,0 +1,121 @@
+#%lvsdb-klayout
+
+# Layout
+layout(
+ top(Rre)
+ unit(0.001)
+
+ # Layer section
+ # This section lists the mask layers (drawing or derived) and their connections.
+
+ # Mask layers
+ layer(l3 '15/0')
+ layer(l4 '16/3')
+ layer(l1)
+
+ # Mask layer connectivity
+ connect(l3 l3 l1)
+ connect(l4 l1)
+ connect(l1 l3 l4 l1)
+
+ # Device class section
+ class(RR1 RES
+ param(L 1 0)
+ param(W 1 0)
+ )
+
+ # Device abstracts section
+ # Device abstracts list the pin shapes of the devices.
+ device(D$RR1 RR1
+ terminal(A
+ rect(l1 (-3160 -300) (160 600))
+ )
+ terminal(B
+ rect(l1 (3000 -300) (160 600))
+ )
+ )
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(Rre
+
+ # Circuit boundary
+ rect((5270 1210) (6320 600))
+
+ # Nets with their geometries
+ net(1 name('gnd!')
+ rect(l3 (5295 1230) (120 560))
+ text(l4 'gnd!' (-60 -60))
+ rect(l1 (-70 -505) (125 570))
+ rect(l1 (-140 -585) (160 600))
+ )
+ net(2 name('vdd!')
+ rect(l3 (11455 1240) (120 540))
+ text(l4 'vdd!' (-65 -60))
+ rect(l1 (-65 -495) (125 560))
+ rect(l1 (-140 -575) (160 600))
+ )
+
+ # Outgoing pins and their connections to nets
+ pin(1 name('gnd!'))
+ pin(2 name('vdd!'))
+
+ # Devices and their connections
+ device(1 D$RR1
+ location(8430 1510)
+ param(R 10)
+ param(L 6)
+ param(W 0.6)
+ param(A 3.6)
+ param(P 13.2)
+ terminal(A 1)
+ terminal(B 2)
+ )
+
+ )
+)
+
+# Reference netlist
+reference(
+
+ # Device class section
+ class(RR1 RES)
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(RRE
+
+ # Nets
+ net(1 name('VDD!'))
+ net(2 name('GND!'))
+
+ # Devices and their connections
+ device(1 RR1
+ name(R0)
+ param(R 10)
+ param(L 7)
+ param(W 0.6)
+ param(A 0)
+ param(P 0)
+ terminal(A 1)
+ terminal(B 2)
+ )
+
+ )
+)
+
+# Cross reference
+xref(
+ circuit(Rre RRE nomatch
+ xref(
+ net(() 2 mismatch)
+ net(() 1 mismatch)
+ net(1 () mismatch)
+ net(2 () mismatch)
+ pin(0 () match)
+ pin(1 () match)
+ device(() 1 mismatch)
+ device(1 () mismatch)
+ )
+ )
+)
diff --git a/testdata/lvs/resistor.cir b/testdata/lvs/resistor.cir
new file mode 100644
index 000000000..c210ac37c
--- /dev/null
+++ b/testdata/lvs/resistor.cir
@@ -0,0 +1,4 @@
+.SUBCKT Rre
+RR0 vdd! gnd! 10 RR1 W=600n L=6u M=1
+.ENDS
+
diff --git a/testdata/lvs/resistor.gds b/testdata/lvs/resistor.gds
new file mode 100644
index 0000000000000000000000000000000000000000..aa2b5869b6abf853da7d377b5e9a885063a1a273
GIT binary patch
literal 2048
zcmZQzV_;%nWsqTHVyFbtEI^(P13MDijDd%V&C$g*z9KC#i9v*!)y}cg-22$_50)-F
z^cT#I3Sp381?gpBkYiwD;AAjE(#y`k!NwL;l*+)s!o$G8#>>R;jDbyzi2=wKX9U{D
zCdCM3^GLHgH~?u7;1OVEU{H9+z`**9K}3=*+95NqxFj(zIn^&QH#HV$jvx?oK+FdPf{4Rtpgg92pcasRovlE9Cm9%YjSw{3Plz~-2Fl~q
zFR~P(PgDs(vjfcqiNk1o`YCn4$TXn6K>x$c0ns3TgT!GpUjIYGP1g-#4u}Tn1BEAy
zhUtgKB{2MfamkDxm-c7C-~uErb-n>3YX<{|BwJZZiXtTZNYO9y8mRveNPl`BOg}XK
z`N8oIjX#m~KzE-5`d=MEv;715A1Dr^f%3@lhoWC+KTzKdVEmgSXtpmv!-3*38YmCe
Y&kj_=0!go<03D!XNB{r;
literal 0
HcmV?d00001
diff --git a/testdata/lvs/resistor2.cir b/testdata/lvs/resistor2.cir
new file mode 100644
index 000000000..38882671e
--- /dev/null
+++ b/testdata/lvs/resistor2.cir
@@ -0,0 +1,4 @@
+.SUBCKT Rre
+RR0 vdd! gnd! 10 RR1 W=600n L=7u M=1
+.ENDS
+
diff --git a/testdata/ruby/dbNetlist.rb b/testdata/ruby/dbNetlist.rb
index bb1d34570..dc09d7f4b 100644
--- a/testdata/ruby/dbNetlist.rb
+++ b/testdata/ruby/dbNetlist.rb
@@ -331,6 +331,8 @@ class DBNetlist_TestClass < TestBase
assert_equal(net.terminal_count, 1)
assert_equal(d1.net_for_terminal(1).name, "NET")
+ assert_equal(d1.net_for_terminal("B").name, "NET")
+ assert_equal(d1.net_for_terminal("X").inspect, "nil")
assert_equal(d1.net_for_terminal(0).inspect, "nil")
d1.disconnect_terminal("B")
From 24c34f1d60c9a731befd2e34c9b344829e23742b Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Mon, 5 Jul 2021 22:29:33 +0200
Subject: [PATCH 16/19] Updated test data
---
testdata/algo/nwriter10_au.txt | 200 ++++++++++++++++----------------
testdata/algo/nwriter1_au.txt | 4 +-
testdata/algo/nwriter1b_au.txt | 4 +-
testdata/algo/nwriter20_au.txt | 4 +-
testdata/algo/nwriter2_au.txt | 4 +-
testdata/algo/nwriter2b_au.txt | 4 +-
testdata/algo/nwriter2c_au.txt | 4 +-
testdata/algo/nwriter2d_au.txt | 4 +-
testdata/lvs/custom_compare.cir | 2 +-
9 files changed, 115 insertions(+), 115 deletions(-)
diff --git a/testdata/algo/nwriter10_au.txt b/testdata/algo/nwriter10_au.txt
index ac5e9c375..aa10b2295 100644
--- a/testdata/algo/nwriter10_au.txt
+++ b/testdata/algo/nwriter10_au.txt
@@ -210,204 +210,204 @@
* net 100 n99
* net 101 n100
* device instance $1 r0 *1 0,0
-R$1 1 2 0
+R$1 1 2 0 L=0U W=0U A=0P P=0U
* device instance $2 r0 *1 0,0
-R$2 1 3 0
+R$2 1 3 0 L=0U W=0U A=0P P=0U
* device instance $3 r0 *1 0,0
-R$3 1 4 0
+R$3 1 4 0 L=0U W=0U A=0P P=0U
* device instance $4 r0 *1 0,0
-R$4 1 5 0
+R$4 1 5 0 L=0U W=0U A=0P P=0U
* device instance $5 r0 *1 0,0
-R$5 1 6 0
+R$5 1 6 0 L=0U W=0U A=0P P=0U
* device instance $6 r0 *1 0,0
-R$6 1 7 0
+R$6 1 7 0 L=0U W=0U A=0P P=0U
* device instance $7 r0 *1 0,0
-R$7 1 8 0
+R$7 1 8 0 L=0U W=0U A=0P P=0U
* device instance $8 r0 *1 0,0
-R$8 1 9 0
+R$8 1 9 0 L=0U W=0U A=0P P=0U
* device instance $9 r0 *1 0,0
-R$9 1 10 0
+R$9 1 10 0 L=0U W=0U A=0P P=0U
* device instance $10 r0 *1 0,0
-R$10 1 11 0
+R$10 1 11 0 L=0U W=0U A=0P P=0U
* device instance $11 r0 *1 0,0
-R$11 1 12 0
+R$11 1 12 0 L=0U W=0U A=0P P=0U
* device instance $12 r0 *1 0,0
-R$12 1 13 0
+R$12 1 13 0 L=0U W=0U A=0P P=0U
* device instance $13 r0 *1 0,0
-R$13 1 14 0
+R$13 1 14 0 L=0U W=0U A=0P P=0U
* device instance $14 r0 *1 0,0
-R$14 1 15 0
+R$14 1 15 0 L=0U W=0U A=0P P=0U
* device instance $15 r0 *1 0,0
-R$15 1 16 0
+R$15 1 16 0 L=0U W=0U A=0P P=0U
* device instance $16 r0 *1 0,0
-R$16 1 17 0
+R$16 1 17 0 L=0U W=0U A=0P P=0U
* device instance $17 r0 *1 0,0
-R$17 1 18 0
+R$17 1 18 0 L=0U W=0U A=0P P=0U
* device instance $18 r0 *1 0,0
-R$18 1 19 0
+R$18 1 19 0 L=0U W=0U A=0P P=0U
* device instance $19 r0 *1 0,0
-R$19 1 20 0
+R$19 1 20 0 L=0U W=0U A=0P P=0U
* device instance $20 r0 *1 0,0
-R$20 1 21 0
+R$20 1 21 0 L=0U W=0U A=0P P=0U
* device instance $21 r0 *1 0,0
-R$21 1 22 0
+R$21 1 22 0 L=0U W=0U A=0P P=0U
* device instance $22 r0 *1 0,0
-R$22 1 23 0
+R$22 1 23 0 L=0U W=0U A=0P P=0U
* device instance $23 r0 *1 0,0
-R$23 1 24 0
+R$23 1 24 0 L=0U W=0U A=0P P=0U
* device instance $24 r0 *1 0,0
-R$24 1 25 0
+R$24 1 25 0 L=0U W=0U A=0P P=0U
* device instance $25 r0 *1 0,0
-R$25 1 26 0
+R$25 1 26 0 L=0U W=0U A=0P P=0U
* device instance $26 r0 *1 0,0
-R$26 1 27 0
+R$26 1 27 0 L=0U W=0U A=0P P=0U
* device instance $27 r0 *1 0,0
-R$27 1 28 0
+R$27 1 28 0 L=0U W=0U A=0P P=0U
* device instance $28 r0 *1 0,0
-R$28 1 29 0
+R$28 1 29 0 L=0U W=0U A=0P P=0U
* device instance $29 r0 *1 0,0
-R$29 1 30 0
+R$29 1 30 0 L=0U W=0U A=0P P=0U
* device instance $30 r0 *1 0,0
-R$30 1 31 0
+R$30 1 31 0 L=0U W=0U A=0P P=0U
* device instance $31 r0 *1 0,0
-R$31 1 32 0
+R$31 1 32 0 L=0U W=0U A=0P P=0U
* device instance $32 r0 *1 0,0
-R$32 1 33 0
+R$32 1 33 0 L=0U W=0U A=0P P=0U
* device instance $33 r0 *1 0,0
-R$33 1 34 0
+R$33 1 34 0 L=0U W=0U A=0P P=0U
* device instance $34 r0 *1 0,0
-R$34 1 35 0
+R$34 1 35 0 L=0U W=0U A=0P P=0U
* device instance $35 r0 *1 0,0
-R$35 1 36 0
+R$35 1 36 0 L=0U W=0U A=0P P=0U
* device instance $36 r0 *1 0,0
-R$36 1 37 0
+R$36 1 37 0 L=0U W=0U A=0P P=0U
* device instance $37 r0 *1 0,0
-R$37 1 38 0
+R$37 1 38 0 L=0U W=0U A=0P P=0U
* device instance $38 r0 *1 0,0
-R$38 1 39 0
+R$38 1 39 0 L=0U W=0U A=0P P=0U
* device instance $39 r0 *1 0,0
-R$39 1 40 0
+R$39 1 40 0 L=0U W=0U A=0P P=0U
* device instance $40 r0 *1 0,0
-R$40 1 41 0
+R$40 1 41 0 L=0U W=0U A=0P P=0U
* device instance $41 r0 *1 0,0
-R$41 1 42 0
+R$41 1 42 0 L=0U W=0U A=0P P=0U
* device instance $42 r0 *1 0,0
-R$42 1 43 0
+R$42 1 43 0 L=0U W=0U A=0P P=0U
* device instance $43 r0 *1 0,0
-R$43 1 44 0
+R$43 1 44 0 L=0U W=0U A=0P P=0U
* device instance $44 r0 *1 0,0
-R$44 1 45 0
+R$44 1 45 0 L=0U W=0U A=0P P=0U
* device instance $45 r0 *1 0,0
-R$45 1 46 0
+R$45 1 46 0 L=0U W=0U A=0P P=0U
* device instance $46 r0 *1 0,0
-R$46 1 47 0
+R$46 1 47 0 L=0U W=0U A=0P P=0U
* device instance $47 r0 *1 0,0
-R$47 1 48 0
+R$47 1 48 0 L=0U W=0U A=0P P=0U
* device instance $48 r0 *1 0,0
-R$48 1 49 0
+R$48 1 49 0 L=0U W=0U A=0P P=0U
* device instance $49 r0 *1 0,0
-R$49 1 50 0
+R$49 1 50 0 L=0U W=0U A=0P P=0U
* device instance $50 r0 *1 0,0
-R$50 1 51 0
+R$50 1 51 0 L=0U W=0U A=0P P=0U
* device instance $51 r0 *1 0,0
-R$51 1 52 0
+R$51 1 52 0 L=0U W=0U A=0P P=0U
* device instance $52 r0 *1 0,0
-R$52 1 53 0
+R$52 1 53 0 L=0U W=0U A=0P P=0U
* device instance $53 r0 *1 0,0
-R$53 1 54 0
+R$53 1 54 0 L=0U W=0U A=0P P=0U
* device instance $54 r0 *1 0,0
-R$54 1 55 0
+R$54 1 55 0 L=0U W=0U A=0P P=0U
* device instance $55 r0 *1 0,0
-R$55 1 56 0
+R$55 1 56 0 L=0U W=0U A=0P P=0U
* device instance $56 r0 *1 0,0
-R$56 1 57 0
+R$56 1 57 0 L=0U W=0U A=0P P=0U
* device instance $57 r0 *1 0,0
-R$57 1 58 0
+R$57 1 58 0 L=0U W=0U A=0P P=0U
* device instance $58 r0 *1 0,0
-R$58 1 59 0
+R$58 1 59 0 L=0U W=0U A=0P P=0U
* device instance $59 r0 *1 0,0
-R$59 1 60 0
+R$59 1 60 0 L=0U W=0U A=0P P=0U
* device instance $60 r0 *1 0,0
-R$60 1 61 0
+R$60 1 61 0 L=0U W=0U A=0P P=0U
* device instance $61 r0 *1 0,0
-R$61 1 62 0
+R$61 1 62 0 L=0U W=0U A=0P P=0U
* device instance $62 r0 *1 0,0
-R$62 1 63 0
+R$62 1 63 0 L=0U W=0U A=0P P=0U
* device instance $63 r0 *1 0,0
-R$63 1 64 0
+R$63 1 64 0 L=0U W=0U A=0P P=0U
* device instance $64 r0 *1 0,0
-R$64 1 65 0
+R$64 1 65 0 L=0U W=0U A=0P P=0U
* device instance $65 r0 *1 0,0
-R$65 1 66 0
+R$65 1 66 0 L=0U W=0U A=0P P=0U
* device instance $66 r0 *1 0,0
-R$66 1 67 0
+R$66 1 67 0 L=0U W=0U A=0P P=0U
* device instance $67 r0 *1 0,0
-R$67 1 68 0
+R$67 1 68 0 L=0U W=0U A=0P P=0U
* device instance $68 r0 *1 0,0
-R$68 1 69 0
+R$68 1 69 0 L=0U W=0U A=0P P=0U
* device instance $69 r0 *1 0,0
-R$69 1 70 0
+R$69 1 70 0 L=0U W=0U A=0P P=0U
* device instance $70 r0 *1 0,0
-R$70 1 71 0
+R$70 1 71 0 L=0U W=0U A=0P P=0U
* device instance $71 r0 *1 0,0
-R$71 1 72 0
+R$71 1 72 0 L=0U W=0U A=0P P=0U
* device instance $72 r0 *1 0,0
-R$72 1 73 0
+R$72 1 73 0 L=0U W=0U A=0P P=0U
* device instance $73 r0 *1 0,0
-R$73 1 74 0
+R$73 1 74 0 L=0U W=0U A=0P P=0U
* device instance $74 r0 *1 0,0
-R$74 1 75 0
+R$74 1 75 0 L=0U W=0U A=0P P=0U
* device instance $75 r0 *1 0,0
-R$75 1 76 0
+R$75 1 76 0 L=0U W=0U A=0P P=0U
* device instance $76 r0 *1 0,0
-R$76 1 77 0
+R$76 1 77 0 L=0U W=0U A=0P P=0U
* device instance $77 r0 *1 0,0
-R$77 1 78 0
+R$77 1 78 0 L=0U W=0U A=0P P=0U
* device instance $78 r0 *1 0,0
-R$78 1 79 0
+R$78 1 79 0 L=0U W=0U A=0P P=0U
* device instance $79 r0 *1 0,0
-R$79 1 80 0
+R$79 1 80 0 L=0U W=0U A=0P P=0U
* device instance $80 r0 *1 0,0
-R$80 1 81 0
+R$80 1 81 0 L=0U W=0U A=0P P=0U
* device instance $81 r0 *1 0,0
-R$81 1 82 0
+R$81 1 82 0 L=0U W=0U A=0P P=0U
* device instance $82 r0 *1 0,0
-R$82 1 83 0
+R$82 1 83 0 L=0U W=0U A=0P P=0U
* device instance $83 r0 *1 0,0
-R$83 1 84 0
+R$83 1 84 0 L=0U W=0U A=0P P=0U
* device instance $84 r0 *1 0,0
-R$84 1 85 0
+R$84 1 85 0 L=0U W=0U A=0P P=0U
* device instance $85 r0 *1 0,0
-R$85 1 86 0
+R$85 1 86 0 L=0U W=0U A=0P P=0U
* device instance $86 r0 *1 0,0
-R$86 1 87 0
+R$86 1 87 0 L=0U W=0U A=0P P=0U
* device instance $87 r0 *1 0,0
-R$87 1 88 0
+R$87 1 88 0 L=0U W=0U A=0P P=0U
* device instance $88 r0 *1 0,0
-R$88 1 89 0
+R$88 1 89 0 L=0U W=0U A=0P P=0U
* device instance $89 r0 *1 0,0
-R$89 1 90 0
+R$89 1 90 0 L=0U W=0U A=0P P=0U
* device instance $90 r0 *1 0,0
-R$90 1 91 0
+R$90 1 91 0 L=0U W=0U A=0P P=0U
* device instance $91 r0 *1 0,0
-R$91 1 92 0
+R$91 1 92 0 L=0U W=0U A=0P P=0U
* device instance $92 r0 *1 0,0
-R$92 1 93 0
+R$92 1 93 0 L=0U W=0U A=0P P=0U
* device instance $93 r0 *1 0,0
-R$93 1 94 0
+R$93 1 94 0 L=0U W=0U A=0P P=0U
* device instance $94 r0 *1 0,0
-R$94 1 95 0
+R$94 1 95 0 L=0U W=0U A=0P P=0U
* device instance $95 r0 *1 0,0
-R$95 1 96 0
+R$95 1 96 0 L=0U W=0U A=0P P=0U
* device instance $96 r0 *1 0,0
-R$96 1 97 0
+R$96 1 97 0 L=0U W=0U A=0P P=0U
* device instance $97 r0 *1 0,0
-R$97 1 98 0
+R$97 1 98 0 L=0U W=0U A=0P P=0U
* device instance $98 r0 *1 0,0
-R$98 1 99 0
+R$98 1 99 0 L=0U W=0U A=0P P=0U
* device instance $99 r0 *1 0,0
-R$99 1 100 0
+R$99 1 100 0 L=0U W=0U A=0P P=0U
* device instance $100 r0 *1 0,0
-R$100 1 101 0
+R$100 1 101 0 L=0U W=0U A=0P P=0U
.ENDS
+ C1withaverylongextensionthatgoesbeyondmultiplelinesunlessipasteeverythingtogetherwhichmakesithardtoreadbutexactlythatisthereasonwhyiwriteitthisway
diff --git a/testdata/algo/nwriter1_au.txt b/testdata/algo/nwriter1_au.txt
index 7143b54b5..323993f8f 100644
--- a/testdata/algo/nwriter1_au.txt
+++ b/testdata/algo/nwriter1_au.txt
@@ -8,7 +8,7 @@
* net 2 n2
* net 3 n3
* device instance $1 r0 *1 0,0 RCLS
-R$1 1 3 1.7 RCLS
+R$1 1 3 1.7 RCLS L=0U W=0U A=0P P=0U
* device instance $2 r0 *1 0,0 RCLS
-R$2 3 2 4.2e-05 RCLS
+R$2 3 2 4.2e-05 RCLS L=0U W=0U A=0P P=0U
.ENDS C1
diff --git a/testdata/algo/nwriter1b_au.txt b/testdata/algo/nwriter1b_au.txt
index 64dd13407..a43f876dc 100644
--- a/testdata/algo/nwriter1b_au.txt
+++ b/testdata/algo/nwriter1b_au.txt
@@ -8,7 +8,7 @@
* net 2 n2
* net 3 n3
* device instance $1 r0 *1 0,0 RCLS
-R$1 1 3 3 1.7 RCLS
+R$1 1 3 3 1.7 RCLS L=0U W=0U A=0P P=0U
* device instance $2 r0 *1 0,0 RCLS
-R$2 3 2 3 4.2e-05 RCLS
+R$2 3 2 3 4.2e-05 RCLS L=0U W=0U A=0P P=0U
.ENDS C1
diff --git a/testdata/algo/nwriter20_au.txt b/testdata/algo/nwriter20_au.txt
index acb7efa2e..8f9c1b5a3 100644
--- a/testdata/algo/nwriter20_au.txt
+++ b/testdata/algo/nwriter20_au.txt
@@ -16,10 +16,10 @@
* net 3 n3
* device instance $1 r0 *1 0,0 RCLS
*** Before device $1
-R$1 1 3 1.7 RCLS
+R$1 1 3 1.7 RCLS L=0U W=0U A=0P P=0U
*** After device $1
* device instance $2 r0 *1 0,0 RCLS
*** Before device $2
-R$2 3 2 4.2e-05 RCLS
+R$2 3 2 4.2e-05 RCLS L=0U W=0U A=0P P=0U
*** After device $2
.ENDS C1
diff --git a/testdata/algo/nwriter2_au.txt b/testdata/algo/nwriter2_au.txt
index 3194cc9d7..80ad5dd94 100644
--- a/testdata/algo/nwriter2_au.txt
+++ b/testdata/algo/nwriter2_au.txt
@@ -8,7 +8,7 @@
* net 2 n2
* net 3 n3
* device instance $1 r0 *1 0,0 CCLS
-C$1 1 3 1.7e-12 CCLS
+C$1 1 3 1.7e-12 CCLS A=0P P=0U
* device instance $2 r0 *1 0,0 CCLS
-C$2 3 2 4.2e-14 CCLS
+C$2 3 2 4.2e-14 CCLS A=0P P=0U
.ENDS C1
diff --git a/testdata/algo/nwriter2b_au.txt b/testdata/algo/nwriter2b_au.txt
index 9ef04cbc3..00bfce2b2 100644
--- a/testdata/algo/nwriter2b_au.txt
+++ b/testdata/algo/nwriter2b_au.txt
@@ -8,7 +8,7 @@
* net 2 n2
* net 3 n3
* device instance $1 r0 *1 0,0
-C$1 1 3 1.7e-12
+C$1 1 3 1.7e-12 A=0P P=0U
* device instance $2 r0 *1 0,0
-C$2 3 2 4.2e-14
+C$2 3 2 4.2e-14 A=0P P=0U
.ENDS C1
diff --git a/testdata/algo/nwriter2c_au.txt b/testdata/algo/nwriter2c_au.txt
index 59ea73fc8..81dcb999e 100644
--- a/testdata/algo/nwriter2c_au.txt
+++ b/testdata/algo/nwriter2c_au.txt
@@ -8,7 +8,7 @@
* net 2 n2
* net 3 n3
* device instance $1 r0 *1 0,0 CCLS
-C$1 1 3 3 1.7e-12 CCLS
+C$1 1 3 3 1.7e-12 CCLS A=0P P=0U
* device instance $2 r0 *1 0,0 CCLS
-C$2 3 2 3 4.2e-14 CCLS
+C$2 3 2 3 4.2e-14 CCLS A=0P P=0U
.ENDS C1
diff --git a/testdata/algo/nwriter2d_au.txt b/testdata/algo/nwriter2d_au.txt
index bb22ba84a..cafcedb5a 100644
--- a/testdata/algo/nwriter2d_au.txt
+++ b/testdata/algo/nwriter2d_au.txt
@@ -8,7 +8,7 @@
* net 2 n2
* net 3 n3
* device instance $1 r0 *1 0,0
-C$1 1 3 3 1.7e-12
+C$1 1 3 3 1.7e-12 A=0P P=0U
* device instance $2 r0 *1 0,0
-C$2 3 2 3 4.2e-14
+C$2 3 2 3 4.2e-14 A=0P P=0U
.ENDS C1
diff --git a/testdata/lvs/custom_compare.cir b/testdata/lvs/custom_compare.cir
index e558a4c04..a078c8c9b 100644
--- a/testdata/lvs/custom_compare.cir
+++ b/testdata/lvs/custom_compare.cir
@@ -3,5 +3,5 @@
* cell TOP
.SUBCKT TOP
* device instance $1 r0 *1 7.52,4.175 RES
-R$1 2 1 51 RES
+R$1 2 1 51 RES L=12.75U W=0.25U A=3.1875P P=26U
.ENDS TOP
From 4e0d8d92ef22600129a641e39393378e1309db58 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Mon, 5 Jul 2021 22:45:40 +0200
Subject: [PATCH 17/19] Updated doc, reverted netlist writer to write all
parameters - it will only write primary parameters for R, L and C
---
src/db/db/dbNetlistSpiceWriter.cc | 10 +-
src/db/db/dbNetlistSpiceWriter.h | 2 +-
src/lay/lay/doc/about/drc_ref_global.xml | 15 ++
src/lay/lay/doc/about/drc_ref_layer.xml | 10 +-
src/lay/lay/doc/about/drc_ref_netter.xml | 3 +
testdata/algo/nwriter10_au.txt | 200 +++++++++++------------
testdata/algo/nwriter1_au.txt | 4 +-
testdata/algo/nwriter1b_au.txt | 4 +-
testdata/algo/nwriter20_au.txt | 4 +-
testdata/algo/nwriter2_au.txt | 4 +-
testdata/algo/nwriter2b_au.txt | 4 +-
testdata/algo/nwriter2c_au.txt | 4 +-
testdata/algo/nwriter2d_au.txt | 4 +-
testdata/lvs/custom_compare.cir | 2 +-
testdata/lvs/enable_wl2.cir | 2 +-
testdata/lvs/enable_wl3.cir | 2 +-
16 files changed, 146 insertions(+), 128 deletions(-)
diff --git a/src/db/db/dbNetlistSpiceWriter.cc b/src/db/db/dbNetlistSpiceWriter.cc
index b5893bee3..a4a689d6d 100644
--- a/src/db/db/dbNetlistSpiceWriter.cc
+++ b/src/db/db/dbNetlistSpiceWriter.cc
@@ -117,7 +117,7 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const
os << " ";
os << format_name (dev.device_class ()->name ());
}
- os << format_params (dev, db::DeviceClassCapacitor::param_id_C);
+ os << format_params (dev, db::DeviceClassCapacitor::param_id_C, true);
} else if (ind) {
@@ -130,7 +130,7 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const
os << " ";
os << format_name (dev.device_class ()->name ());
}
- os << format_params (dev, db::DeviceClassInductor::param_id_L);
+ os << format_params (dev, db::DeviceClassInductor::param_id_L, true);
} else if (res || res3) {
@@ -143,7 +143,7 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const
os << " ";
os << format_name (dev.device_class ()->name ());
}
- os << format_params (dev, db::DeviceClassResistor::param_id_R);
+ os << format_params (dev, db::DeviceClassResistor::param_id_R, true);
} else if (diode) {
@@ -212,13 +212,13 @@ std::string NetlistSpiceWriterDelegate::format_terminals (const db::Device &dev,
return os.str ();
}
-std::string NetlistSpiceWriterDelegate::format_params (const db::Device &dev, size_t without_id) const
+std::string NetlistSpiceWriterDelegate::format_params (const db::Device &dev, size_t without_id, bool only_primary) const
{
std::ostringstream os;
const std::vector &pd = dev.device_class ()->parameter_definitions ();
for (std::vector::const_iterator i = pd.begin (); i != pd.end (); ++i) {
- if (i->id () != without_id) {
+ if (i->id () != without_id && (! only_primary || i->is_primary ())) {
double sis = i->si_scaling ();
os << " " << i->name () << "=";
// for compatibility
diff --git a/src/db/db/dbNetlistSpiceWriter.h b/src/db/db/dbNetlistSpiceWriter.h
index bb47b6ba8..d3dcc35d1 100644
--- a/src/db/db/dbNetlistSpiceWriter.h
+++ b/src/db/db/dbNetlistSpiceWriter.h
@@ -63,7 +63,7 @@ public:
void emit_comment (const std::string &comment) const;
std::string format_name (const std::string &s) const;
std::string format_terminals (const db::Device &dev, size_t max_terminals = std::numeric_limits::max ()) const;
- std::string format_params (const db::Device &dev, size_t without_id = std::numeric_limits::max ()) const;
+ std::string format_params (const db::Device &dev, size_t without_id = std::numeric_limits::max (), bool only_primary = false) const;
private:
friend class NetlistSpiceWriter;
diff --git a/src/lay/lay/doc/about/drc_ref_global.xml b/src/lay/lay/doc/about/drc_ref_global.xml
index ef4aa3e2c..917ada706 100644
--- a/src/lay/lay/doc/about/drc_ref_global.xml
+++ b/src/lay/lay/doc/about/drc_ref_global.xml
@@ -107,6 +107,7 @@ See Layer#drc, Usage:
- bjt3(name)
+- bjt3(name, class)
Use this class with extract_devices to specify extraction of a
@@ -120,6 +121,7 @@ about this extractor.
Usage:
- bjt4(name)
+- bjt4(name, class)
Use this class with extract_devices to specify extraction of a
@@ -143,6 +145,7 @@ This function creates a box object. The arguments are the same than for the
Usage:
- capacitor(name, area_cap)
+- capacitor(name, area_cap, class)
Use this class with extract_devices to specify extraction of a capacitor.
@@ -156,6 +159,7 @@ about this extractor.
Usage:
- capacitor_with_bulk(name, area_cap)
+- capacitor_with_bulk(name, area_cap, class)
Use this class with extract_devices to specify extraction of a capacitor
@@ -442,6 +446,7 @@ See Netter#device_scaling
Usage:
- diode(name)
+- diode(name, class)
Use this class with extract_devices to specify extraction of a
@@ -455,6 +460,7 @@ about this extractor.
Usage:
- dmos3(name)
+- dmos3(name, class)
Use this class with extract_devices to specify extraction of a
@@ -470,6 +476,7 @@ about this extractor (strict mode applies for 'dmos3').
Usage:
- dmos4(name)
+- dmos4(name, class)
Use this class with extract_devices to specify extraction of a
@@ -1054,6 +1061,7 @@ argument, "middle" represents the bounding box center marker generator on primar
Usage:
- mos3(name)
+- mos3(name, class)
Use this class with extract_devices to specify extraction of a
@@ -1067,6 +1075,7 @@ about this extractor (non-strict mode applies for 'mos3').
Usage:
- mos4(name)
+- mos4(name, class)
Use this class with extract_devices to specify extraction of a
@@ -1402,6 +1411,7 @@ version of the L2N DB format will be used.
Usage:
- resistor(name, sheet_rho)
+- resistor(name, sheet_rho, class)
Use this class with extract_devices to specify extraction of a resistor.
@@ -1417,6 +1427,7 @@ about this extractor.
Usage:
- resistor_with_bulk(name, sheet_rho)
+- resistor_with_bulk(name, sheet_rho, class)
Use this class with extract_devices to specify extraction of a resistor
@@ -1922,6 +1933,7 @@ shape.
Usage:
- write_spice([ use_net_names [, with_comments ] ])
+- write_spice(writer_delegate [, use_net_names [, with_comments ] ])
Use this option in target_netlist for the format parameter to
@@ -1929,5 +1941,8 @@ specify SPICE format.
"use_net_names" and "with_comments" are boolean parameters indicating
whether to use named nets (numbers if false) and whether to add
information comments such as instance coordinates or pin names.
+
+"writer_delegate" allows using a NetlistSpiceWriterDelegate object to
+control the actual writing.
diff --git a/src/lay/lay/doc/about/drc_ref_layer.xml b/src/lay/lay/doc/about/drc_ref_layer.xml
index 9c2e565dc..d41750cfc 100644
--- a/src/lay/lay/doc/about/drc_ref_layer.xml
+++ b/src/lay/lay/doc/about/drc_ref_layer.xml
@@ -3334,7 +3334,7 @@ The tile size must be specified with the "tile_size" option:
# reports areas where layer 1/0 density is below 10% on 20x20 um tiles
-low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um))
+low_density = input(1, 0).with_density(0.0 .. 0.1, tile_size(20.um))
Anisotropic tiles can be specified by giving two values, like "tile_size(10.um, 20.um)".
@@ -3348,7 +3348,7 @@ in increments of the tile step:
# reports areas where layer 1/0 density is below 10% on 30x30 um tiles
# with a tile step of 20x20 um:
-low_density = input(1, 0).density(0.0 .. 0.1, tile_size(30.um), tile_step(20.um))
+low_density = input(1, 0).with_density(0.0 .. 0.1, tile_size(30.um), tile_step(20.um))
For "tile_step", anisotropic values can be given as well by using two values: the first for the
@@ -3366,7 +3366,7 @@ drawn boundary layer. To specify a separate, additional layer included in the bo
# reports density of layer 1/0 below 10% on 20x20 um tiles. The layout's boundary is taken from
# layer 0/0:
cell_frame = input(0, 0)
-low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um), tile_boundary(cell_frame))
+low_density = input(1, 0).with_density(0.0 .. 0.1, tile_size(20.um), tile_boundary(cell_frame))
Note that the layer given in "tile_boundary" adds to the input layer for computing the bounding box.
@@ -3378,7 +3378,7 @@ direction. With the "tile_origin" option this allows full control over the area
# reports density of layer 1/0 below 10% on 20x20 um tiles in the region 0,0 .. 2000,3000
# (100 and 150 tiles of 20 um each are used in horizontal and vertical direction):
-low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um), tile_origin(0.0, 0.0), tile_count(100, 150))
+low_density = input(1, 0).with_density(0.0 .. 0.1, tile_size(20.um), tile_origin(0.0, 0.0), tile_count(100, 150))
The "padding mode" indicates how the area outside the layout's bounding box is considered.
@@ -3392,7 +3392,7 @@ There are two modes:
Example:
-low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um), padding_ignore)
+low_density = input(1, 0).with_density(0.0 .. 0.1, tile_size(20.um), padding_ignore)
The complementary version of "with_density" is without_density.
diff --git a/src/lay/lay/doc/about/drc_ref_netter.xml b/src/lay/lay/doc/about/drc_ref_netter.xml
index 8e8cf429d..999473569 100644
--- a/src/lay/lay/doc/about/drc_ref_netter.xml
+++ b/src/lay/lay/doc/about/drc_ref_netter.xml
@@ -386,6 +386,9 @@ gate = nactive & poly # gate area
extract_devices(mos4("NMOS4"), { :SD => nsd, :G => gate, :P => poly, :W => bulk })
+
+The return value of this method will be the device class of the devices
+generated in the extraction step (see DeviceClass).
"l2n_data" - Gets the internal LayoutToNetlist object
diff --git a/testdata/algo/nwriter10_au.txt b/testdata/algo/nwriter10_au.txt
index aa10b2295..ac5e9c375 100644
--- a/testdata/algo/nwriter10_au.txt
+++ b/testdata/algo/nwriter10_au.txt
@@ -210,204 +210,204 @@
* net 100 n99
* net 101 n100
* device instance $1 r0 *1 0,0
-R$1 1 2 0 L=0U W=0U A=0P P=0U
+R$1 1 2 0
* device instance $2 r0 *1 0,0
-R$2 1 3 0 L=0U W=0U A=0P P=0U
+R$2 1 3 0
* device instance $3 r0 *1 0,0
-R$3 1 4 0 L=0U W=0U A=0P P=0U
+R$3 1 4 0
* device instance $4 r0 *1 0,0
-R$4 1 5 0 L=0U W=0U A=0P P=0U
+R$4 1 5 0
* device instance $5 r0 *1 0,0
-R$5 1 6 0 L=0U W=0U A=0P P=0U
+R$5 1 6 0
* device instance $6 r0 *1 0,0
-R$6 1 7 0 L=0U W=0U A=0P P=0U
+R$6 1 7 0
* device instance $7 r0 *1 0,0
-R$7 1 8 0 L=0U W=0U A=0P P=0U
+R$7 1 8 0
* device instance $8 r0 *1 0,0
-R$8 1 9 0 L=0U W=0U A=0P P=0U
+R$8 1 9 0
* device instance $9 r0 *1 0,0
-R$9 1 10 0 L=0U W=0U A=0P P=0U
+R$9 1 10 0
* device instance $10 r0 *1 0,0
-R$10 1 11 0 L=0U W=0U A=0P P=0U
+R$10 1 11 0
* device instance $11 r0 *1 0,0
-R$11 1 12 0 L=0U W=0U A=0P P=0U
+R$11 1 12 0
* device instance $12 r0 *1 0,0
-R$12 1 13 0 L=0U W=0U A=0P P=0U
+R$12 1 13 0
* device instance $13 r0 *1 0,0
-R$13 1 14 0 L=0U W=0U A=0P P=0U
+R$13 1 14 0
* device instance $14 r0 *1 0,0
-R$14 1 15 0 L=0U W=0U A=0P P=0U
+R$14 1 15 0
* device instance $15 r0 *1 0,0
-R$15 1 16 0 L=0U W=0U A=0P P=0U
+R$15 1 16 0
* device instance $16 r0 *1 0,0
-R$16 1 17 0 L=0U W=0U A=0P P=0U
+R$16 1 17 0
* device instance $17 r0 *1 0,0
-R$17 1 18 0 L=0U W=0U A=0P P=0U
+R$17 1 18 0
* device instance $18 r0 *1 0,0
-R$18 1 19 0 L=0U W=0U A=0P P=0U
+R$18 1 19 0
* device instance $19 r0 *1 0,0
-R$19 1 20 0 L=0U W=0U A=0P P=0U
+R$19 1 20 0
* device instance $20 r0 *1 0,0
-R$20 1 21 0 L=0U W=0U A=0P P=0U
+R$20 1 21 0
* device instance $21 r0 *1 0,0
-R$21 1 22 0 L=0U W=0U A=0P P=0U
+R$21 1 22 0
* device instance $22 r0 *1 0,0
-R$22 1 23 0 L=0U W=0U A=0P P=0U
+R$22 1 23 0
* device instance $23 r0 *1 0,0
-R$23 1 24 0 L=0U W=0U A=0P P=0U
+R$23 1 24 0
* device instance $24 r0 *1 0,0
-R$24 1 25 0 L=0U W=0U A=0P P=0U
+R$24 1 25 0
* device instance $25 r0 *1 0,0
-R$25 1 26 0 L=0U W=0U A=0P P=0U
+R$25 1 26 0
* device instance $26 r0 *1 0,0
-R$26 1 27 0 L=0U W=0U A=0P P=0U
+R$26 1 27 0
* device instance $27 r0 *1 0,0
-R$27 1 28 0 L=0U W=0U A=0P P=0U
+R$27 1 28 0
* device instance $28 r0 *1 0,0
-R$28 1 29 0 L=0U W=0U A=0P P=0U
+R$28 1 29 0
* device instance $29 r0 *1 0,0
-R$29 1 30 0 L=0U W=0U A=0P P=0U
+R$29 1 30 0
* device instance $30 r0 *1 0,0
-R$30 1 31 0 L=0U W=0U A=0P P=0U
+R$30 1 31 0
* device instance $31 r0 *1 0,0
-R$31 1 32 0 L=0U W=0U A=0P P=0U
+R$31 1 32 0
* device instance $32 r0 *1 0,0
-R$32 1 33 0 L=0U W=0U A=0P P=0U
+R$32 1 33 0
* device instance $33 r0 *1 0,0
-R$33 1 34 0 L=0U W=0U A=0P P=0U
+R$33 1 34 0
* device instance $34 r0 *1 0,0
-R$34 1 35 0 L=0U W=0U A=0P P=0U
+R$34 1 35 0
* device instance $35 r0 *1 0,0
-R$35 1 36 0 L=0U W=0U A=0P P=0U
+R$35 1 36 0
* device instance $36 r0 *1 0,0
-R$36 1 37 0 L=0U W=0U A=0P P=0U
+R$36 1 37 0
* device instance $37 r0 *1 0,0
-R$37 1 38 0 L=0U W=0U A=0P P=0U
+R$37 1 38 0
* device instance $38 r0 *1 0,0
-R$38 1 39 0 L=0U W=0U A=0P P=0U
+R$38 1 39 0
* device instance $39 r0 *1 0,0
-R$39 1 40 0 L=0U W=0U A=0P P=0U
+R$39 1 40 0
* device instance $40 r0 *1 0,0
-R$40 1 41 0 L=0U W=0U A=0P P=0U
+R$40 1 41 0
* device instance $41 r0 *1 0,0
-R$41 1 42 0 L=0U W=0U A=0P P=0U
+R$41 1 42 0
* device instance $42 r0 *1 0,0
-R$42 1 43 0 L=0U W=0U A=0P P=0U
+R$42 1 43 0
* device instance $43 r0 *1 0,0
-R$43 1 44 0 L=0U W=0U A=0P P=0U
+R$43 1 44 0
* device instance $44 r0 *1 0,0
-R$44 1 45 0 L=0U W=0U A=0P P=0U
+R$44 1 45 0
* device instance $45 r0 *1 0,0
-R$45 1 46 0 L=0U W=0U A=0P P=0U
+R$45 1 46 0
* device instance $46 r0 *1 0,0
-R$46 1 47 0 L=0U W=0U A=0P P=0U
+R$46 1 47 0
* device instance $47 r0 *1 0,0
-R$47 1 48 0 L=0U W=0U A=0P P=0U
+R$47 1 48 0
* device instance $48 r0 *1 0,0
-R$48 1 49 0 L=0U W=0U A=0P P=0U
+R$48 1 49 0
* device instance $49 r0 *1 0,0
-R$49 1 50 0 L=0U W=0U A=0P P=0U
+R$49 1 50 0
* device instance $50 r0 *1 0,0
-R$50 1 51 0 L=0U W=0U A=0P P=0U
+R$50 1 51 0
* device instance $51 r0 *1 0,0
-R$51 1 52 0 L=0U W=0U A=0P P=0U
+R$51 1 52 0
* device instance $52 r0 *1 0,0
-R$52 1 53 0 L=0U W=0U A=0P P=0U
+R$52 1 53 0
* device instance $53 r0 *1 0,0
-R$53 1 54 0 L=0U W=0U A=0P P=0U
+R$53 1 54 0
* device instance $54 r0 *1 0,0
-R$54 1 55 0 L=0U W=0U A=0P P=0U
+R$54 1 55 0
* device instance $55 r0 *1 0,0
-R$55 1 56 0 L=0U W=0U A=0P P=0U
+R$55 1 56 0
* device instance $56 r0 *1 0,0
-R$56 1 57 0 L=0U W=0U A=0P P=0U
+R$56 1 57 0
* device instance $57 r0 *1 0,0
-R$57 1 58 0 L=0U W=0U A=0P P=0U
+R$57 1 58 0
* device instance $58 r0 *1 0,0
-R$58 1 59 0 L=0U W=0U A=0P P=0U
+R$58 1 59 0
* device instance $59 r0 *1 0,0
-R$59 1 60 0 L=0U W=0U A=0P P=0U
+R$59 1 60 0
* device instance $60 r0 *1 0,0
-R$60 1 61 0 L=0U W=0U A=0P P=0U
+R$60 1 61 0
* device instance $61 r0 *1 0,0
-R$61 1 62 0 L=0U W=0U A=0P P=0U
+R$61 1 62 0
* device instance $62 r0 *1 0,0
-R$62 1 63 0 L=0U W=0U A=0P P=0U
+R$62 1 63 0
* device instance $63 r0 *1 0,0
-R$63 1 64 0 L=0U W=0U A=0P P=0U
+R$63 1 64 0
* device instance $64 r0 *1 0,0
-R$64 1 65 0 L=0U W=0U A=0P P=0U
+R$64 1 65 0
* device instance $65 r0 *1 0,0
-R$65 1 66 0 L=0U W=0U A=0P P=0U
+R$65 1 66 0
* device instance $66 r0 *1 0,0
-R$66 1 67 0 L=0U W=0U A=0P P=0U
+R$66 1 67 0
* device instance $67 r0 *1 0,0
-R$67 1 68 0 L=0U W=0U A=0P P=0U
+R$67 1 68 0
* device instance $68 r0 *1 0,0
-R$68 1 69 0 L=0U W=0U A=0P P=0U
+R$68 1 69 0
* device instance $69 r0 *1 0,0
-R$69 1 70 0 L=0U W=0U A=0P P=0U
+R$69 1 70 0
* device instance $70 r0 *1 0,0
-R$70 1 71 0 L=0U W=0U A=0P P=0U
+R$70 1 71 0
* device instance $71 r0 *1 0,0
-R$71 1 72 0 L=0U W=0U A=0P P=0U
+R$71 1 72 0
* device instance $72 r0 *1 0,0
-R$72 1 73 0 L=0U W=0U A=0P P=0U
+R$72 1 73 0
* device instance $73 r0 *1 0,0
-R$73 1 74 0 L=0U W=0U A=0P P=0U
+R$73 1 74 0
* device instance $74 r0 *1 0,0
-R$74 1 75 0 L=0U W=0U A=0P P=0U
+R$74 1 75 0
* device instance $75 r0 *1 0,0
-R$75 1 76 0 L=0U W=0U A=0P P=0U
+R$75 1 76 0
* device instance $76 r0 *1 0,0
-R$76 1 77 0 L=0U W=0U A=0P P=0U
+R$76 1 77 0
* device instance $77 r0 *1 0,0
-R$77 1 78 0 L=0U W=0U A=0P P=0U
+R$77 1 78 0
* device instance $78 r0 *1 0,0
-R$78 1 79 0 L=0U W=0U A=0P P=0U
+R$78 1 79 0
* device instance $79 r0 *1 0,0
-R$79 1 80 0 L=0U W=0U A=0P P=0U
+R$79 1 80 0
* device instance $80 r0 *1 0,0
-R$80 1 81 0 L=0U W=0U A=0P P=0U
+R$80 1 81 0
* device instance $81 r0 *1 0,0
-R$81 1 82 0 L=0U W=0U A=0P P=0U
+R$81 1 82 0
* device instance $82 r0 *1 0,0
-R$82 1 83 0 L=0U W=0U A=0P P=0U
+R$82 1 83 0
* device instance $83 r0 *1 0,0
-R$83 1 84 0 L=0U W=0U A=0P P=0U
+R$83 1 84 0
* device instance $84 r0 *1 0,0
-R$84 1 85 0 L=0U W=0U A=0P P=0U
+R$84 1 85 0
* device instance $85 r0 *1 0,0
-R$85 1 86 0 L=0U W=0U A=0P P=0U
+R$85 1 86 0
* device instance $86 r0 *1 0,0
-R$86 1 87 0 L=0U W=0U A=0P P=0U
+R$86 1 87 0
* device instance $87 r0 *1 0,0
-R$87 1 88 0 L=0U W=0U A=0P P=0U
+R$87 1 88 0
* device instance $88 r0 *1 0,0
-R$88 1 89 0 L=0U W=0U A=0P P=0U
+R$88 1 89 0
* device instance $89 r0 *1 0,0
-R$89 1 90 0 L=0U W=0U A=0P P=0U
+R$89 1 90 0
* device instance $90 r0 *1 0,0
-R$90 1 91 0 L=0U W=0U A=0P P=0U
+R$90 1 91 0
* device instance $91 r0 *1 0,0
-R$91 1 92 0 L=0U W=0U A=0P P=0U
+R$91 1 92 0
* device instance $92 r0 *1 0,0
-R$92 1 93 0 L=0U W=0U A=0P P=0U
+R$92 1 93 0
* device instance $93 r0 *1 0,0
-R$93 1 94 0 L=0U W=0U A=0P P=0U
+R$93 1 94 0
* device instance $94 r0 *1 0,0
-R$94 1 95 0 L=0U W=0U A=0P P=0U
+R$94 1 95 0
* device instance $95 r0 *1 0,0
-R$95 1 96 0 L=0U W=0U A=0P P=0U
+R$95 1 96 0
* device instance $96 r0 *1 0,0
-R$96 1 97 0 L=0U W=0U A=0P P=0U
+R$96 1 97 0
* device instance $97 r0 *1 0,0
-R$97 1 98 0 L=0U W=0U A=0P P=0U
+R$97 1 98 0
* device instance $98 r0 *1 0,0
-R$98 1 99 0 L=0U W=0U A=0P P=0U
+R$98 1 99 0
* device instance $99 r0 *1 0,0
-R$99 1 100 0 L=0U W=0U A=0P P=0U
+R$99 1 100 0
* device instance $100 r0 *1 0,0
-R$100 1 101 0 L=0U W=0U A=0P P=0U
+R$100 1 101 0
.ENDS
+ C1withaverylongextensionthatgoesbeyondmultiplelinesunlessipasteeverythingtogetherwhichmakesithardtoreadbutexactlythatisthereasonwhyiwriteitthisway
diff --git a/testdata/algo/nwriter1_au.txt b/testdata/algo/nwriter1_au.txt
index 323993f8f..7143b54b5 100644
--- a/testdata/algo/nwriter1_au.txt
+++ b/testdata/algo/nwriter1_au.txt
@@ -8,7 +8,7 @@
* net 2 n2
* net 3 n3
* device instance $1 r0 *1 0,0 RCLS
-R$1 1 3 1.7 RCLS L=0U W=0U A=0P P=0U
+R$1 1 3 1.7 RCLS
* device instance $2 r0 *1 0,0 RCLS
-R$2 3 2 4.2e-05 RCLS L=0U W=0U A=0P P=0U
+R$2 3 2 4.2e-05 RCLS
.ENDS C1
diff --git a/testdata/algo/nwriter1b_au.txt b/testdata/algo/nwriter1b_au.txt
index a43f876dc..64dd13407 100644
--- a/testdata/algo/nwriter1b_au.txt
+++ b/testdata/algo/nwriter1b_au.txt
@@ -8,7 +8,7 @@
* net 2 n2
* net 3 n3
* device instance $1 r0 *1 0,0 RCLS
-R$1 1 3 3 1.7 RCLS L=0U W=0U A=0P P=0U
+R$1 1 3 3 1.7 RCLS
* device instance $2 r0 *1 0,0 RCLS
-R$2 3 2 3 4.2e-05 RCLS L=0U W=0U A=0P P=0U
+R$2 3 2 3 4.2e-05 RCLS
.ENDS C1
diff --git a/testdata/algo/nwriter20_au.txt b/testdata/algo/nwriter20_au.txt
index 8f9c1b5a3..acb7efa2e 100644
--- a/testdata/algo/nwriter20_au.txt
+++ b/testdata/algo/nwriter20_au.txt
@@ -16,10 +16,10 @@
* net 3 n3
* device instance $1 r0 *1 0,0 RCLS
*** Before device $1
-R$1 1 3 1.7 RCLS L=0U W=0U A=0P P=0U
+R$1 1 3 1.7 RCLS
*** After device $1
* device instance $2 r0 *1 0,0 RCLS
*** Before device $2
-R$2 3 2 4.2e-05 RCLS L=0U W=0U A=0P P=0U
+R$2 3 2 4.2e-05 RCLS
*** After device $2
.ENDS C1
diff --git a/testdata/algo/nwriter2_au.txt b/testdata/algo/nwriter2_au.txt
index 80ad5dd94..3194cc9d7 100644
--- a/testdata/algo/nwriter2_au.txt
+++ b/testdata/algo/nwriter2_au.txt
@@ -8,7 +8,7 @@
* net 2 n2
* net 3 n3
* device instance $1 r0 *1 0,0 CCLS
-C$1 1 3 1.7e-12 CCLS A=0P P=0U
+C$1 1 3 1.7e-12 CCLS
* device instance $2 r0 *1 0,0 CCLS
-C$2 3 2 4.2e-14 CCLS A=0P P=0U
+C$2 3 2 4.2e-14 CCLS
.ENDS C1
diff --git a/testdata/algo/nwriter2b_au.txt b/testdata/algo/nwriter2b_au.txt
index 00bfce2b2..9ef04cbc3 100644
--- a/testdata/algo/nwriter2b_au.txt
+++ b/testdata/algo/nwriter2b_au.txt
@@ -8,7 +8,7 @@
* net 2 n2
* net 3 n3
* device instance $1 r0 *1 0,0
-C$1 1 3 1.7e-12 A=0P P=0U
+C$1 1 3 1.7e-12
* device instance $2 r0 *1 0,0
-C$2 3 2 4.2e-14 A=0P P=0U
+C$2 3 2 4.2e-14
.ENDS C1
diff --git a/testdata/algo/nwriter2c_au.txt b/testdata/algo/nwriter2c_au.txt
index 81dcb999e..59ea73fc8 100644
--- a/testdata/algo/nwriter2c_au.txt
+++ b/testdata/algo/nwriter2c_au.txt
@@ -8,7 +8,7 @@
* net 2 n2
* net 3 n3
* device instance $1 r0 *1 0,0 CCLS
-C$1 1 3 3 1.7e-12 CCLS A=0P P=0U
+C$1 1 3 3 1.7e-12 CCLS
* device instance $2 r0 *1 0,0 CCLS
-C$2 3 2 3 4.2e-14 CCLS A=0P P=0U
+C$2 3 2 3 4.2e-14 CCLS
.ENDS C1
diff --git a/testdata/algo/nwriter2d_au.txt b/testdata/algo/nwriter2d_au.txt
index cafcedb5a..bb22ba84a 100644
--- a/testdata/algo/nwriter2d_au.txt
+++ b/testdata/algo/nwriter2d_au.txt
@@ -8,7 +8,7 @@
* net 2 n2
* net 3 n3
* device instance $1 r0 *1 0,0
-C$1 1 3 3 1.7e-12 A=0P P=0U
+C$1 1 3 3 1.7e-12
* device instance $2 r0 *1 0,0
-C$2 3 2 3 4.2e-14 A=0P P=0U
+C$2 3 2 3 4.2e-14
.ENDS C1
diff --git a/testdata/lvs/custom_compare.cir b/testdata/lvs/custom_compare.cir
index a078c8c9b..e558a4c04 100644
--- a/testdata/lvs/custom_compare.cir
+++ b/testdata/lvs/custom_compare.cir
@@ -3,5 +3,5 @@
* cell TOP
.SUBCKT TOP
* device instance $1 r0 *1 7.52,4.175 RES
-R$1 2 1 51 RES L=12.75U W=0.25U A=3.1875P P=26U
+R$1 2 1 51 RES
.ENDS TOP
diff --git a/testdata/lvs/enable_wl2.cir b/testdata/lvs/enable_wl2.cir
index 5ce133250..d668c488e 100644
--- a/testdata/lvs/enable_wl2.cir
+++ b/testdata/lvs/enable_wl2.cir
@@ -7,5 +7,5 @@
* net 1 gnd!
* net 2 vdd!
* device instance $1 r0 *1 8.43,1.51 RR1
-R$1 1 2 10 RR1 L=6U W=0.6U A=3.6P P=13.2U
+R$1 1 2 10 RR1 L=6U W=0.6U
.ENDS Rre
diff --git a/testdata/lvs/enable_wl3.cir b/testdata/lvs/enable_wl3.cir
index 5ce133250..d668c488e 100644
--- a/testdata/lvs/enable_wl3.cir
+++ b/testdata/lvs/enable_wl3.cir
@@ -7,5 +7,5 @@
* net 1 gnd!
* net 2 vdd!
* device instance $1 r0 *1 8.43,1.51 RR1
-R$1 1 2 10 RR1 L=6U W=0.6U A=3.6P P=13.2U
+R$1 1 2 10 RR1 L=6U W=0.6U
.ENDS Rre
From 8f65ab099f9745f604071348c01173f519bc78ba Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Tue, 6 Jul 2021 07:56:27 +0200
Subject: [PATCH 18/19] Fixed DeviceClass assignment operator
---
src/db/db/dbDeviceClass.cc | 15 +-
src/db/db/dbDeviceClass.h | 122 ++++-
src/db/db/dbNetlistDeviceClasses.cc | 779 ++++++++++++++++------------
src/db/db/dbNetlistDeviceClasses.h | 75 +--
src/db/db/gsiDeclDbNetlist.cc | 238 ++++++---
testdata/ruby/dbNetlist.rb | 14 +-
6 files changed, 710 insertions(+), 533 deletions(-)
diff --git a/src/db/db/dbDeviceClass.cc b/src/db/db/dbDeviceClass.cc
index c51933143..4c27c7409 100644
--- a/src/db/db/dbDeviceClass.cc
+++ b/src/db/db/dbDeviceClass.cc
@@ -120,11 +120,6 @@ public:
virtual bool less (const db::Device &a, const db::Device &b) const;
- virtual DeviceParameterCompareDelegate *clone () const
- {
- return new PrimaryDeviceParametersAreEqual (*this);
- }
-
private:
double m_relative;
};
@@ -159,13 +154,13 @@ bool PrimaryDeviceParametersAreEqual::less (const db::Device &a, const db::Devic
// DeviceClass class implementation
DeviceClass::DeviceClass ()
- : m_strict (false), mp_netlist (0)
+ : m_strict (false), mp_netlist (0), m_supports_parallel_combination (false), m_supports_serial_combination (false)
{
// .. nothing yet ..
}
DeviceClass::DeviceClass (const DeviceClass &other)
- : gsi::ObjectBase (other), tl::Object (other), tl::UniqueId (other), m_strict (false), mp_netlist (0)
+ : gsi::ObjectBase (other), tl::Object (other), tl::UniqueId (other), m_strict (false), mp_netlist (0), m_supports_parallel_combination (false), m_supports_serial_combination (false)
{
operator= (other);
}
@@ -173,12 +168,18 @@ DeviceClass::DeviceClass (const DeviceClass &other)
DeviceClass &DeviceClass::operator= (const DeviceClass &other)
{
if (this != &other) {
+
m_terminal_definitions = other.m_terminal_definitions;
m_parameter_definitions = other.m_parameter_definitions;
m_name = other.m_name;
m_description = other.m_description;
m_strict = other.m_strict;
mp_pc_delegate.reset (const_cast (other.mp_pc_delegate.get ()));
+ mp_device_combiner.reset (const_cast (other.mp_device_combiner.get ()));
+ m_supports_serial_combination = other.m_supports_serial_combination;
+ m_supports_parallel_combination = other.m_supports_parallel_combination;
+ m_equivalent_terminal_ids = other.m_equivalent_terminal_ids;
+
}
return *this;
}
diff --git a/src/db/db/dbDeviceClass.h b/src/db/db/dbDeviceClass.h
index 01e8dc06e..a6306cdf8 100644
--- a/src/db/db/dbDeviceClass.h
+++ b/src/db/db/dbDeviceClass.h
@@ -295,7 +295,6 @@ public:
DeviceParameterCompareDelegate () { }
virtual ~DeviceParameterCompareDelegate () { }
- virtual DeviceParameterCompareDelegate *clone () const = 0;
virtual bool less (const db::Device &a, const db::Device &b) const = 0;
};
@@ -315,11 +314,6 @@ public:
virtual bool less (const db::Device &a, const db::Device &b) const;
- virtual DeviceParameterCompareDelegate *clone () const
- {
- return new EqualDeviceParameters (*this);
- }
-
EqualDeviceParameters &operator+= (const EqualDeviceParameters &other);
EqualDeviceParameters operator+ (const EqualDeviceParameters &other) const
@@ -344,15 +338,35 @@ public:
virtual bool less (const db::Device &a, const db::Device &b) const;
- virtual DeviceParameterCompareDelegate *clone () const
- {
- return new AllDeviceParametersAreEqual (*this);
- }
-
private:
double m_relative;
};
+/**
+ * @brief A device combiner
+ *
+ * The device combiner is a delegate that combines devices
+ */
+class DB_PUBLIC DeviceCombiner
+ : public gsi::ObjectBase, public tl::Object
+{
+public:
+ DeviceCombiner () { }
+ virtual ~DeviceCombiner () { }
+
+ /**
+ * @brief Combines two devices
+ *
+ * This method shall test, whether the two devices can be combined. Both devices
+ * are guaranteed to share the same device class.
+ * If they cannot be combined, this method shall do nothing and return false.
+ * If they can be combined, this method shall reconnect the nets of the first
+ * device and entirely disconnect the nets of the second device.
+ * The second device will be deleted afterwards.
+ */
+ virtual bool combine_devices (db::Device *a, db::Device *b) const = 0;
+};
+
/**
* @brief A device class
*
@@ -553,25 +567,57 @@ public:
* device and entirely disconnect the nets of the second device.
* The second device will be deleted afterwards.
*/
- virtual bool combine_devices (db::Device * /*a*/, db::Device * /*b*/) const
+ bool combine_devices (db::Device *a, db::Device *b) const
{
- return false;
+ return mp_device_combiner.get () ? mp_device_combiner->combine_devices (a, b) : false;
}
/**
* @brief Returns true if the device class supports device combination in parallel mode
*/
- virtual bool supports_parallel_combination () const
+ bool supports_parallel_combination () const
{
- return false;
+ return m_supports_parallel_combination;
}
/**
* @brief Returns true if the device class supports device combination in serial mode
*/
- virtual bool supports_serial_combination () const
+ bool supports_serial_combination () const
{
- return false;
+ return m_supports_serial_combination;
+ }
+
+ /**
+ * @brief Sets a value indicating that the class supports device combination in parallel mode
+ */
+ void set_supports_parallel_combination (bool f)
+ {
+ m_supports_parallel_combination = f;
+ }
+
+ /**
+ * @brief Sets a value indicating that the class supports device combination in serial mode
+ */
+ void set_supports_serial_combination (bool f)
+ {
+ m_supports_serial_combination = f;
+ }
+
+ /**
+ * @brief Marks two terminals as equivalent (swappable)
+ */
+ void equivalent_terminal_id (size_t tid, size_t equiv_tid)
+ {
+ m_equivalent_terminal_ids.insert (std::make_pair (tid, equiv_tid));
+ }
+
+ /**
+ * @brief Clears all equivalent terminal ids
+ */
+ void clear_equivalent_terminal_ids ()
+ {
+ m_equivalent_terminal_ids.clear ();
}
/**
@@ -580,9 +626,14 @@ public:
* This method returns a "normalized" terminal ID. For example, for MOS
* transistors where S and D can be exchanged, D will be mapped to S.
*/
- virtual size_t normalize_terminal_id (size_t tid) const
+ size_t normalize_terminal_id (size_t tid) const
{
- return tid;
+ std::map::const_iterator ntid = m_equivalent_terminal_ids.find (tid);
+ if (ntid != m_equivalent_terminal_ids.end ()) {
+ return ntid->second;
+ } else {
+ return tid;
+ }
}
/**
@@ -643,6 +694,35 @@ public:
return mp_pc_delegate.get ();
}
+ /**
+ * @brief Registers a device combiner
+ *
+ * The device class takes ownership of the combiner.
+ */
+ void set_device_combiner (db::DeviceCombiner *combiner)
+ {
+ if (combiner) {
+ combiner->keep (); // assume transfer of ownership for scripts
+ }
+ mp_device_combiner.reset (combiner);
+ }
+
+ /**
+ * @brief Gets the device combiner or null if no such delegate is registered
+ */
+ const db::DeviceCombiner *device_combiner () const
+ {
+ return mp_device_combiner.get ();
+ }
+
+ /**
+ * @brief Gets the device combiner or null if no such delegate is registered (non-const version)
+ */
+ db::DeviceCombiner *device_combiner ()
+ {
+ return mp_device_combiner.get ();
+ }
+
/**
* @brief Generate memory statistics
*/
@@ -667,6 +747,10 @@ private:
bool m_strict;
db::Netlist *mp_netlist;
tl::shared_ptr mp_pc_delegate;
+ tl::shared_ptr mp_device_combiner;
+ bool m_supports_parallel_combination;
+ bool m_supports_serial_combination;
+ std::map m_equivalent_terminal_ids;
void set_netlist (db::Netlist *nl)
{
diff --git a/src/db/db/dbNetlistDeviceClasses.cc b/src/db/db/dbNetlistDeviceClasses.cc
index ad1fae98f..c9936e0e8 100644
--- a/src/db/db/dbNetlistDeviceClasses.cc
+++ b/src/db/db/dbNetlistDeviceClasses.cc
@@ -43,58 +43,424 @@ static tl::RegisteredClass dct_bjt4 (new db::device
// ------------------------------------------------------------------------------------
// DeviceClassTwoTerminalDevice implementation
-bool DeviceClassTwoTerminalDevice::combine_devices (Device *a, Device *b) const
+namespace
{
- db::Net *na1 = a->net_for_terminal (0);
- db::Net *na2 = a->net_for_terminal (1);
- db::Net *nb1 = b->net_for_terminal (0);
- db::Net *nb2 = b->net_for_terminal (1);
- if ((na1 == nb1 && na2 == nb2) || (na1 == nb2 && na2 == nb1)) {
+class TwoTerminalDeviceCombiner
+ : public db::DeviceCombiner
+{
+public:
+ bool combine_devices(db::Device *a, db::Device *b) const
+ {
+ db::Net *na1 = a->net_for_terminal (0);
+ db::Net *na2 = a->net_for_terminal (1);
+ db::Net *nb1 = b->net_for_terminal (0);
+ db::Net *nb2 = b->net_for_terminal (1);
- parallel (a, b);
+ if ((na1 == nb1 && na2 == nb2) || (na1 == nb2 && na2 == nb1)) {
+ parallel (a, b);
+
+ if (na1 == nb1 && na2 == nb2) {
+ a->join_terminals (0, b, 0);
+ a->join_terminals (1, b, 1);
+ } else {
+ a->join_terminals (0, b, 1);
+ a->join_terminals (1, b, 0);
+ }
+
+ return true;
+
+ } else if ((na2 == nb1 || na2 == nb2) && na2->is_internal ()) {
+
+ // serial a(B) to b(A or B)
+ serial (a, b);
+
+ if (na2 == nb1) {
+ a->reroute_terminal (1, b, 0, 1);
+ } else {
+ a->reroute_terminal (1, b, 1, 0);
+ }
+
+ return true;
+
+ } else if ((na1 == nb1 || na1 == nb2) && na1->is_internal ()) {
+
+ // serial a(A) to b(A or B)
+ serial (a, b);
+
+ if (na1 == nb1) {
+ a->reroute_terminal (0, b, 0, 1);
+ } else {
+ a->reroute_terminal (0, b, 1, 0);
+ }
+
+ return true;
+
+ } else {
+ return false;
+ }
+ }
+
+ virtual void parallel (Device *a, Device *b) const = 0;
+ virtual void serial (Device *a, Device *b) const = 0;
+};
+
+class ResistorDeviceCombiner
+ : public TwoTerminalDeviceCombiner
+{
+public:
+ void parallel (Device *a, Device *b) const
+ {
+ double va = a->parameter_value (0);
+ double vb = b->parameter_value (0);
+ a->set_parameter_value (0, va + vb < 1e-10 ? 0.0 : va * vb / (va + vb));
+
+ // parallel width is sum of both, length is the one that gives the same value of resistance
+ // R = 1/(1/R1 + 1/R2)
+ // R = L/(W1+W2)
+ // R1 = L1/W1
+ // R2 = L2/W2
+ // -> L = (L1*L2*(W1+W2))/(L2*W1+L1*W2))
+ double l1 = a->parameter_value (1);
+ double w1 = a->parameter_value (2);
+ double l2 = b->parameter_value (1);
+ double w2 = b->parameter_value (2);
+ double dnom = (l2 * w1 + l1 * w2);
+ if (fabs (dnom) > 1e-15) {
+ a->set_parameter_value (1, (l1 * l2 * (w1 + w2)) / dnom);
+ }
+ a->set_parameter_value (2, w1 + w2);
+
+ // TODO: does this implementation make sense? (area)
+ double aa = a->parameter_value (3);
+ double ab = b->parameter_value (3);
+ a->set_parameter_value (3, aa + ab);
+
+ // TODO: does this implementation make sense? (perimeter)
+ double pa = a->parameter_value (4);
+ double pb = b->parameter_value (4);
+ a->set_parameter_value (4, pa + pb);
+ }
+
+ void serial (Device *a, Device *b) const
+ {
+ double va = a->parameter_value (0);
+ double vb = b->parameter_value (0);
+ a->set_parameter_value (0, va + vb);
+
+ // parallel length is sum of both, width is the one that gives the same value of resistance
+ // assuming same sheet rho
+ // R = R1+R2
+ // R = (L1+L2)/W
+ // R1 = L1/W1
+ // R2 = L2/W2
+ // -> W = ((L1+L2)*W1*W2)/(W1*L2+W2*L1)
+ double l1 = a->parameter_value (1);
+ double w1 = a->parameter_value (2);
+ double l2 = b->parameter_value (1);
+ double w2 = b->parameter_value (2);
+ a->set_parameter_value (1, l1 + l2);
+ double dnom = (l2 * w1 + l1 * w2);
+ if (fabs (dnom) > 1e-15) {
+ a->set_parameter_value (2, (w1 * w2 * (l1 + l2)) / dnom);
+ }
+
+ double aa = a->parameter_value (3);
+ double ab = b->parameter_value (3);
+ a->set_parameter_value (3, aa + ab);
+
+ double pa = a->parameter_value (4);
+ double pb = b->parameter_value (4);
+ a->set_parameter_value (4, pa + pb);
+ }
+};
+
+class ResistorWithBulkDeviceCombiner
+ : public ResistorDeviceCombiner
+{
+public:
+ bool combine_devices (Device *a, Device *b) const
+ {
+ db::Net *nab = a->net_for_terminal (2);
+ db::Net *nbb = b->net_for_terminal (2);
+
+ if (nab == nbb && ResistorDeviceCombiner::combine_devices (a, b)) {
+ a->join_terminals (2, b, 2);
+ return true;
+ } else {
+ return false;
+ }
+ }
+};
+
+class CapacitorDeviceCombiner
+ : public TwoTerminalDeviceCombiner
+{
+public:
+ void serial (Device *a, Device *b) const
+ {
+ double va = a->parameter_value (0);
+ double vb = b->parameter_value (0);
+ a->set_parameter_value (0, va + vb < 1e-10 ? 0.0 : va * vb / (va + vb));
+
+ // TODO: does this implementation make sense?
+ double aa = a->parameter_value (1);
+ double ab = b->parameter_value (1);
+ a->set_parameter_value (1, aa + ab);
+
+ // TODO: does this implementation make sense?
+ double pa = a->parameter_value (2);
+ double pb = b->parameter_value (2);
+ a->set_parameter_value (2, pa + pb);
+ }
+
+ void parallel (Device *a, Device *b) const
+ {
+ double va = a->parameter_value (0);
+ double vb = b->parameter_value (0);
+ a->set_parameter_value (0, va + vb);
+
+ double aa = a->parameter_value (1);
+ double ab = b->parameter_value (1);
+ a->set_parameter_value (1, aa + ab);
+
+ double pa = a->parameter_value (2);
+ double pb = b->parameter_value (2);
+ a->set_parameter_value (2, pa + pb);
+ }
+};
+
+class CapacitorWithBulkDeviceCombiner
+ : public CapacitorDeviceCombiner
+{
+public:
+ bool combine_devices (Device *a, Device *b) const
+ {
+ db::Net *nab = a->net_for_terminal (2);
+ db::Net *nbb = b->net_for_terminal (2);
+
+ if (nab == nbb && CapacitorDeviceCombiner::combine_devices (a, b)) {
+ a->join_terminals (2, b, 2);
+ return true;
+ } else {
+ return false;
+ }
+ }
+};
+
+class InductorDeviceCombiner
+ : public TwoTerminalDeviceCombiner
+{
+public:
+ void parallel (Device *a, Device *b) const
+ {
+ double va = a->parameter_value (0);
+ double vb = b->parameter_value (0);
+ a->set_parameter_value (0, va + vb < 1e-10 ? 0.0 : va * vb / (va + vb));
+ }
+
+ void serial (Device *a, Device *b) const
+ {
+ double va = a->parameter_value (0);
+ double vb = b->parameter_value (0);
+ a->set_parameter_value (0, va + vb);
+ }
+};
+
+class DiodeDeviceCombiner
+ : public db::DeviceCombiner
+{
+public:
+ bool combine_devices (Device *a, Device *b) const
+ {
+ const db::Net *na1 = a->net_for_terminal (0);
+ const db::Net *na2 = a->net_for_terminal (1);
+ const db::Net *nb1 = b->net_for_terminal (0);
+ const db::Net *nb2 = b->net_for_terminal (1);
+
+ // only parallel diodes can be combined and their areas will add
if (na1 == nb1 && na2 == nb2) {
+
+ a->set_parameter_value (0, a->parameter_value (0) + b->parameter_value (0));
+ a->set_parameter_value (1, a->parameter_value (1) + b->parameter_value (1));
+
a->join_terminals (0, b, 0);
a->join_terminals (1, b, 1);
+
+ return true;
+
} else {
- a->join_terminals (0, b, 1);
- a->join_terminals (1, b, 0);
+ return false;
+ }
+ }
+};
+
+class MOS3DeviceCombiner
+ : public db::DeviceCombiner
+{
+public:
+ bool combine_devices (Device *a, Device *b) const
+ {
+ const db::Net *nas = a->net_for_terminal (0);
+ const db::Net *nag = a->net_for_terminal (1);
+ const db::Net *nad = a->net_for_terminal (2);
+ const db::Net *nbs = b->net_for_terminal (0);
+ const db::Net *nbg = b->net_for_terminal (1);
+ const db::Net *nbd = b->net_for_terminal (2);
+
+ // parallel transistors can be combined into one
+ if (((nas == nbs && nad == nbd) || (nas == nbd && nad == nbs)) && nag == nbg) {
+
+ // for combination the gate length must be identical
+ if (fabs (a->parameter_value (0) - b->parameter_value (0)) < 1e-6) {
+
+ combine_parameters (a, b);
+
+ if (nas == nbs && nad == nbd) {
+ a->join_terminals (0, b, 0);
+ a->join_terminals (2, b, 2);
+ } else {
+ a->join_terminals (0, b, 2);
+ a->join_terminals (2, b, 0);
+ }
+
+ a->join_terminals (1, b, 1);
+
+ return true;
+
+ }
+
}
- return true;
-
- } else if ((na2 == nb1 || na2 == nb2) && na2->is_internal ()) {
-
- // serial a(B) to b(A or B)
- serial (a, b);
-
- if (na2 == nb1) {
- a->reroute_terminal (1, b, 0, 1);
- } else {
- a->reroute_terminal (1, b, 1, 0);
- }
-
- return true;
-
- } else if ((na1 == nb1 || na1 == nb2) && na1->is_internal ()) {
-
- // serial a(A) to b(A or B)
- serial (a, b);
-
- if (na1 == nb1) {
- a->reroute_terminal (0, b, 0, 1);
- } else {
- a->reroute_terminal (0, b, 1, 0);
- }
-
- return true;
-
- } else {
return false;
}
-}
+ void combine_parameters (Device *a, Device *b) const
+ {
+ a->set_parameter_value (1, a->parameter_value (1) + b->parameter_value (1));
+ a->set_parameter_value (2, a->parameter_value (2) + b->parameter_value (2));
+ a->set_parameter_value (3, a->parameter_value (3) + b->parameter_value (3));
+ a->set_parameter_value (4, a->parameter_value (4) + b->parameter_value (4));
+ a->set_parameter_value (5, a->parameter_value (5) + b->parameter_value (5));
+ }
+};
+
+class MOS4DeviceCombiner
+ : public MOS3DeviceCombiner
+{
+public:
+ bool combine_devices (Device *a, Device *b) const
+ {
+ const db::Net *nas = a->net_for_terminal (0);
+ const db::Net *nag = a->net_for_terminal (1);
+ const db::Net *nad = a->net_for_terminal (2);
+ const db::Net *nab = a->net_for_terminal (3);
+ const db::Net *nbs = b->net_for_terminal (0);
+ const db::Net *nbg = b->net_for_terminal (1);
+ const db::Net *nbd = b->net_for_terminal (2);
+ const db::Net *nbb = b->net_for_terminal (3);
+
+ // parallel transistors can be combined into one
+ if (((nas == nbs && nad == nbd) || (nas == nbd && nad == nbs)) && nag == nbg && nab == nbb) {
+
+ // for combination the gate length must be identical
+ if (fabs (a->parameter_value (0) - b->parameter_value (0)) < 1e-6) {
+
+ combine_parameters (a, b);
+
+ if (nas == nbs && nad == nbd) {
+ a->join_terminals (0, b, 0);
+ a->join_terminals (2, b, 2);
+ } else {
+ a->join_terminals (0, b, 2);
+ a->join_terminals (2, b, 0);
+ }
+
+ a->join_terminals (1, b, 1);
+ a->join_terminals (3, b, 3);
+
+ return true;
+
+ }
+
+ }
+
+ return false;
+ }
+};
+
+class BJT3DeviceCombiner
+ : public db::DeviceCombiner
+{
+public:
+ bool combine_devices (Device *a, Device *b) const
+ {
+ const db::Net *nac = a->net_for_terminal (0);
+ const db::Net *nab = a->net_for_terminal (1);
+ const db::Net *nae = a->net_for_terminal (2);
+ const db::Net *nbc = b->net_for_terminal (0);
+ const db::Net *nbb = b->net_for_terminal (1);
+ const db::Net *nbe = b->net_for_terminal (2);
+
+ // parallel transistors can be combined into one
+ if (nac == nbc && nae == nbe && nab == nbb) {
+
+ combine_parameters (a, b);
+
+ a->join_terminals (0, b, 0);
+ a->join_terminals (1, b, 1);
+ a->join_terminals (2, b, 2);
+
+ return true;
+
+ }
+
+ return false;
+ }
+
+ void combine_parameters (Device *a, Device *b) const
+ {
+ a->set_parameter_value (DeviceClassBJT3Transistor::param_id_AE, a->parameter_value (DeviceClassBJT3Transistor::param_id_AE) + b->parameter_value (DeviceClassBJT3Transistor::param_id_AE));
+ a->set_parameter_value (DeviceClassBJT3Transistor::param_id_PE, a->parameter_value (DeviceClassBJT3Transistor::param_id_PE) + b->parameter_value (DeviceClassBJT3Transistor::param_id_PE));
+ a->set_parameter_value (DeviceClassBJT3Transistor::param_id_NE, a->parameter_value (DeviceClassBJT3Transistor::param_id_NE) + b->parameter_value (DeviceClassBJT3Transistor::param_id_NE));
+ }
+};
+
+class BJT4DeviceCombiner
+ : public BJT3DeviceCombiner
+{
+public:
+ bool combine_devices (Device *a, Device *b) const
+ {
+ const db::Net *nac = a->net_for_terminal (0);
+ const db::Net *nab = a->net_for_terminal (1);
+ const db::Net *nae = a->net_for_terminal (2);
+ const db::Net *nas = a->net_for_terminal (3);
+ const db::Net *nbc = b->net_for_terminal (0);
+ const db::Net *nbb = b->net_for_terminal (1);
+ const db::Net *nbe = b->net_for_terminal (2);
+ const db::Net *nbs = b->net_for_terminal (3);
+
+ // parallel transistors can be combined into one
+ if (nac == nbc && nae == nbe && nab == nbb && nas == nbs) {
+
+ combine_parameters (a, b);
+
+ a->join_terminals (0, b, 0);
+ a->join_terminals (1, b, 1);
+ a->join_terminals (2, b, 2);
+ a->join_terminals (3, b, 3);
+
+ return true;
+
+ }
+
+ return false;
+ }
+};
+
+}
// ------------------------------------------------------------------------------------
// DeviceClassResistor implementation
@@ -110,8 +476,13 @@ DB_PUBLIC size_t DeviceClassResistor::terminal_id_B = 1;
DeviceClassResistor::DeviceClassResistor ()
{
+ set_supports_serial_combination (true);
+ set_supports_parallel_combination (true);
+ set_device_combiner (new ResistorDeviceCombiner ());
+
add_terminal_definition (db::DeviceTerminalDefinition ("A", "Terminal A"));
add_terminal_definition (db::DeviceTerminalDefinition ("B", "Terminal B"));
+ equivalent_terminal_id (terminal_id_A, terminal_id_B);
add_parameter_definition (db::DeviceParameterDefinition ("R", "Resistance (Ohm)", 0.0));
add_parameter_definition (db::DeviceParameterDefinition ("L", "Length (micrometer)", 0.0, false, 1e-6));
@@ -120,71 +491,6 @@ DeviceClassResistor::DeviceClassResistor ()
add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0, false, 1e-6));
}
-void DeviceClassResistor::parallel (Device *a, Device *b) const
-{
- double va = a->parameter_value (0);
- double vb = b->parameter_value (0);
- a->set_parameter_value (0, va + vb < 1e-10 ? 0.0 : va * vb / (va + vb));
-
- // parallel width is sum of both, length is the one that gives the same value of resistance
- // R = 1/(1/R1 + 1/R2)
- // R = L/(W1+W2)
- // R1 = L1/W1
- // R2 = L2/W2
- // -> L = (L1*L2*(W1+W2))/(L2*W1+L1*W2))
- double l1 = a->parameter_value (1);
- double w1 = a->parameter_value (2);
- double l2 = b->parameter_value (1);
- double w2 = b->parameter_value (2);
- double dnom = (l2 * w1 + l1 * w2);
- if (fabs (dnom) > 1e-15) {
- a->set_parameter_value (1, (l1 * l2 * (w1 + w2)) / dnom);
- }
- a->set_parameter_value (2, w1 + w2);
-
- // TODO: does this implementation make sense? (area)
- double aa = a->parameter_value (3);
- double ab = b->parameter_value (3);
- a->set_parameter_value (3, aa + ab);
-
- // TODO: does this implementation make sense? (perimeter)
- double pa = a->parameter_value (4);
- double pb = b->parameter_value (4);
- a->set_parameter_value (4, pa + pb);
-}
-
-void DeviceClassResistor::serial (Device *a, Device *b) const
-{
- double va = a->parameter_value (0);
- double vb = b->parameter_value (0);
- a->set_parameter_value (0, va + vb);
-
- // parallel length is sum of both, width is the one that gives the same value of resistance
- // assuming same sheet rho
- // R = R1+R2
- // R = (L1+L2)/W
- // R1 = L1/W1
- // R2 = L2/W2
- // -> W = ((L1+L2)*W1*W2)/(W1*L2+W2*L1)
- double l1 = a->parameter_value (1);
- double w1 = a->parameter_value (2);
- double l2 = b->parameter_value (1);
- double w2 = b->parameter_value (2);
- a->set_parameter_value (1, l1 + l2);
- double dnom = (l2 * w1 + l1 * w2);
- if (fabs (dnom) > 1e-15) {
- a->set_parameter_value (2, (w1 * w2 * (l1 + l2)) / dnom);
- }
-
- double aa = a->parameter_value (3);
- double ab = b->parameter_value (3);
- a->set_parameter_value (3, aa + ab);
-
- double pa = a->parameter_value (4);
- double pb = b->parameter_value (4);
- a->set_parameter_value (4, pa + pb);
-}
-
// ------------------------------------------------------------------------------------
// DeviceClassResistorWithBulk implementation
@@ -193,22 +499,10 @@ DB_PUBLIC size_t DeviceClassResistorWithBulk::terminal_id_W = 2;
DeviceClassResistorWithBulk::DeviceClassResistorWithBulk ()
: DeviceClassResistor ()
{
+ set_device_combiner (new ResistorWithBulkDeviceCombiner ());
add_terminal_definition (db::DeviceTerminalDefinition ("W", "Terminal W (well, bulk)"));
}
-bool DeviceClassResistorWithBulk::combine_devices (Device *a, Device *b) const
-{
- db::Net *nab = a->net_for_terminal (2);
- db::Net *nbb = b->net_for_terminal (2);
-
- if (nab == nbb && DeviceClassResistor::combine_devices (a, b)) {
- a->join_terminals (2, b, 2);
- return true;
- } else {
- return false;
- }
-}
-
// ------------------------------------------------------------------------------------
// DeviceClassCapacitor implementation
@@ -221,46 +515,19 @@ DB_PUBLIC size_t DeviceClassCapacitor::terminal_id_B = 1;
DeviceClassCapacitor::DeviceClassCapacitor ()
{
+ set_supports_serial_combination (true);
+ set_supports_parallel_combination (true);
+ set_device_combiner (new CapacitorDeviceCombiner ());
+
add_terminal_definition (db::DeviceTerminalDefinition ("A", "Terminal A"));
add_terminal_definition (db::DeviceTerminalDefinition ("B", "Terminal B"));
+ equivalent_terminal_id (terminal_id_A, terminal_id_B);
add_parameter_definition (db::DeviceParameterDefinition ("C", "Capacitance (Farad)", 0.0));
add_parameter_definition (db::DeviceParameterDefinition ("A", "Area (square micrometer)", 0.0, false, 1e-12));
add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0, false, 1e-6));
}
-void DeviceClassCapacitor::serial (Device *a, Device *b) const
-{
- double va = a->parameter_value (0);
- double vb = b->parameter_value (0);
- a->set_parameter_value (0, va + vb < 1e-10 ? 0.0 : va * vb / (va + vb));
-
- // TODO: does this implementation make sense?
- double aa = a->parameter_value (1);
- double ab = b->parameter_value (1);
- a->set_parameter_value (1, aa + ab);
-
- // TODO: does this implementation make sense?
- double pa = a->parameter_value (2);
- double pb = b->parameter_value (2);
- a->set_parameter_value (2, pa + pb);
-}
-
-void DeviceClassCapacitor::parallel (Device *a, Device *b) const
-{
- double va = a->parameter_value (0);
- double vb = b->parameter_value (0);
- a->set_parameter_value (0, va + vb);
-
- double aa = a->parameter_value (1);
- double ab = b->parameter_value (1);
- a->set_parameter_value (1, aa + ab);
-
- double pa = a->parameter_value (2);
- double pb = b->parameter_value (2);
- a->set_parameter_value (2, pa + pb);
-}
-
// ------------------------------------------------------------------------------------
// DeviceClassCapacitorWithBulk implementation
@@ -269,22 +536,10 @@ DB_PUBLIC size_t DeviceClassCapacitorWithBulk::terminal_id_W = 2;
DeviceClassCapacitorWithBulk::DeviceClassCapacitorWithBulk ()
: DeviceClassCapacitor ()
{
+ set_device_combiner (new CapacitorWithBulkDeviceCombiner ());
add_terminal_definition (db::DeviceTerminalDefinition ("W", "Terminal W (well, bulk)"));
}
-bool DeviceClassCapacitorWithBulk::combine_devices (Device *a, Device *b) const
-{
- db::Net *nab = a->net_for_terminal (2);
- db::Net *nbb = b->net_for_terminal (2);
-
- if (nab == nbb && DeviceClassCapacitor::combine_devices (a, b)) {
- a->join_terminals (2, b, 2);
- return true;
- } else {
- return false;
- }
-}
-
// ------------------------------------------------------------------------------------
// DeviceClassInductor implementation
@@ -295,28 +550,19 @@ DB_PUBLIC size_t DeviceClassInductor::terminal_id_B = 1;
DeviceClassInductor::DeviceClassInductor ()
{
+ set_supports_serial_combination (true);
+ set_supports_parallel_combination (true);
+ set_device_combiner (new InductorDeviceCombiner ());
+
add_terminal_definition (db::DeviceTerminalDefinition ("A", "Terminal A"));
add_terminal_definition (db::DeviceTerminalDefinition ("B", "Terminal B"));
+ equivalent_terminal_id (terminal_id_A, terminal_id_B);
add_parameter_definition (db::DeviceParameterDefinition ("L", "Inductance (Henry)", 0.0));
}
-void DeviceClassInductor::parallel (Device *a, Device *b) const
-{
- double va = a->parameter_value (0);
- double vb = b->parameter_value (0);
- a->set_parameter_value (0, va + vb < 1e-10 ? 0.0 : va * vb / (va + vb));
-}
-
-void DeviceClassInductor::serial (Device *a, Device *b) const
-{
- double va = a->parameter_value (0);
- double vb = b->parameter_value (0);
- a->set_parameter_value (0, va + vb);
-}
-
// ------------------------------------------------------------------------------------
-// DeviceClassInductor implementation
+// DeviceClassDiode implementation
DB_PUBLIC size_t DeviceClassDiode::param_id_A = 0;
DB_PUBLIC size_t DeviceClassDiode::param_id_P = 1;
@@ -326,6 +572,9 @@ DB_PUBLIC size_t DeviceClassDiode::terminal_id_C = 1;
DeviceClassDiode::DeviceClassDiode ()
{
+ set_supports_parallel_combination (true);
+ set_device_combiner (new DiodeDeviceCombiner ());
+
add_terminal_definition (db::DeviceTerminalDefinition ("A", "Anode"));
add_terminal_definition (db::DeviceTerminalDefinition ("C", "Cathode"));
@@ -333,29 +582,6 @@ DeviceClassDiode::DeviceClassDiode ()
add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0, false, 1e-6));
}
-bool DeviceClassDiode::combine_devices (Device *a, Device *b) const
-{
- const db::Net *na1 = a->net_for_terminal (0);
- const db::Net *na2 = a->net_for_terminal (1);
- const db::Net *nb1 = b->net_for_terminal (0);
- const db::Net *nb2 = b->net_for_terminal (1);
-
- // only parallel diodes can be combined and their areas will add
- if (na1 == nb1 && na2 == nb2) {
-
- a->set_parameter_value (0, a->parameter_value (0) + b->parameter_value (0));
- a->set_parameter_value (1, a->parameter_value (1) + b->parameter_value (1));
-
- a->join_terminals (0, b, 0);
- a->join_terminals (1, b, 1);
-
- return true;
-
- } else {
- return false;
- }
-}
-
// ------------------------------------------------------------------------------------
// DeviceClassMOS3Transistor implementation
@@ -372,9 +598,13 @@ DB_PUBLIC size_t DeviceClassMOS3Transistor::terminal_id_D = 2;
DeviceClassMOS3Transistor::DeviceClassMOS3Transistor ()
{
+ set_supports_parallel_combination (true);
+ set_device_combiner (new MOS3DeviceCombiner ());
+
add_terminal_definition (db::DeviceTerminalDefinition ("S", "Source"));
add_terminal_definition (db::DeviceTerminalDefinition ("G", "Gate"));
add_terminal_definition (db::DeviceTerminalDefinition ("D", "Drain"));
+ equivalent_terminal_id (terminal_id_D, terminal_id_S);
add_parameter_definition (db::DeviceParameterDefinition ("L", "Gate length (micrometer)", 0.0, true, 1e-6));
add_parameter_definition (db::DeviceParameterDefinition ("W", "Gate width (micrometer)", 0.0, true, 1e-6));
@@ -384,51 +614,6 @@ DeviceClassMOS3Transistor::DeviceClassMOS3Transistor ()
add_parameter_definition (db::DeviceParameterDefinition ("PD", "Drain perimeter (micrometer)", 0.0, false, 1e-6));
}
-bool DeviceClassMOS3Transistor::combine_devices (Device *a, Device *b) const
-{
- const db::Net *nas = a->net_for_terminal (0);
- const db::Net *nag = a->net_for_terminal (1);
- const db::Net *nad = a->net_for_terminal (2);
- const db::Net *nbs = b->net_for_terminal (0);
- const db::Net *nbg = b->net_for_terminal (1);
- const db::Net *nbd = b->net_for_terminal (2);
-
- // parallel transistors can be combined into one
- if (((nas == nbs && nad == nbd) || (nas == nbd && nad == nbs)) && nag == nbg) {
-
- // for combination the gate length must be identical
- if (fabs (a->parameter_value (0) - b->parameter_value (0)) < 1e-6) {
-
- combine_parameters (a, b);
-
- if (nas == nbs && nad == nbd) {
- a->join_terminals (0, b, 0);
- a->join_terminals (2, b, 2);
- } else {
- a->join_terminals (0, b, 2);
- a->join_terminals (2, b, 0);
- }
-
- a->join_terminals (1, b, 1);
-
- return true;
-
- }
-
- }
-
- return false;
-}
-
-void DeviceClassMOS3Transistor::combine_parameters (Device *a, Device *b) const
-{
- a->set_parameter_value (1, a->parameter_value (1) + b->parameter_value (1));
- a->set_parameter_value (2, a->parameter_value (2) + b->parameter_value (2));
- a->set_parameter_value (3, a->parameter_value (3) + b->parameter_value (3));
- a->set_parameter_value (4, a->parameter_value (4) + b->parameter_value (4));
- a->set_parameter_value (5, a->parameter_value (5) + b->parameter_value (5));
-}
-
// ------------------------------------------------------------------------------------
// DeviceClassMOS4Transistor implementation
@@ -436,48 +621,10 @@ DB_PUBLIC size_t DeviceClassMOS4Transistor::terminal_id_B = 3;
DeviceClassMOS4Transistor::DeviceClassMOS4Transistor ()
{
+ set_device_combiner (new MOS4DeviceCombiner ());
add_terminal_definition (db::DeviceTerminalDefinition ("B", "Bulk"));
}
-bool DeviceClassMOS4Transistor::combine_devices (Device *a, Device *b) const
-{
- const db::Net *nas = a->net_for_terminal (0);
- const db::Net *nag = a->net_for_terminal (1);
- const db::Net *nad = a->net_for_terminal (2);
- const db::Net *nab = a->net_for_terminal (3);
- const db::Net *nbs = b->net_for_terminal (0);
- const db::Net *nbg = b->net_for_terminal (1);
- const db::Net *nbd = b->net_for_terminal (2);
- const db::Net *nbb = b->net_for_terminal (3);
-
- // parallel transistors can be combined into one
- if (((nas == nbs && nad == nbd) || (nas == nbd && nad == nbs)) && nag == nbg && nab == nbb) {
-
- // for combination the gate length must be identical
- if (fabs (a->parameter_value (0) - b->parameter_value (0)) < 1e-6) {
-
- combine_parameters (a, b);
-
- if (nas == nbs && nad == nbd) {
- a->join_terminals (0, b, 0);
- a->join_terminals (2, b, 2);
- } else {
- a->join_terminals (0, b, 2);
- a->join_terminals (2, b, 0);
- }
-
- a->join_terminals (1, b, 1);
- a->join_terminals (3, b, 3);
-
- return true;
-
- }
-
- }
-
- return false;
-}
-
// ------------------------------------------------------------------------------------
// DeviceClassBJT3Transistor implementation
@@ -495,6 +642,9 @@ DB_PUBLIC size_t DeviceClassBJT3Transistor::terminal_id_E = 2;
DeviceClassBJT3Transistor::DeviceClassBJT3Transistor ()
{
+ set_supports_parallel_combination (true);
+ set_device_combiner (new BJT3DeviceCombiner ());
+
add_terminal_definition (db::DeviceTerminalDefinition ("C", "Collector"));
add_terminal_definition (db::DeviceTerminalDefinition ("B", "Base"));
add_terminal_definition (db::DeviceTerminalDefinition ("E", "Emitter"));
@@ -509,38 +659,6 @@ DeviceClassBJT3Transistor::DeviceClassBJT3Transistor ()
add_parameter_definition (db::DeviceParameterDefinition ("NE", "Emitter count", 1.0, true));
}
-bool DeviceClassBJT3Transistor::combine_devices (Device *a, Device *b) const
-{
- const db::Net *nac = a->net_for_terminal (0);
- const db::Net *nab = a->net_for_terminal (1);
- const db::Net *nae = a->net_for_terminal (2);
- const db::Net *nbc = b->net_for_terminal (0);
- const db::Net *nbb = b->net_for_terminal (1);
- const db::Net *nbe = b->net_for_terminal (2);
-
- // parallel transistors can be combined into one
- if (nac == nbc && nae == nbe && nab == nbb) {
-
- combine_parameters (a, b);
-
- a->join_terminals (0, b, 0);
- a->join_terminals (1, b, 1);
- a->join_terminals (2, b, 2);
-
- return true;
-
- }
-
- return false;
-}
-
-void DeviceClassBJT3Transistor::combine_parameters (Device *a, Device *b) const
-{
- a->set_parameter_value (param_id_AE, a->parameter_value (param_id_AE) + b->parameter_value (param_id_AE));
- a->set_parameter_value (param_id_PE, a->parameter_value (param_id_PE) + b->parameter_value (param_id_PE));
- a->set_parameter_value (param_id_NE, a->parameter_value (param_id_NE) + b->parameter_value (param_id_NE));
-}
-
// ------------------------------------------------------------------------------------
// DeviceClassBJT4Transistor implementation
@@ -548,35 +666,8 @@ DB_PUBLIC size_t DeviceClassBJT4Transistor::terminal_id_S = 3;
DeviceClassBJT4Transistor::DeviceClassBJT4Transistor ()
{
+ set_device_combiner (new BJT4DeviceCombiner ());
add_terminal_definition (db::DeviceTerminalDefinition ("S", "Substrate"));
}
-bool DeviceClassBJT4Transistor::combine_devices (Device *a, Device *b) const
-{
- const db::Net *nac = a->net_for_terminal (0);
- const db::Net *nab = a->net_for_terminal (1);
- const db::Net *nae = a->net_for_terminal (2);
- const db::Net *nas = a->net_for_terminal (3);
- const db::Net *nbc = b->net_for_terminal (0);
- const db::Net *nbb = b->net_for_terminal (1);
- const db::Net *nbe = b->net_for_terminal (2);
- const db::Net *nbs = b->net_for_terminal (3);
-
- // parallel transistors can be combined into one
- if (nac == nbc && nae == nbe && nab == nbb && nas == nbs) {
-
- combine_parameters (a, b);
-
- a->join_terminals (0, b, 0);
- a->join_terminals (1, b, 1);
- a->join_terminals (2, b, 2);
- a->join_terminals (3, b, 3);
-
- return true;
-
- }
-
- return false;
-}
-
}
diff --git a/src/db/db/dbNetlistDeviceClasses.h b/src/db/db/dbNetlistDeviceClasses.h
index e54f518e5..385759f87 100644
--- a/src/db/db/dbNetlistDeviceClasses.h
+++ b/src/db/db/dbNetlistDeviceClasses.h
@@ -29,28 +29,13 @@
namespace db
{
-/**
- * @brief A basic two-terminal device class
- */
-class DB_PUBLIC DeviceClassTwoTerminalDevice
- : public db::DeviceClass
-{
-public:
- virtual bool combine_devices (Device *a, Device *b) const;
-
- virtual void parallel (Device *a, Device *b) const = 0;
- virtual void serial (Device *a, Device *b) const = 0;
- virtual bool supports_parallel_combination () const { return true; }
- virtual bool supports_serial_combination () const { return true; }
-};
-
/**
* @brief A basic resistor device class
* A resistor defines a single parameter, "R", which is the resistance in Ohm.
* It defines two terminals, "A" and "B" for the two terminals.
*/
class DB_PUBLIC DeviceClassResistor
- : public db::DeviceClassTwoTerminalDevice
+ : public db::DeviceClass
{
public:
DeviceClassResistor ();
@@ -68,14 +53,6 @@ public:
static size_t terminal_id_A;
static size_t terminal_id_B;
-
- virtual void parallel (Device *a, Device *b) const;
- virtual void serial (Device *a, Device *b) const;
-
- virtual size_t normalize_terminal_id (size_t id) const
- {
- return id == terminal_id_B ? terminal_id_A : id;
- }
};
/**
@@ -95,8 +72,6 @@ public:
}
static size_t terminal_id_W;
-
- virtual bool combine_devices (Device *a, Device *b) const;
};
/**
@@ -105,7 +80,7 @@ public:
* It defines two terminals, "A" and "B" for the two terminals.
*/
class DB_PUBLIC DeviceClassCapacitor
- : public db::DeviceClassTwoTerminalDevice
+ : public db::DeviceClass
{
public:
DeviceClassCapacitor ();
@@ -121,14 +96,6 @@ public:
static size_t terminal_id_A;
static size_t terminal_id_B;
-
- virtual void parallel (Device *a, Device *b) const;
- virtual void serial (Device *a, Device *b) const;
-
- virtual size_t normalize_terminal_id (size_t id) const
- {
- return id == terminal_id_B ? terminal_id_A : id;
- }
};
/**
@@ -148,8 +115,6 @@ public:
}
static size_t terminal_id_W;
-
- virtual bool combine_devices (Device *a, Device *b) const;
};
/**
@@ -158,7 +123,7 @@ public:
* It defines two terminals, "A" and "B" for the two terminals.
*/
class DB_PUBLIC DeviceClassInductor
- : public db::DeviceClassTwoTerminalDevice
+ : public db::DeviceClass
{
public:
DeviceClassInductor ();
@@ -172,14 +137,6 @@ public:
static size_t terminal_id_A;
static size_t terminal_id_B;
-
- virtual void parallel (Device *a, Device *b) const;
- virtual void serial (Device *a, Device *b) const;
-
- virtual size_t normalize_terminal_id (size_t id) const
- {
- return id == terminal_id_B ? terminal_id_A : id;
- }
};
/**
@@ -204,9 +161,6 @@ public:
{
return new DeviceClassDiode (*this);
}
-
- virtual bool combine_devices (Device *a, Device *b) const;
- virtual bool supports_parallel_combination () const { return true; }
};
/**
@@ -237,14 +191,6 @@ public:
return new DeviceClassMOS3Transistor (*this);
}
- virtual bool combine_devices (Device *a, Device *b) const;
- virtual bool supports_parallel_combination () const { return true; }
-
- virtual size_t normalize_terminal_id (size_t tid) const
- {
- return tid == terminal_id_D ? terminal_id_S : tid;
- }
-
protected:
void combine_parameters (Device *a, Device *b) const;
};
@@ -266,13 +212,6 @@ public:
{
return new DeviceClassMOS4Transistor (*this);
}
-
- virtual size_t normalize_terminal_id (size_t tid) const
- {
- return tid == terminal_id_D ? terminal_id_S : tid;
- }
-
- virtual bool combine_devices (Device *a, Device *b) const;
};
/**
@@ -303,12 +242,6 @@ public:
{
return new DeviceClassBJT3Transistor (*this);
}
-
- virtual bool combine_devices (Device *a, Device *b) const;
- virtual bool supports_parallel_combination () const { return true; }
-
-protected:
- void combine_parameters (Device *a, Device *b) const;
};
/**
@@ -328,8 +261,6 @@ public:
{
return new DeviceClassBJT4Transistor (*this);
}
-
- virtual bool combine_devices (Device *a, Device *b) const;
};
}
diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc
index 0941d63c3..d095c936a 100644
--- a/src/db/db/gsiDeclDbNetlist.cc
+++ b/src/db/db/gsiDeclDbNetlist.cc
@@ -876,6 +876,31 @@ public:
gsi::Callback cb_less;
};
+/**
+ * @brief A DeviceCombiner implementation that allows reimplementation of the virtual methods
+ */
+class GenericDeviceCombiner
+ : public db::DeviceCombiner
+{
+public:
+ GenericDeviceCombiner ()
+ : db::DeviceCombiner ()
+ {
+ // .. nothing yet ..
+ }
+
+ virtual bool combine_devices (db::Device *a, db::Device *b) const
+ {
+ if (cb_combine.can_issue ()) {
+ return cb_combine.issue (&db::DeviceCombiner::combine_devices, a, b);
+ } else {
+ return false;
+ }
+ }
+
+ gsi::Callback cb_combine;
+};
+
}
db::EqualDeviceParameters *make_equal_dp (size_t param_id, double absolute, double relative)
@@ -942,6 +967,29 @@ Class decl_GenericDeviceParameterCompare (decl_db
"This class has been added in version 0.26. The 'equal' method has been dropped in 0.27.1 as it can be expressed as !less(a,b) && !less(b,a)."
);
+Class decl_GenericDeviceCombiner ("db", "GenericDeviceCombiner",
+ gsi::callback ("combine_devices", &GenericDeviceCombiner::combine_devices, &GenericDeviceCombiner::cb_combine, gsi::arg ("device_a"), gsi::arg ("device_b"),
+ "@brief Combines two devices if possible.\n"
+ "This method needs to test, whether the two devices can be combined. Both devices "
+ "are guaranteed to share the same device class. "
+ "If they cannot be combined, this method shall do nothing and return false. "
+ "If they can be combined, this method shall reconnect the nets of the first "
+ "device and entirely disconnect the nets of the second device. "
+ "The second device will be deleted afterwards. "
+ ),
+ "@brief A class implementing the combination of two devices (parallel or serial mode).\n"
+ "Reimplement this class to provide a custom device combiner.\n"
+ "Device combination requires 'supports_paralell_combination' or 'supports_serial_combination' to be set "
+ "to true for the device class. In the netlist device combination step, the algorithm will try to identify "
+ "devices which can be combined into single devices and use the combiner object to implement the actual "
+ "joining of such devices.\n"
+ "\n"
+ "Attach this object to a device class with \\DeviceClass#combiner= to make the device "
+ "class use this combiner.\n"
+ "\n"
+ "This class has been added in version 0.27.3."
+);
+
static tl::id_type id_of_device_class (const db::DeviceClass *cls)
{
return tl::id_of (cls);
@@ -957,6 +1005,16 @@ static db::EqualDeviceParameters *get_equal_parameters (db::DeviceClass *cls)
return dynamic_cast (cls->parameter_compare_delegate ());
}
+static void set_combiner (db::DeviceClass *cls, GenericDeviceCombiner *combiner)
+{
+ cls->set_device_combiner (combiner);
+}
+
+static GenericDeviceCombiner *get_combiner (db::DeviceClass *cls)
+{
+ return dynamic_cast (cls->device_combiner ());
+}
+
static void enable_parameter (db::DeviceClass *cls, size_t id, bool en)
{
db::DeviceParameterDefinition *pd = cls->parameter_definition_non_const (id);
@@ -987,6 +1045,20 @@ static const db::DeviceParameterDefinition *parameter_definition2 (const db::Dev
}
}
+static void dc_add_terminal_definition (db::DeviceClass *cls, db::DeviceTerminalDefinition *terminal_def)
+{
+ if (terminal_def) {
+ *terminal_def = cls->add_terminal_definition (*terminal_def);
+ }
+}
+
+static void dc_add_parameter_definition (db::DeviceClass *cls, db::DeviceParameterDefinition *parameter_def)
+{
+ if (parameter_def) {
+ *parameter_def = cls->add_parameter_definition (*parameter_def);
+ }
+}
+
Class decl_dbDeviceClass ("db", "DeviceClass",
gsi::method ("name", &db::DeviceClass::name,
"@brief Gets the name of the device class."
@@ -1088,7 +1160,7 @@ Class decl_dbDeviceClass ("db", "DeviceClass",
"@brief Gets the device parameter comparer for netlist verification or nil if no comparer is registered.\n"
"See \\equal_parameters= for the setter.\n"
"\n"
- "This getter has been introduced in version 0.26.4.\n"
+ "This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n"
) +
gsi::method_ext ("equal_parameters=", &equal_parameters, gsi::arg ("comparer"),
"@brief Specifies a device parameter comparer for netlist verification.\n"
@@ -1099,7 +1171,85 @@ Class decl_dbDeviceClass ("db", "DeviceClass",
"\n"
"You can assign nil for the parameter comparer to remove it.\n"
"\n"
- "In special cases, you can even implement a custom compare scheme by deriving your own comparer from the \\GenericDeviceParameterCompare class."
+ "In special cases, you can even implement a custom compare scheme by deriving your own comparer from the \\GenericDeviceParameterCompare class.\n"
+ "\n"
+ "This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n"
+ ) +
+ gsi::method_ext ("add_terminal", &gsi::dc_add_terminal_definition, gsi::arg ("terminal_def"),
+ "@brief Adds the given terminal definition to the device class\n"
+ "This method will define a new terminal. The new terminal is added at the end of existing terminals. "
+ "The terminal definition object passed as the argument is modified to contain the "
+ "new ID of the terminal.\n"
+ "\n"
+ "The terminal is copied into the device class. Modifying the terminal object later "
+ "does not have the effect of changing the terminal definition.\n"
+ "\n"
+ "This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n"
+ ) +
+ gsi::method ("clear_terminals", &db::DeviceClass::clear_terminal_definitions,
+ "@brief Clears the list of terminals\n"
+ "\n"
+ "This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n"
+ ) +
+ gsi::method_ext ("add_parameter", &gsi::dc_add_parameter_definition, gsi::arg ("parameter_def"),
+ "@brief Adds the given parameter definition to the device class\n"
+ "This method will define a new parameter. The new parameter is added at the end of existing parameters. "
+ "The parameter definition object passed as the argument is modified to contain the "
+ "new ID of the parameter."
+ "\n"
+ "The parameter is copied into the device class. Modifying the parameter object later "
+ "does not have the effect of changing the parameter definition.\n"
+ "\n"
+ "This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n"
+ ) +
+ gsi::method ("clear_parameters", &db::DeviceClass::clear_parameter_definitions,
+ "@brief Clears the list of parameters\n"
+ "\n"
+ "This method has been added in version 0.27.3.\n"
+ ) +
+ gsi::method_ext ("combiner=", &set_combiner, gsi::arg ("combiner"),
+ "@brief Specifies a device combiner (parallel or serial device combination).\n"
+ "\n"
+ "You can assign nil for the combiner to remove it.\n"
+ "\n"
+ "In special cases, you can even implement a custom combiner by deriving your own comparer from the \\GenericDeviceCombiner class.\n"
+ "\n"
+ "This method has been added in version 0.27.3.\n"
+ ) +
+ gsi::method_ext ("combiner", &get_combiner,
+ "@brief Gets a device combiner or nil if none is registered.\n"
+ "\n"
+ "This method has been added in version 0.27.3.\n"
+ ) +
+ gsi::method ("supports_parallel_combination=", &db::DeviceClass::set_supports_parallel_combination, gsi::arg ("f"),
+ "@brief Specifies whether the device supports parallel device combination.\n"
+ "Parallel device combination means that all terminals of two combination candidates are connected to the same nets. "
+ "If the device does not support this combination mode, this predicate can be set to false. This will make the device "
+ "extractor skip the combination test in parallel mode and improve performance somewhat.\n"
+ "\n"
+ "This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n"
+ ) +
+ gsi::method ("supports_serial_combination=", &db::DeviceClass::set_supports_serial_combination, gsi::arg ("f"),
+ "@brief Specifies whether the device supports serial device combination.\n"
+ "Serial device combination means that the devices are connected by internal nodes. "
+ "If the device does not support this combination mode, this predicate can be set to false. This will make the device "
+ "extractor skip the combination test in serial mode and improve performance somewhat.\n"
+ "\n"
+ "This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n"
+ ) +
+ gsi::method ("equivalent_terminal_id", &db::DeviceClass::equivalent_terminal_id, gsi::arg ("original_id"), gsi::arg ("equivalent_id"),
+ "@brief Specifies a terminal to be equivalent to another.\n"
+ "Use this method to specify two terminals to be exchangeable. For example to make S and D of a MOS transistor equivalent, "
+ "call this method with S and D terminal IDs. In netlist matching, S will be translated to D and thus made equivalent to D.\n"
+ "\n"
+ "Note that terminal equivalence is not effective if the device class operates in strict mode (see \\DeviceClass#strict=).\n"
+ "\n"
+ "This method has been moved from 'GenericDeviceClass' to 'DeviceClass' in version 0.27.3.\n"
+ ) +
+ gsi::method ("clear_equivalent_terminal_ids", &db::DeviceClass::clear_equivalent_terminal_ids,
+ "@brief Clears all equivalent terminal ids\n"
+ "\n"
+ "This method has been added in version 0.27.3.\n"
),
"@brief A class describing a specific type of device.\n"
"Device class objects live in the context of a \\Netlist object. After a "
@@ -1109,7 +1259,8 @@ Class decl_dbDeviceClass ("db", "DeviceClass",
"\n"
"The \\DeviceClass class is the base class for other device classes.\n"
"\n"
- "This class has been added in version 0.26."
+ "This class has been added in version 0.26. In version 0.27.3, the 'GenericDeviceClass' has been integrated with \\DeviceClass "
+ "and the device class was made writeable in most respects. This enables manipulating built-in device classes."
);
namespace {
@@ -1184,87 +1335,6 @@ private:
}
-static void gdc_add_terminal_definition (GenericDeviceClass *cls, db::DeviceTerminalDefinition *terminal_def)
-{
- if (terminal_def) {
- *terminal_def = cls->add_terminal_definition (*terminal_def);
- }
-}
-
-static void gdc_add_parameter_definition (GenericDeviceClass *cls, db::DeviceParameterDefinition *parameter_def)
-{
- if (parameter_def) {
- *parameter_def = cls->add_parameter_definition (*parameter_def);
- }
-}
-
-Class decl_GenericDeviceClass (decl_dbDeviceClass, "db", "GenericDeviceClass",
- gsi::method_ext ("add_terminal", &gsi::gdc_add_terminal_definition, gsi::arg ("terminal_def"),
- "@brief Adds the given terminal definition to the device class\n"
- "This method will define a new terminal. The new terminal is added at the end of existing terminals. "
- "The terminal definition object passed as the argument is modified to contain the "
- "new ID of the terminal.\n"
- "\n"
- "The terminal is copied into the device class. Modifying the terminal object later "
- "does not have the effect of changing the terminal definition."
- ) +
- gsi::method ("clear_terminals", &GenericDeviceClass::clear_terminal_definitions,
- "@brief Clears the list of terminals\n"
- ) +
- gsi::method_ext ("add_parameter", &gsi::gdc_add_parameter_definition, gsi::arg ("parameter_def"),
- "@brief Adds the given parameter definition to the device class\n"
- "This method will define a new parameter. The new parameter is added at the end of existing parameters. "
- "The parameter definition object passed as the argument is modified to contain the "
- "new ID of the parameter."
- "\n"
- "The parameter is copied into the device class. Modifying the parameter object later "
- "does not have the effect of changing the parameter definition."
- ) +
- gsi::method ("clear_parameters", &GenericDeviceClass::clear_parameter_definitions,
- "@brief Clears the list of parameters\n"
- ) +
- gsi::callback ("combine_devices", &GenericDeviceClass::combine_devices, &GenericDeviceClass::cb_combine_devices, gsi::arg ("a"), gsi::arg ("b"),
- "@brief Combines two devices.\n"
- "This method shall test, whether the two devices can be combined. Both devices "
- "are guaranteed to share the same device class (self). "
- "If they cannot be combined, this method shall do nothing and return false. "
- "If they can be combined, this method shall reconnect the nets of the first "
- "device and entirely disconnect the nets of the second device. "
- "It shall combine the parameters of both devices into the first. "
- "The second device will be deleted afterwards.\n"
- ) +
- gsi::method ("supports_parallel_combination=", &GenericDeviceClass::set_supports_parallel_combination, gsi::arg ("f"),
- "@brief Specifies whether the device supports parallel device combination.\n"
- "Parallel device combination means that all terminals of two combination candidates are connected to the same nets. "
- "If the device does not support this combination mode, this predicate can be set to false. This will make the device "
- "extractor skip the combination test in parallel mode and improve performance somewhat."
- ) +
- gsi::method ("supports_serial_combination=", &GenericDeviceClass::set_supports_serial_combination, gsi::arg ("f"),
- "@brief Specifies whether the device supports serial device combination.\n"
- "Serial device combination means that the devices are connected by internal nodes. "
- "If the device does not support this combination mode, this predicate can be set to false. This will make the device "
- "extractor skip the combination test in serial mode and improve performance somewhat."
- ) +
- gsi::method ("equivalent_terminal_id", &GenericDeviceClass::equivalent_terminal_id, gsi::arg ("original_id"), gsi::arg ("equivalent_id"),
- "@brief Specifies a terminal to be equivalent to another.\n"
- "Use this method to specify two terminals to be exchangeable. For example to make S and D of a MOS transistor equivalent, "
- "call this method with S and D terminal IDs. In netlist matching, S will be translated to D and thus made equivalent to D.\n"
- "\n"
- "Note that terminal equivalence is not effective if the device class operates in strict mode (see \\DeviceClass#strict=)."
- ),
- "@brief A generic device class\n"
- "This class allows building generic device classes. Specifically, terminals can be defined "
- "by adding terminal definitions. Terminal definitions should not be added dynamically. To create "
- "your own device, instantiate the \\GenericDeviceClass object, set name and description and "
- "specify the terminals. Then add this new device class to the \\Netlist object where it will live "
- "and be used to define device instances (\\Device objects).\n"
- "\n"
- "In addition, parameters can be defined which correspond to values stored inside the "
- "specific device instance (\\Device object)."
- "\n"
- "This class has been added in version 0.26."
-);
-
static db::Net *create_net (db::Circuit *c, const std::string &name)
{
db::Net *n = new db::Net ();
diff --git a/testdata/ruby/dbNetlist.rb b/testdata/ruby/dbNetlist.rb
index dc09d7f4b..9f0081795 100644
--- a/testdata/ruby/dbNetlist.rb
+++ b/testdata/ruby/dbNetlist.rb
@@ -124,13 +124,13 @@ class DBNetlist_TestClass < TestBase
def test_2_NetlistBasicDeviceClass
nl = RBA::Netlist::new
- c = RBA::GenericDeviceClass::new
+ c = RBA::DeviceClass::new
nl.add(c)
c.name = "XYZ"
assert_equal(c.name, "XYZ")
- cc = RBA::GenericDeviceClass::new
+ cc = RBA::DeviceClass::new
begin
nl.remove(cc) # not in netlist yet
@@ -158,7 +158,7 @@ class DBNetlist_TestClass < TestBase
nl.each_device_class { |i| names << i.name }
assert_equal(names, [ c.name ])
- cc = RBA::GenericDeviceClass::new
+ cc = RBA::DeviceClass::new
nl.add(cc)
cc.name = "UVW"
@@ -239,7 +239,7 @@ class DBNetlist_TestClass < TestBase
nl = RBA::Netlist::new
- dc = RBA::GenericDeviceClass::new
+ dc = RBA::DeviceClass::new
nl.add(dc)
assert_equal(dc.netlist.object_id, nl.object_id)
dc.name = "DC"
@@ -576,11 +576,11 @@ class DBNetlist_TestClass < TestBase
end
- def test_7_GenericDeviceClass
+ def test_7_DeviceClass
nl = RBA::Netlist::new
- dc = RBA::GenericDeviceClass::new
+ dc = RBA::DeviceClass::new
nl.add(dc)
dc.name = "DC"
assert_equal(dc.name, "DC")
@@ -758,7 +758,7 @@ class DBNetlist_TestClass < TestBase
nl = RBA::Netlist::new
- dc = RBA::GenericDeviceClass::new
+ dc = RBA::DeviceClass::new
dc.name = "DC"
nl.add(dc)
From 720057e07157deded5cc3f8dc83f0a24907612aa Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Tue, 6 Jul 2021 21:16:57 +0200
Subject: [PATCH 19/19] Added a #include which was missing
---
src/db/db/dbNetlistSpiceReader.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/db/db/dbNetlistSpiceReader.h b/src/db/db/dbNetlistSpiceReader.h
index 01491e6c9..394b45a69 100644
--- a/src/db/db/dbNetlistSpiceReader.h
+++ b/src/db/db/dbNetlistSpiceReader.h
@@ -31,6 +31,7 @@
#include
#include