From 24b985f32e51aef9d0fae7464b04d4ba3cabb6ce Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 19 Aug 2019 21:45:40 +0200 Subject: [PATCH 01/27] Better .include for Spice reader * .inc is allowed as synonym * Paths can be URL's (with HTTP) * Relative resolution of paths/URL's vs. parent of .include --- src/db/db/dbNetlistSpiceReader.cc | 19 +++++++++-- src/db/unit_tests/dbNetlistReaderTests.cc | 39 +++++++++++++++++++++++ testdata/algo/nreader8.cir | 5 +++ testdata/algo/nreader8a.cir | 4 +++ testdata/algo/nreader8b.cir | 8 +++++ testdata/algo/nreader8c.cir | 15 +++++++++ testdata/algo/nreader8x.cir | 3 ++ 7 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 testdata/algo/nreader8.cir create mode 100644 testdata/algo/nreader8a.cir create mode 100644 testdata/algo/nreader8b.cir create mode 100644 testdata/algo/nreader8c.cir create mode 100644 testdata/algo/nreader8x.cir diff --git a/src/db/db/dbNetlistSpiceReader.cc b/src/db/db/dbNetlistSpiceReader.cc index 50218d7d2..38773716b 100644 --- a/src/db/db/dbNetlistSpiceReader.cc +++ b/src/db/db/dbNetlistSpiceReader.cc @@ -27,6 +27,8 @@ #include "tlStream.h" #include "tlLog.h" #include "tlString.h" +#include "tlFileUtils.h" +#include "tlUri.h" #include #include @@ -243,7 +245,20 @@ void NetlistSpiceReader::finish () void NetlistSpiceReader::push_stream (const std::string &path) { - tl::InputStream *istream = new tl::InputStream (path); + tl::URI current_uri (mp_stream->source ()); + tl::URI new_uri (path); + + tl::InputStream *istream; + if (current_uri.scheme ().empty () && new_uri.scheme ().empty ()) { + if (tl::is_absolute (path)) { + istream = new tl::InputStream (path); + } else { + istream = new tl::InputStream (tl::combine_path (tl::dirname (mp_stream->source ()), path)); + } + } else { + istream = new tl::InputStream (current_uri.resolved (new_uri).to_string ()); + } + m_streams.push_back (std::make_pair (istream, mp_stream.release ())); mp_stream.reset (new tl::TextInputStream (*istream)); } @@ -291,7 +306,7 @@ std::string NetlistSpiceReader::get_line () } tl::Extractor ex (l.c_str ()); - if (ex.test_without_case (".include")) { + if (ex.test_without_case (".include") || ex.test_without_case (".inc")) { std::string path = read_name_with_case (ex); diff --git a/src/db/unit_tests/dbNetlistReaderTests.cc b/src/db/unit_tests/dbNetlistReaderTests.cc index c39e477a6..3a66a4468 100644 --- a/src/db/unit_tests/dbNetlistReaderTests.cc +++ b/src/db/unit_tests/dbNetlistReaderTests.cc @@ -294,3 +294,42 @@ TEST(7_GlobalNets) "end;\n" ); } + +TEST(8_Include) +{ + db::Netlist nl; + + std::string path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nreader8.cir"); + + db::NetlistSpiceReader reader; + tl::InputStream is (path); + reader.read (is, nl); + + EXPECT_EQ (nl.to_string (), + "circuit INVX1 ('1'='1','2'='2','3'='3','4'='4','5'='5','6'='6');\n" + " device MLVPMOS $1 (S='1',G='5',D='2',B='4') (L=0.25,W=1.5,AS=0,AD=0,PS=0,PD=0);\n" + " device MLVNMOS $2 (S='3',G='5',D='2',B='6') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + "end;\n" + "circuit ND2X1 ('1'='1','2'='2','3'='3','4'='4','5'='5','6'='6','7'='7');\n" + " device MLVPMOS $1 (S='2',G='6',D='1',B='4') (L=0.25,W=1.5,AS=0,AD=0,PS=0,PD=0);\n" + " device MLVPMOS $2 (S='1',G='5',D='2',B='4') (L=0.25,W=1.5,AS=0,AD=0,PS=0,PD=0);\n" + " device MLVNMOS $3 (S='3',G='6',D='8',B='7') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + " device MLVNMOS $4 (S='8',G='5',D='2',B='7') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + "end;\n" + "circuit RINGO ('11'='11','12'='12','13'='13','14'='14','15'='15');\n" + " subcircuit ND2X1 $1 ('1'='12','2'='1','3'='15','4'='12','5'='11','6'='14','7'='15');\n" + " subcircuit INVX1 $2 ('1'='12','2'='2','3'='15','4'='12','5'='1','6'='15');\n" + " subcircuit INVX1 $3 ('1'='12','2'='3','3'='15','4'='12','5'='2','6'='15');\n" + " subcircuit INVX1 $4 ('1'='12','2'='4','3'='15','4'='12','5'='3','6'='15');\n" + " subcircuit INVX1 $5 ('1'='12','2'='5','3'='15','4'='12','5'='4','6'='15');\n" + " subcircuit INVX1 $6 ('1'='12','2'='6','3'='15','4'='12','5'='5','6'='15');\n" + " subcircuit INVX1 $7 ('1'='12','2'='7','3'='15','4'='12','5'='6','6'='15');\n" + " subcircuit INVX1 $8 ('1'='12','2'='8','3'='15','4'='12','5'='7','6'='15');\n" + " subcircuit INVX1 $9 ('1'='12','2'='9','3'='15','4'='12','5'='8','6'='15');\n" + " subcircuit INVX1 $10 ('1'='12','2'='10','3'='15','4'='12','5'='9','6'='15');\n" + " subcircuit INVX1 $11 ('1'='12','2'='11','3'='15','4'='12','5'='10','6'='15');\n" + " subcircuit INVX1 $12 ('1'='12','2'='13','3'='15','4'='12','5'='11','6'='15');\n" + "end;\n" + ); +} + diff --git a/testdata/algo/nreader8.cir b/testdata/algo/nreader8.cir new file mode 100644 index 000000000..5a655897d --- /dev/null +++ b/testdata/algo/nreader8.cir @@ -0,0 +1,5 @@ + +.include "nreader8a.cir" +.include ../algo/nreader8b.cir +.inc nreader8c.cir + diff --git a/testdata/algo/nreader8a.cir b/testdata/algo/nreader8a.cir new file mode 100644 index 000000000..929d24588 --- /dev/null +++ b/testdata/algo/nreader8a.cir @@ -0,0 +1,4 @@ +.subckt INVX1 1 2 3 4 5 6 + .include nreader8x.cir +.ends + diff --git a/testdata/algo/nreader8b.cir b/testdata/algo/nreader8b.cir new file mode 100644 index 000000000..ddd4bee8c --- /dev/null +++ b/testdata/algo/nreader8b.cir @@ -0,0 +1,8 @@ + +.subckt ND2X1 1 2 3 4 5 6 7 + m$1 2 6 1 4 MLVPMOS L=0.25um W=1.5um + m$2 1 5 2 4 MLVPMOS L=0.25um W=1.5um + m$3 3 6 8 7 MLVNMOS L=0.25um W=0.95um + m$4 8 5 2 7 MLVNMOS L=0.25um W=0.95um +.ends ND2X1 + diff --git a/testdata/algo/nreader8c.cir b/testdata/algo/nreader8c.cir new file mode 100644 index 000000000..cb91dbfa5 --- /dev/null +++ b/testdata/algo/nreader8c.cir @@ -0,0 +1,15 @@ +.subckt RINGO 11 12 13 14 15 + x$1 12 1 15 12 11 14 15 ND2X1 + x$2 12 2 15 12 1 15 INVX1 + x$3 12 3 15 12 2 15 INVX1 + x$4 12 4 15 12 3 15 INVX1 + x$5 12 5 15 12 4 15 INVX1 + x$6 12 6 15 12 5 15 INVX1 + x$7 12 7 15 12 6 15 INVX1 + x$8 12 8 15 12 7 15 INVX1 + x$9 12 9 15 12 8 15 INVX1 + x$10 12 10 15 12 9 15 INVX1 + x$11 12 11 15 12 10 15 INVX1 + x$12 12 13 15 12 11 15 INVX1 +.ends RINGO + diff --git a/testdata/algo/nreader8x.cir b/testdata/algo/nreader8x.cir new file mode 100644 index 000000000..f3a8e9ced --- /dev/null +++ b/testdata/algo/nreader8x.cir @@ -0,0 +1,3 @@ +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 + From fa4da4ba0bd0679059982cb9fd7ccc820d00bd40 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 19 Aug 2019 21:58:32 +0200 Subject: [PATCH 02/27] Doc typo fixed. --- src/lay/lay/doc/manual/lvs_compare.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lay/lay/doc/manual/lvs_compare.xml b/src/lay/lay/doc/manual/lvs_compare.xml index 221bee1f6..1908fd2a1 100644 --- a/src/lay/lay/doc/manual/lvs_compare.xml +++ b/src/lay/lay/doc/manual/lvs_compare.xml @@ -119,11 +119,11 @@ same_device_classes("NMOS_IN_LAYOUT", "NMOS_IN_SCHEMATIC")

To eliminate all capacitors with a capacitance value below a certain threshold, use the - max_caps function. This will + min_caps function. This will eliminate all capacitances with a value <= 0.1fF:

-
max_caps(1e-16)
+
min_caps(1e-16)

How the compare algorithm works

From 207e44837c4d01f705cfc1b8d635ceb349548fce Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 19 Aug 2019 22:26:50 +0200 Subject: [PATCH 03/27] LVS: allow missing device classes in reference schematic Reasoning: some devices may simply not be used in the reference schematic. --- src/lvs/lvs/built-in-macros/_lvs_netter.rb | 8 +- .../lvs/ringo_simple_same_device_classes.lvs | 35 +- .../ringo_simple_same_device_classes.lvsdb.1 | 498 +++++++++--------- .../ringo_simple_same_device_classes.lvsdb.2 | 498 +++++++++--------- 4 files changed, 534 insertions(+), 505 deletions(-) diff --git a/src/lvs/lvs/built-in-macros/_lvs_netter.rb b/src/lvs/lvs/built-in-macros/_lvs_netter.rb index 4b445e3da..3e68b3d1c 100644 --- a/src/lvs/lvs/built-in-macros/_lvs_netter.rb +++ b/src/lvs/lvs/built-in-macros/_lvs_netter.rb @@ -285,9 +285,13 @@ module LVS ( nl_a, nl_b ) = _ensure_two_netlists dc_a = a && (nl_a.device_class_by_name(a) || raise("Not a valid device class in extracted netlist: #{a}")) - dc_b = b && (nl_b.device_class_by_name(b) || raise("Not a valid device class in reference netlist: #{b}")) + dc_b = b && nl_b.device_class_by_name(b) - @comparer.same_device_classes(dc_a, dc_b) + # NOTE: a device class is allowed to be missing in the reference netlist because the + # device may simply not be used there. + if dc_b + @comparer.same_device_classes(dc_a, dc_b) + end end diff --git a/testdata/lvs/ringo_simple_same_device_classes.lvs b/testdata/lvs/ringo_simple_same_device_classes.lvs index da0ec1196..9a2bad4d1 100644 --- a/testdata/lvs/ringo_simple_same_device_classes.lvs +++ b/testdata/lvs/ringo_simple_same_device_classes.lvs @@ -21,6 +21,7 @@ contact = input(8, 0) metal1 = input(9, 0) via1 = input(10, 0) metal2 = input(11, 0) +thickox = input(12, 0) # Bulk layer for terminal provisioning @@ -30,24 +31,42 @@ bulk = polygon_layer active_in_nwell = active & nwell pactive = active_in_nwell & pplus -pgate = pactive & poly -psd = pactive - pgate +pactive_hv = pactive & thickox +pgate_hv = pactive_hv & poly +psd_hv = pactive_hv - pgate_hv +pactive_lv = pactive - thickox +pgate_lv = pactive_lv & poly +psd_lv = pactive_lv - pgate_lv +psd = pactive - poly ntie = active_in_nwell & nplus active_outside_nwell = active - nwell nactive = active_outside_nwell & nplus -ngate = nactive & poly -nsd = nactive - ngate +nactive_hv = nactive & thickox +ngate_hv = nactive_hv & poly +nsd_hv = nactive_hv - ngate_hv +nactive_lv = nactive - thickox +ngate_lv = nactive_lv & poly +nsd_lv = nactive_lv - ngate_lv +nsd = nactive - poly ptie = active_outside_nwell & pplus # Device extraction # PMOS transistor device extraction -extract_devices(mos4("PM"), { "SD" => psd, "G" => pgate, "W" => nwell, - "tS" => psd, "tD" => psd, "tG" => poly, "tW" => nwell }) +extract_devices(mos4("PM"), { "SD" => psd_lv, "G" => pgate_lv, "W" => nwell, + "tS" => psd, "tD" => psd, "tG" => poly, "tW" => nwell }) # NMOS transistor device extraction -extract_devices(mos4("NM"), { "SD" => nsd, "G" => ngate, "W" => bulk, +extract_devices(mos4("NM"), { "SD" => nsd_lv, "G" => ngate_lv, "W" => bulk, + "tS" => nsd, "tD" => nsd, "tG" => poly, "tW" => bulk }) + +# PMOS transistor device extraction (HV) +extract_devices(mos4("PMHV"), { "SD" => psd_hv, "G" => pgate_hv, "W" => nwell, + "tS" => psd, "tD" => psd, "tG" => poly, "tW" => nwell }) + +# NMOS transistor device extraction (HV) +extract_devices(mos4("NMHV"), { "SD" => nsd_hv, "G" => ngate_hv, "W" => bulk, "tS" => nsd, "tD" => nsd, "tG" => poly, "tW" => bulk }) # Define connectivity for netlist extraction @@ -73,6 +92,8 @@ netlist.simplify same_device_classes("PM", "PMOS") same_device_classes("NM", "NMOS") +same_device_classes("PMHV", "PMOSHV") +same_device_classes("NMHV", "NMOSHV") compare diff --git a/testdata/lvs/ringo_simple_same_device_classes.lvsdb.1 b/testdata/lvs/ringo_simple_same_device_classes.lvsdb.1 index 7fc246d6a..bff454e1e 100644 --- a/testdata/lvs/ringo_simple_same_device_classes.lvsdb.1 +++ b/testdata/lvs/ringo_simple_same_device_classes.lvsdb.1 @@ -10,49 +10,51 @@ layout( # Mask layers layer(l3 '1/0') - layer(l4 '5/0') - layer(l8 '8/0') - layer(l11 '9/0') - layer(l12 '10/0') - layer(l13 '11/0') - layer(l7) - layer(l2) + layer(l5 '5/0') + layer(l14 '8/0') + layer(l17 '9/0') + layer(l18 '10/0') + layer(l19 '11/0') + layer(l8) + layer(l4) + layer(l15) layer(l9) - layer(l6) - layer(l10) + layer(l16) # Mask layer connectivity - connect(l3 l3 l9) - connect(l4 l4 l8) - connect(l8 l4 l8 l11 l2 l9 l6 l10) - connect(l11 l8 l11 l12) - connect(l12 l11 l12 l13) - connect(l13 l12 l13) - connect(l7 l7) - connect(l2 l8 l2) - connect(l9 l3 l8 l9) - connect(l6 l8 l6) - connect(l10 l8 l10) + connect(l3 l3 l15) + connect(l5 l5 l14) + connect(l14 l5 l14 l17 l4 l15 l9 l16) + connect(l17 l14 l17 l18) + connect(l18 l17 l18 l19) + connect(l19 l18 l19) + connect(l8 l8) + connect(l4 l14 l4) + connect(l15 l3 l14 l15) + connect(l9 l14 l9) + connect(l16 l14 l16) # Global nets and connectivity - global(l7 SUBSTRATE) - global(l10 SUBSTRATE) + global(l8 SUBSTRATE) + global(l16 SUBSTRATE) # Device class section class(PM MOS4) class(NM MOS4) + class(PMHV MOS4) + class(NMHV MOS4) # Device abstracts section # Device abstracts list the pin shapes of the devices. device(D$PM PM terminal(S - rect(l2 (-550 -750) (425 1500)) + rect(l4 (-550 -750) (425 1500)) ) terminal(G - rect(l4 (-125 -750) (250 1500)) + rect(l5 (-125 -750) (250 1500)) ) terminal(D - rect(l2 (125 -750) (450 1500)) + rect(l4 (125 -750) (450 1500)) ) terminal(B rect(l3 (-125 -750) (250 1500)) @@ -60,13 +62,13 @@ layout( ) device(D$PM$1 PM terminal(S - rect(l2 (-575 -750) (450 1500)) + rect(l4 (-575 -750) (450 1500)) ) terminal(G - rect(l4 (-125 -750) (250 1500)) + rect(l5 (-125 -750) (250 1500)) ) terminal(D - rect(l2 (125 -750) (425 1500)) + rect(l4 (125 -750) (425 1500)) ) terminal(B rect(l3 (-125 -750) (250 1500)) @@ -74,13 +76,13 @@ layout( ) device(D$PM$2 PM terminal(S - rect(l2 (-550 -750) (425 1500)) + rect(l4 (-550 -750) (425 1500)) ) terminal(G - rect(l4 (-125 -750) (250 1500)) + rect(l5 (-125 -750) (250 1500)) ) terminal(D - rect(l2 (125 -750) (425 1500)) + rect(l4 (125 -750) (425 1500)) ) terminal(B rect(l3 (-125 -750) (250 1500)) @@ -88,44 +90,44 @@ layout( ) device(D$NM NM terminal(S - rect(l6 (-550 -475) (425 950)) + rect(l9 (-550 -475) (425 950)) ) terminal(G - rect(l4 (-125 -475) (250 950)) + rect(l5 (-125 -475) (250 950)) ) terminal(D - rect(l6 (125 -475) (450 950)) + rect(l9 (125 -475) (450 950)) ) terminal(B - rect(l7 (-125 -475) (250 950)) + rect(l8 (-125 -475) (250 950)) ) ) device(D$NM$1 NM terminal(S - rect(l6 (-575 -475) (450 950)) + rect(l9 (-575 -475) (450 950)) ) terminal(G - rect(l4 (-125 -475) (250 950)) + rect(l5 (-125 -475) (250 950)) ) terminal(D - rect(l6 (125 -475) (425 950)) + rect(l9 (125 -475) (425 950)) ) terminal(B - rect(l7 (-125 -475) (250 950)) + rect(l8 (-125 -475) (250 950)) ) ) device(D$NM$2 NM terminal(S - rect(l6 (-550 -475) (425 950)) + rect(l9 (-550 -475) (425 950)) ) terminal(G - rect(l4 (-125 -475) (250 950)) + rect(l5 (-125 -475) (250 950)) ) terminal(D - rect(l6 (125 -475) (425 950)) + rect(l9 (125 -475) (425 950)) ) terminal(B - rect(l7 (-125 -475) (250 950)) + rect(l8 (-125 -475) (250 950)) ) ) @@ -138,70 +140,70 @@ layout( # Nets with their geometries net(1 name(VDD) - rect(l8 (1110 5160) (180 180)) - rect(l8 (-180 920) (180 180)) - rect(l8 (-180 -730) (180 180)) - rect(l11 (-240 -790) (300 1700)) - rect(l11 (-1350 0) (2400 800)) - rect(l11 (-1151 -401) (2 2)) - rect(l2 (-276 -2151) (425 1500)) - rect(l2 (-400 -1500) (425 1500)) + rect(l14 (1110 5160) (180 180)) + rect(l14 (-180 920) (180 180)) + rect(l14 (-180 -730) (180 180)) + rect(l17 (-240 -790) (300 1700)) + rect(l17 (-1350 0) (2400 800)) + rect(l17 (-1151 -401) (2 2)) + rect(l4 (-276 -2151) (425 1500)) + rect(l4 (-400 -1500) (425 1500)) ) net(2 name(OUT) - rect(l8 (1810 1770) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l8 (-1580 3760) (180 180)) - rect(l8 (-180 -730) (180 180)) - rect(l8 (-180 -730) (180 180)) - rect(l8 (1220 920) (180 180)) - rect(l8 (-180 -1280) (180 180)) - rect(l8 (-180 370) (180 180)) - polygon(l11 (-240 -4180) (0 1390) (490 0) (0 -300) (-190 0) (0 -1090)) - rect(l11 (-110 1390) (300 1400)) - polygon(l11 (-1890 0) (0 600) (300 0) (0 -300) (1590 0) (0 -300)) - rect(l11 (-141 -501) (2 2)) - rect(l11 (-1751 1099) (300 1400)) - rect(l11 (1100 -1700) (300 300)) - rect(l11 (-300 0) (300 1400)) - rect(l2 (-1750 -1450) (425 1500)) - rect(l2 (950 -1500) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (1810 1770) (180 180)) + rect(l14 (-180 370) (180 180)) + rect(l14 (-1580 3760) (180 180)) + rect(l14 (-180 -730) (180 180)) + rect(l14 (-180 -730) (180 180)) + rect(l14 (1220 920) (180 180)) + rect(l14 (-180 -1280) (180 180)) + rect(l14 (-180 370) (180 180)) + polygon(l17 (-240 -4180) (0 1390) (490 0) (0 -300) (-190 0) (0 -1090)) + rect(l17 (-110 1390) (300 1400)) + polygon(l17 (-1890 0) (0 600) (300 0) (0 -300) (1590 0) (0 -300)) + rect(l17 (-141 -501) (2 2)) + rect(l17 (-1751 1099) (300 1400)) + rect(l17 (1100 -1700) (300 300)) + rect(l17 (-300 0) (300 1400)) + rect(l4 (-1750 -1450) (425 1500)) + rect(l4 (950 -1500) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(3 name(VSS) - rect(l8 (410 1770) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l11 (-240 -1300) (300 1360)) - rect(l11 (-650 -2160) (2400 800)) - rect(l11 (-1151 -401) (2 2)) - rect(l6 (-951 859) (425 950)) + rect(l14 (410 1770) (180 180)) + rect(l14 (-180 370) (180 180)) + rect(l17 (-240 -1300) (300 1360)) + rect(l17 (-650 -2160) (2400 800)) + rect(l17 (-1151 -401) (2 2)) + rect(l9 (-951 859) (425 950)) ) net(4 rect(l3 (-100 4500) (2600 3500)) ) net(5 name(B) - rect(l4 (1425 2860) (250 1940)) - rect(l4 (-345 -950) (300 300)) - rect(l4 (-205 650) (250 2000)) - rect(l4 (-250 -2000) (250 2000)) - rect(l4 (-250 -5390) (250 1450)) - rect(l8 (-285 1050) (180 180)) - rect(l11 (-71 -91) (2 2)) - rect(l11 (-171 -151) (300 300)) + rect(l5 (1425 2860) (250 1940)) + rect(l5 (-345 -950) (300 300)) + rect(l5 (-205 650) (250 2000)) + rect(l5 (-250 -2000) (250 2000)) + rect(l5 (-250 -5390) (250 1450)) + rect(l14 (-285 1050) (180 180)) + rect(l17 (-71 -91) (2 2)) + rect(l17 (-171 -151) (300 300)) ) net(6 name(A) - rect(l4 (725 2860) (250 1940)) - rect(l4 (-325 -1850) (300 300)) - rect(l4 (-225 1550) (250 2000)) - rect(l4 (-250 -2000) (250 2000)) - rect(l4 (-250 -5390) (250 1450)) - rect(l8 (-265 150) (180 180)) - rect(l11 (-91 -91) (2 2)) - rect(l11 (-151 -151) (300 300)) + rect(l5 (725 2860) (250 1940)) + rect(l5 (-325 -1850) (300 300)) + rect(l5 (-225 1550) (250 2000)) + rect(l5 (-250 -2000) (250 2000)) + rect(l5 (-250 -5390) (250 1450)) + rect(l14 (-265 150) (180 180)) + rect(l17 (-91 -91) (2 2)) + rect(l17 (-151 -151) (300 300)) ) net(7 name(SUBSTRATE)) net(8 - rect(l6 (975 1660) (425 950)) - rect(l6 (-400 -950) (425 950)) + rect(l9 (975 1660) (425 950)) + rect(l9 (-400 -950) (425 950)) ) # Outgoing pins and their connections to nets @@ -275,46 +277,46 @@ layout( # Nets with their geometries net(1 name(VDD) - rect(l8 (410 6260) (180 180)) - rect(l8 (-180 -730) (180 180)) - rect(l8 (-180 -730) (180 180)) - rect(l11 (-240 -240) (300 1400)) - rect(l11 (-650 300) (1800 800)) - rect(l11 (-1450 -1100) (300 300)) - rect(l11 (299 399) (2 2)) - rect(l2 (-651 -2151) (425 1500)) + rect(l14 (410 6260) (180 180)) + rect(l14 (-180 -730) (180 180)) + rect(l14 (-180 -730) (180 180)) + rect(l17 (-240 -240) (300 1400)) + rect(l17 (-650 300) (1800 800)) + rect(l17 (-1450 -1100) (300 300)) + rect(l17 (299 399) (2 2)) + rect(l4 (-651 -2151) (425 1500)) ) net(2 name(OUT) - rect(l8 (1110 5160) (180 180)) - rect(l8 (-180 920) (180 180)) - rect(l8 (-180 -730) (180 180)) - rect(l8 (-180 -4120) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l11 (-240 -790) (300 4790)) - rect(l11 (-151 -2501) (2 2)) - rect(l2 (-226 1049) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (1110 5160) (180 180)) + rect(l14 (-180 920) (180 180)) + rect(l14 (-180 -730) (180 180)) + rect(l14 (-180 -4120) (180 180)) + rect(l14 (-180 370) (180 180)) + rect(l17 (-240 -790) (300 4790)) + rect(l17 (-151 -2501) (2 2)) + rect(l4 (-226 1049) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(3 name(VSS) - rect(l8 (410 1770) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l11 (-240 -1300) (300 1360)) - rect(l11 (-650 -2160) (1800 800)) - rect(l11 (-851 -401) (2 2)) - rect(l6 (-651 859) (425 950)) + rect(l14 (410 1770) (180 180)) + rect(l14 (-180 370) (180 180)) + rect(l17 (-240 -1300) (300 1360)) + rect(l17 (-650 -2160) (1800 800)) + rect(l17 (-851 -401) (2 2)) + rect(l9 (-651 859) (425 950)) ) net(4 rect(l3 (-100 4500) (2000 3500)) ) net(5 name(IN) - rect(l4 (725 2860) (250 1940)) - rect(l4 (-525 -1850) (300 300)) - rect(l4 (-25 1550) (250 2000)) - rect(l4 (-250 -2000) (250 2000)) - rect(l4 (-250 -5390) (250 1450)) - rect(l8 (-465 150) (180 180)) - rect(l11 (-91 -91) (2 2)) - rect(l11 (-151 -151) (300 300)) + rect(l5 (725 2860) (250 1940)) + rect(l5 (-525 -1850) (300 300)) + rect(l5 (-25 1550) (250 2000)) + rect(l5 (-250 -2000) (250 2000)) + rect(l5 (-250 -5390) (250 1450)) + rect(l14 (-465 150) (180 180)) + rect(l17 (-91 -91) (2 2)) + rect(l17 (-151 -151) (300 300)) ) net(6 name(SUBSTRATE)) @@ -362,162 +364,162 @@ layout( # Nets with their geometries net(1 - rect(l8 (4710 3010) (180 180)) - rect(l11 (-850 -240) (610 300)) - rect(l2 (-2550 1800) (425 1500)) - rect(l2 (950 -1500) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (4710 3010) (180 180)) + rect(l17 (-850 -240) (610 300)) + rect(l4 (-2550 1800) (425 1500)) + rect(l4 (950 -1500) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(2 - rect(l8 (6510 3010) (180 180)) - rect(l11 (-1140 -240) (900 300)) - rect(l2 (-1275 1800) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (6510 3010) (180 180)) + rect(l17 (-1140 -240) (900 300)) + rect(l4 (-1275 1800) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(3 - rect(l8 (8310 3010) (180 180)) - rect(l11 (-1140 -240) (900 300)) - rect(l2 (-1275 1800) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (8310 3010) (180 180)) + rect(l17 (-1140 -240) (900 300)) + rect(l4 (-1275 1800) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(4 - rect(l8 (10110 3010) (180 180)) - rect(l11 (-1140 -240) (900 300)) - rect(l2 (-1275 1800) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (10110 3010) (180 180)) + rect(l17 (-1140 -240) (900 300)) + rect(l4 (-1275 1800) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(5 - rect(l8 (11910 3010) (180 180)) - rect(l11 (-1140 -240) (900 300)) - rect(l2 (-1275 1800) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (11910 3010) (180 180)) + rect(l17 (-1140 -240) (900 300)) + rect(l4 (-1275 1800) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(6 - rect(l8 (13710 3010) (180 180)) - rect(l11 (-1140 -240) (900 300)) - rect(l2 (-1275 1800) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (13710 3010) (180 180)) + rect(l17 (-1140 -240) (900 300)) + rect(l4 (-1275 1800) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(7 - rect(l8 (15510 3010) (180 180)) - rect(l11 (-1140 -240) (900 300)) - rect(l2 (-1275 1800) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (15510 3010) (180 180)) + rect(l17 (-1140 -240) (900 300)) + rect(l4 (-1275 1800) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(8 - rect(l8 (17310 3010) (180 180)) - rect(l11 (-1140 -240) (900 300)) - rect(l2 (-1275 1800) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (17310 3010) (180 180)) + rect(l17 (-1140 -240) (900 300)) + rect(l4 (-1275 1800) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(9 - rect(l8 (19110 3010) (180 180)) - rect(l11 (-1140 -240) (900 300)) - rect(l2 (-1275 1800) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (19110 3010) (180 180)) + rect(l17 (-1140 -240) (900 300)) + rect(l4 (-1275 1800) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(10 - rect(l8 (20910 3010) (180 180)) - rect(l11 (-1140 -240) (900 300)) - rect(l2 (-1275 1800) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (20910 3010) (180 180)) + rect(l17 (-1140 -240) (900 300)) + rect(l4 (-1275 1800) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(11 name(FB) - rect(l8 (22710 3010) (180 180)) - rect(l8 (-19700 720) (180 180)) - rect(l11 (18380 -1140) (900 300)) - rect(l11 (-19530 590) (320 320)) - rect(l11 (17820 -320) (320 320)) - rect(l12 (-18400 -260) (200 200)) - rect(l12 (17940 -200) (200 200)) - rect(l13 (-18040 -300) (17740 400)) - rect(l13 (-17921 -201) (2 2)) - rect(l13 (-221 -201) (400 400)) - rect(l13 (17740 -400) (400 400)) - rect(l2 (-245 850) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (22710 3010) (180 180)) + rect(l14 (-19700 720) (180 180)) + rect(l17 (18380 -1140) (900 300)) + rect(l17 (-19530 590) (320 320)) + rect(l17 (17820 -320) (320 320)) + rect(l18 (-18400 -260) (200 200)) + rect(l18 (17940 -200) (200 200)) + rect(l19 (-18040 -300) (17740 400)) + rect(l19 (-17921 -201) (2 2)) + rect(l19 (-221 -201) (400 400)) + rect(l19 (17740 -400) (400 400)) + rect(l4 (-245 850) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(12 name(VDD) rect(l3 (500 4500) (1400 3500)) rect(l3 (-1900 -3500) (600 3500)) rect(l3 (23300 -3500) (1400 3500)) rect(l3 (-100 -3500) (600 3500)) - rect(l8 (-24690 -1240) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l8 (-180 -1280) (180 180)) - rect(l8 (23220 370) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l8 (-180 -1280) (180 180)) - rect(l11 (-21741 859) (2 2)) - rect(l11 (-2351 -451) (1200 800)) - rect(l11 (-750 -1450) (300 1400)) - rect(l11 (-101 -351) (2 2)) - rect(l11 (-1251 -401) (600 800)) - rect(l11 (23400 -800) (1200 800)) - rect(l11 (-750 -1450) (300 1400)) - rect(l11 (-101 -351) (2 2)) - rect(l11 (549 -401) (600 800)) - rect(l2 (-23025 -2550) (425 1500)) - rect(l2 (-400 -1500) (425 1500)) - rect(l2 (1275 -1500) (425 1500)) - rect(l2 (1375 -1500) (425 1500)) - rect(l2 (1375 -1500) (425 1500)) - rect(l2 (1375 -1500) (425 1500)) - rect(l2 (1375 -1500) (425 1500)) - rect(l2 (1375 -1500) (425 1500)) - rect(l2 (1375 -1500) (425 1500)) - rect(l2 (1375 -1500) (425 1500)) - rect(l2 (1375 -1500) (425 1500)) - rect(l2 (1375 -1500) (425 1500)) - rect(l2 (1375 -1500) (425 1500)) - rect(l9 (-21975 -450) (500 1500)) - rect(l9 (22900 -1500) (500 1500)) + rect(l14 (-24690 -1240) (180 180)) + rect(l14 (-180 370) (180 180)) + rect(l14 (-180 -1280) (180 180)) + rect(l14 (23220 370) (180 180)) + rect(l14 (-180 370) (180 180)) + rect(l14 (-180 -1280) (180 180)) + rect(l17 (-21741 859) (2 2)) + rect(l17 (-2351 -451) (1200 800)) + rect(l17 (-750 -1450) (300 1400)) + rect(l17 (-101 -351) (2 2)) + rect(l17 (-1251 -401) (600 800)) + rect(l17 (23400 -800) (1200 800)) + rect(l17 (-750 -1450) (300 1400)) + rect(l17 (-101 -351) (2 2)) + rect(l17 (549 -401) (600 800)) + rect(l4 (-23025 -2550) (425 1500)) + rect(l4 (-400 -1500) (425 1500)) + rect(l4 (1275 -1500) (425 1500)) + rect(l4 (1375 -1500) (425 1500)) + rect(l4 (1375 -1500) (425 1500)) + rect(l4 (1375 -1500) (425 1500)) + rect(l4 (1375 -1500) (425 1500)) + rect(l4 (1375 -1500) (425 1500)) + rect(l4 (1375 -1500) (425 1500)) + rect(l4 (1375 -1500) (425 1500)) + rect(l4 (1375 -1500) (425 1500)) + rect(l4 (1375 -1500) (425 1500)) + rect(l4 (1375 -1500) (425 1500)) + rect(l15 (-21975 -450) (500 1500)) + rect(l15 (22900 -1500) (500 1500)) ) net(13 name(OUT) - rect(l11 (23440 3840) (320 320)) - rect(l12 (-260 -260) (200 200)) - rect(l13 (-101 -101) (2 2)) - rect(l13 (-201 -201) (400 400)) - rect(l2 (-625 850) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l17 (23440 3840) (320 320)) + rect(l18 (-260 -260) (200 200)) + rect(l19 (-101 -101) (2 2)) + rect(l19 (-201 -201) (400 400)) + rect(l4 (-625 850) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(14 name(ENABLE) - rect(l8 (2510 3010) (180 180)) - rect(l11 (-250 -250) (320 320)) - rect(l12 (-260 -260) (200 200)) - rect(l13 (-101 -101) (2 2)) - rect(l13 (-201 -201) (400 400)) + rect(l14 (2510 3010) (180 180)) + rect(l17 (-250 -250) (320 320)) + rect(l18 (-260 -260) (200 200)) + rect(l19 (-101 -101) (2 2)) + rect(l19 (-201 -201) (400 400)) ) net(15 name(VSS) - rect(l8 (1110 1610) (180 180)) - rect(l8 (-180 -1280) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l8 (23220 370) (180 180)) - rect(l8 (-180 -1280) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l11 (-21741 -391) (2 2)) - rect(l11 (-1901 -401) (300 1400)) - rect(l11 (-750 -1450) (1200 800)) - rect(l11 (-551 -401) (2 2)) - rect(l11 (-1251 -401) (600 800)) - rect(l11 (23850 -750) (300 1400)) - rect(l11 (-750 -1450) (1200 800)) - rect(l11 (-551 -401) (2 2)) - rect(l11 (549 -401) (600 800)) - rect(l6 (-23700 460) (425 950)) - rect(l6 (1975 -950) (425 950)) - rect(l6 (1375 -950) (425 950)) - rect(l6 (1375 -950) (425 950)) - rect(l6 (1375 -950) (425 950)) - rect(l6 (1375 -950) (425 950)) - rect(l6 (1375 -950) (425 950)) - rect(l6 (1375 -950) (425 950)) - rect(l6 (1375 -950) (425 950)) - rect(l6 (1375 -950) (425 950)) - rect(l6 (1375 -950) (425 950)) - rect(l6 (1375 -950) (425 950)) - rect(l10 (-21975 -2210) (500 1500)) - rect(l10 (22900 -1500) (500 1500)) + rect(l14 (1110 1610) (180 180)) + rect(l14 (-180 -1280) (180 180)) + rect(l14 (-180 370) (180 180)) + rect(l14 (23220 370) (180 180)) + rect(l14 (-180 -1280) (180 180)) + rect(l14 (-180 370) (180 180)) + rect(l17 (-21741 -391) (2 2)) + rect(l17 (-1901 -401) (300 1400)) + rect(l17 (-750 -1450) (1200 800)) + rect(l17 (-551 -401) (2 2)) + rect(l17 (-1251 -401) (600 800)) + rect(l17 (23850 -750) (300 1400)) + rect(l17 (-750 -1450) (1200 800)) + rect(l17 (-551 -401) (2 2)) + rect(l17 (549 -401) (600 800)) + rect(l9 (-23700 460) (425 950)) + rect(l9 (1975 -950) (425 950)) + rect(l9 (1375 -950) (425 950)) + rect(l9 (1375 -950) (425 950)) + rect(l9 (1375 -950) (425 950)) + rect(l9 (1375 -950) (425 950)) + rect(l9 (1375 -950) (425 950)) + rect(l9 (1375 -950) (425 950)) + rect(l9 (1375 -950) (425 950)) + rect(l9 (1375 -950) (425 950)) + rect(l9 (1375 -950) (425 950)) + rect(l9 (1375 -950) (425 950)) + rect(l16 (-21975 -2210) (500 1500)) + rect(l16 (22900 -1500) (500 1500)) ) # Outgoing pins and their connections to nets diff --git a/testdata/lvs/ringo_simple_same_device_classes.lvsdb.2 b/testdata/lvs/ringo_simple_same_device_classes.lvsdb.2 index 7ea0be0cd..2d7583393 100644 --- a/testdata/lvs/ringo_simple_same_device_classes.lvsdb.2 +++ b/testdata/lvs/ringo_simple_same_device_classes.lvsdb.2 @@ -10,49 +10,51 @@ layout( # Mask layers layer(l3 '1/0') - layer(l4 '5/0') - layer(l8 '8/0') - layer(l11 '9/0') - layer(l12 '10/0') - layer(l13 '11/0') - layer(l7) - layer(l2) + layer(l5 '5/0') + layer(l14 '8/0') + layer(l17 '9/0') + layer(l18 '10/0') + layer(l19 '11/0') + layer(l8) + layer(l4) + layer(l15) layer(l9) - layer(l6) - layer(l10) + layer(l16) # Mask layer connectivity - connect(l3 l3 l9) - connect(l4 l4 l8) - connect(l8 l4 l8 l11 l2 l9 l6 l10) - connect(l11 l8 l11 l12) - connect(l12 l11 l12 l13) - connect(l13 l12 l13) - connect(l7 l7) - connect(l2 l8 l2) - connect(l9 l3 l8 l9) - connect(l6 l8 l6) - connect(l10 l8 l10) + connect(l3 l3 l15) + connect(l5 l5 l14) + connect(l14 l5 l14 l17 l4 l15 l9 l16) + connect(l17 l14 l17 l18) + connect(l18 l17 l18 l19) + connect(l19 l18 l19) + connect(l8 l8) + connect(l4 l14 l4) + connect(l15 l3 l14 l15) + connect(l9 l14 l9) + connect(l16 l14 l16) # Global nets and connectivity - global(l7 SUBSTRATE) - global(l10 SUBSTRATE) + global(l8 SUBSTRATE) + global(l16 SUBSTRATE) # Device class section class(PM MOS4) class(NM MOS4) + class(PMHV MOS4) + class(NMHV MOS4) # Device abstracts section # Device abstracts list the pin shapes of the devices. device(D$PM PM terminal(S - rect(l2 (-550 -750) (425 1500)) + rect(l4 (-550 -750) (425 1500)) ) terminal(G - rect(l4 (-125 -750) (250 1500)) + rect(l5 (-125 -750) (250 1500)) ) terminal(D - rect(l2 (125 -750) (450 1500)) + rect(l4 (125 -750) (450 1500)) ) terminal(B rect(l3 (-125 -750) (250 1500)) @@ -60,13 +62,13 @@ layout( ) device(D$PM$1 PM terminal(S - rect(l2 (-575 -750) (450 1500)) + rect(l4 (-575 -750) (450 1500)) ) terminal(G - rect(l4 (-125 -750) (250 1500)) + rect(l5 (-125 -750) (250 1500)) ) terminal(D - rect(l2 (125 -750) (425 1500)) + rect(l4 (125 -750) (425 1500)) ) terminal(B rect(l3 (-125 -750) (250 1500)) @@ -74,13 +76,13 @@ layout( ) device(D$PM$2 PM terminal(S - rect(l2 (-550 -750) (425 1500)) + rect(l4 (-550 -750) (425 1500)) ) terminal(G - rect(l4 (-125 -750) (250 1500)) + rect(l5 (-125 -750) (250 1500)) ) terminal(D - rect(l2 (125 -750) (425 1500)) + rect(l4 (125 -750) (425 1500)) ) terminal(B rect(l3 (-125 -750) (250 1500)) @@ -88,44 +90,44 @@ layout( ) device(D$NM NM terminal(S - rect(l6 (-550 -475) (425 950)) + rect(l9 (-550 -475) (425 950)) ) terminal(G - rect(l4 (-125 -475) (250 950)) + rect(l5 (-125 -475) (250 950)) ) terminal(D - rect(l6 (125 -475) (450 950)) + rect(l9 (125 -475) (450 950)) ) terminal(B - rect(l7 (-125 -475) (250 950)) + rect(l8 (-125 -475) (250 950)) ) ) device(D$NM$1 NM terminal(S - rect(l6 (-575 -475) (450 950)) + rect(l9 (-575 -475) (450 950)) ) terminal(G - rect(l4 (-125 -475) (250 950)) + rect(l5 (-125 -475) (250 950)) ) terminal(D - rect(l6 (125 -475) (425 950)) + rect(l9 (125 -475) (425 950)) ) terminal(B - rect(l7 (-125 -475) (250 950)) + rect(l8 (-125 -475) (250 950)) ) ) device(D$NM$2 NM terminal(S - rect(l6 (-550 -475) (425 950)) + rect(l9 (-550 -475) (425 950)) ) terminal(G - rect(l4 (-125 -475) (250 950)) + rect(l5 (-125 -475) (250 950)) ) terminal(D - rect(l6 (125 -475) (425 950)) + rect(l9 (125 -475) (425 950)) ) terminal(B - rect(l7 (-125 -475) (250 950)) + rect(l8 (-125 -475) (250 950)) ) ) @@ -138,70 +140,70 @@ layout( # Nets with their geometries net(1 name(VDD) - rect(l8 (1110 5160) (180 180)) - rect(l8 (-180 920) (180 180)) - rect(l8 (-180 -730) (180 180)) - rect(l11 (-240 -790) (300 1700)) - rect(l11 (-1350 0) (2400 800)) - rect(l11 (-1151 -401) (2 2)) - rect(l2 (-276 -2151) (425 1500)) - rect(l2 (-400 -1500) (425 1500)) + rect(l14 (1110 5160) (180 180)) + rect(l14 (-180 920) (180 180)) + rect(l14 (-180 -730) (180 180)) + rect(l17 (-240 -790) (300 1700)) + rect(l17 (-1350 0) (2400 800)) + rect(l17 (-1151 -401) (2 2)) + rect(l4 (-276 -2151) (425 1500)) + rect(l4 (-400 -1500) (425 1500)) ) net(2 name(OUT) - rect(l8 (1810 1770) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l8 (-1580 3760) (180 180)) - rect(l8 (-180 -730) (180 180)) - rect(l8 (-180 -730) (180 180)) - rect(l8 (1220 920) (180 180)) - rect(l8 (-180 -1280) (180 180)) - rect(l8 (-180 370) (180 180)) - polygon(l11 (-240 -4180) (0 1390) (490 0) (0 -300) (-190 0) (0 -1090)) - rect(l11 (-110 1390) (300 1400)) - polygon(l11 (-1890 0) (0 600) (300 0) (0 -300) (1590 0) (0 -300)) - rect(l11 (-141 -501) (2 2)) - rect(l11 (-1751 1099) (300 1400)) - rect(l11 (1100 -1700) (300 300)) - rect(l11 (-300 0) (300 1400)) - rect(l2 (-375 -1450) (425 1500)) - rect(l2 (-1800 -1500) (425 1500)) - rect(l6 (950 -4890) (425 950)) + rect(l14 (1810 1770) (180 180)) + rect(l14 (-180 370) (180 180)) + rect(l14 (-1580 3760) (180 180)) + rect(l14 (-180 -730) (180 180)) + rect(l14 (-180 -730) (180 180)) + rect(l14 (1220 920) (180 180)) + rect(l14 (-180 -1280) (180 180)) + rect(l14 (-180 370) (180 180)) + polygon(l17 (-240 -4180) (0 1390) (490 0) (0 -300) (-190 0) (0 -1090)) + rect(l17 (-110 1390) (300 1400)) + polygon(l17 (-1890 0) (0 600) (300 0) (0 -300) (1590 0) (0 -300)) + rect(l17 (-141 -501) (2 2)) + rect(l17 (-1751 1099) (300 1400)) + rect(l17 (1100 -1700) (300 300)) + rect(l17 (-300 0) (300 1400)) + rect(l4 (-375 -1450) (425 1500)) + rect(l4 (-1800 -1500) (425 1500)) + rect(l9 (950 -4890) (425 950)) ) net(3 name(VSS) - rect(l8 (410 1770) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l11 (-240 -1300) (300 1360)) - rect(l11 (-650 -2160) (2400 800)) - rect(l11 (-1151 -401) (2 2)) - rect(l6 (-951 859) (425 950)) + rect(l14 (410 1770) (180 180)) + rect(l14 (-180 370) (180 180)) + rect(l17 (-240 -1300) (300 1360)) + rect(l17 (-650 -2160) (2400 800)) + rect(l17 (-1151 -401) (2 2)) + rect(l9 (-951 859) (425 950)) ) net(4 rect(l3 (-100 4500) (2600 3500)) ) net(5 name(B) - rect(l4 (1425 2860) (250 1940)) - rect(l4 (-345 -950) (300 300)) - rect(l4 (-205 650) (250 2000)) - rect(l4 (-250 -2000) (250 2000)) - rect(l4 (-250 -5390) (250 1450)) - rect(l8 (-285 1050) (180 180)) - rect(l11 (-71 -91) (2 2)) - rect(l11 (-171 -151) (300 300)) + rect(l5 (1425 2860) (250 1940)) + rect(l5 (-345 -950) (300 300)) + rect(l5 (-205 650) (250 2000)) + rect(l5 (-250 -2000) (250 2000)) + rect(l5 (-250 -5390) (250 1450)) + rect(l14 (-285 1050) (180 180)) + rect(l17 (-71 -91) (2 2)) + rect(l17 (-171 -151) (300 300)) ) net(6 name(A) - rect(l4 (725 2860) (250 1940)) - rect(l4 (-325 -1850) (300 300)) - rect(l4 (-225 1550) (250 2000)) - rect(l4 (-250 -2000) (250 2000)) - rect(l4 (-250 -5390) (250 1450)) - rect(l8 (-265 150) (180 180)) - rect(l11 (-91 -91) (2 2)) - rect(l11 (-151 -151) (300 300)) + rect(l5 (725 2860) (250 1940)) + rect(l5 (-325 -1850) (300 300)) + rect(l5 (-225 1550) (250 2000)) + rect(l5 (-250 -2000) (250 2000)) + rect(l5 (-250 -5390) (250 1450)) + rect(l14 (-265 150) (180 180)) + rect(l17 (-91 -91) (2 2)) + rect(l17 (-151 -151) (300 300)) ) net(7 name(SUBSTRATE)) net(8 - rect(l6 (975 1660) (425 950)) - rect(l6 (-400 -950) (425 950)) + rect(l9 (975 1660) (425 950)) + rect(l9 (-400 -950) (425 950)) ) # Outgoing pins and their connections to nets @@ -275,46 +277,46 @@ layout( # Nets with their geometries net(1 name(VDD) - rect(l8 (410 6260) (180 180)) - rect(l8 (-180 -730) (180 180)) - rect(l8 (-180 -730) (180 180)) - rect(l11 (-240 -240) (300 1400)) - rect(l11 (-650 300) (1800 800)) - rect(l11 (-1450 -1100) (300 300)) - rect(l11 (299 399) (2 2)) - rect(l2 (-651 -2151) (425 1500)) + rect(l14 (410 6260) (180 180)) + rect(l14 (-180 -730) (180 180)) + rect(l14 (-180 -730) (180 180)) + rect(l17 (-240 -240) (300 1400)) + rect(l17 (-650 300) (1800 800)) + rect(l17 (-1450 -1100) (300 300)) + rect(l17 (299 399) (2 2)) + rect(l4 (-651 -2151) (425 1500)) ) net(2 name(OUT) - rect(l8 (1110 5160) (180 180)) - rect(l8 (-180 920) (180 180)) - rect(l8 (-180 -730) (180 180)) - rect(l8 (-180 -4120) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l11 (-240 -790) (300 4790)) - rect(l11 (-151 -2501) (2 2)) - rect(l2 (-226 1049) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (1110 5160) (180 180)) + rect(l14 (-180 920) (180 180)) + rect(l14 (-180 -730) (180 180)) + rect(l14 (-180 -4120) (180 180)) + rect(l14 (-180 370) (180 180)) + rect(l17 (-240 -790) (300 4790)) + rect(l17 (-151 -2501) (2 2)) + rect(l4 (-226 1049) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(3 name(VSS) - rect(l8 (410 1770) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l11 (-240 -1300) (300 1360)) - rect(l11 (-650 -2160) (1800 800)) - rect(l11 (-851 -401) (2 2)) - rect(l6 (-651 859) (425 950)) + rect(l14 (410 1770) (180 180)) + rect(l14 (-180 370) (180 180)) + rect(l17 (-240 -1300) (300 1360)) + rect(l17 (-650 -2160) (1800 800)) + rect(l17 (-851 -401) (2 2)) + rect(l9 (-651 859) (425 950)) ) net(4 rect(l3 (-100 4500) (2000 3500)) ) net(5 name(IN) - rect(l4 (725 2860) (250 1940)) - rect(l4 (-525 -1850) (300 300)) - rect(l4 (-25 1550) (250 2000)) - rect(l4 (-250 -2000) (250 2000)) - rect(l4 (-250 -5390) (250 1450)) - rect(l8 (-465 150) (180 180)) - rect(l11 (-91 -91) (2 2)) - rect(l11 (-151 -151) (300 300)) + rect(l5 (725 2860) (250 1940)) + rect(l5 (-525 -1850) (300 300)) + rect(l5 (-25 1550) (250 2000)) + rect(l5 (-250 -2000) (250 2000)) + rect(l5 (-250 -5390) (250 1450)) + rect(l14 (-465 150) (180 180)) + rect(l17 (-91 -91) (2 2)) + rect(l17 (-151 -151) (300 300)) ) net(6 name(SUBSTRATE)) @@ -362,162 +364,162 @@ layout( # Nets with their geometries net(1 - rect(l8 (4710 3010) (180 180)) - rect(l11 (-850 -240) (610 300)) - rect(l2 (-1175 1800) (425 1500)) - rect(l2 (-1800 -1500) (425 1500)) - rect(l6 (950 -4890) (425 950)) + rect(l14 (4710 3010) (180 180)) + rect(l17 (-850 -240) (610 300)) + rect(l4 (-1175 1800) (425 1500)) + rect(l4 (-1800 -1500) (425 1500)) + rect(l9 (950 -4890) (425 950)) ) net(2 - rect(l8 (6510 3010) (180 180)) - rect(l11 (-1140 -240) (900 300)) - rect(l2 (-1275 1800) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (6510 3010) (180 180)) + rect(l17 (-1140 -240) (900 300)) + rect(l4 (-1275 1800) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(3 - rect(l8 (8310 3010) (180 180)) - rect(l11 (-1140 -240) (900 300)) - rect(l2 (-1275 1800) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (8310 3010) (180 180)) + rect(l17 (-1140 -240) (900 300)) + rect(l4 (-1275 1800) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(4 - rect(l8 (10110 3010) (180 180)) - rect(l11 (-1140 -240) (900 300)) - rect(l2 (-1275 1800) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (10110 3010) (180 180)) + rect(l17 (-1140 -240) (900 300)) + rect(l4 (-1275 1800) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(5 - rect(l8 (11910 3010) (180 180)) - rect(l11 (-1140 -240) (900 300)) - rect(l2 (-1275 1800) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (11910 3010) (180 180)) + rect(l17 (-1140 -240) (900 300)) + rect(l4 (-1275 1800) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(6 - rect(l8 (13710 3010) (180 180)) - rect(l11 (-1140 -240) (900 300)) - rect(l2 (-1275 1800) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (13710 3010) (180 180)) + rect(l17 (-1140 -240) (900 300)) + rect(l4 (-1275 1800) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(7 - rect(l8 (15510 3010) (180 180)) - rect(l11 (-1140 -240) (900 300)) - rect(l2 (-1275 1800) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (15510 3010) (180 180)) + rect(l17 (-1140 -240) (900 300)) + rect(l4 (-1275 1800) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(8 - rect(l8 (17310 3010) (180 180)) - rect(l11 (-1140 -240) (900 300)) - rect(l2 (-1275 1800) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (17310 3010) (180 180)) + rect(l17 (-1140 -240) (900 300)) + rect(l4 (-1275 1800) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(9 - rect(l8 (19110 3010) (180 180)) - rect(l11 (-1140 -240) (900 300)) - rect(l2 (-1275 1800) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (19110 3010) (180 180)) + rect(l17 (-1140 -240) (900 300)) + rect(l4 (-1275 1800) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(10 - rect(l8 (20910 3010) (180 180)) - rect(l11 (-1140 -240) (900 300)) - rect(l2 (-1275 1800) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (20910 3010) (180 180)) + rect(l17 (-1140 -240) (900 300)) + rect(l4 (-1275 1800) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(11 name(FB) - rect(l8 (22710 3010) (180 180)) - rect(l8 (-19700 720) (180 180)) - rect(l11 (18380 -1140) (900 300)) - rect(l11 (-19530 590) (320 320)) - rect(l11 (17820 -320) (320 320)) - rect(l12 (-18400 -260) (200 200)) - rect(l12 (17940 -200) (200 200)) - rect(l13 (-18040 -300) (17740 400)) - rect(l13 (-17921 -201) (2 2)) - rect(l13 (-221 -201) (400 400)) - rect(l13 (17740 -400) (400 400)) - rect(l2 (-245 850) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l14 (22710 3010) (180 180)) + rect(l14 (-19700 720) (180 180)) + rect(l17 (18380 -1140) (900 300)) + rect(l17 (-19530 590) (320 320)) + rect(l17 (17820 -320) (320 320)) + rect(l18 (-18400 -260) (200 200)) + rect(l18 (17940 -200) (200 200)) + rect(l19 (-18040 -300) (17740 400)) + rect(l19 (-17921 -201) (2 2)) + rect(l19 (-221 -201) (400 400)) + rect(l19 (17740 -400) (400 400)) + rect(l4 (-245 850) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(12 name(VDD) rect(l3 (500 4500) (1400 3500)) rect(l3 (-1900 -3500) (600 3500)) rect(l3 (23300 -3500) (1400 3500)) rect(l3 (-100 -3500) (600 3500)) - rect(l8 (-24690 -1240) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l8 (-180 -1280) (180 180)) - rect(l8 (23220 370) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l8 (-180 -1280) (180 180)) - rect(l11 (-21741 859) (2 2)) - rect(l11 (-2351 -451) (1200 800)) - rect(l11 (-750 -1450) (300 1400)) - rect(l11 (-101 -351) (2 2)) - rect(l11 (-1251 -401) (600 800)) - rect(l11 (23400 -800) (1200 800)) - rect(l11 (-750 -1450) (300 1400)) - rect(l11 (-101 -351) (2 2)) - rect(l11 (549 -401) (600 800)) - rect(l2 (-23025 -2550) (425 1500)) - rect(l2 (-400 -1500) (425 1500)) - rect(l2 (1275 -1500) (425 1500)) - rect(l2 (1375 -1500) (425 1500)) - rect(l2 (1375 -1500) (425 1500)) - rect(l2 (1375 -1500) (425 1500)) - rect(l2 (1375 -1500) (425 1500)) - rect(l2 (1375 -1500) (425 1500)) - rect(l2 (1375 -1500) (425 1500)) - rect(l2 (1375 -1500) (425 1500)) - rect(l2 (1375 -1500) (425 1500)) - rect(l2 (1375 -1500) (425 1500)) - rect(l2 (1375 -1500) (425 1500)) - rect(l9 (-21975 -450) (500 1500)) - rect(l9 (22900 -1500) (500 1500)) + rect(l14 (-24690 -1240) (180 180)) + rect(l14 (-180 370) (180 180)) + rect(l14 (-180 -1280) (180 180)) + rect(l14 (23220 370) (180 180)) + rect(l14 (-180 370) (180 180)) + rect(l14 (-180 -1280) (180 180)) + rect(l17 (-21741 859) (2 2)) + rect(l17 (-2351 -451) (1200 800)) + rect(l17 (-750 -1450) (300 1400)) + rect(l17 (-101 -351) (2 2)) + rect(l17 (-1251 -401) (600 800)) + rect(l17 (23400 -800) (1200 800)) + rect(l17 (-750 -1450) (300 1400)) + rect(l17 (-101 -351) (2 2)) + rect(l17 (549 -401) (600 800)) + rect(l4 (-23025 -2550) (425 1500)) + rect(l4 (-400 -1500) (425 1500)) + rect(l4 (1275 -1500) (425 1500)) + rect(l4 (1375 -1500) (425 1500)) + rect(l4 (1375 -1500) (425 1500)) + rect(l4 (1375 -1500) (425 1500)) + rect(l4 (1375 -1500) (425 1500)) + rect(l4 (1375 -1500) (425 1500)) + rect(l4 (1375 -1500) (425 1500)) + rect(l4 (1375 -1500) (425 1500)) + rect(l4 (1375 -1500) (425 1500)) + rect(l4 (1375 -1500) (425 1500)) + rect(l4 (1375 -1500) (425 1500)) + rect(l15 (-21975 -450) (500 1500)) + rect(l15 (22900 -1500) (500 1500)) ) net(13 name(OUT) - rect(l11 (23440 3840) (320 320)) - rect(l12 (-260 -260) (200 200)) - rect(l13 (-101 -101) (2 2)) - rect(l13 (-201 -201) (400 400)) - rect(l2 (-625 850) (425 1500)) - rect(l6 (-425 -4890) (425 950)) + rect(l17 (23440 3840) (320 320)) + rect(l18 (-260 -260) (200 200)) + rect(l19 (-101 -101) (2 2)) + rect(l19 (-201 -201) (400 400)) + rect(l4 (-625 850) (425 1500)) + rect(l9 (-425 -4890) (425 950)) ) net(14 name(ENABLE) - rect(l8 (2510 3010) (180 180)) - rect(l11 (-250 -250) (320 320)) - rect(l12 (-260 -260) (200 200)) - rect(l13 (-101 -101) (2 2)) - rect(l13 (-201 -201) (400 400)) + rect(l14 (2510 3010) (180 180)) + rect(l17 (-250 -250) (320 320)) + rect(l18 (-260 -260) (200 200)) + rect(l19 (-101 -101) (2 2)) + rect(l19 (-201 -201) (400 400)) ) net(15 name(VSS) - rect(l8 (1110 1610) (180 180)) - rect(l8 (-180 -1280) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l8 (23220 370) (180 180)) - rect(l8 (-180 -1280) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l11 (-21741 -391) (2 2)) - rect(l11 (-1901 -401) (300 1400)) - rect(l11 (-750 -1450) (1200 800)) - rect(l11 (-551 -401) (2 2)) - rect(l11 (-1251 -401) (600 800)) - rect(l11 (23850 -750) (300 1400)) - rect(l11 (-750 -1450) (1200 800)) - rect(l11 (-551 -401) (2 2)) - rect(l11 (549 -401) (600 800)) - rect(l6 (-23700 460) (425 950)) - rect(l6 (1975 -950) (425 950)) - rect(l6 (1375 -950) (425 950)) - rect(l6 (1375 -950) (425 950)) - rect(l6 (1375 -950) (425 950)) - rect(l6 (1375 -950) (425 950)) - rect(l6 (1375 -950) (425 950)) - rect(l6 (1375 -950) (425 950)) - rect(l6 (1375 -950) (425 950)) - rect(l6 (1375 -950) (425 950)) - rect(l6 (1375 -950) (425 950)) - rect(l6 (1375 -950) (425 950)) - rect(l10 (-21975 -2210) (500 1500)) - rect(l10 (22900 -1500) (500 1500)) + rect(l14 (1110 1610) (180 180)) + rect(l14 (-180 -1280) (180 180)) + rect(l14 (-180 370) (180 180)) + rect(l14 (23220 370) (180 180)) + rect(l14 (-180 -1280) (180 180)) + rect(l14 (-180 370) (180 180)) + rect(l17 (-21741 -391) (2 2)) + rect(l17 (-1901 -401) (300 1400)) + rect(l17 (-750 -1450) (1200 800)) + rect(l17 (-551 -401) (2 2)) + rect(l17 (-1251 -401) (600 800)) + rect(l17 (23850 -750) (300 1400)) + rect(l17 (-750 -1450) (1200 800)) + rect(l17 (-551 -401) (2 2)) + rect(l17 (549 -401) (600 800)) + rect(l9 (-23700 460) (425 950)) + rect(l9 (1975 -950) (425 950)) + rect(l9 (1375 -950) (425 950)) + rect(l9 (1375 -950) (425 950)) + rect(l9 (1375 -950) (425 950)) + rect(l9 (1375 -950) (425 950)) + rect(l9 (1375 -950) (425 950)) + rect(l9 (1375 -950) (425 950)) + rect(l9 (1375 -950) (425 950)) + rect(l9 (1375 -950) (425 950)) + rect(l9 (1375 -950) (425 950)) + rect(l9 (1375 -950) (425 950)) + rect(l16 (-21975 -2210) (500 1500)) + rect(l16 (22900 -1500) (500 1500)) ) # Outgoing pins and their connections to nets From 1bc03c3b79049cec4fddd6395066dd2b0d26e6a2 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 19 Aug 2019 22:51:22 +0200 Subject: [PATCH 04/27] Implement "M" parameter for Spice This implementation is pretty simplistic and applies "M" the following way: * R: R(final) = R/M * L: L(final) = L/M * C: C(final) = C*M * M: W(final) = W*M * D: A(final) = A*M * Q: AE(final) = AE*M The other parameters (specifically the other geometry parameters) are not scaled yet. --- src/db/db/dbNetlistSpiceReader.cc | 58 ++++++++++++++++++++++- src/db/unit_tests/dbNetlistReaderTests.cc | 26 ++++++++++ testdata/algo/nreader9.cir | 12 +++++ 3 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 testdata/algo/nreader9.cir diff --git a/src/db/db/dbNetlistSpiceReader.cc b/src/db/db/dbNetlistSpiceReader.cc index 38773716b..ce4477c7d 100644 --- a/src/db/db/dbNetlistSpiceReader.cc +++ b/src/db/db/dbNetlistSpiceReader.cc @@ -85,34 +85,73 @@ static db::DeviceClass *make_device_class (db::Circuit *circuit, const std::stri return cls; } -bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::string &element, const std::string &name, const std::string &model, double value, const std::vector &nets, const std::map ¶ms) +bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::string &element, const std::string &name, const std::string &model, double value, const std::vector &nets, const std::map &pv) { + std::map params = pv; + + double mult = 1.0; + std::map::const_iterator mp = params.find ("M"); + if (mp != params.end ()) { + mult = mp->second; + } + + if (mult < 1e-10) { + error (tl::sprintf (tl::to_string (tr ("Invalid multiplier value (M=%.12g) - must not be zero or negative")), mult)); + } + std::string cn = model; db::DeviceClass *cls = circuit->netlist ()->device_class_by_name (cn); if (cls) { + // use given class + } else if (element == "R") { + if (cn.empty ()) { cn = "RES"; } cls = make_device_class (circuit, cn); + + // Apply multiplier + value /= mult; + } else if (element == "L") { + if (cn.empty ()) { cn = "IND"; } cls = make_device_class (circuit, cn); + + // Apply multiplier + value /= mult; + } else if (element == "C") { + if (cn.empty ()) { cn = "CAP"; } cls = make_device_class (circuit, cn); + + // Apply multiplier + value *= mult; + } else if (element == "D") { + if (cn.empty ()) { cn = "DIODE"; } cls = make_device_class (circuit, cn); + + // Apply multiplier to "A" + std::map::iterator p; + p = params.find ("A"); + if (p != params.end ()) { + p->second *= mult; + } + } else if (element == "Q") { + if (nets.size () == 3) { if (cn.empty ()) { cn = "BJT3"; @@ -126,12 +165,29 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin } else { error (tl::to_string (tr ("'Q' element needs to have 3 or 4 terminals"))); } + + // Apply multiplier to "AE" + std::map::iterator p; + p = params.find ("AE"); + if (p != params.end ()) { + p->second *= mult; + } + } else if (element == "M") { + if (nets.size () == 4) { if (cn.empty ()) { cn = "MOS4"; } cls = make_device_class (circuit, cn); + + // Apply multiplier to "W" + std::map::iterator p; + p = params.find ("W"); + if (p != params.end ()) { + p->second *= mult; + } + } else { error (tl::to_string (tr ("'M' element needs to have 4 terminals"))); } diff --git a/src/db/unit_tests/dbNetlistReaderTests.cc b/src/db/unit_tests/dbNetlistReaderTests.cc index 3a66a4468..664373d22 100644 --- a/src/db/unit_tests/dbNetlistReaderTests.cc +++ b/src/db/unit_tests/dbNetlistReaderTests.cc @@ -333,3 +333,29 @@ TEST(8_Include) ); } +TEST(9_DeviceMultipliers) +{ + db::Netlist nl; + + std::string path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nreader9.cir"); + + db::NetlistSpiceReader reader; + tl::InputStream is (path); + reader.read (is, nl); + + EXPECT_EQ (nl.to_string (), + "circuit .TOP ();\n" + " device RES $1 (A='1',B='2') (R=850,L=0,W=0,A=0,P=0);\n" + " device RES $2 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n" + " device NMOS $1 (S='1',G='2',D='3',B='4') (L=7,W=4,AS=0,AD=0,PS=0,PD=0);\n" + " device PMOS $2 (S='1',G='2',D='3',B='4') (L=7,W=2,AS=0,AD=0,PS=0,PD=0);\n" + " device CAP $1 (A='1',B='2') (C=2e-09,A=0,P=0);\n" + " device CAP $2 (A='3',B='4') (C=1e-09,A=0,P=0);\n" + " device DIODE $1 (A='1',C='2') (A=20,P=0);\n" + " device DIODE $2 (A='3',C='4') (A=10,P=0);\n" + " device BIP $1 (C='1',B='2',E='3',S='4') (AE=20,PE=0,AB=0,PB=0,AC=0,PC=0,NE=1);\n" + " device BIP $2 (C='1',B='2',E='3',S='4') (AE=10,PE=0,AB=0,PB=0,AC=0,PC=0,NE=1);\n" + "end;\n" + ); +} + diff --git a/testdata/algo/nreader9.cir b/testdata/algo/nreader9.cir new file mode 100644 index 000000000..302b7a0a2 --- /dev/null +++ b/testdata/algo/nreader9.cir @@ -0,0 +1,12 @@ + +R$1 1 2 1.7k M=2 +R$2 3 4 1.7k +M$1 1 2 3 4 NMOS W=2u L=7u M=2 +M$2 1 2 3 4 PMOS W=2u L=7u +C$1 1 2 1e-9 M=2 +C$2 3 4 1e-9 +D$1 1 2 DIODE A=10P M=2 +D$2 3 4 DIODE A=10P +Q$1 1 2 3 4 BIP AE=10P M=2 +Q$2 1 2 3 4 BIP AE=10P + From b7c83eaaa61f7390be516b8da05001285ca623d0 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 19 Aug 2019 23:00:24 +0200 Subject: [PATCH 05/27] Spice reader: subcircuits w/o pins This happens for subcircuits which only connect to global nets. Plus: ".global" now accepts more than just one net --- src/db/db/dbNetlistSpiceReader.cc | 10 ++++------ src/db/unit_tests/dbNetlistReaderTests.cc | 21 +++++++++++++++++++++ testdata/algo/nreader10.cir | 10 ++++++++++ 3 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 testdata/algo/nreader10.cir diff --git a/src/db/db/dbNetlistSpiceReader.cc b/src/db/db/dbNetlistSpiceReader.cc index ce4477c7d..928aba2aa 100644 --- a/src/db/db/dbNetlistSpiceReader.cc +++ b/src/db/db/dbNetlistSpiceReader.cc @@ -417,8 +417,10 @@ bool NetlistSpiceReader::read_card () } else if (ex.test_without_case ("global")) { - std::string n = read_name (ex); - m_global_nets.push_back (n); + while (! ex.at_end ()) { + std::string n = read_name (ex); + m_global_nets.push_back (n); + } } else if (ex.test_without_case ("subckt")) { @@ -812,10 +814,6 @@ bool NetlistSpiceReader::read_element (tl::Extractor &ex, const std::string &ele void NetlistSpiceReader::read_subcircuit (const std::string &sc_name, const std::string &nc_name, const std::vector &nets) { - if (nets.empty ()) { - error (tl::to_string (tr ("A circuit call needs at least one net"))); - } - db::Circuit *cc = mp_netlist->circuit_by_name (nc_name); if (! cc) { diff --git a/src/db/unit_tests/dbNetlistReaderTests.cc b/src/db/unit_tests/dbNetlistReaderTests.cc index 664373d22..149bc22f6 100644 --- a/src/db/unit_tests/dbNetlistReaderTests.cc +++ b/src/db/unit_tests/dbNetlistReaderTests.cc @@ -359,3 +359,24 @@ TEST(9_DeviceMultipliers) ); } +TEST(10_SubcircuitsNoPins) +{ + db::Netlist nl; + + std::string path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nreader10.cir"); + + db::NetlistSpiceReader reader; + tl::InputStream is (path); + reader.read (is, nl); + + EXPECT_EQ (nl.to_string (), + "circuit .TOP ();\n" + " device RES $1 (A=VDD,B=GND) (R=1000,L=0,W=0,A=0,P=0);\n" + " subcircuit FILLER_CAP '0' (VDD=VDD,GND=GND);\n" + "end;\n" + "circuit FILLER_CAP (VDD=VDD,GND=GND);\n" + " device NMOS '0' (S=GND,G=VDD,D=GND,B=GND) (L=10,W=10,AS=0,AD=0,PS=0,PD=0);\n" + "end;\n" + ); +} + diff --git a/testdata/algo/nreader10.cir b/testdata/algo/nreader10.cir new file mode 100644 index 000000000..f7e8a574e --- /dev/null +++ b/testdata/algo/nreader10.cir @@ -0,0 +1,10 @@ + +.global vdd gnd + +X0 FILLER_CAP +R$1 vdd gnd 1k + +.subckt FILLER_CAP +M0 gnd vdd gnd gnd NMOS W=10u L=10u +.ends FILLER_CAP + From 50a341232c404a6c0da958b4720f41b401ba49a2 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 20 Aug 2019 19:17:56 +0200 Subject: [PATCH 06/27] Documentation fixes (e.g. better LVS layout pictures) --- src/lay/lay/doc/about/layer_sources.xml | 2 +- src/lay/lay/doc/manual/bjt_ex_layout.png | Bin 4305 -> 4245 bytes src/lay/lay/doc/manual/bjt_ex_tb.png | Bin 6177 -> 5999 bytes src/lay/lay/doc/manual/bjt_ex_tc.png | Bin 5922 -> 5965 bytes src/lay/lay/doc/manual/bjt_ex_te.png | Bin 6138 -> 6053 bytes src/lay/lay/doc/manual/bjt_ex_ts.png | Bin 6131 -> 6158 bytes src/lay/lay/doc/manual/bjtlat_ex_layout.png | Bin 4311 -> 4225 bytes src/lay/lay/doc/manual/bjtlat_ex_tb.png | Bin 5992 -> 5889 bytes src/lay/lay/doc/manual/bjtlat_ex_tc.png | Bin 5745 -> 5763 bytes src/lay/lay/doc/manual/bjtlat_ex_te.png | Bin 5899 -> 5826 bytes src/lay/lay/doc/manual/bjtlat_ex_ts.png | Bin 5920 -> 5909 bytes src/lay/lay/doc/manual/cap_ex_layout.png | Bin 3492 -> 3468 bytes src/lay/lay/doc/manual/cap_ex_ta.png | Bin 4381 -> 4320 bytes src/lay/lay/doc/manual/cap_ex_tb.png | Bin 4371 -> 4357 bytes src/lay/lay/doc/manual/cap_ex_tw.png | Bin 4337 -> 4279 bytes src/lay/lay/doc/manual/diode_ex_layout.png | Bin 3466 -> 3427 bytes src/lay/lay/doc/manual/diode_ex_ta.png | Bin 4472 -> 4538 bytes src/lay/lay/doc/manual/diode_ex_tc.png | Bin 4231 -> 4328 bytes src/lay/lay/doc/manual/inv.png | Bin 25668 -> 25997 bytes src/lay/lay/doc/manual/inv_no_transistors.png | Bin 18916 -> 18865 bytes src/lay/lay/doc/manual/inv_transistors.png | Bin 17654 -> 17413 bytes src/lay/lay/doc/manual/inv_with_diodes.png | Bin 30833 -> 31101 bytes src/lay/lay/doc/manual/mos_ex_layout.png | Bin 2816 -> 2837 bytes src/lay/lay/doc/manual/mos_ex_tb.png | Bin 4541 -> 4471 bytes src/lay/lay/doc/manual/mos_ex_td.png | Bin 4256 -> 4155 bytes src/lay/lay/doc/manual/mos_ex_tg.png | Bin 4631 -> 4563 bytes src/lay/lay/doc/manual/mos_ex_ts.png | Bin 4568 -> 4557 bytes src/lay/lay/doc/manual/res_ex_layout.png | Bin 3132 -> 3130 bytes src/lay/lay/doc/manual/res_ex_ta.png | Bin 4595 -> 4509 bytes src/lay/lay/doc/manual/res_ex_tb.png | Bin 4413 -> 4523 bytes src/lay/lay/doc/manual/res_ex_tw.png | Bin 4456 -> 5088 bytes 31 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lay/lay/doc/about/layer_sources.xml b/src/lay/lay/doc/about/layer_sources.xml index a8a8d8ea1..d914b9c3d 100644 --- a/src/lay/lay/doc/about/layer_sources.xml +++ b/src/lay/lay/doc/about/layer_sources.xml @@ -7,7 +7,7 @@

KLayout implements a concept of "layer views". The layer list is made up of such layer views. - A "view" is bascically a specification of what is shown how. + A "view" is basically a specification of what is shown how. The "how" part is given by the colors, stipples, styles etc. The "what" part is given by the source specification.

diff --git a/src/lay/lay/doc/manual/bjt_ex_layout.png b/src/lay/lay/doc/manual/bjt_ex_layout.png index c896b73081fc8490a2db36223d2421fef4a3c0a8..ffbb7e4b45f54fc2440824067d3ab03790c6742f 100644 GIT binary patch literal 4245 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 Oc<(>t$#nnj(*FT<0hj{- literal 4305 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 diff --git a/src/lay/lay/doc/manual/bjt_ex_tb.png b/src/lay/lay/doc/manual/bjt_ex_tb.png index 2f605fb5a091666b5b12b226f85ac38d531b6447..50f4053fd57adc324b148ad6090140372b2a8b4b 100644 GIT binary patch literal 5999 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⪼ki5=J@BiVlfpyT>2_7W#l9WmUT#L@=U2MvHoo1+Ve4Lkl{SEmMSl7oK zB8c4&(3cAd8#*i)=|h0q1{Iv;cC8MWM^tAN7W{p>Y{Wcqqd&c0B!&<%F~?k4-|7t9 zZc+wl#&_i1CEiB~FAGdK*`vyy_ENYd$8N8y<2-vmJR+NN}3_|o?y@}Y7!;H32oBsxd{`yEL zJ}8O&+A}>)rPaIP7b&&^tDv+NM>!z+CVVs(uTy*hx%x; z(dlA__x=Gn-zt0ACn|Doq%q|96!cksy8O=LP!90#chG#GQ)B%%NTtd_c?tg-kZvM_ z;PX-7mQSVN)zpjT&;+*%@2nk)tk&uO#TtC(=Lh`g4r~1{mXG9ARAXEH=;|{W(>=*o z%lUFHL-6GAFzPqPC{&^DLO99xq%^cYdA_sQktn)7Jvfr^I*}T!^>&akmgnZmR)e}G zUxnfoQu7b!G>6Nu4+OfqG_1OqbbLZefa=St!b%g~ zHB-*pjBOA12;Xp`_o%0I&8qy%kV^P>w8cd~$YZ3ukkqKuQxJU8G!fOnB z?6e{4w$n$;hN&+0lB+}S3=!MlE^QPS|BSJ!+n?}5N zJHO^-*81gv=5qHzA+@q4ba(l)mTfhI8|E8!lkZW7lrtIeC*h*XtIyRfPW{d&Am-Yh zucK;13G5#6lT@U37~H4P+8$1~{eVw|vWfMLryF81qRZ16&uvm({PmCd%2N9A0UU=) z>I`V5#C~66+Y)$nXiJeyC@mcE~=%+(Zy>1Esdx6kA86gL0J@?3ic?pF7^5 z+L5FTfXcCz5hbWU(@&P7rtL6dP@Q9kUKv?zgbHk1h%-q75UoLEX=;!F=n9e%a1{(@ z#X;yd^N}G&4lMLW`_m|Ho|BXgHbowUDAH|`*^1O_2R(L}J*lN=e~U8}m}`ZOhUF07 zLvypyM)5!+vZlcW#|X`C2D784|KZsZlETX$zjsji3bvtfHHGIUsxtz`ug@;N6$)iFMfBj4z~qSN<~ao#$C}}!)v8mKrn=-p z{hFAD&R9sDLd()rSANCN`o{9)`_m~cQl;tB4AIW$pB{etg}!LI?Bloiq=xz`l_Q<6 zRJN`&x`HRZ{ONO~=@VUJU?Mh#ny+@%CS4InZWB17$yzb#N0E>Zn|^wIKcH$wa-pA9 zP`0ve9(tSs8UTZ|0RNY9qhUV5(A`8?33&Z#RLO4TV(;@3Xu}QO)BHyUX?p|yjI<*A z?UGzmX3)6k9hyysCZ<1;aaVpX{xiDo4Xv-uZU~tRLRSSUyOAbmgN!H7X~f;HP8Ho; zaSX%=hyNj#D&!Q+jI6q~^sT1+&7(kZ?04q=CZg!V+N}SH2_z}1GfNKjwZyKk9Me4W z{!>qwXPYLme-~u=(JYY_s?(>0k@k)Qcrzdg&c1$tT`*m!ka@EP=t}6#F9?_n-|QZo zbCF!c;%K8Zh(UzIlTq_mYN@i!iz;xw1Exbrsb^j*Q2hn9$;ilm+a%=pzwPZ~k}zjo z1CGG54@!Gr4O%bKKu(yE){tEyELyKyerUb4MPWEc9CnodHV!88NG)F@6E%P0S3iN- zZv7R>apTC_)dH|Q?Uk>YAnf6AYW8)7l^EodSzosVEa0*5;=S$<~sD{OMoeW^8L1(FA9Rp3t68NSt zuRK_LZYgzL4#z>e$US4a=IyzGgYCOS(&VKJqlIDFPts$0@BFmdjs-b?#Ae)>Q)_nC z7v~C4vYcF@Dw+2>{1Q3q2`)X&_y^*U)NZNaQViA{{cDQaKHcn literal 6177 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

?WZ7I#?P_YWuhBVD9`cY+HNo>pWTBgWIX; zf^CyR7|a(Ys#vN+*W`q?>V>j9R72R*&(V1-$S1pRD^|ZZR~+eGD^RFvLIYGSbPgX_ zt33F+fG7V(1aoO6lMUGMl+V8;R#--Y?-KK%E41Q{EVDr_ee z_}RY$ezy~ne^n)#0K0W-)7XQa1W5j814{P|phJPJ@wglWY>0}y4+y}3^ac4T7|(vu z40+5b)q7)}rLJIA9Y9D(WLr_P(_>5HKPtG6f}9fpqgjZnc*RpT3z(iPtD3%|p4{y>Rya&9 zp(jNGVt}!xk&>FE9gmOQV76;OB~Xg-Fs-bxRRS&?av@OqbC*UqX@6X=8Jt9-D#1oP zyZgS`0`jdFf9%$Jx<5;*bOiA$n^6_;w3^oZ5-1T@TRJ(?m M8e@!#j$gg~AA;{tG5`Po diff --git a/src/lay/lay/doc/manual/bjt_ex_te.png b/src/lay/lay/doc/manual/bjt_ex_te.png index 882bf5da4e912015ef91e15604e0e9fe69cf3a73..079a2208bb948ada9c5b5e10b925cd90f8ae4a73 100644 GIT binary patch literal 6053 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 literal 6138 zcmds5XH=8Rx(*-~Jc8Q|79wCdYDAhE6QnB`2t9x(9YLfep@kMqC@QEBKoCKs2LzN* z6Cxl41*9nu2%v=K2Bd>%Xu-hw;$HV|*FNX|xqt3jH*0+*@63Gjwt1d+=7FiP?j8|I z5fBKp2dSrH1_BAZ1unUrf`DWM`p;3|A>?-%X|Z$XPWERL{@-2RdRBfQkZ2?S5=c5D z3g!!OSFYoz<>Uo1$2y@Vq*ZV9Z5CO6m z?DSiiD_e{|a^K2UaP-6^Jvc)G1Ufvi+6O#d!9GGjTKoTB-9o9wpfIK3VVi!(hVSOH zlJy!f2mw&JBUEJck9A~iZOx85{+x>KO?6~kSj7YDG&z{aXbvUntwKkn2lYrpu5`Vy zH2#Y5;imjBl3-(aRNK)mOZhZ$u<(75SW*Ml=BgL64aL7@N2faHncy4kirsLa}Q$Fo$T;XP8xc+{;)hy+?S^;gch$C zdYW(N`vRZj7ZZk558JKAQOe19P7wqY5)|_!GrTgf@SOT=7Ws@`Bgunx`n_}(($f+17`T-&K%%TXQi^z@g9Im0 zg9PNOER%msaC zr_z|;G>Xnr=< zIbZc5L9Z!4W#7iIQLQE`k&GJdlIJxi`#3!qD;{z@C}!uV4%IULaNfj<iK-i7UF->khiPYlSncfzu2DtZ1PI7;Y%TkBXP z{z4T~u-Xtj^bkqGp(~tgRu2ZL#3!K~IGt8;=jgiq)!ff5YPGLlrv=$6eqOxB@~WGB zGberfF{25G81}Y0b!By0zmQSKIG7e@o45ghS+G#pr?ANWlc>Cm>6+H6FQUI+g83d2&q=89a}a%b&XN+*rL2_>4w;l zI`%=Ao3_WNsqnhhAGiueDLs($rMi5&Lz}b|>$PTXt*JG=Q^iN{nXK5ITbx=&x-gtg zhId`XF9Uh*9YJW@z~2AM(qiKJ&iso{kCmt?v~!2aO}5r+c7RgJOv<;}XHbdiMsW zPAvB#Jf#BD1|eFq{upTSB8BPDzcOXSsi$F@f_obg*@4_v(kAaXCq!q;h7i*80O)y= zHcSkagL^Qx-Do|p;;*cgrOvA^NpqrY+iT=ih00@nd#TeN=D7i{etP>DT*O;M_`pBj zdd)A-t{8nzSymJATrlF>v#yM~4^M}5ph+cSo^~OP za__5h0gaoe`4m-+0UlA&jl2~i!P%j3NwbPciRyTpW)NF!<4#xKLr5ER^P6o%DC%lf zp`4*A(LM_9)s;-|5J|3b6*DZfm(^L$RH(f^K+7*CJ$X+Wkmh%}Sbc*WzH%4_pP7A_ zR4W1Ab7VeOcEAlc(j%QpB~BhDbqJ;zq+&n1-Bc}srBa87qDg%+nNDPZ+;j_hu+emg zOt^#3*OC$W?MHj6#;2Z>5Sk7$DKcn!;8Z`IdD8DT01wo}7f$2{gwE@c(YA~p>7yS2 zlU|aZt2r#znJ*4(MiU8O%q!!EByN0w*#zeCV8K7_9Nb$-+>hLAHewVs`7`@MxbN*V z`@-28(Y|YaT|uy!jg}JCiVHQff$T#sA(IKuO@6Op?yWYU*E%?SLOAbtJ-+z5=}eT# zUhoO{fLT9<%Fc*fcwPCy7~e|bYEa1iRAw&N;YOaZ=q0@lr1=n{l~mbBBSo@%x(NNS z-+jrarjtvV4UZzFp!@~LM{$r>V9*Qa=t3SxxBzZR0MqWvs7UmdF@0+?jU@oRWRVX1!Mht6 zlEsN_R20RTocax>kF`iBE`g3C2x#6*N>m?}$(k5t#a#!hi&UW=aiNdEd$LJc^E~d) zWjj0e*(vb&j*o7@fQjkqqyWHx^#00EyQ-MyIlp6|-xk)<=^Hn|v}pYy_42PNi7&ML z`7W{Uhe={hv{wNbXdz|f(tYn9Y_u$r@COuf^BgK=YK2JRM+YjqQCN$X%!Xyf9nv1= zOu$KPU3-Ax9$kYfWz2R|`%j4xAQ55e*}J+K{ACtI=T7)`fU?FBC#Jdj+F0>XIS-?m z`M4j|=WQx#i1hTbhrSB#d~<}A6ZZpFQ`7&<;-O&7vvgZExJbPI-!(1H1Qu*wG2luJ z1q_pPGtm~aWm{IakOXth{!&gP9x2cFt~MMn2BHPKismO2fd)hf#o+e7t ze|OnstaxN@4xnRFHW)BV{79lTKc=^oMxX0iq)Du8x@9#;~Hs zMk%eM3kYbAz+taVa8DPchb^XEePry=E{eh%5 zspLUOSRB!pe0-MuZ1G;~&-Qg2!_-E9=m`EW-X?w76qFdT-wqB}DX)t~ME^NJ7MA*P zRYSDa3wM*?>$Bh^MNfg=5NiU^w2ke?U29q>+t(*^VzvjGq*2_DXc$ohN*PlkhNFdL zT^`_OLG4ao<-Y2;Q*JDhC0@l;zyaaga}+*s#~3S~b#xpN($z{5gx(#5r~qzN6S3x; zsRAM#gUAkTA+2Po`jKZ1QahCus!$-AaRighAFja-9+@)betQwhd)TYeOdHqeN6N(M z&dL@IVpr$_e-s2oBmG7RYn>*sfu-bYtR$m2X%X+c5y$O($x_o};|NU+{%_OsgBi)( z_!MJr_*_PRb7Xf?;kU#9n-fkya&)!f6CXF1B8RoM0MXKz>BdM{&=Vw&?lm%CIX2mu zITM5AjV(?2x*YMgZ->9)u`E0Cehd_RF~vfOyoE)Xz`V!Y&lgp=h>=a~RS(tk$vaw= z=lxM_b|?=DNqQ=za5m68ta~;WB;kI6Q|v@OL|8O18AdPmB$)w`MKQM9vKdUqk01}* zkW}N;Rhv&Bf|>Ua4U6TR_t5BU2S+c5dTk*bMy3q0tcDhPN(}oPn;4=i}GH3;byZdlqM6%vz7xG6YW5I_N`MkQsCMM61Q^clY`a+IoYkbca==1 zzcCaLL^R9N={C%_*tlbRjQIx5()FN-vVuWi(n839 zc4FUR8kuPo=7;Rr116y-dl89!HD$~?G;8meF1Z)1%qOF92;&NUjF}*+)~m?+hB4|8KFfDhPnRq!~V_(~2?BL4bN|DxcbF@-f}+ zC;PzB(5{R~=~tB$96$hidH*wB{-Tu~74O)JoP8GtX=C$Mt*+~i2QM=RE;72R&mMVb zorvE!&RBTgH&;A@aV^RLsum5SafG(qW-nLRgf;@lUrd|qorz$*1wvQZ<9}wpGCy0j z1XGb1J&7n|8jMyj>sKaHbE<#xizj#wJwJP+7<00}ljKBBKGKT_)clbBAIJx2bhP-B zaQI9k0K@N!qykWM4%Y)rWF3Phzf*rYU-#Lic_`<0P42L;$cXC9z|Zu#1`L~VG6efu zo5dhMIlYgqG|EpnXfY zNZ0%ixwZ`^*>ybXY0Z_1OzUnpDmAf^Uz^P1hV*LyF6r=O&)prI`UsOeFI|KtyGpSD zr2l(85P%^^9@Lanue9>m<;>5~UlI(cm-S%y`W7>|f&2~7uVzaY0`U2nr#D~i2#9;5pt)(-nb(&)y!oGszVuIS zyZE&WU>h+s8o%F9yUnjy15tC>*8=CyC_5=0cSgixPSH_7zs%oGK8A5AS-dB0W%LS&EX z(XqgGyFdeAAwi||Kr!mBQ#T4AP!)$YIMxqPhjk zys6!}=17|L(uNRWalLiv@g!Rn?`QXk^G7yF7oyw^#QYIp1TJ`2U+5OE|Hq>HM#Owf zPphKNk&f@FD-erAzT_zsuyH^QO{9iEV3PH&P;OvP z*^eBD%bLoZg15PG_QhZTJ>v!ov;cz(wu!kwtJ~{glKrayX0e)ENwI2@>9B(v+uN2d zT93+64-U)O7S&!m1E#DUKgP5=WbdN*gze|_WjaFhSot_&Yke|PbL&UN{K!nq;1rJ- zclzeV+4(2NO$u%Modawiw^Xmo9yWif!g@H82%o!iqfU31wDq3+4LO+WnH!lR;uE;; z80(NTjxszBIYs>Nbe;5jQqC&bA;3(NHBjIMwi!v+(cPaE>T!oc5}5+50ibIMnyFsm08~*^d)ZCY5Qe2|!*I0`t}! zB0bSUH(8@LZxjUDF}BlcTZZfdM0E@5I9fe-087D;4JU@+;B!9>-XE*EcSdr%}^T! z?@R_MZR4Lv-hDd&0o^W7Us0%VRFBv_(!C_FI|E?oUHI<)QqDtHHQ+1Ca;?{qP+R|+ zr$<$yeN%_R#V>vAqwmhTFrS1}ub+~8a&yi2W3E|rd7#|m#%|qEHR;}rT;QY=w4=4` zZ4S9$v585FO@ zYz|it0Yt62qE}{>z0QO-BLonxha4rP#Y=O;!nqG$oae2Q9w*ECMDGHL?sLB1;rcLk z&qAzv25uD6ky~3akY|)8^P9lh+wNWWUVB-5Q9q1TIHV*g?CsrWlQ?Uxa{NKmKq)Xm zyl^5ObpKv}2m2*u zg^L7}zX?WHuV2@M*;rVjud`9mqNH%q>ME81Q$3`9NcX5ZLhbgx7I_#ar-^huj8?=svZ72i-t zbB+^iF%9dQk@zEvGWgaD0fTua4Z0y=u%W(e3@lW=OBH6g4JQrTxd9;oyC)78hc%0W zqOdDrfC%ilAsGg<`~R^mgo%fR9@YXr3$xvN`_$92 zv{b+Axrk}kQr^-ZVM2G>%1P8p2ThyaPV|QvRLB*&27f>CvfgG4g^(D^d1SOBD{?&n zvoY}z1}39zbD-8?@29YKQ1k`2D`$BB(Xh&oQXkWw%RG$&lY@RjuJS@mcRiI*nb0X6 z*WSA01M^y0Z&adx=sJHNir4ys*ZLS$Y5`4=c^X}+4GQkMh^UN*PK0C!Pb;ZSe?;ZI zbE?<|7oRa=aU)0mEGV7L9o!mNRz5fMSfN2o%R(li1_RqVWU2T-UrqWnC}~WF9rX9X z74B%f`gpNlihO1S((4W5snJw5{pn-TZG89fZw_V7CpYL}{=iA^3_q=lc)k>*M*A2^ zdy2FT2RkOrBA1WGVT(Cyy6)&v3O;xFV~c{mSq!yWS&`F}HL{g^QEVFl)%F8Xn;Cxk z3=HNMJ96{qjliGt6EcIMYF3#{oHFZ?p=Bg}WH4gwQ9z1G#?oW#N`hOiCs;{en80+$CZKw^|?lH@V$5=;`4&8hUD*`ir{vcoAdEmBws|cz53E!P0exvf}8P z`YoskP9{5ow;_`mQXii+?L=MJwyBwO?TU9RP_9Xg>Uhd!hj~Bn?F<9u+hAdUTmgOb5{QgvFa1Ga%To~u>y}IC*B3!T{Lvp=S zUv35CJ}W=y#Vtgey(6%{KFAumS}wNbRo^IJQg6KX+1b%cln0n-a;#<^{+m^kg*A&( zc9B23D|u~N!tLp5Uzsx5p@AfyrsloR-8GBnD(oU-m|(bhUywY>WT87jBP;o>i<0y6 z{$qoAlUt>93689l>bkQ_4JTeDluX~oPY-zNzII~QkF=cT#C4aX_$=?wV$NG5(-7G7 za>M0l)1-qQCrz*{ZlT8ew#44nplNseql*u;Q1458YbZdFK|!%Z*N9Ty)z9|cugV4; z+7i#Th)ug&WK5@>d%x<9j3UO>?ZF7DZPdBsUdoV+x(c1liv4kZiy!Od@S>$kF+J*a zsq~NvO3nK=gTbPf ztNbb2z>kLTLDwHB9hmQi!iLQo=k%YNIf(Y!qrfGtRP94fjE* zh#nCzLD9$F;1AIC#|6KrYI%6~$}u&=KR=6GT>JTf-}C;u#$P4;AA(@l3H#BhsgB7x zj`EEQj(5Dc;-yTn$GdMv<=&ldf@iROWRlc6r(PstSm3h z3!Hd5S$D=d%~oE%Ng{OIJAI~0WQqwMl+Sr%hvGi~3S=u5I1UV{3*o-wfEVtuQ5HNG z&om(tA2He(<}9u+qObwlcxgLDcH`4;$re{c7wzEg@0$8P1-K5VdJO1%&zQf`Pog&F zBuJ8YkNuoE0sYJVI>{j`-ge+w0$2MHV^g1RVI(jgS2y*SEHb2uaC@`!SbNlTqW@Rq z_}*ibzuFi$n7gi03F8jdgZKvM931XS2`pfEhTy#i1MG*0%S-$;_?+I}hhzq<&-c_> zvKQ@>k22nC3U{qF`Cv+lOxG86(qi7kZjLFG_&L2*yFiKBt>BujO6zdA-g#t=R-Oti zN3*(^(d_pwcpM*CIDo}HL~5#in2-OKVw60s7q&9MuIm90{`_{}EJ~&u z_inpRM)MiF+iU5(q+Xmai@WI@=Y>4D&+{Q2iW*XfNKU_cij&;M9sU^K?l9qv7!PdD z>W71=t3CuLEp+qo1V_W2)RJGt9SX!VL4BHK<_N7~Pm=a&XZ^q|rnS&@o2A=`u7nF! zGatH}G|uAYy8l|0H+jmbq}8sEmkXfB0SBBX?!^w%Y>dbiEq@B0AVwsoLcXHNvWED{ zPwjhL33LWGHXDe45B9Y|UFS>JlrtpOf{Y2IJ+QbzSwII zRL&UD&2mc=s%KM3o3md6{Ba;3n_0uy!Vjxq?9^09@S;>|_Qv)__MGs<6ZrQG;-AQ} z*uvxLS2C8eY8W#o(F^EZD0|yvI9$&LiHiI3K7|P?v`5QmB~uHbjHpu7?dTokY^;p7IzT%?qfhC z!wP=o!eJ-WiMwTlQDHVn+yn0bF;Jj=0I*$V)fhS#(YA{-hr^ry-xw7XG6qO$Ks*0X#MucxZ z|Cci3Kn#k|DpWTH4i$H~>#qb_l@8rj8aacJKYS7)MTfprdC8gW(hr7X+b7!g*{zJV zC@MNp2V${{v?yKb;Pl4>Un8ojsupiJh2VK(Ce?Lt>}4lf>6`8IuVKYAwFA~oiUDu8 zWAUS$#=UIMSaz^^pu9+5{?N&DmH4EWICGY2sMKFzG}JR?Iv|B+pbn$z$H;&vk>Usk zNE~IDr>Q6z=v5hEQ&hwcy}i=`LOp=@MO&d*R!JjGs3DmIQHn=U5ec0HzcCr4P%{V} zact((_cx0rcYz#YUxBPra!aa|_y;RX#xxVGT(#^L^crPV&}zem9Ji2-Pdc{mA5oUb zQwqsK0ss3(=*>{|l}-McVzf^aZSFN|e@yuL@oK7{xisg*)5yMCG6(QgeP*FS#sGN- z?bFoUB58NqNXvesJ_b1zvk^+E&YKBq) z&2eCv^d{9=En4TN5 z>_Qjs_|p!|lM9HKLaz{S*YZ+-WOJI?^QShlP`=6FO#o%(Zm^;de-`iS{Q z5;G_(%fA|bQI{TdG@Vzx*-`zaT|lw5|0HZ`z=JThPKo|5wG;stEG`9qMfT+bq*Kue zN%C)>;M`CTn%_2e(FMOj$!sw&$Y5S}%931vHE?Oe-h}kl!CE>ZO+Q%2m&%yJ*@Qu5 z+IYy5%7Ebz_t26@ZXh2}-AFFX`FjR8J|()}SdokZpfX4tC6T7x`4b}-Ru(tFr_PY| zt?Y@}9eOV1?E)Y<&hj$^B{M-*odSTA&G4-M^9!0x+jg3D0tr9hOU1~+6E(EpUpvh{ zK^qu2?W{(*1X~79r=``koGk#H(Oj>G^wqNU4WMEW@YMZG+|4#K98|92Li`EN!%Kq) z`Pfl2SKE|>!ctB9)l^YTF846@g~)K!$#??}kgmNOM3g5tkvXA(bLdK@{rfZg@wDtiwTr7)bTs zR)!u?UA2gz6@px~Xc1yv4F&7yAYOsTq4&YZfllxLX|7htnigc6R7}~A-2Z~eU;VWL zPjLBTHE^!;&O7t*(hX5hfbIz(nYO&l_0}iQe@Cr5mkHu2i#bX$eIyagI#&c4PbgdV znXHCIy=D7SP3Vc=t&!*ZGxodQSYx~^m+`WO!I}LzB{~jB{bCE6i$&izWw;{mhC zaM%qUghSNfnU3$1{~P~aLg6&g3O<5k!wy|DvF|Q;90zocTd1tkCRdH=b_kX5Ziweu z0Y$RK?wH&`YihbNeqYG6Z&X9r@rkjME{Ia-Pzb~uSHb9fHp5Usr+t8Bvr?i20;kh$ zj3J0BY&j?7l;ZG>Y)v@0LrTK!+Y^;Jj3e}DU)$Po;MTtitrnts?9Kw&1LIw4Q2woj zZ{+ygG`vy}lZ($$fnfN&mSVldc!4Z29N6Q7KGUK5@` z54N&TgKL%&YZ$=@R89MKyx~Gl%6^PyvBbSXM%hyLzj3v+hye?Wpy};zGMEnQ!9J~0 zq~>#W3pvj(baiE<0H?DnFI6nK%b~6B#Am(T&R@E$ADq@JGcQ`QJbNitv#OVqgexJ*VGkMw;(lIqZ=l4hXZZ){})_*;N3hX4HXtuCM420Nt_E89ueh`rvGUi`!Uxh@CG-1WwJEcn`vrYIA4HmId3%To} z?4{6wR75)>J-qd$cgBQAKU{^{)xFVofGzQLoksIQ@YOx2*>PJw8Uk2|ItMLZR(y79 zbZr2=4!)6EkCR4aFAs3TYA_qz`M2apeQ|&CAH&|BOd9N$Te#2-0p_BMiTCWl${FJ# z$&tqFd(r>El0(qGgbT-<7!)HB$(`PA_pfgDn(Uy>bZ9>e3A}f%`COIq-5V4^h@oCL z?i(#$k(fR^(W~L}7FXUA?}3_kn?Li&^4z*ired0unP33vH3E-P^_UGdjFRSB_ofFp5wkcJMN->}>Xrm?Xeh1GVB>SqrdeDKj9e#vp<&RxZS zQ*8$$XFI^7{#H;$ZGpb%8g+u*j%`bs+nV0cBg-*LH(NZrUSr#b$>o6d^SKFiRtB6` zSPeockrGYLWL`@>0@sV4!4di0Q39EqH!`H`7w3cUDXr;@gCao&`9t8n`d?(s_^Yxt0C9=GP*%X*;bP|L1sQAW4JIc&{ey#rO6v1A-}T-qx8=N%DDcWBr58>DlQG4Rj?L@yK|om zjXxzfQMJ~G;=j%ZOer7p3kWD;{qX^s*{#k+LvK-kuGB73^Rrz&gLa1rYV4&w%%-eF zU=Du{F3%5!Z2d{nzIua)e6(pWSchMR>Rt;M|2yYZPMN92N76E=`X;}PX=^S5iaxoB z@Lw;9E0@DbUyN82br{YP2SvHL90vF4#WING=#$02UzTi)i9ouQMgSr<*{^bVWK913 z%X_azY3}b!GjFQ;dUx7zHX9SVmGAX8E9WwNqpF(L-2t1GPZ8&29;*G4`9A)(2Go|Q$5hN9(n>DX(0zbG<0uteRV@q4S!0tILW4Ul1*HW*=40*|P|CXaLwhb&cMg@fpe`2W)hb<l4QvKp>Hqz*k*D6tE0I4-NxAVqwRuog^eAK7T_9AGd^@I2#56Nxv3;MN$t-Lxjd~ z%QN8?=YxX&0y!b>N*N$)rnz#>9|`&2;YyU?k1nrV!4vCh z_F2Q{gO(b0yMPyHw!QxAK_p?9ZzJiqr#CFBI`7sj%J-?5%j-Ky=d}fRJ3uA3fuvJk zd3&DbSkvJm3G%NC*APL*1gMg>%z2EL9pq5>vF&Kt=iU0!{PMojWH09TzOrTSDj7LG z2m{7>cPK?KppDIx~?bQzUC67UN8-Xhh@k9U~^Z|~uK zVKs>yd}bFgNH?y_c2hjyy;+ZQweCgfM;_C1OK4J$6a!4!3(~}tXdvXy{CNDW4w2el1nEpPBI_b_VM$>Ms z7qjxUvBc3syacErLsu2dKavMW$vj9*@^mKl*xrMi6d*->vRhnnX9>Lo)3dI;WiTIq zZbzL$V=F!5f346MtSn~7wm|FU$al_6^hU02 zV0k-fl?12NMk*hm$yE>K zV1Cy_fp+Ri=rcX>ow=?sGG1v{jj4VpCQ|_kbJeagh7eF4anYo~LG)_rq&hEx1*^JU z%zyD9j1l!Y4~08V=(V+VbtI0b#Y#!EKdImII0>GuA6|*VDP5LYB$+s;&2WSpwN06K@6wOz zjB8~lir39_K}OZuW<|X=Nme#Hzy^_~c1)E`6&jhZb%)UKZLXUIM4YkIMLZ2b(f61zT?575uZK?X2^Sl zDS#*Y4w+3ObQ+Aq7neQkiR*1!mc`Nw^2tc%AIEYI>3FV%_UAWW%OO+8S;vX#MBs%2 z_#qq2UzpHTdW@lsRAnul1zaQ%)*C>zt&1%K^)b#Tr;({CbQpYfOsA7R58-e!(48zwsPpgwKr zzRJA-=u15cpYmK@VI4BTs4ytm!Gkz}CD!#)2kAaM$|K#%FQCSdcf315uq#HH!N(`0-(T4 zGj6cv8CdeTx_?s%n*?EgaL+~0htfWvFEb~L|1zRmGpu6tPhM!Fs$hxRPWd18OjiSI z*aHWw5A7?IAvnM!U+lG)8Pf%u;Rh%gi@D2=JYkMFmNx2+xh@P$%=sK-$NA8bNfE0}_}@veTBZSr~yJ%>e%tGV-sD zAQJWEeKw|)ZR04}sPYBHU(IN|vXp4-FKFumH zi&&bq92ky_mV1&YI{%XMCV$_D!o=!@9)`SLeZ*ME2`7A|blr}XWzp~sCEz8!kb-z8 zUkl@3azVg+!c5k)yrY#SD)ZDGl|xNn=kR8bzoffShv-w z!?@TYaNNgDgoI96?JDVJdYYaI+ouqg|Y)KH^qd2MLp&AT)gIaxlQ`&D`XZYlUV_%U0 z6@)+UxAyamP87@=s+wE6+P0RXp+3{W@Mra{hdsy7dakeXv`T2*`BkHVv#j+3obz|A z9O!_32(u2uoSg6BE-cMVKyBCCdJ=C7n$rP{Il{F%)tq>KKH8+C+H`dNwx5)bnZzl8j!pH}1Z=epkpUg8}sg!ZA8gWU08+}42bY`Jz zb9{jV44p1vUX%s4HxD2uhmjZt%m>c+okm*kbfE)i^^yw!krod4# z=JxcSo9l~fn{!TL32zyM%2zl#ys`3DrjQ#bL>)q!dC)6Yq>FH%!Ra^!j{-cGrwqtK0lYy3wK~fM~^Jq$9DCZv=oi0GRH|iWL|qiGRD4Y=GYT zs?XD*znDE-6~JRL={koEYD)A*Fei6QOHETyLP2##)ugKxI;NY2f(5k8=1ydism1>R zcz}9oKJ_1n2lj-K$7>#)4AgvgR-4DKh!cW1sgk-#Mn)fI!Fh^gHVkj3)YcH`(NVQ- z2^1YzUEn_fn3GKOh02J*X_SoAwToe`37%U3E%tLy>>u<{m4EgG1kBzvSFmjbgkLpe za^IYZ4%uK8(0~&a4NzpQ(?owg{#wUfGF3j7#W87Kn;#va5$cy;K1`+OiX2U0Ozy@K z$BofcfTFiF)tSkWAh}eP*N&Hh!xxf_U{=$a zMmeHUe^xyHbsi0L`t57&9tAbUW1g*mF9b+NvB#OQvG2_4NCRm9K;iyUs~ZXLy%+=yuIWE;zmWR0S`OEa%>DF7 zC?Io%1dU+9sU*+STlU8@)qhBcp#c&UX)2{Y$2|g|Vm1`eN+#(o0OYXq%i);=T(2&Ex(baPMdF(?59x@J9NCzC$xR2DJR0go{9xZsrYdqKtx}E0IG~gDo_^y;^ik7|155n z>Zm%V6RH2^%`$=YYF2Z7{=`5FPIjXXT(x^0WJ$>ccy=Rhc{F-b!#flwIO?*n!2gFg z-zf3ZWFFEjden5e^^ptgLYH-I720FxrRbOaQMhN~JXh|_z-U5&_iP5zp?Q5hP#7Pb^dAL-1V=+iY&Q}=DK^COCO2)iuF z39+P$AL)fHaPfp-uCsxAP7-@rvwU^c{ShWbz%`h+tQtzR8MXl~U#_=M?tNljK_$F| z5X?0+2)CMcs=dg2x0-vEYZtnWqW$7aX72&hL~~RuYlZ6>09?M3fyCb9adeJsiS53R zZFwnk>TJi1A@E$oOnBL~cGil$E?CZ)x94flymeRIy`wLo)x zs-vUOsPa-f5}4w;rfRs$YNXvdFd>fn`&yjDl}Wy`wYIQU9bFwo*UH^nOQU}J??>6q z1x4_&`@!6Rjh0Xe5(%_oE+oJUBMz?FnM9gxSh+_0Bl@ytM;Wz^$UPu)tCSp|leyKr z!Yvu(emgxqoo;(&Zh3i-yd`8S&~)4AY#QO$S0i4n=f#k^_;;`LvfmV333N@D1a+Rv zdgPzAw!U(bCsmGZI6EY940;(QN-B2hHVjacGMcEjv!RlJ;nt>DZHURi zqr@?wX$r|8c!)wJ_sVUN4%UU_LNBjeO&HP6n&|P8TFqXP37n0AiyS{P9z-iE-e#TY z-I?&{ksB?^%TW}G*6Cvoa0g{zBW&L zmtH2usn2LFun%ZyX$fk(q-Sw5K%*IG%u2+Rl6K;D%YqVATb)Dvfi5k`_r>7WoQHN^$mER;a8)KU~HSwm80T-Uj;xVs+K z(=pW1($dm%JmTP?r8VyvcuW@02P1;LKlOp11vq<0uf>ZOcYkoxye>I+R$x$HGw2Z<6su*l%Vd|eg~{G+zZy5ewX_T- z932jL;q!)jy5qW!f4|Tj?;X15z&>4ZtK$*f(^lHsmu|m&ZISGN?UdI33k!RVmnE8} z;Nj@K>)XZ~vNnG{EKtC;6w_{#dRp%+%ypLijhbiw)@c7_!-b2{6s-;6D}Hn!&Hwct z`ogmR!^xRu#yt1eA9g5L<>8^sD?(Ze?>gJ~u5~FveOLweY38JtLa76hE4B<% z4^jgjX4m9*uCHa33@-IGgwfJMTRTo%N(W0Gk@ZQJ`CWQFoRg8C125}0oGd06McI>{*;rLt zBR9b7o?d6H4x&~Pz^pdBc7q62xDNia@xazJQ8Rv5yODF3WBSghmjk=orY79BdkeX! zK)$O8MQgF5Mn7@5O7d&}JbTQSe8Wz%KIZ`G*=2qNUj_}PPboD&>1C%Yw)+E zt0s`sjF#!@!oLSbXG3~&svp;uu?{$_4PU`MW))ld&f7}MSJ9WmDQ5j5z$@VGyf9~x_=^GeKMC~NA3d=j# zf()1BG}%5vu}y?$3gOJ`+G~DO2cSMq&2wXn2WR~0TGh?JkCG-AazFLQNyE*%5YZmy zR)HT~@A3uphRNz=b(&Nhhu1#Is8%T>K20t3{0pUg3}Rucv!Hk~f!@Ins{+!o1^WeI+$3Z&bZ&Oe}V4Gcc(f8P0G~=gG{Va_PoW z9_`%FGlS-n<*3y?C5Kkup1pF_>m5_w? z07ai5Md!;>I`2kYgnX~BoXkmHT{rrsyYn6$P3YnCjk;TFt6w1|RsstilIrA6^Ucq` zZx0i=+1e?6Ng*>Kt=AC;2epY9Nut7O#s*^3uEq%!rInkY81$c0C_(@tXe?8p4WU(W zVoTG@WZSMib_qjL8O?acO#P0!hz8j~3*7F;XGqigF^RJ4J%bMZ2Rn8$V!m4^{?#?Q zDTWyKQR+l1;n*G>Xe}>&P@JN+tzS&$zVa_#v(b$mkRnj1yx+YgZwbmu@@0H1B7SUn zmqv{qlc#Ib!Uw1=_0oa5H_jIg)hea1af|ff=o1gUjiXHRh&9)7@NF1*950%DR{02F z;xuFW9pv+?z{XU`HHhvR=kFNcAGJduQ)yW{$O404u4ACrpm4Nl@5GbG!6M5psOia%ge$7kNIPYoe2|~icl3w{l(zwsS;4zL z7ysuo$SDCUqn1H~(4MLcI$C>M>yqH`SYAs&Kytvb$Yl`b=H%5BhCfIO$b4FzA3uU3 zP89y8w~<`n3TtUMg8hLcGP~|1a4=r|uoNb`rYtTx7uIu(@sy4}UIHS150}mLzu$T% zm$fL=I3(|83EJW(8fw!h!s_u$%ZB=Td!nr;dPa>3EG97pVO6;OP%I-~0ZW5))Vm~| ziq}H7TtBfG2|xak`hzf)kRWyDq!2w**2u|6k-F2>>+ATxs4$FG%-|{6tNcFg+f=LWEy@a>BedHDh;^#@8ILhq0OJdR^ z>0zZ9q>r4koQ#*1Xd{EC%}%z}RyPPF{qu+)cG>ryPwBij ze(jAy@+R^-iyRnS>0Xi4=%Ri>ez??4z#TBq^KWl+BNK#&w2#OlDu?)zMo(#Ie?&wb zG_IcmYZyC&qg;2NycE1`%*g?8?~Isvex_HizNBs>x^W-Y*%h&AG<`%+2Yy*z9oatbR{wnRtnqTMaVN$;ULM zT1KR-t}DqA=Vl}gz5Qr!Bp3ERA@}5A()iS9oW9i3!blvq2$Dr9D|;BdE8YtxYwEY`c>ETM3i; z!=Gk|+8<5vjI-Dk(yEat93>b;(1YLV4b2fb`MI#PV?VXuqw@^uboAw~3IVeDY)`ic z#qJlO0#`!jRa2taNFmoFjJcUc0Y5mj?C?YQ|xl0+qYRKe$m?bGmJ(EyJVV1vig=)8r5r!p5D zSfFG5vl z%&CK;ES3Hu&IObLzJZql#qTwW4|$MsU}YJA+&&xyAq^Mb2CY|~Cfh2Vzwsjw^2W(wh~ z?(i{ki@}Ie;zh4uJw*R0n z0ZSKnXacIX6sWOwF9PndivVguL2dh{8a!G6_Eg0^2uxirGXxH24!=UBdNudP08G1orcJ^xj~ zTsMB+y!n#GsAvd3^9qO!#CrK7fTbxl z>Xo*+H;_bw2T@>Gv<1vhk$q<8p|e;|x4>*1g|hkv+YM)aG|DlQ^59kldhYVlmSnCo m=6nDD_wE*CE5WA$EyqKy4(0Zze)%s$u(js^ literal 4311 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 F{{ou0;#vRz diff --git a/src/lay/lay/doc/manual/bjtlat_ex_tb.png b/src/lay/lay/doc/manual/bjtlat_ex_tb.png index 3eed2fa541580da8c5c4d29cec4a578e110e923c..c8e2524d35cc94fa05f7e3d20d88cdc3bc22adc5 100644 GIT binary patch literal 5889 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 diff --git a/src/lay/lay/doc/manual/bjtlat_ex_tc.png b/src/lay/lay/doc/manual/bjtlat_ex_tc.png index 468eaf9e69866216468957830c74f111ebdc85db..84abe9031fd4f6154b02262aa922f5984a5a8bd5 100644 GIT binary patch literal 5763 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 O8K1K-sxZ8K`+or3_D**I diff --git a/src/lay/lay/doc/manual/bjtlat_ex_te.png b/src/lay/lay/doc/manual/bjtlat_ex_te.png index deddcf8fd88f083ad994d86f050cdcb071a374f0..de58805576d29fc8940f7b382c4409153a0c5ee4 100644 GIT binary patch literal 5826 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 literal 5899 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 diff --git a/src/lay/lay/doc/manual/bjtlat_ex_ts.png b/src/lay/lay/doc/manual/bjtlat_ex_ts.png index 3076b03de0a5b94bc594f040fcecbbf6efdc458d..fdaaef5c2464980be5e186d1da6121bfc9ca2407 100644 GIT binary patch literal 5909 zcmds5XHZjJw+L352kp~9-r@sbw~qP2g|{=-Il40hkpZdQdrly4t9Vu1>M zI!_D8T(15zYsg+6wPeV`9kW5fj7~$HMV*nE(9eq#-p+3cX!=Z7k}S& zNTVLhPI->LuO#EzFa1S%?$drbDF|fdr}`-PnU*(#LJ}qaKfONC+T|hk4NF#4lKOjT z?YhyJ96$_GLV-#8>Ftx4RG-Kz%5%@tnyDQX^9xRT-~2ZfVsXSo$tYJ;p}Ag42#L%x zL3J*oZO*$}S1G_HziaR_nJ+xW-ToTP>d}gpH9_ex(EDnIz1PN7N+KFu1whv9e9;?)rOP#O;yo= z5JM72`=b?Gw!Ii8rU_TuwJ&Q!!pnSKSAEobiW-jk0U&zL7jLE86?jqU>jMI*vkAm7!;ZyNy@s?#cFh(W z6Zs{y=pc4EKu_1@RS}FzoPQy~+-`svyZy5+Z6DU!263|qfwL6+>^95k-mgw9JhEAZ zX@{-#<)LGxM52!3)a}xYhMq&MQQLEh9VDmx`FNbXk@17zhQCzd^6L)nPMS)oV6=sV zNWqsrS8af+W|0jtUiR`w?5=5Kz&nk=6`fMQ4u7p1MV%w2dyn_0Th!j1KZtX#O7_8R zAiz(z=K>Pm`9N6@pK<}I;FeI>0uV=R`vw5B*bsDb_6~{0N0S={cCnbMW_iS?q{5N< zo1Tg330B?Is1@IP_4}b{oVOs0gfYlgiC+|KpnXHWF_*s6qgCmEtF5}=i@JzJ`J_+# zhj16kA1_Zu5KBUEzFXUdCgx@X){EX+UgOLtjv0P#%+z5R%8gyR*8Z^5J3VrnTiBPFhbBiS@FtY8fCc6Q`isQLW8a3hJnxN%#^9QD<_{Y(>#NhUbkA3{} zaw`V)&eb7UER_o|7U<6pjzwra$ST8zO9^#(YUN?Z63Z4xM-U4$J$FyN_?Fln;DY+@i$8A>OBZ zw1)MxO1gvy<K^_=RTvf^KYN&{_z=(*}(E_H|BYLZLM}R@%cas){vOBb-$~cr_W>n-jQj$F{15 z#d#LEFpRN6E8#QSgaE;?H6nca5we1jJzlK8$)7`8S!Rb~YX`KKg zrY&67mz~OTc^EorSdS?lUon+ZBwh@q!K zT9!P@Y@R_9V$FDc0L-Or2LhBh$<8 zSTp|Z1mE_wt85&juFhf|Jaf?;jW-^z`LZ*y*H$WckP8A zohRz=KPQ-F2N877rbSImd~?9m?rhEKX6Bj8j;r?)OAvEQB?BjGq-Q$%D$Zi3QFx+& z)OU%}w58tP&;#@gK z8iZNFDnpDA%Zp$?*ilp$E zLzz2*?bkMu@WOt~($SEqRGtdHi;&Mvf|CP76;ENz9q-{9e=Jzm!39m8Twqm$4sxNxjvgIZq=jY4#Z8VjfpkhJGttRojB$FXuwo0Sun$HPJigUjCz zA@T+@EOF(>l?{#Zu(gb^+U$=D$48NHT~fPb8;z<#Sd0 zt%zqU-O4%2xL2z&=8DGMO51m>W`Lgu>l`9HpROb+f2$Zj88`7O%w9SKP@$mAWwcEJ zEW5cfy%aCLDIpi=7nGBfC;mMGEOG(V4QgYhjJHe2e3jzkYe*BH zHYLM#pLsNs#4qkxP3zC6N55$s@2+$>CZRqLSfp zRM6ywfH*F2mwy^;sd}6GL43Oj#?^OhLGx^*#o>fHcdRnKnWWrKYqKB}tfJO5ze`f! zf`)?&Ad~)k7k*iIV^x7TyPWa!-&mhnm{u}oz)gu;_yx$&=(sQHtrgkG_0_7!7+?eu zDlG%3*3&wb4$){X2Auu?Np`c=1kKYlk0BvFXb4$87myw8=27ZgqJq=lOUxrLU*1#! zYk;{gI6R(}QyRF}JGd(`_9=+TnbL+SJ-#|lbxH8T;5m9a$Gs-ZU3Uex_CEh|R@t*F+;=N=67vi4x6?JvF$1I3KJe(9&@E+(M= za9glM5ku`Y=#M=5FKVlf0BvY$e*b|ff|K;8!NVr^)9^d^9e=;vDQ|y)+SV;-5jU=6 zSc-&)a%i0y>=EF(TWJ}of%WkA9*9?PDaJTOwbR=av~HcA2jE-!4_LmgFO`#X`P&fM zjivNwd~EWUgPD)nLfW}jLg;1yvM(1RogN&)(oCK!Jxc5{u8n;EN zADm#+jajvZ3nW~k>gd(M*cE5T*4wU9f2Rra>aTs`TVMaP_4)tDerQ@R=z0Nqt0IGBugV6efnYVwH-nzdH;{xGDj5ovg2BmI9 zDFte3XFH2I!tI0lP#}BOPhH{ypT+{=x;@zbN6-K&24i4;VQ3qzM7HL{=Lx+V3F^M) zXSu()MDV3LgMpV*O6oGlyvzC{#I96SI_xw!EC^lAPk%7|KjeQBF8mY85@N!<{b$%) zs`%u4$^Sw8K2KjIjZObE^m>2Ee+Pfwj@1U?Kj|iUbU4*>%gGZH>K^;{(h{om8fwlf zn-S8wD#IS^+oWrOu_3(?Y`$LCCv^v`+$&2IS*h z!smWtvkkL~fnkKo2*Qo>Ag_CRWx|&Z#bzPrJ^tBPMG2bkxARr1y=S|c#psmfLu%^t zuxi~fR&3STRBa(J%U=-sm!?M&)JHl`ZbV|Fg$a$+7WjwnKYwm#ujv82?ajPIpSfd} z)W~W1TDnlu{%(Y!v5Shpb!2(4E*7^^#rsm{lv$u`73DrrDyUv$uge9Z7RD=#u)HBo z)QaKGJVxV?e^YW-n0rjpkxtu08epSb_IWA%A0F7W6h4+Ubx(Lz2U!UH@jcXJ>{NGC zFaJRV{-^ME3GxKIO0vqwR3wV@TuO(0`*N!@ho}E8g8xRyoVOoy;)?}P`2{#IUD}s^ zCIKzPG5)7QJqm3>`tHB$yWAHc`BfZ}_H`pZ=kzbztC#`v$C zK&z7BrrF>El&pu(8iU=#;FploO<+z?^DAT(W6S>HWWFb^I1?7T@x=Ixi&?#dn&;J% z_PuAf;yel6!m^7!cK5dR z!s$ky9lI^<{OG5~yT%r$GihpLTf+!1IHb|sXC_-w(is^U?WgFs9!u|0jP2fvA4p2{7p*EHvltfiMh0Fa`~YO` z;113HgTVWdg}~tV(iuz}1$nvd+qqeGF5TsBW}B~OVGw7=j_d>W^HZ!Gq1!GT34aEUB}b1d~fSjF0_7Il;1)@D`9V0{!>Feu28@Gib4WBveN#-sY1`21m^M^>TD z?MSpLMV*`P;Pv^g|L41=6MSB0W3RJI=tmlmP?daZs^;(Xjm}iPr9#A=$cyY`v1f_% zPZ;~#B3aI4saVyRl=7^ZYjo@_+VO9U{J|OsXui>gbdy>@j7Pv5}FOPtk z!JO~>Jrsp8tlBV?&mcTWF|{<+{P1h!P2n+?LGNdmO=jXoP`Zq~T3#i1k%7jE!zIs{ z8^WlQfdg4CalM{jd$i1V7=(Hc`QZExdA$-FRL4BNTI2*D=@gaM~DXy<%`$Es{l+EWz zKrUJsLLtTWcZ>&{DUhO;gWWMi<4l+&r0II410;G6=)M2D*RrDAC?COJTYVP1u7(`5 Mwmnj4dExrM0A5jB&j0`b literal 5920 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 diff --git a/src/lay/lay/doc/manual/cap_ex_layout.png b/src/lay/lay/doc/manual/cap_ex_layout.png index 9086c73662230f43280c4e7acfc096adbba77989..73a15771b9f6654e588fcbc2de4fb20f70411068 100644 GIT binary patch literal 3468 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 literal 3492 zcmeHKYgAHe8b({5Z=Ej2A_-tnQph(ZoA9EdfO$lH^#tH zzqvU6;c@Q%!~n|6$Yq7j5xdjU)}2q+yv1e*e99O}dUr7xWp?oTqwDE|oF0?pwJQvF z+By884S)3;62u;Ze_RcU;xbM5T?6arqR6227{hgr1no=3s0+)Xddu?>S`PnPH(%pd za-|~HOBkJ&hpwss3Gas*t~)iHpn`JnkV~0Z3sR2N-uY)wa5r{Tft5opbF8fyG;}5@ zw7rOr%wyueDu~HCTLW>Y&{|x|%)@zka6*I`DQ8K{CbyO^UFIW+{5+=B?ANZDuU!ez zqr}+}wAIiq_dpk@i2}O(LmS8YyXsB?=fOVkfLOBOA4do` zwZBbyzxDYG^^Gf`u|uwrM=1#BxaykrUO|fBrS7I-~kb=TH#o5z(iKP&oee_-8Z#VI^t^?|KmKKDW&nvGXdnJE&iP0mv)L}kt3BqZN5H=uS@L@re| zE8iw;Dq1}qC!!Myd4-JN(<=`Pvx@2iiWsi@C4+cYVDEMNEgvtuMcg_jtc3KSemQ z$6$LhbpR`83%XxJxEo~;aUT`(oEPG36prhXn_GVhe~%eejG|F=UweE&{QHLF2;YS`FZUS|5`( zcpJ%wY(z`M#SLXp0`QDMN~2WBrHb#)2BxFQP}vn@HCG+m&+gkxLCB6sTW$}VoKt-0 zvG2GOP0XDTTb4$!Y86}Jp zi7)gUz?Zj)!)kb%IYHNz10hf5j@PZZcJR?;PiXNc&g5qRd~j*D+(yd0 zi{D}(w^cJxq6+M#)DO&_k(kKX7?3y2ckPuy9SUQs6c~tM)4DOg&)Rpf0?R%sx*v)xVaRB-pQ?i!&Wt*VDBLca*>z8)xy_}Bi?IHD zz%>Uo)sfH~d~TLSiHZqw~D@$v!s&j@VD$#BlGGUKxnqTQI)ATKbTN zCgq{&X$ri(oHio1Y%Z;cSJsdC_nS1oiA?rgj}|E@UIooTci7g7-a+@iYNIvjCN=~t zt%Y!sS65*+Q=VI{jrCc2NL6X&PHvTI1R{_GxrBGmmN6j4t1B3Qc5W|fM=&1rCZfB( z0eXHFmV}6G`Y34P2YB8 z%K61zyfG|xsgwgbuWzvGBb1Wy`?p<@Y^{Enj*<3`gC`@YEQ70g=-dkgIK}h zHqJ~#k5T>Rzoyks#;Wj+e-+{1H_iSqrzH-PjFt>?w~eVci;?uRL??M_IRH9F(z6mp z*8(cgS1n!rO`qDrva`K8R1_hN_^T%-)^Imq23d-hyJ0EgR`Sg%zj6eidQu78bAsR5 zH1Z6x!kpc}kg%=w&IDs>J}lS*T-Kl_26b-(9_AYX{{Z zcBe&}^xTI<2&8AfQC!F0{5E;j$B;)GLJbEO<=$c_hx*2RpY>hH`i`5`zy<(VSbUUB zURd4%y2or{ne8yfu<&1v^`CngFn!Fw`}i^@)}s$dj$YG4w`fN8o)M8iRoGiTpMePG z7ox72FGvumgcZ{H-Ti>%F|*IHHp?^AKpw9Ubua%Q;pRe===BPUYZjS0U)sm1^wVc= zc-*3nfWzeF-i3(Ng-R+I*$V*_Pwtgo9Ee_LrUrI)9tMca02_aEfS$TlsL(~GBpy$i zgX-4QJDs=;^foUCvA+BeVHLo$rjiA7Xy~U*{MaNfydTC4%WU_cJCsw(+sQgne9QzwONiu|D!-6gMH^MK8{`~$`;bAn zR~5qbZ0AWn#;|3qH{^MF0uy)*|J;hHInJ_+0^;k+L8xza*xKDd{Or#H9~Rxc0=(3J z$1p=KyM^8ZBJ06E!m814gL+Is!Rj|Mdavo*Bmc!yc~vig-x!1Y1O_& n*CiL&EeZHS{`374C=IrZoh@D=99ahZJ%L=D+#Jgtj{p6i$lb|Z diff --git a/src/lay/lay/doc/manual/cap_ex_ta.png b/src/lay/lay/doc/manual/cap_ex_ta.png index b835085cbedce4e906ae61695c1ec57daea4adbe..2b3917a9508e9f6c5986ab9f8839f5c543ec1b0f 100644 GIT binary patch literal 4320 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 HXRrMm=-nSq literal 4381 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 diff --git a/src/lay/lay/doc/manual/cap_ex_tb.png b/src/lay/lay/doc/manual/cap_ex_tb.png index 03c2a243f919eb56e5e9a25e69b8d9ccf19aafd4..46620d4ffb66099717a9c86cc49c6ade469c378f 100644 GIT binary patch literal 4357 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 F{x>qGJhK1* literal 4371 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 diff --git a/src/lay/lay/doc/manual/cap_ex_tw.png b/src/lay/lay/doc/manual/cap_ex_tw.png index f8c6478f78a75f16cdfcd395a50036885617fa51..bda7bbdd3010a58c4f723a9ac0fce351060414bf 100644 GIT binary patch literal 4279 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 literal 4337 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 MWqz_q|NQlT0~&ZXb^rhX diff --git a/src/lay/lay/doc/manual/diode_ex_layout.png b/src/lay/lay/doc/manual/diode_ex_layout.png index 77d4908c0593f47916b0f3821b94945b186c46ac..8d9e8d647293931ad0f171eeb928161400f44d96 100644 GIT binary patch literal 3427 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 literal 3466 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 SW`JiTi2IIx+e=(Se*GsHUdS8( diff --git a/src/lay/lay/doc/manual/diode_ex_ta.png b/src/lay/lay/doc/manual/diode_ex_ta.png index 139dce40391329d53b0f2516877cf9eb8c4323bb..718df9b05fe5e818e860877549a89716abdeb965 100644 GIT binary patch literal 4538 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 literal 25668 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�OZ?psB94OO$sS)qR0)GiL+Jy{L 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 literal 18916 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 literal 30833 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

X8WFw6=cboFUPbnIgsMNzUwg8I7 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 literal 2816 zcmeHJ`#0O!7LTfFo0iU^Lo$5)lv-jC&ol|%v z$WI&mEf@p>Y5QOF2?c>Peo-&z;R9-9&dF?E9W;p-{KF0(J}men7}y?3x)?zOfpi9d zrBQC9V+epG-|HmrSUlby6c&8N5C6$k4e9`3XzWcA$m%TgteZ2`$@<=zVIvR-O!D{f z3j4llZ3dk-jnXd&5tsZ)seH0{e*JQt0pC`zJzsW6!~ax!0av$%_{n@y!@u8P55H=1 zZTnz zzM0*YG1DILjivTg33dMQXJ{?A1H2*0jAe_2ONX{w2;tteF>V}6NP;2i@ve}9Z}bfR zp&|(eEq(|Ig%p^7%Q-7XMi0yJOUq>8E@6f(!9xWTfwzh<*{tMU!Jx_d2TGzhq`irJJC^MMsGv^wb|1AJ0~|cwX+o&eV|Tse?(8iNY0LxcJ|YduJu;K zX#B)0S^}!_zQjofc7@^YDfF3%^@it8J|bPcW9LcU zetBIxFJ1{`I|SwTkEk9c88SCI&6mGDGg_i;)_rTPJFL)gdk_=1yky&ir>ZR2lVD zRwmd3uKMhdd1QWm_3;7e2X~e7=bW6qZT_3Y-8KPNf4LN+LMtg$#-606zIj8!IY4zH z&M)uPDy6lOwN%B)tq}q%@-@>F&P?LA^V5@`JapxMnsT|Nis>+{r}KzV9N&x;=Ta9+;j0R_^sUVGRxe#g)REY! zH!oACmSiciL<-NhzS3NjBfbA1>k(Vt-?vzfK+pcf0`i(zbjqX2 zcHCqU$$IwhEkZgoo8z@Nm0IznQ#?(fM=2nRx4|9@+H(y43c`w39`U?-?3rEPl|{Nb zE7%32`VE54axCff@Ec<^GbL^|=ex4|ZX#`(pu6aJ@D$sHiAEYEB)<67$cBV+l*oD$ zf^qCOg1(04VcYYSQ1a^dMR^(C+QJs5%1AqEyx~Z3mCz7HX1)c<&cXZI_HbQfG-ne_5C~KOH_A z7vh7oVL{inUb|2qM|@{CIX}^M+MHG%sgFoJaowPd$AK0xLT+3Q2TqPWYn6045@}Np zT}0+;6hfNrwe5Ip_g5$&m!U;eIQUp4mFF4|G5YvGps52&5o-?zH(ngZnNxlfTD8~# zL!wWl_5avd9F77={DIhx6iy7`#L0hF@B*xWJfokBEuO2{XYpj@iWMLLEgZs$_61D$ zZK(yiYm39<0D;Oj2h?qV6sbqyajXG>zr`SJUIO;)w;X@C4y0>QK$>V}fCDpAS~&)Q z9+ee`rvL&gc@C%-fB>Gu!PS+kN&j14g`w8qC>Iw4uzy{|c9ety0#6?nhm!%wCe#5n zykF;04lWjO-ePS-D-Q=q=aL~!Rc&g4ugu~)boc9Y1a7A~-IqpvY1IBik;5k5n*spr#De$SnGK==7uHSz>8u04gCxA89I0V^7kIKDTDT`)!hg3wVL~i;z)KgU Sn5ciIAb;N=ANqwGdH(?dMgaW) diff --git a/src/lay/lay/doc/manual/mos_ex_tb.png b/src/lay/lay/doc/manual/mos_ex_tb.png index 0c0979484b500622c911e06d9bb781d7d7fbdaf0..d4cee108e60703814c28aaa8869859652b816dd6 100644 GIT binary patch literal 4471 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 B(*Xbg literal 4541 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 diff --git a/src/lay/lay/doc/manual/mos_ex_td.png b/src/lay/lay/doc/manual/mos_ex_td.png index d723abc34ff29929d65b9529ca152555f7d411a3..b9f99685848bf636f5f31c442b4099854da67674 100644 GIT binary patch literal 4155 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 E0+5X(iU0rr literal 4568 zcmds5c{E#lyN>qg;43*j)q5H_r8CtTrKO>jilKrSt5xbKF>{PHMzy6qq9|&XI*F-O zRLm9WM^DWns2oxWClpOlN>tLs_e(l_{noncuKUmZ=kB%k+H3!&{SMFbyzAX}EzAsM zWfWu}5Qwa?(RoV<@n*_I+}+y4&GAj*a?AbH8nne z&iZ=p?C3v(nJ*P$F#J3_q_&0h!Pd(^@0ztbCu0Qn+;!nu0!ixe&9eS~Hc79ltotPf zxg};*>UBh95@G}h|M+mhri?3 zS*KuPRMliG4F2CvikRV$AG?#Nmy^a`GMp|a#k6$;Uo#W+%|aADa^{z7X(taV@-GSc zbW9TGO7Z$xC*dY{1$&34cW9T!uTxM!^X^0mYdQ*jV7Co5G_q6n4*fxbpDM*gM0EM$ za5$&1eZQo{Ew*n^3s+Ei!(`^%uPU>Z^{JVD%j4!32iHNvWG8h61+4NoUDr=;lTLF( zeCh*B?~00wR6QB1$hAXJYurU8q}D}eLGX@rnb3f>$*RjHJg3FG9K-9c568ROGMhC$ zH9IX8dXWr*X&%*mo@*8X!MfY65bBAKVa#5Y!;`0EpJ3F-d`1T_^oqo0D)re0lT8Yj zN;+uOWz zWG@8T%swfOmu3nucA^%o`(jBXibf2?OYigN~1H{~kdj2_xgJ+dpFW za~!7VpLS%p6S0GTU`BRi->DgKoNJ1oA{i8{|$e*~q=ItC^H`DXG9{p1x1& z_6AdfK+ROl!@|Of?cVk;@Y>EBHLtaDQBr&EoPtaL^&=U;`N+>_Zbzw33F_Ex?5Vbc z(>1FZ6;BKyaIB_`Me(@cETvg|i9SV#VH;WOC$-e(=A#Swu6opB0{hrnN{xueO^#8R zRabaK%D}t5s#&hJKWCy!w4ZAIX#$$lCnAZ2LSd2~J9;f7j8@2`GT6GOI_;fY{+{H{ za10;Lo=uP2OwAKYXQjTu5(9HNZ1bbpG~=GosyMkW6m5IRCvyk2FemIiwl4AD^W{EA zV;y4djJ5}lUEyQws^K+JS=Mj`Wtg`12=2kfk6<;djRmm0`KLv@0&|(OYS|~FuW5#s zS5k3*FGN^h?_KfNGxs3S<;PMA2an9SMv`?MmBy7nL<>aGFW+8)cIozR=dGB38boND zppfZH>cqf`Fd4PB8K2i|+C>Vpwd!WzZJ}^mmwQ`-{nqmMB46Vta6}c$d6?hOLZ&wy zx!&>H4t^hv9v>9WIGRr(PijTKm3e+m5}v$Nz9JWuG%l+2<~tPlD-TCp3HZe%8iDn* z(yc9P;RL4Piy#c7RUIkosV&W%)BRgq+zWeNrT2get+3Osjv+339CR`NMZKBe9!NFOGmlKAC zSZ_;PyVIkC=fPxc`lC_6`22;v z-*a@jU|Ftfh_?N|I^8En%No4Q^NN-BgS{iCOXr{ZF723ub`{aKcNWK+M@8Uq)8kTQ zO~SzLJ_T`@iLk48RB9K&8W!5!+w{^#Uy%upe~*uL zu-xv>uS)!i6#I1_i(7XT~8A=P&My((ZLb76+ri93*lJKc<(tHEtcshwBo zXR?%DJIwD~qHS^@c@c#f4 ze|1PQWdV%q_(BRWdYu%7vWgK~-QV@G3@$ALoG7^;?Kaqmd1xxYqv{p28~1~CDhzRM zKj%ljUBZ`e_qPu;)NR3eQW9rZ@t3q@ws?uD6fSn{GsK1B(KG#D%>o1iW=Ts7&{G$i zUlfJf>i|WM-UsW_z;28Ev$=yS7qw(2J}2pGrk}@r%cOK%jU<1-$g5S~a4W6&&8#Ig zU0~KaiCF}(^C}=NU&$%m33iv<4>5Zi0UQnhrbtV??7_bR=baVj)I*mDtZe-}1&lmC zoRQXFno?I+_W{>LrBW%Byfu-KDNw>SkNVmN3WCpM>=u0#EG;v-`v`2&Z~WyTZA#=U zZh~Xz#?fZds+15_+&b4E2<+c~;1Pz_pIZK%*GBN8;<#GAHM4msJ&e9jynz|lw)oR2T8@J{o3Vov{Bt5gDrpBP=7~H(Vjo*0&K0Xi^}wb9E4r8KJU+yg6X*;$g|>5;W3J59kbngs!cOv4 zh10}=PQhTwOZ1(O`QmyfoQDGOQ`Se?mx*;Kgw=Rpa|Mmm0b(+{Hz69 zTRjBjyH{ipd1eXCp+>EtvK_t~Jx}ItX6Mrluj54_Mo~kFu>-6BrgG=FL9;E>K`cT^ zhwZgwOo4s?1(2xL-p};}kk;`f7I65XSb{)l1f+2VKDLOXTgrfc$FwHa|Da7vM$xE# z{#6T-F!dZ$S3s^qs5fWjuMek@^_`U!4m4>=WLG#0RHZF2e}jlQ;y|WT%siA>6(^OK z|HGE)-5t{h@UJTb$ht4^7pu%P28?bQtypL}s*wq_^L@MJ+Xv!enMy~uvnm#Jo=u5a zKSgS8Yoxm*)6vQF1g1J4PyuKHz4cT8DgxT|I(m+*+{H_VG6biNhzlOTI;0F&%%; zk2-o$7oHbF#;zQ1W&(hIj(#xF@Bop+tblu&J$4P!WDGmyevv%H2H26;ipPnZ2v*=% z?eD$_P__kjWLWn}lX;?NE?|AHC^k)lAg<*TF)(z4+CAviPe>@S!2uP&q0#|qbxTs6 zp1>zPaX>o)IM!NZ_^RrDg5$4|Yn=6&b`l-c1CUUp^{O@As$B0?_#dSPK@wM8P;_~% z0ngSZLz*$O?DM4AXK_olI61HK6}cJTmGa${NKkh3`3Cih;er(|DEP@()$CUiBvLiQ zyBaZa-ZNg(IiG9WS5E&g%HG5UlhRjvZU9AZ)AAe_GX2Q&A2?~3<+eZXVhrt#N%W%n z%3mG0)Qge|8KXYg2zeSA8Ck8^Qk;>IF@zjDp}Y*S=|=75WH?28=)~YetJnuZu;N{S zNe;znSpDwyxn}%2!HK~k1DCfX#lOg48@LRPg>|V^;u0QMgAS@*Q^w(SFQa#$j=TTQ zl=w%Ax+AH==`gXF8rHWM(Dc=0uH7Hhk)E?z=DAT4hp)K0XgO~`XFSB1A}QXR%OyFc z&+WAd2>VUk$?SM^GyR%;X32ru&pf6(j1k8xENDen;_>SWSA9U<~ zdhsss_agM}Vg$mY#jYXxZVFcR@Y1V@rn{Sha&dAun^^AMZT@HK2VFE}V1X3RMgD{6 zqJ}tDpbzMgQ^OyomAXGj4Ig`Ys>0;w?%t!dW~Ui8W5YBGiy=zgKjO}X@H zf4h~ME5GhJop#|L`7w7qE$b~9aYdAbazZ-hs#!rkIwFK3_sqiBRbIs=05l0F25x0PzR=Ww3?4~;hS@a6h+A<0r2os`51*j;((GzR5AGQF;{q`@Fgstae>L`B D*Kq`} diff --git a/src/lay/lay/doc/manual/res_ex_layout.png b/src/lay/lay/doc/manual/res_ex_layout.png index 4b16e19ff0f81e19c62fa4b1e8fc1377151e34fa..ee30d5e9e2e6b64f69064163b32fa64cfe634732 100644 GIT binary patch literal 3130 zcmeHJ`BxHZ8b-=Am8{0OC6>0CnU+hqE7+wlBU5jdTZ&!xTvN;x(P*Jf@=g(`spN&D zS)!Gq=7z0Wnn)Vt2ATj3}&koS>8zX1SRFEz(n7pOt_kX>V%vMT*o?*Lt0-QjWHmFwEnBf;qaz`EBfN9&%| zI+GO;eK-gWk4{Xq0|fZ`c_n^z)qv|(z~7=H(SSX+*0yer))31pd*5vZ0Q76T4;>7+ zP%=I0pLYNAFL-~&DVEhM(KyY$#1w%bEj`%V7syG{3H3>@sD!1iLzC-&95J zP@;raF00l!v83v$@i#iFghDS!V_*J6oF z#|zLTGPLsCRAqa=+(|m)YB-idiW8kwDr4nx)+{BNLh+~YLBgEdwDO!u<-cF`1cL}6 z`#J)5*f%%Ld8I>joS&A*eyB`YR?8ygbppfpxw1-V+W;peOW7Ts`gTx1`}NnNxgZXK z)WhkMzAEw!YrzT@dw}>Bn~a|O9`QE~-;4gFQC%pt_vz(Rsv63t#C!Aa$RXT@xtO~g z_vmP}ofV;i_6nU8cX+b!R?7KAV!{{u<~`rydW8V6qE%j2P)cFbi@K`kpS4u>%5zHb z?HED3nkbv=!C~(cEu`y@!W&P^y1d-d!K$Z;c|s0ng862-!E1){kuLrt{U|ePR5VnT z&fh8A8uS%XEQj3~>}e3hliPH%ddv)Bb1X!63fagUP*@iy@Z?eM%wlBh<>b0{WsIE!0V&RRXYU}ly#*^SzsiTZ9EJ2GSuJwMAO zCFIsV%&NrQazt|zaushvnX)3dic={+gVg@r{(G@mx7<2gSvsbZQt$;CXFgHq&s7HX zT5Q=90nYefD9kzKj5J)_+ibCoS|g8irUWF?p}Tib6To`$r|%5gLrqji;GNC${RT~! zp5%u(xsq6=<4fkz0}e2fWbL)<^2GVV1Zdu)t?;CbbwGXDlzqh*OfY8ioKch5AIc#wB^Uo zk6?IGR9L!HI0ts^dVat%aDy!&d@}vjV+i_bGMZKu!$PGjtAfEs6HVkQ~ z>GCuBs7HGeOkDwu0GHCsGhsqTGUT%X_;R~_p*X)T=@(|u9mft#p!Zsc_J1WxXdELhrT5T2Wi4UCIlpj7Rd9ClD8FC{_ zgj$%L=xw85!UH;Dsp8%cC&kzWlB$11G6i>l6lPE}J<>1mu|IH?dt$&zIjoipCAj!Q zGrRL+$U<*3Ti8%ADjpRIGP!r#e<&*Z`VLl`gz0Zt11pxc6vix#*iNU1o7!V|jK))u z{Kz41{Vq`=h>(qc`?n$T{CNQ7_V|nK9=ak95=2=~{l!0eWFXJ}4BR&h|F(a>D(YL& zHlBK7qBh56Mx#l$>VhBD1>iaR;)Y~2v7WU)08@F3gy!n!J_jxfiYD9z@wr`I^=FKy zvsw3*1_VsQnx}OQ!XvruXwpR%f}eqHFOeGqZIARoh8D}X&1|IIS&s;#HmgXmLoMNx z6nn00Sds~9v--Jn4k7IzP~q7DaSersLgANhXh)%wUgFPgIejV|K{wgj&JP>LmA8ve8Si|ntR{ntuE zgc8Psb@ItbmB zMwqO#fP5dvO@Pwx1;QxncaM3id?qreHvgQgp6Pplg0-Uk+o)i@)4`qy z2cxEE7xQc4_oQykGG-(jH4#_l(>whE#mrlVCh(cO^UEYNm`#J%gSIE}Mq_7z>OWfv zH^kgwvtiWcU1s8${;67-TWW!4q|lcN%jFqzI17)(o8km3F-7ymAq2VW4$yt4ITac1 ztyQ*x$ewH+^z+7%HF?5?76&!dUURcs^yS^gR7+tjCUppJ;T!rw^i+dN@|i_y7PEBD9W189g}kKT^IfyB2$&*!~VNsmb&J N@59Fr)%+T9>0e{G${qj! literal 3132 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 delta 4179 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 SEc+4#V1Cv5O4a2X5B>}A_}Op( literal 4413 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 literal 4456 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 From 45cdefcf9a33ea381f4d958b5cef27396fb5cfad Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 20 Aug 2019 23:12:17 +0200 Subject: [PATCH 07/27] Provide strict mode for device classes, dmos3/dmos4 for LVS --- src/db/db/dbDeviceClass.cc | 5 +- src/db/db/dbDeviceClass.h | 21 + src/db/db/dbNetlistCompare.cc | 43 +- src/db/db/dbNetlistDeviceExtractorClasses.cc | 334 +++++-- src/db/db/dbNetlistDeviceExtractorClasses.h | 11 +- src/db/db/gsiDeclDbNetlist.cc | 18 +- src/db/db/gsiDeclDbNetlistDeviceExtractor.cc | 22 +- src/db/unit_tests/dbNetlistExtractorTests.cc | 244 +++++ src/drc/drc/built-in-macros/_drc_engine.rb | 26 + src/lay/lay/doc/about/drc_ref_global.xml | 24 + .../lay/doc/manual/lvs_device_extractors.xml | 21 + src/lvs/unit_tests/lvsSimpleTests.cc | 5 + testdata/algo/device_extract_au9.gds | Bin 0 -> 7982 bytes testdata/algo/device_extract_l9.gds | Bin 0 -> 2826 bytes testdata/lvs/ringo.gds | Bin 9954 -> 10210 bytes testdata/lvs/ringo_simple_dmos.cir | 83 ++ testdata/lvs/ringo_simple_dmos.lvs | 81 ++ testdata/lvs/ringo_simple_dmos.lvsdb | 925 ++++++++++++++++++ testdata/ruby/dbNetlist.rb | 4 + 19 files changed, 1763 insertions(+), 104 deletions(-) create mode 100644 testdata/algo/device_extract_au9.gds create mode 100644 testdata/algo/device_extract_l9.gds create mode 100644 testdata/lvs/ringo_simple_dmos.cir create mode 100644 testdata/lvs/ringo_simple_dmos.lvs create mode 100644 testdata/lvs/ringo_simple_dmos.lvsdb diff --git a/src/db/db/dbDeviceClass.cc b/src/db/db/dbDeviceClass.cc index 7ff6619f3..d16daf212 100644 --- a/src/db/db/dbDeviceClass.cc +++ b/src/db/db/dbDeviceClass.cc @@ -136,13 +136,13 @@ bool AllDeviceParametersAreEqual::equal (const db::Device &a, const db::Device & // DeviceClass class implementation DeviceClass::DeviceClass () - : mp_netlist (0) + : mp_netlist (0), m_strict (false) { // .. nothing yet .. } DeviceClass::DeviceClass (const DeviceClass &other) - : gsi::ObjectBase (other), tl::Object (other), tl::UniqueId (other), mp_netlist (0) + : gsi::ObjectBase (other), tl::Object (other), tl::UniqueId (other), mp_netlist (0), m_strict (false) { operator= (other); } @@ -154,6 +154,7 @@ DeviceClass &DeviceClass::operator= (const DeviceClass &other) 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 ())); } return *this; diff --git a/src/db/db/dbDeviceClass.h b/src/db/db/dbDeviceClass.h index 62530e712..ff3d96b15 100644 --- a/src/db/db/dbDeviceClass.h +++ b/src/db/db/dbDeviceClass.h @@ -350,6 +350,26 @@ public: return mp_netlist; } + /** + * @brief Sets a value indicating whether this class performs strict terminal mapping + * + * Classes with this flag set don't allow terminal swapping, independently of the + * "normalize_terminal_id" implementation. If two classes are involved in a compare, + * both classes are treated strict if one of them operates in strict mode. + */ + void set_strict (bool s) + { + m_strict = s; + } + + /** + * @brief Gets a value indicating whether this class performs strict terminal mapping + */ + bool is_strict () const + { + return m_strict; + } + /** * @brief Gets the name of the device class * @@ -555,6 +575,7 @@ private: std::string m_name, m_description; std::vector m_terminal_definitions; std::vector m_parameter_definitions; + bool m_strict; db::Netlist *mp_netlist; tl::shared_ptr mp_pc_delegate; diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index dbcb61d3c..f76bb6235 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -447,6 +447,24 @@ public: { return generic_categorizer::cat_for (cls); } + + void clear_strict_device_categories () + { + m_strict_device_categories.clear (); + } + + void set_strict_device_category (size_t cat) + { + m_strict_device_categories.insert (cat); + } + + bool is_strict_device_category (size_t cat) const + { + return m_strict_device_categories.find (cat) != m_strict_device_categories.end (); + } + +private: + std::set m_strict_device_categories; }; // -------------------------------------------------------------------------------------------------------------------- @@ -1070,14 +1088,17 @@ NetGraphNode::NetGraphNode (const db::Net *net, DeviceCategorizer &device_catego continue; } - size_t terminal1_id = translate_terminal_id (i->terminal_id (), d); + bool is_strict = device_categorizer.is_strict_device_category (device_cat); + + // strict device checking means no terminal swapping + size_t terminal1_id = is_strict ? i->terminal_id () : translate_terminal_id (i->terminal_id (), d); const std::vector &td = d->device_class ()->terminal_definitions (); for (std::vector::const_iterator it = td.begin (); it != td.end (); ++it) { if (it->id () != i->terminal_id ()) { - size_t terminal2_id = translate_terminal_id (it->id (), d); + size_t terminal2_id = is_strict ? it->id () : translate_terminal_id (it->id (), d); Transition ed2 (d, device_cat, terminal1_id, terminal2_id); const db::Net *net2 = d->net_for_terminal (it->id ()); @@ -2203,6 +2224,16 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const } } + // device whether to use a device category in strict mode + + device_categorizer.clear_strict_device_categories (); + + for (std::map >::const_iterator i = cat2dc.begin (); i != cat2dc.end (); ++i) { + if (i->second.first && i->second.second && (i->second.first->is_strict () || i->second.second->is_strict ())) { + device_categorizer.set_strict_device_category (i->first); + } + } + // check for circuits that don't match for (std::map >::const_iterator i = cat2circuits.begin (); i != cat2circuits.end (); ++i) { @@ -2333,13 +2364,13 @@ NetlistComparer::all_subcircuits_verified (const db::Circuit *c, const std::set< } static std::vector > -compute_device_key (const db::Device &device, const db::NetGraph &g) +compute_device_key (const db::Device &device, const db::NetGraph &g, bool strict) { std::vector > k; const std::vector &td = device.device_class ()->terminal_definitions (); for (std::vector::const_iterator t = td.begin (); t != td.end (); ++t) { - size_t terminal_id = translate_terminal_id (t->id (), &device); + size_t terminal_id = strict ? t->id () : translate_terminal_id (t->id (), &device); const db::Net *net = device.net_for_terminal (t->id ()); size_t net_id = g.node_index_for_net (net); k.push_back (std::make_pair (terminal_id, net_id)); @@ -2872,7 +2903,7 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph continue; } - std::vector > k = compute_device_key (*d, g1); + std::vector > k = compute_device_key (*d, g1, device_categorizer.is_strict_device_category (device_cat)); bool mapped = true; for (std::vector >::iterator i = k.begin (); i != k.end (); ++i) { @@ -2906,7 +2937,7 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph continue; } - std::vector > k = compute_device_key (*d, g2); + std::vector > k = compute_device_key (*d, g2, device_categorizer.is_strict_device_category (device_cat)); bool mapped = true; for (std::vector >::iterator i = k.begin (); i != k.end (); ++i) { diff --git a/src/db/db/dbNetlistDeviceExtractorClasses.cc b/src/db/db/dbNetlistDeviceExtractorClasses.cc index 394c74bad..01406124e 100644 --- a/src/db/db/dbNetlistDeviceExtractorClasses.cc +++ b/src/db/db/dbNetlistDeviceExtractorClasses.cc @@ -30,114 +30,252 @@ namespace db // --------------------------------------------------------------------------------- // NetlistDeviceExtractorMOS3Transistor implementation -NetlistDeviceExtractorMOS3Transistor::NetlistDeviceExtractorMOS3Transistor (const std::string &name) - : db::NetlistDeviceExtractor (name) +NetlistDeviceExtractorMOS3Transistor::NetlistDeviceExtractorMOS3Transistor (const std::string &name, bool strict) + : db::NetlistDeviceExtractor (name), + m_strict (strict) { // .. nothing yet .. } void NetlistDeviceExtractorMOS3Transistor::setup () { - define_layer ("SD", "Source/drain diffusion"); // #0 - define_layer ("G", "Gate input"); // #1 - // for backward compatibility - define_layer ("P", 1, "Gate terminal output"); // #2 -> G + if (! is_strict ()) { - // terminal output - define_layer ("tG", 2, "Gate terminal output"); // #3 -> P -> G - define_layer ("tS", 0, "Source terminal output (default is SD)"); // #4 - define_layer ("tD", 0, "Drain terminal output (default is SD)"); // #5 + define_layer ("SD", "Source/drain diffusion"); // #0 + define_layer ("G", "Gate input"); // #1 + // for backward compatibility + define_layer ("P", 1, "Gate terminal output"); // #2 -> G - register_device_class (new db::DeviceClassMOS3Transistor ()); + // terminal output + define_layer ("tG", 2, "Gate terminal output"); // #3 -> P -> G + define_layer ("tS", 0, "Source terminal output (default is SD)"); // #4 + define_layer ("tD", 0, "Drain terminal output (default is SD)"); // #5 + + } else { + + define_layer ("S", "Source diffusion"); // #0 + define_layer ("D", "Drain diffusion"); // #1 + define_layer ("G", "Gate input"); // #2 + // for backward compatibility + define_layer ("P", 2, "Gate terminal output"); // #3 -> G + + // terminal output + define_layer ("tG", 3, "Gate terminal output"); // #4 -> P -> G + define_layer ("tS", 0, "Source terminal output (default is S)"); // #5 + define_layer ("tD", 1, "Drain terminal output (default is D)"); // #6 + + } + + db::DeviceClass *cls = new db::DeviceClassMOS3Transistor (); + cls->set_strict (m_strict); + register_device_class (cls); } db::Connectivity NetlistDeviceExtractorMOS3Transistor::get_connectivity (const db::Layout & /*layout*/, const std::vector &layers) const { - tl_assert (layers.size () >= 3); + if (! is_strict ()) { - unsigned int diff = layers [0]; - unsigned int gate = layers [1]; - // not used for device recognition: poly (2), but used for producing the gate terminals + tl_assert (layers.size () >= 3); - // The layer definition is diff, gate - db::Connectivity conn; - // collect all connected diffusion shapes - conn.connect (diff, diff); - // collect all connected gate shapes - conn.connect (gate, gate); - // connect gate with diff to detect gate/diffusion boundary - conn.connect (diff, gate); - return conn; + unsigned int diff = layers [0]; + unsigned int gate = layers [1]; + + // The layer definition is diff, gate + db::Connectivity conn; + // collect all connected diffusion shapes + conn.connect (diff, diff); + // collect all connected gate shapes + conn.connect (gate, gate); + // connect gate with diff to detect gate/diffusion boundary + conn.connect (diff, gate); + return conn; + + } else { + + + tl_assert (layers.size () >= 4); + + unsigned int sdiff = layers [0]; + unsigned int ddiff = layers [1]; + unsigned int gate = layers [2]; + + // The layer definition is diff, gate + db::Connectivity conn; + // collect all connected diffusion shapes + conn.connect (sdiff, sdiff); + conn.connect (ddiff, ddiff); + // collect all connected gate shapes + conn.connect (gate, gate); + // connect gate with diff to detect gate/diffusion boundary + conn.connect (sdiff, gate); + conn.connect (ddiff, gate); + return conn; + + } } void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector &layer_geometry) { - unsigned int diff_geometry_index = 0; - unsigned int gate_geometry_index = 1; - unsigned int gate_terminal_geometry_index = 3; - unsigned int source_terminal_geometry_index = 4; - unsigned int drain_terminal_geometry_index = 5; + if (! is_strict ()) { - const db::Region &rdiff = layer_geometry [diff_geometry_index]; - const db::Region &rgates = layer_geometry [gate_geometry_index]; + // See setup() for the geometry indexes + unsigned int diff_geometry_index = 0; + unsigned int gate_geometry_index = 1; + unsigned int gate_terminal_geometry_index = 3; + unsigned int source_terminal_geometry_index = 4; + unsigned int drain_terminal_geometry_index = 5; - for (db::Region::const_iterator p = rgates.begin_merged (); !p.at_end (); ++p) { + const db::Region &rdiff = layer_geometry [diff_geometry_index]; + const db::Region &rgates = layer_geometry [gate_geometry_index]; - db::Region rgate (*p); - rgate.set_base_verbosity (rgates.base_verbosity ()); + for (db::Region::const_iterator p = rgates.begin_merged (); !p.at_end (); ++p) { - db::Region rdiff2gate = rdiff.selected_interacting (rgate); - rdiff2gate.set_base_verbosity (rdiff.base_verbosity ()); + db::Region rgate (*p); + rgate.set_base_verbosity (rgates.base_verbosity ()); - if (rdiff2gate.empty ()) { - error (tl::to_string (tr ("Gate shape touches no diffusion - ignored")), *p); - } else { + db::Region rdiff2gate = rdiff.selected_interacting (rgate); + rdiff2gate.set_base_verbosity (rdiff.base_verbosity ()); - if (rdiff2gate.size () != 2) { - error (tl::sprintf (tl::to_string (tr ("Expected two polygons on diff interacting with one gate shape (found %d) - gate shape ignored")), int (rdiff2gate.size ())), *p); - continue; - } + if (rdiff2gate.empty ()) { + error (tl::to_string (tr ("Gate shape touches no diffusion - ignored")), *p); + } else { - db::Edges edges (rgate.edges () & rdiff2gate.edges ()); - if (edges.size () != 2) { - error (tl::sprintf (tl::to_string (tr ("Expected two edges interacting gate/diff (found %d) - width and length may be incorrect")), int (edges.size ())), *p); - continue; - } + if (rdiff2gate.size () != 2) { + error (tl::sprintf (tl::to_string (tr ("Expected two polygons on diff interacting with one gate shape (found %d) - gate shape ignored")), int (rdiff2gate.size ())), *p); + continue; + } - if (! p->is_box ()) { - error (tl::to_string (tr ("Gate shape is not a box - width and length may be incorrect")), *p); - } + db::Edges edges (rgate.edges () & rdiff2gate.edges ()); + if (edges.size () != 2) { + error (tl::sprintf (tl::to_string (tr ("Expected two edges interacting gate/diff (found %d) - width and length may be incorrect")), int (edges.size ())), *p); + continue; + } - db::Device *device = create_device (); + if (! p->is_box ()) { + error (tl::to_string (tr ("Gate shape is not a box - width and length may be incorrect")), *p); + } - device->set_trans (db::DCplxTrans ((p->box ().center () - db::Point ()) * dbu ())); + db::Device *device = create_device (); - device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, sdbu () * edges.length () * 0.5); - device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, sdbu () * (p->perimeter () - edges.length ()) * 0.5); + device->set_trans (db::DCplxTrans ((p->box ().center () - db::Point ()) * dbu ())); - int diff_index = 0; - for (db::Region::const_iterator d = rdiff2gate.begin (); !d.at_end () && diff_index < 2; ++d, ++diff_index) { + device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, sdbu () * edges.length () * 0.5); + device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, sdbu () * (p->perimeter () - edges.length ()) * 0.5); - // count the number of gate shapes attached to this shape and distribute the area of the - // diffusion region to the number of gates - size_t n = rgates.selected_interacting (db::Region (*d)).size (); - tl_assert (n > 0); + int diff_index = 0; + for (db::Region::const_iterator d = rdiff2gate.begin (); !d.at_end () && diff_index < 2; ++d, ++diff_index) { - device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_AS : db::DeviceClassMOS3Transistor::param_id_AD, sdbu () * sdbu () * d->area () / double (n)); - device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_PS : db::DeviceClassMOS3Transistor::param_id_PD, sdbu () * d->perimeter () / double (n)); + // count the number of gate shapes attached to this shape and distribute the area of the + // diffusion region to the number of gates + size_t n = rgates.selected_interacting (db::Region (*d)).size (); + tl_assert (n > 0); - unsigned int sd_index = diff_index == 0 ? source_terminal_geometry_index : drain_terminal_geometry_index; - define_terminal (device, diff_index == 0 ? db::DeviceClassMOS3Transistor::terminal_id_S : db::DeviceClassMOS3Transistor::terminal_id_D, sd_index, *d); + device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_AS : db::DeviceClassMOS3Transistor::param_id_AD, sdbu () * sdbu () * d->area () / double (n)); + device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_PS : db::DeviceClassMOS3Transistor::param_id_PD, sdbu () * d->perimeter () / double (n)); + + unsigned int sd_index = diff_index == 0 ? source_terminal_geometry_index : drain_terminal_geometry_index; + define_terminal (device, diff_index == 0 ? db::DeviceClassMOS3Transistor::terminal_id_S : db::DeviceClassMOS3Transistor::terminal_id_D, sd_index, *d); + + } + + define_terminal (device, db::DeviceClassMOS3Transistor::terminal_id_G, gate_terminal_geometry_index, *p); + + // allow derived classes to modify the device + modify_device (*p, layer_geometry, device); + + // output the device for debugging + device_out (device, rdiff2gate, rgate); } - define_terminal (device, db::DeviceClassMOS3Transistor::terminal_id_G, gate_terminal_geometry_index, *p); + } - // allow derived classes to modify the device - modify_device (*p, layer_geometry, device); + } else { - // output the device for debugging - device_out (device, rdiff2gate, rgate); + // See setup() for the geometry indexes + unsigned int source_geometry_index = 0; + unsigned int drain_geometry_index = 1; + unsigned int gate_geometry_index = 2; + unsigned int gate_terminal_geometry_index = 4; + unsigned int source_terminal_geometry_index = 5; + unsigned int drain_terminal_geometry_index = 6; + + const db::Region &sdiff = layer_geometry [source_geometry_index]; + const db::Region &ddiff = layer_geometry [drain_geometry_index]; + const db::Region &rgates = layer_geometry [gate_geometry_index]; + + for (db::Region::const_iterator p = rgates.begin_merged (); !p.at_end (); ++p) { + + db::Region rgate (*p); + rgate.set_base_verbosity (rgates.base_verbosity ()); + + db::Region sdiff2gate = sdiff.selected_interacting (rgate); + sdiff2gate.set_base_verbosity (sdiff.base_verbosity ()); + + db::Region ddiff2gate = ddiff.selected_interacting (rgate); + ddiff2gate.set_base_verbosity (ddiff.base_verbosity ()); + + if (sdiff2gate.empty () && ddiff2gate.empty ()) { + error (tl::to_string (tr ("Gate shape touches no diffusion - ignored")), *p); + } else if (sdiff2gate.empty () || ddiff2gate.empty ()) { + error (tl::to_string (tr ("Gate shape touches a single diffusion only - ignored")), *p); + } else { + + if (sdiff2gate.size () != 1) { + error (tl::sprintf (tl::to_string (tr ("Expected one polygons on source diff interacting with one gate shape (found %d) - gate shape ignored")), int (sdiff2gate.size ())), *p); + continue; + } + + if (ddiff2gate.size () != 1) { + error (tl::sprintf (tl::to_string (tr ("Expected one polygons on drain diff interacting with one gate shape (found %d) - gate shape ignored")), int (ddiff2gate.size ())), *p); + continue; + } + + db::Region diff2gate = sdiff2gate + ddiff2gate; + + db::Edges edges (rgate.edges () & diff2gate.edges ()); + if (edges.size () != 2) { + error (tl::sprintf (tl::to_string (tr ("Expected two edges interacting gate/diff (found %d) - width and length may be incorrect")), int (edges.size ())), *p); + continue; + } + + if (! p->is_box ()) { + error (tl::to_string (tr ("Gate shape is not a box - width and length may be incorrect")), *p); + } + + db::Device *device = create_device (); + + device->set_trans (db::DCplxTrans ((p->box ().center () - db::Point ()) * dbu ())); + + device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, sdbu () * edges.length () * 0.5); + device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, sdbu () * (p->perimeter () - edges.length ()) * 0.5); + + for (int diff_index = 0; diff_index < 2; ++diff_index) { + + const db::Region *diff = diff_index == 0 ? &sdiff2gate : &ddiff2gate; + + // count the number of gate shapes attached to this shape and distribute the area of the + // diffusion region to the number of gates + size_t n = rgates.selected_interacting (*diff).size (); + tl_assert (n > 0); + + device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_AS : db::DeviceClassMOS3Transistor::param_id_AD, sdbu () * sdbu () * diff->area () / double (n)); + device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_PS : db::DeviceClassMOS3Transistor::param_id_PD, sdbu () * diff->perimeter () / double (n)); + + unsigned int sd_index = diff_index == 0 ? source_terminal_geometry_index : drain_terminal_geometry_index; + define_terminal (device, diff_index == 0 ? db::DeviceClassMOS3Transistor::terminal_id_S : db::DeviceClassMOS3Transistor::terminal_id_D, sd_index, *diff); + + } + + define_terminal (device, db::DeviceClassMOS3Transistor::terminal_id_G, gate_terminal_geometry_index, *p); + + // allow derived classes to modify the device + modify_device (*p, layer_geometry, device); + + // output the device for debugging + device_out (device, diff2gate, rgate); + + } } @@ -147,35 +285,61 @@ void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector G + if (! is_strict ()) { - // terminal output - define_layer ("tG", 2, "Gate terminal output"); // #3 -> P -> G - define_layer ("tS", 0, "Source terminal output (default is SD)"); // #4 - define_layer ("tD", 0, "Drain terminal output (default is SD)"); // #5 + define_layer ("SD", "Source/drain diffusion"); // #0 + define_layer ("G", "Gate input"); // #1 + // for backward compatibility + define_layer ("P", 1, "Gate terminal output"); // #2 -> G - // for backward compatibility - define_layer ("W", "Well (bulk) terminal output"); // #6 + // terminal output + define_layer ("tG", 2, "Gate terminal output"); // #3 -> P -> G + define_layer ("tS", 0, "Source terminal output (default is SD)"); // #4 + define_layer ("tD", 0, "Drain terminal output (default is SD)"); // #5 - define_layer ("tB", 6, "Well (bulk) terminal output"); // #7 -> W + // for backward compatibility + define_layer ("W", "Well (bulk) terminal output"); // #6 - register_device_class (new db::DeviceClassMOS4Transistor ()); + define_layer ("tB", 6, "Well (bulk) terminal output"); // #7 -> W + + } else { + + define_layer ("S", "Source diffusion"); // #0 + define_layer ("D", "Drain diffusion"); // #1 + define_layer ("G", "Gate input"); // #2 + // for backward compatibility + define_layer ("P", 2, "Gate terminal output"); // #3 -> G + + // terminal output + define_layer ("tG", 3, "Gate terminal output"); // #4 -> P -> G + define_layer ("tS", 0, "Source terminal output (default is S)"); // #5 + define_layer ("tD", 1, "Drain terminal output (default is D)"); // #6 + + // for backward compatibility + define_layer ("W", "Well (bulk) terminal output"); // #7 + + define_layer ("tB", 7, "Well (bulk) terminal output"); // #8 -> W + + } + + db::DeviceClass *cls = new db::DeviceClassMOS4Transistor (); + cls->set_strict (is_strict ()); + register_device_class (cls); } void NetlistDeviceExtractorMOS4Transistor::modify_device (const db::Polygon &rgate, const std::vector & /*layer_geometry*/, db::Device *device) { - unsigned int bulk_terminal_geometry_index = 7; + // see setup() for the layer indexes: + unsigned int bulk_terminal_geometry_index = is_strict () ? 8 : 7; + define_terminal (device, db::DeviceClassMOS4Transistor::terminal_id_B, bulk_terminal_geometry_index, rgate); } diff --git a/src/db/db/dbNetlistDeviceExtractorClasses.h b/src/db/db/dbNetlistDeviceExtractorClasses.h index d623bd486..0dbb0743e 100644 --- a/src/db/db/dbNetlistDeviceExtractorClasses.h +++ b/src/db/db/dbNetlistDeviceExtractorClasses.h @@ -48,12 +48,17 @@ class DB_PUBLIC NetlistDeviceExtractorMOS3Transistor : public db::NetlistDeviceExtractor { public: - NetlistDeviceExtractorMOS3Transistor (const std::string &name); + NetlistDeviceExtractorMOS3Transistor (const std::string &name, bool strict = false); virtual void setup (); virtual db::Connectivity get_connectivity (const db::Layout &layout, const std::vector &layers) const; virtual void extract_devices (const std::vector &layer_geometry); + bool is_strict () const + { + return m_strict; + } + protected: /** * @brief A callback when the device is produced @@ -72,6 +77,8 @@ protected: // .. no specific implementation .. } +private: + bool m_strict; }; /** @@ -87,7 +94,7 @@ class DB_PUBLIC NetlistDeviceExtractorMOS4Transistor : public NetlistDeviceExtractorMOS3Transistor { public: - NetlistDeviceExtractorMOS4Transistor (const std::string &name); + NetlistDeviceExtractorMOS4Transistor (const std::string &name, bool strict = false); virtual void setup (); diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index 9523e7b7f..2b5d4b559 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -809,6 +809,20 @@ Class decl_dbDeviceClass ("db", "DeviceClass", gsi::method ("name=", &db::DeviceClass::set_name, gsi::arg ("name"), "@brief Sets the name of the device class." ) + + gsi::method ("strict?", &db::DeviceClass::is_strict, + "@brief Gets a value indicating whether this class performs strict terminal mapping\n" + "See \\strict= for details about this attribute." + ) + + gsi::method ("strict=", &db::DeviceClass::set_strict, gsi::arg ("s"), + "@brief Sets a value indicating whether this class performs strict terminal mapping\n" + "\n" + "Classes with this flag set never allow terminal swapping, even if the device symmetry supports that. " + "If two classes are involved in a netlist compare,\n" + "terminal swapping will be disabled if one of the classes is in strict mode.\n" + "\n" + "By default, device classes are not strict and terminal swapping is allowed as far as the " + "device symmetry supports that." + ) + gsi::method ("description", &db::DeviceClass::description, "@brief Gets the description text of the device class." ) + @@ -1014,7 +1028,9 @@ Class decl_GenericDeviceClass (decl_dbDeviceClass, "db", "Ge 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." + "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. Specificially, terminals can be defined " diff --git a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc index 0851b5f4f..9b2275b5c 100644 --- a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc +++ b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc @@ -397,14 +397,19 @@ Class decl_GenericDeviceExtractor (decl_dbNetlistDeviceE "This class has been introduced in version 0.26." ); -db::NetlistDeviceExtractorMOS3Transistor *make_mos3_extractor (const std::string &name) +static db::NetlistDeviceExtractorMOS3Transistor *make_mos3_extractor (const std::string &name, bool strict) { - return new db::NetlistDeviceExtractorMOS3Transistor (name); + return new db::NetlistDeviceExtractorMOS3Transistor (name, strict); } Class decl_NetlistDeviceExtractorMOS3Transistor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorMOS3Transistor", - gsi::constructor ("new", &make_mos3_extractor, gsi::arg ("name"), - "@brief Creates a new device extractor with the given name." + gsi::constructor ("new", &make_mos3_extractor, gsi::arg ("name"), gsi::arg ("strict", false), + "@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." + ) + + gsi::method ("strict?", &db::NetlistDeviceExtractorMOS3Transistor::is_strict, + "@brief Returns a value indicating whether extraction happens in strict mode." ), "@brief A device extractor for a three-terminal MOS transistor\n" "\n" @@ -418,7 +423,8 @@ Class decl_NetlistDeviceExtractorMOS3T "The device class produced by this extractor is \\DeviceClassMOS3Transistor.\n" "The extractor extracts the six parameters of this class: L, W, AS, AD, PS and PD.\n" "\n" - "The device recognition layer names are 'SD' (source/drain) and 'G' (gate).\n" + "In strict mode, the device recognition layer names are 'S' (source), 'D' (drain) and 'G' (gate).\n" + "Otherwise, they are 'SD' (source/drain) and 'G' (gate).\n" "The terminal output layer names are 'tS' (source), 'tG' (gate) and 'tD' (drain).\n" "\n" "The diffusion area is distributed on the number of gates connecting to\n" @@ -430,13 +436,13 @@ Class decl_NetlistDeviceExtractorMOS3T "This class has been introduced in version 0.26." ); -db::NetlistDeviceExtractorMOS4Transistor *make_mos4_extractor (const std::string &name) +static db::NetlistDeviceExtractorMOS4Transistor *make_mos4_extractor (const std::string &name, bool strict) { - return new db::NetlistDeviceExtractorMOS4Transistor (name); + return new db::NetlistDeviceExtractorMOS4Transistor (name, strict); } Class decl_NetlistDeviceExtractorMOS4Transistor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorMOS4Transistor", - gsi::constructor ("new", &make_mos4_extractor, gsi::arg ("name"), + gsi::constructor ("new", &make_mos4_extractor, gsi::arg ("name"), gsi::arg ("strict", false), "@brief Creates a new device extractor with the given name." ), "@brief A device extractor for a four-terminal MOS transistor\n" diff --git a/src/db/unit_tests/dbNetlistExtractorTests.cc b/src/db/unit_tests/dbNetlistExtractorTests.cc index e841c2cb8..38c2d7789 100644 --- a/src/db/unit_tests/dbNetlistExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistExtractorTests.cc @@ -36,6 +36,7 @@ #include "dbTestSupport.h" #include "dbCellMapping.h" #include "dbTestSupport.h" +#include "dbNetlistCompare.h" #include "tlUnitTest.h" #include "tlString.h" @@ -1864,3 +1865,246 @@ TEST(8_DiodeExtractionScaled) db::compare_layouts (_this, ly, au); } + +TEST(9_StrictDeviceExtraction) +{ + db::Layout ly; + db::LayerMap lmap; + + unsigned int nwell = define_layer (ly, lmap, 1); + unsigned int active = define_layer (ly, lmap, 2); + unsigned int poly = define_layer (ly, lmap, 3); + unsigned int poly_lbl = define_layer (ly, lmap, 3, 1); + unsigned int diff_cont = define_layer (ly, lmap, 4); + unsigned int poly_cont = define_layer (ly, lmap, 5); + unsigned int metal1 = define_layer (ly, lmap, 6); + unsigned int metal1_lbl = define_layer (ly, lmap, 6, 1); + unsigned int via1 = define_layer (ly, lmap, 7); + unsigned int metal2 = define_layer (ly, lmap, 8); + unsigned int metal2_lbl = define_layer (ly, lmap, 8, 1); + unsigned int source = define_layer (ly, lmap, 10); + + { + db::LoadLayoutOptions options; + options.get_options ().layer_map = lmap; + options.get_options ().create_other_layers = false; + + std::string fn (tl::testsrc ()); + fn = tl::combine_path (fn, "testdata"); + fn = tl::combine_path (fn, "algo"); + fn = tl::combine_path (fn, "device_extract_l9.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 rnwell (db::RecursiveShapeIterator (ly, tc, nwell), dss); + db::Region ractive (db::RecursiveShapeIterator (ly, tc, active), dss); + db::Region rpoly (db::RecursiveShapeIterator (ly, tc, poly), dss); + db::Region rpoly_lbl (db::RecursiveShapeIterator (ly, tc, poly_lbl), dss); + db::Region rdiff_cont (db::RecursiveShapeIterator (ly, tc, diff_cont), dss); + db::Region rpoly_cont (db::RecursiveShapeIterator (ly, tc, poly_cont), dss); + db::Region rmetal1 (db::RecursiveShapeIterator (ly, tc, metal1), dss); + db::Region rmetal1_lbl (db::RecursiveShapeIterator (ly, tc, metal1_lbl), dss); + db::Region rvia1 (db::RecursiveShapeIterator (ly, tc, via1), dss); + db::Region rmetal2 (db::RecursiveShapeIterator (ly, tc, metal2), dss); + db::Region rmetal2_lbl (db::RecursiveShapeIterator (ly, tc, metal2_lbl), dss); + db::Region rsource (db::RecursiveShapeIterator (ly, tc, source), dss); + + // derived regions + + db::Region rpactive = ractive & rnwell; + db::Region rpgate = rpactive & rpoly; + db::Region rpsd = rpactive - rpgate; + db::Region rps = rpsd & rsource; + db::Region rpd = rpsd - rsource; + + db::Region rnactive = ractive - rnwell; + db::Region rngate = rnactive & rpoly; + db::Region rnsd = rnactive - rngate; + db::Region rns = rnsd & rsource; + db::Region rnd = rnsd - rsource; + + // return the computed layers into the original layout and write it for debugging purposes + + unsigned int lgate = ly.insert_layer (db::LayerProperties (20, 0)); // 10/0 -> Gate + unsigned int lsd = ly.insert_layer (db::LayerProperties (21, 0)); // 11/0 -> Source/Drain + unsigned int lpdiff = ly.insert_layer (db::LayerProperties (22, 0)); // 12/0 -> P Diffusion + unsigned int lndiff = ly.insert_layer (db::LayerProperties (23, 0)); // 13/0 -> N Diffusion + + rpgate.insert_into (&ly, tc.cell_index (), lgate); + rngate.insert_into (&ly, tc.cell_index (), lgate); + rps.insert_into (&ly, tc.cell_index (), lsd); + rpd.insert_into (&ly, tc.cell_index (), lsd); + rns.insert_into (&ly, tc.cell_index (), lsd); + rnd.insert_into (&ly, tc.cell_index (), lsd); + rpsd.insert_into (&ly, tc.cell_index (), lpdiff); + rnsd.insert_into (&ly, tc.cell_index (), lndiff); + + // perform the extraction + + db::Netlist nl; + db::hier_clusters cl; + + db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS", true /*strict*/); + db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS", true /*strict*/); + + db::NetlistDeviceExtractor::input_layers dl; + + dl["S"] = &rps; + dl["D"] = &rpd; + dl["G"] = &rpgate; + dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes + pmos_ex.extract (dss, 0, dl, nl, cl); + + dl["S"] = &rns; + dl["D"] = &rnd; + dl["G"] = &rngate; + dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes + nmos_ex.extract (dss, 0, dl, nl, cl); + + // perform the net extraction + + db::NetlistExtractor net_ex; + + db::Connectivity conn; + // Intra-layer + conn.connect (rps); + conn.connect (rpd); + conn.connect (rns); + conn.connect (rnd); + conn.connect (rpoly); + conn.connect (rdiff_cont); + conn.connect (rpoly_cont); + conn.connect (rmetal1); + conn.connect (rvia1); + conn.connect (rmetal2); + // Inter-layer + conn.connect (rps, rdiff_cont); + conn.connect (rpd, rdiff_cont); + conn.connect (rns, rdiff_cont); + conn.connect (rnd, rdiff_cont); + conn.connect (rpoly, rpoly_cont); + conn.connect (rpoly_cont, rmetal1); + conn.connect (rdiff_cont, rmetal1); + conn.connect (rmetal1, rvia1); + conn.connect (rvia1, rmetal2); + conn.connect (rpoly, rpoly_lbl); // attaches labels + conn.connect (rmetal1, rmetal1_lbl); // attaches labels + conn.connect (rmetal2, rmetal2_lbl); // attaches labels + + // extract the nets + + net_ex.extract_nets (dss, 0, conn, nl, cl); + + // debug layers produced for nets + // 202/0 -> Active + // 203/0 -> Poly + // 204/0 -> Diffusion contacts + // 205/0 -> Poly contacts + // 206/0 -> Metal1 + // 207/0 -> Via1 + // 208/0 -> Metal2 + // 210/0 -> N source/drain + // 211/0 -> P source/drain + std::map dump_map; + dump_map [layer_of (rps) ] = ly.insert_layer (db::LayerProperties (210, 0)); + dump_map [layer_of (rpd) ] = ly.insert_layer (db::LayerProperties (211, 0)); + dump_map [layer_of (rns) ] = ly.insert_layer (db::LayerProperties (212, 0)); + dump_map [layer_of (rnd) ] = ly.insert_layer (db::LayerProperties (213, 0)); + dump_map [layer_of (rpoly) ] = ly.insert_layer (db::LayerProperties (203, 0)); + dump_map [layer_of (rdiff_cont)] = ly.insert_layer (db::LayerProperties (204, 0)); + dump_map [layer_of (rpoly_cont)] = ly.insert_layer (db::LayerProperties (205, 0)); + dump_map [layer_of (rmetal1) ] = ly.insert_layer (db::LayerProperties (206, 0)); + dump_map [layer_of (rvia1) ] = ly.insert_layer (db::LayerProperties (207, 0)); + dump_map [layer_of (rmetal2) ] = ly.insert_layer (db::LayerProperties (208, 0)); + + // write nets to layout + db::CellMapping cm = dss.cell_mapping_to_original (0, &ly, tc.cell_index ()); + dump_nets_to_layout (nl, cl, ly, dump_map, cm); + + std::string nl_au_string = + "circuit RINGO ();\n" + " subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $3 (IN=$I19,$2=$I39,OUT=$I1,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $4 (IN=$I1,$2=$I40,OUT=$I2,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $5 (IN=$I2,$2=$I41,OUT=$I3,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $6 (IN=$I3,$2=$I42,OUT=$I4,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $7 (IN=$I4,$2=$I43,OUT=$I5,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $8 (IN=$I5,$2=$I44,OUT=$I6,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $9 (IN=$I6,$2=$I45,OUT=$I7,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $10 (IN=$I7,$2=$I46,OUT=$I8,$4=VSS,$5=VDD);\n" + "end;\n" + "circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n" + " device PMOS $1 (S=$5,G=IN,D=$2) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + " device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" + " device NMOS $3 (S=$4,G=IN,D=$2) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + " device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" + " subcircuit TRANS $1 ($1=$2,$2=$4,$3=IN);\n" + " subcircuit TRANS $2 ($1=$2,$2=$5,$3=IN);\n" + " subcircuit TRANS $3 ($1=$5,$2=OUT,$3=$2);\n" + " subcircuit TRANS $4 ($1=$4,$2=OUT,$3=$2);\n" + "end;\n" + "circuit TRANS ($1=$1,$2=$2,$3=$3);\n" + "end;\n"; + + // compare netlist as string + CHECKPOINT (); + db::compare_netlist (_this, nl, nl_au_string); + + { + // compare vs. non-strict device classes + db::Netlist au_nl; + // non-strict + db::DeviceClass *dc; + dc = new db::DeviceClassMOS3Transistor (); + dc->set_name ("PMOS"); + au_nl.add_device_class (dc); + dc = new db::DeviceClassMOS3Transistor (); + dc->set_name ("NMOS"); + au_nl.add_device_class (dc); + au_nl.from_string (nl_au_string); + + CHECKPOINT (); + db::compare_netlist (_this, nl, au_nl); + } + + { + std::string nl_au_string_wrong_terminals = nl_au_string; + nl_au_string_wrong_terminals = tl::replaced (nl_au_string_wrong_terminals, "(S=$5,G=IN,D=$2)", "(S=$2,G=IN,D=$5)"); + nl_au_string_wrong_terminals = tl::replaced (nl_au_string_wrong_terminals, "(S=$4,G=IN,D=$2)", "(S=$2,G=IN,D=$4)"); + + // compare vs. non-strict device classes with WRONG terminal assignment + db::Netlist au_nl; + // non-strict + db::DeviceClass *dc; + dc = new db::DeviceClassMOS3Transistor (); + dc->set_name ("PMOS"); + au_nl.add_device_class (dc); + dc = new db::DeviceClassMOS3Transistor (); + dc->set_name ("NMOS"); + au_nl.add_device_class (dc); + au_nl.from_string (nl_au_string_wrong_terminals); + + db::NetlistComparer comp (0); + EXPECT_EQ (comp.compare (&nl, &au_nl), false); + } + + // compare the collected test data + + std::string au = tl::testsrc (); + au = tl::combine_path (au, "testdata"); + au = tl::combine_path (au, "algo"); + au = tl::combine_path (au, "device_extract_au9.gds"); + + db::compare_layouts (_this, ly, au); +} diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index 9ffaf7d79..ab1373625 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -161,6 +161,32 @@ module DRC RBA::DeviceExtractorMOS4Transistor::new(name) end + # %DRC% + # @brief Supplies the DMOS3 transistor extractor class + # @name dmos3 + # @synopsis dmos3(name) + # 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 + # separated. + + def dmos3(name) + RBA::DeviceExtractorMOS3Transistor::new(name, true) + end + + # %DRC% + # @brief Supplies the MOS4 transistor extractor class + # @name dmos4 + # @synopsis dmos4(name) + # 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 + # separated. + + def dmos4(name) + RBA::DeviceExtractorMOS4Transistor::new(name, true) + end + # %DRC% # @brief Supplies the BJT3 transistor extractor class # @name bjt3 diff --git a/src/lay/lay/doc/about/drc_ref_global.xml b/src/lay/lay/doc/about/drc_ref_global.xml index 0b3b3b2a6..ef89cacdd 100644 --- a/src/lay/lay/doc/about/drc_ref_global.xml +++ b/src/lay/lay/doc/about/drc_ref_global.xml @@ -204,6 +204,30 @@ See Netter#device_scaling Use this class with extract_devices to specify extraction of a planar diode

+

"dmos3" - Supplies the DMOS3 transistor extractor class

+ +

Usage:

+
    +
  • dmos3(name)
  • +
+

+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 +separated. +

+

"dmos4" - Supplies the MOS4 transistor extractor class

+ +

Usage:

+
    +
  • dmos4(name)
  • +
+

+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 +separated. +

"edge" - Creates an edge object

Usage:

diff --git a/src/lay/lay/doc/manual/lvs_device_extractors.xml b/src/lay/lay/doc/manual/lvs_device_extractors.xml index c3d07fd71..4af511c2a 100644 --- a/src/lay/lay/doc/manual/lvs_device_extractors.xml +++ b/src/lay/lay/doc/manual/lvs_device_extractors.xml @@ -187,6 +187,27 @@ extract_devices(mos4(model_name), { "SD" => (active - poly) & pplus, "G" =>

+

Diffusion MOS transistor extractor (dmos3 and dmos4)

+ +

+ DMOS devices are basically identical to MOS devices, but for those source and drain are + separated. This is often the case for diffusion MOS transistory, hence this name. +

+ +

+ DMOS and MOS devices share the same device class. DMOS devices are configured + such that source and drain cannot be swapped. The netlist compare will report + source/drain swapping as errors for such devices. +

+ +

+ DMOS transistors are recognized by their gate ("G" input), source ("S" input) and drain ("D" input) + regions. Source and drain needs to be separated from the gate shape. The touching edges of gate and + source/drain regions define the width of the device, the perpendicular dimension the gate length. + The terminal output layers for DMOS devices are the same than for MOS devices: "tS" for source, + "tD" for drain, "tG" for gate, "tB" for bulk (4-terminal version). +

+

Bipolar transistor extractor (bjt3 and bjt4)

diff --git a/src/lvs/unit_tests/lvsSimpleTests.cc b/src/lvs/unit_tests/lvsSimpleTests.cc index 5c3319b22..1a7c9143c 100644 --- a/src/lvs/unit_tests/lvsSimpleTests.cc +++ b/src/lvs/unit_tests/lvsSimpleTests.cc @@ -129,3 +129,8 @@ TEST(11_device_scaling) run_test (_this, "ringo_simple_device_scaling", "ringo.gds"); } +TEST(12_simple_dmos) +{ + run_test (_this, "ringo_simple_dmos", "ringo.gds"); +} + diff --git a/testdata/algo/device_extract_au9.gds b/testdata/algo/device_extract_au9.gds new file mode 100644 index 0000000000000000000000000000000000000000..f8c19fbd8fd9cc2435e62cf928a5d7bcbd9b653b GIT binary patch literal 7982 zcmc&(Ux<`d6u!XxA79ytBs z?2Oqkkj)#4qRBlo^D_r_O-|1@$4t3uOti9SE}Cdn(HJu_REp#H%{absjc811Bc!h@ zs+?%bw;5Bem>l{>Tl&6F^chpQCytjc2*ziCOVI65?tvAKT8fVGJZyWgusvPL^ zfAsa6tI&TO-?$3iYsM7E6;*CAzr9;J*^6%#@w*@xp8@_(dj(aVZ7+GWSFo^+JlZR$ z@@#wK_~uubdz?r+p}VQ5a$=tNPD~ygoo_yb{ovyBbK+lo>$)+uHG=hv&~>{piYl+I z3F7mU&*wg@ot6DK_^IqiMU~giF3(@FUHEk@lKWXvDH$jyzonMX*&OY&1 zVUPGrQRQY|z)$%L`ge%G3SW!A1XWJV?XRh4W?K8}m&9Kt%ltRi4^k zzlMCQXOr;hXYvG9Zn0DTm>Vj&+}IFg{wRIU^CTF};JYs%$vUjP4EbfO%V7m)aG+s~ zBC@^Y+(vHyG)I&D>dg zcR$#>4*CUEucFFR`a}K*{4)ps2;&a_eW0jvV(xfPOu`J8Z#{o8KJ=%=smgl>`BzZo z%lSKw|DNN16|C^CIKurYsB-LQ-(Q};!TT8eQ-YPF$OCVH?@;B@sh;euN6~n5^69DR zW^$JXx$@>AtP6Yd<{`utdy{vCpvsBCT7$FC+{m-fJAr4u__m_T+xUU6nPaJ6^d{et z?^2%dyVOd9YHKU1o~8Vi@FTMs)@+f997!dimGR6hn04Zs%NQ2jd;tWiv4T*3S^~0V}^$PPGgIy^QLrv zHgmMi8SP=tSo<8e*NaKUPkSYOs&!oUdQCc@lH*5r7qQCfYOZ$CG-TD1`?>nk#^8jM zeXV`e^(j6S~QJ?a$L!xTtx2=)Q^!_22Yi!_wy-n3#NW zYJO_^@#LoTDrIBlUqbNT5v-gr=J1QSsT`^t=-+f+r3>D@;O`WyTmt_b_zqPLwEQmF z-*x7);wN^uvPDoyq;KZMZ{%hsX57r4y||Izr@exe6S$e*rM-eGPuc77jd^ZN{6(an zX75js{&M3P{(|1U^p_z0G>cA3QRO}Qs~Sb@I&H2Q9M;T(EQ39SdIf))Wjc%wE_4`; z))$VUFy@IbyqEEX)Ew_SF5lTsn3dTw`A)iJRO{X5u;b}Ar-{P2>l`$_o#wzZ<4t=v zVO0F)Syb0i)LxcNuXy8@&DxBkZCSYyCGonevGcvir1i{56EvHNyr zkBx;DY_OKcu4VJ~KA1gr;8^z9+@)a5Rl}`rrjvh$<%PiO(b{Hpy0g=DQV%^)aF_Mb z19|*bk7IkC9($mG-$&0G+=Y31sP?-wU(f1l9_UYMo_Xv@)Ml)CY+ucP1@1JD`$6ha gcC*XP!bE)S;PkXRJ6T^t@4JU5Xa~3d;WIc)6~o&L!zXh!YtAZkwne@h@qh`DG~J8B@mK`s1Qo9Bnawc z9VEyO-hx2TQ$&QPjzJMZ=Rok}Bj5I&ogH^q+%-WzkD1^1H^1M^{N_o9Eb9i)ZeKa*pbtKFSM)#;M9j;H5(zPw*;=~_57`+6u(wI%VooH6cU`x5lu4BOL1aBss+~!h-GM$6))y`Km+=d_bKtLlYA-G)>2Z=F z)+25+>jSEthT`;CTL;au(47N|9ABvR`1q{j_`*~(>+tJS?OWoT@clQI5dR7Cw*=h- z#6F@_J2P_rkRGvrdVY{~$bXko?SVck^-KHl&0(&hQ<28s0##Qs$#ws(Fp1KKB&tn` z{oxqX-8*=OGC87LmG(**_eOEd+sLc^_TJp8#E5v!fz$*McEC+u#O$zTjqc;$P%{*| zVd@t5t9L7+uV}_m?CjGTkEl~V1@1pNwPHA$8;Z=_yI zwWpgRdaakdw>9*LLEJTzj^E86rP`TsdSrBu=LcDb_`8&9Pu6pv;e1}d>A96^Pdfkl zFq$y$x=fpUA3dT}yU9n+?}Xn=VG5cy*DXxpE}w`>?kUyIOwyxX4WcjmAbO?Rvkeh_ zDjJ{rMD*p~MXyvl`Y1f_N&-F3T8I4I7iI=Q%nPO3!5BUA_7?e@5!#r&g-1A#Pqmww zh~5t3qqdKcpGBej5p{fs&py>&TujnK)5Ch4{UYlFs-1e0_1SsR=iZ54srKxAvc9xc z^krv7uT*kdQ%X$z|1C4Sx%K7}Na!hfa5I9&Vi{h0iiinEx|R)~{e) zJKhs$Bi0b+iBj#RJ<&(8y@-AqT~ zhx9}@8(A;3CvpChtQV?1Nk4K&^i0-`-VVrm-|yAie^0o7@KQ!rvECtmDFYY$zSwRZ jS5e;GrB1m`+$t=@Zi52@JM4z&Ji$&=(#aah16WW-+2!N9=A%f!IPz{bbKz`&p*zzif$Ffa(KKxio)1_tI9 z1_l@n69>{Pf(#5Sxb(B$f#~P@0MQSlVd6jl8Ai{d<109JZWjsO4v delta 334 zcmaFl|HxN~fsKKQDS|eC$GGUk6 z7!}HlU1qb4qA)J=#Kbc=<=7b*WLR;!bF&-25j!C@6FB7=C+9NqPTs>?JUN${dvX<@ j>12IAhsEo;m?!@im7RQsFBOODBG{F2cxkhX(mYlGooFw0 diff --git a/testdata/lvs/ringo_simple_dmos.cir b/testdata/lvs/ringo_simple_dmos.cir new file mode 100644 index 000000000..d517e69ba --- /dev/null +++ b/testdata/lvs/ringo_simple_dmos.cir @@ -0,0 +1,83 @@ +* Extracted by KLayout + +* cell RINGO +* pin FB +* pin VDD +* pin OUT +* pin ENABLE +* pin VSS +.SUBCKT RINGO 11 12 13 14 15 +* net 11 FB +* net 12 VDD +* net 13 OUT +* net 14 ENABLE +* net 15 VSS +* cell instance $1 r0 *1 1.8,0 +X$1 12 1 15 12 11 14 15 ND2X1 +* cell instance $2 r0 *1 4.2,0 +X$2 12 2 15 12 1 15 INVX1 +* cell instance $3 r0 *1 6,0 +X$3 12 3 15 12 2 15 INVX1 +* cell instance $4 r0 *1 7.8,0 +X$4 12 4 15 12 3 15 INVX1 +* cell instance $5 r0 *1 9.6,0 +X$5 12 5 15 12 4 15 INVX1 +* cell instance $6 r0 *1 11.4,0 +X$6 12 6 15 12 5 15 INVX1 +* cell instance $7 r0 *1 13.2,0 +X$7 12 7 15 12 6 15 INVX1 +* cell instance $8 r0 *1 15,0 +X$8 12 8 15 12 7 15 INVX1 +* cell instance $9 r0 *1 16.8,0 +X$9 12 9 15 12 8 15 INVX1 +* cell instance $10 r0 *1 18.6,0 +X$10 12 10 15 12 9 15 INVX1 +* cell instance $11 r0 *1 20.4,0 +X$11 12 11 15 12 10 15 INVX1 +* cell instance $12 r0 *1 22.2,0 +X$12 12 13 15 12 11 15 INVX1 +.ENDS RINGO + +* cell INVX1 +* pin VDD +* pin OUT +* pin VSS +* pin +* pin IN +* pin SUBSTRATE +.SUBCKT INVX1 1 2 3 4 5 6 +* net 1 VDD +* net 2 OUT +* net 3 VSS +* net 5 IN +* net 6 SUBSTRATE +* device instance $1 r0 *1 0.85,5.8 PMOS +M$1 1 5 2 4 PMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U +* device instance $2 r0 *1 0.85,2.135 NMOS +M$2 3 5 2 6 NMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U +.ENDS INVX1 + +* cell ND2X1 +* pin VDD +* pin OUT +* pin VSS +* pin +* pin B +* pin A +* pin SUBSTRATE +.SUBCKT ND2X1 1 2 3 5 6 7 8 +* net 1 VDD +* net 2 OUT +* net 3 VSS +* net 6 B +* net 7 A +* net 8 SUBSTRATE +* device instance $1 r0 *1 0.85,5.8 PMOS +M$1 1 7 2 5 PMOS L=0.25U W=1.5U AS=0.3375P AD=0.6375P PS=1.95U PD=3.85U +* device instance $2 r0 *1 1.55,5.8 PMOS +M$2 1 6 2 5 PMOS L=0.25U W=1.5U AS=0.3375P AD=0.6375P PS=1.95U PD=3.85U +* device instance $3 r0 *1 0.85,2.135 NMOS +M$3 4 7 3 8 NMOS L=0.25U W=0.95U AS=0.21375P AD=0.40375P PS=1.4U PD=2.75U +* device instance $4 r0 *1 1.55,2.135 NMOS +M$4 4 6 2 8 NMOS L=0.25U W=0.95U AS=0.21375P AD=0.40375P PS=1.4U PD=2.75U +.ENDS ND2X1 diff --git a/testdata/lvs/ringo_simple_dmos.lvs b/testdata/lvs/ringo_simple_dmos.lvs new file mode 100644 index 000000000..0879f5e1b --- /dev/null +++ b/testdata/lvs/ringo_simple_dmos.lvs @@ -0,0 +1,81 @@ + +source($lvs_test_source, "RINGO") + +report_lvs($lvs_test_target_lvsdb, true) + +target_netlist($lvs_test_target_cir, write_spice, "Extracted by KLayout") + +schematic("ringo.cir") + +deep + +# Drawing layers + +nwell = input(1, 0) +active = input(2, 0) +pplus = input(3, 0) +nplus = input(4, 0) +poly = input(5, 0) +contact = input(8, 0) +metal1 = input(9, 0) +via1 = input(10, 0) +metal2 = input(11, 0) +source = input(14, 0) + +# Bulk layer for terminal provisioning + +bulk = polygon_layer + +# Computed layers + +active_in_nwell = active & nwell +pactive = active_in_nwell & pplus +pgate = pactive & poly +psd = pactive - pgate +ps = psd & source +pd = psd - source +ntie = active_in_nwell & nplus + +active_outside_nwell = active - nwell +nactive = active_outside_nwell & nplus +ngate = nactive & poly +nsd = nactive - ngate +ns = nsd & source +nd = nsd - source +ptie = active_outside_nwell & pplus + +# Device extraction + +# PMOS transistor device extraction +extract_devices(dmos4("PMOS"), { "S" => ps, "D" => pd, "G" => pgate, "W" => nwell, + "tS" => ps, "tD" => pd, "tG" => poly, "tW" => nwell }) + +# NMOS transistor device extraction +extract_devices(dmos4("NMOS"), { "S" => ns, "D" => nd, "G" => ngate, "W" => bulk, + "tS" => ns, "tD" => nd, "tG" => poly, "tW" => bulk }) + +# Define connectivity for netlist extraction + +# Inter-layer +connect(ps, contact) +connect(pd, contact) +connect(ns, contact) +connect(nd, contact) +connect(poly, contact) +connect(ntie, contact) +connect(nwell, ntie) +connect(ptie, contact) +connect(contact, metal1) +connect(metal1, via1) +connect(via1, metal2) + +# Global +connect_global(bulk, "SUBSTRATE") +connect_global(ptie, "SUBSTRATE") + +# Compare section + +netlist.simplify + +compare + diff --git a/testdata/lvs/ringo_simple_dmos.lvsdb b/testdata/lvs/ringo_simple_dmos.lvsdb new file mode 100644 index 000000000..9e3146d88 --- /dev/null +++ b/testdata/lvs/ringo_simple_dmos.lvsdb @@ -0,0 +1,925 @@ +#%lvsdb-klayout + +# Layout +layout( + top(RINGO) + unit(0.001) + + # Layer section + # This section lists the mask layers (drawing or derived) and their connections. + + # Mask layers + layer(l4 '1/0') + layer(l5 '5/0') + layer(l10 '8/0') + layer(l13 '9/0') + layer(l14 '10/0') + layer(l15 '11/0') + layer(l9) + layer(l3) + layer(l1) + layer(l11) + layer(l8) + layer(l6) + layer(l12) + + # Mask layer connectivity + connect(l4 l4 l11) + connect(l5 l5 l10) + connect(l10 l5 l10 l13 l3 l1 l11 l8 l6 l12) + connect(l13 l10 l13 l14) + connect(l14 l13 l14 l15) + connect(l15 l14 l15) + connect(l9 l9) + connect(l3 l10 l3) + connect(l1 l10 l1) + connect(l11 l4 l10 l11) + connect(l8 l10 l8) + connect(l6 l10 l6) + connect(l12 l10 l12) + + # Global nets and connectivity + global(l9 SUBSTRATE) + global(l12 SUBSTRATE) + + # Device class section + class(PMOS MOS4) + class(NMOS MOS4) + + # Device abstracts section + # Device abstracts list the pin shapes of the devices. + device(D$PMOS PMOS + terminal(S + rect(l3 (125 -750) (450 1500)) + ) + terminal(G + rect(l5 (-125 -750) (250 1500)) + ) + terminal(D + rect(l1 (-550 -750) (425 1500)) + ) + terminal(B + rect(l4 (-125 -750) (250 1500)) + ) + ) + device(D$PMOS$1 PMOS + terminal(S + rect(l3 (-575 -750) (450 1500)) + ) + terminal(G + rect(l5 (-125 -750) (250 1500)) + ) + terminal(D + rect(l1 (125 -750) (425 1500)) + ) + terminal(B + rect(l4 (-125 -750) (250 1500)) + ) + ) + device(D$PMOS$2 PMOS + terminal(S + rect(l3 (-550 -750) (425 1500)) + ) + terminal(G + rect(l5 (-125 -750) (250 1500)) + ) + terminal(D + rect(l1 (125 -750) (425 1500)) + ) + terminal(B + rect(l4 (-125 -750) (250 1500)) + ) + ) + device(D$NMOS NMOS + terminal(S + rect(l8 (125 -475) (450 950)) + ) + terminal(G + rect(l5 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (-550 -475) (425 950)) + ) + terminal(B + rect(l9 (-125 -475) (250 950)) + ) + ) + device(D$NMOS$1 NMOS + terminal(S + rect(l8 (-575 -475) (450 950)) + ) + terminal(G + rect(l5 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (425 950)) + ) + terminal(B + rect(l9 (-125 -475) (250 950)) + ) + ) + device(D$NMOS$2 NMOS + terminal(S + rect(l8 (-550 -475) (425 950)) + ) + terminal(G + rect(l5 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (425 950)) + ) + terminal(B + rect(l9 (-125 -475) (250 950)) + ) + ) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(ND2X1 + + # Circuit boundary + rect((-100 400) (2600 7600)) + + # Nets with their geometries + net(1 name(VDD) + rect(l10 (1110 5160) (180 180)) + rect(l10 (-180 920) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l13 (-240 -790) (300 1700)) + rect(l13 (-1350 0) (2400 800)) + rect(l13 (-1151 -401) (2 2)) + rect(l3 (-276 -2151) (425 1500)) + rect(l3 (-400 -1500) (425 1500)) + ) + net(2 name(OUT) + rect(l10 (1810 1770) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l10 (-1580 3760) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l10 (1220 920) (180 180)) + rect(l10 (-180 -1280) (180 180)) + rect(l10 (-180 370) (180 180)) + polygon(l13 (-240 -4180) (0 1390) (490 0) (0 -300) (-190 0) (0 -1090)) + rect(l13 (-110 1390) (300 1400)) + polygon(l13 (-1890 0) (0 600) (300 0) (0 -300) (1590 0) (0 -300)) + rect(l13 (-141 -501) (2 2)) + rect(l13 (-1751 1099) (300 1400)) + rect(l13 (1100 -1700) (300 300)) + rect(l13 (-300 0) (300 1400)) + rect(l1 (-1750 -1450) (425 1500)) + rect(l1 (950 -1500) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(3 name(VSS) + rect(l10 (410 1770) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l13 (-240 -1300) (300 1360)) + rect(l13 (-650 -2160) (2400 800)) + rect(l13 (-1151 -401) (2 2)) + rect(l6 (-951 859) (425 950)) + ) + net(4 + rect(l8 (975 1660) (425 950)) + rect(l8 (-400 -950) (425 950)) + ) + net(5 + rect(l4 (-100 4500) (2600 3500)) + ) + net(6 name(B) + rect(l5 (1425 2860) (250 1940)) + rect(l5 (-345 -950) (300 300)) + rect(l5 (-205 650) (250 2000)) + rect(l5 (-250 -2000) (250 2000)) + rect(l5 (-250 -5390) (250 1450)) + rect(l10 (-285 1050) (180 180)) + rect(l13 (-71 -91) (2 2)) + rect(l13 (-171 -151) (300 300)) + ) + net(7 name(A) + rect(l5 (725 2860) (250 1940)) + rect(l5 (-325 -1850) (300 300)) + rect(l5 (-225 1550) (250 2000)) + rect(l5 (-250 -2000) (250 2000)) + rect(l5 (-250 -5390) (250 1450)) + rect(l10 (-265 150) (180 180)) + rect(l13 (-91 -91) (2 2)) + rect(l13 (-151 -151) (300 300)) + ) + net(8 name(SUBSTRATE)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(5) + pin(6 name(B)) + pin(7 name(A)) + pin(8 name(SUBSTRATE)) + + # Devices and their connections + device(1 D$PMOS + location(850 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.3375) + param(AD 0.6375) + param(PS 1.95) + param(PD 3.85) + terminal(S 1) + terminal(G 7) + terminal(D 2) + terminal(B 5) + ) + device(2 D$PMOS$1 + location(1550 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.3375) + param(AD 0.6375) + param(PS 1.95) + param(PD 3.85) + terminal(S 1) + terminal(G 6) + terminal(D 2) + terminal(B 5) + ) + device(3 D$NMOS + location(850 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.21375) + param(AD 0.40375) + param(PS 1.4) + param(PD 2.75) + terminal(S 4) + terminal(G 7) + terminal(D 3) + terminal(B 8) + ) + device(4 D$NMOS$1 + location(1550 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.21375) + param(AD 0.40375) + param(PS 1.4) + param(PD 2.75) + terminal(S 4) + terminal(G 6) + terminal(D 2) + terminal(B 8) + ) + + ) + circuit(INVX1 + + # Circuit boundary + rect((-100 400) (2000 7600)) + + # Nets with their geometries + net(1 name(VDD) + rect(l10 (410 6260) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l13 (-240 -240) (300 1400)) + rect(l13 (-650 300) (1800 800)) + rect(l13 (-1450 -1100) (300 300)) + rect(l13 (299 399) (2 2)) + rect(l3 (-651 -2151) (425 1500)) + ) + net(2 name(OUT) + rect(l10 (1110 5160) (180 180)) + rect(l10 (-180 920) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l10 (-180 -4120) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l13 (-240 -790) (300 4790)) + rect(l13 (-151 -2501) (2 2)) + rect(l1 (-226 1049) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(3 name(VSS) + rect(l10 (410 1770) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l13 (-240 -1300) (300 1360)) + rect(l13 (-650 -2160) (1800 800)) + rect(l13 (-851 -401) (2 2)) + rect(l8 (-651 859) (425 950)) + ) + net(4 + rect(l4 (-100 4500) (2000 3500)) + ) + net(5 name(IN) + rect(l5 (725 2860) (250 1940)) + rect(l5 (-525 -1850) (300 300)) + rect(l5 (-25 1550) (250 2000)) + rect(l5 (-250 -2000) (250 2000)) + rect(l5 (-250 -5390) (250 1450)) + rect(l10 (-465 150) (180 180)) + rect(l13 (-91 -91) (2 2)) + rect(l13 (-151 -151) (300 300)) + ) + net(6 name(SUBSTRATE)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4) + pin(5 name(IN)) + pin(6 name(SUBSTRATE)) + + # Devices and their connections + device(1 D$PMOS$2 + location(850 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.6375) + param(AD 0.6375) + param(PS 3.85) + param(PD 3.85) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(2 D$NMOS$2 + location(850 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.40375) + param(AD 0.40375) + param(PS 2.75) + param(PD 2.75) + terminal(S 3) + terminal(G 5) + terminal(D 2) + terminal(B 6) + ) + + ) + circuit(RINGO + + # Circuit boundary + rect((0 350) (25800 7650)) + + # Nets with their geometries + net(1 + rect(l10 (4710 3010) (180 180)) + rect(l13 (-850 -240) (610 300)) + ) + net(2 + rect(l10 (6510 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(3 + rect(l10 (8310 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(4 + rect(l10 (10110 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(5 + rect(l10 (11910 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(6 + rect(l10 (13710 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(7 + rect(l10 (15510 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(8 + rect(l10 (17310 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(9 + rect(l10 (19110 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(10 + rect(l10 (20910 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(11 name(FB) + rect(l10 (22710 3010) (180 180)) + rect(l10 (-19700 720) (180 180)) + rect(l13 (18380 -1140) (900 300)) + rect(l13 (-19530 590) (320 320)) + rect(l13 (17820 -320) (320 320)) + rect(l14 (-18400 -260) (200 200)) + rect(l14 (17940 -200) (200 200)) + rect(l15 (-18040 -300) (17740 400)) + rect(l15 (-17921 -201) (2 2)) + rect(l15 (-221 -201) (400 400)) + rect(l15 (17740 -400) (400 400)) + ) + net(12 name(VDD) + rect(l4 (500 4500) (1400 3500)) + rect(l4 (-1900 -3500) (600 3500)) + rect(l4 (23300 -3500) (1400 3500)) + rect(l4 (-100 -3500) (600 3500)) + rect(l10 (-24690 -1240) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l10 (-180 -1280) (180 180)) + rect(l10 (23220 370) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l10 (-180 -1280) (180 180)) + rect(l13 (-21741 859) (2 2)) + rect(l13 (-2351 -451) (1200 800)) + rect(l13 (-750 -1450) (300 1400)) + rect(l13 (-101 -351) (2 2)) + rect(l13 (-1251 -401) (600 800)) + rect(l13 (23400 -800) (1200 800)) + rect(l13 (-750 -1450) (300 1400)) + rect(l13 (-101 -351) (2 2)) + rect(l13 (549 -401) (600 800)) + rect(l11 (-24850 -1500) (500 1500)) + rect(l11 (22900 -1500) (500 1500)) + ) + net(13 name(OUT) + rect(l13 (23440 3840) (320 320)) + rect(l14 (-260 -260) (200 200)) + rect(l15 (-101 -101) (2 2)) + rect(l15 (-201 -201) (400 400)) + ) + net(14 name(ENABLE) + rect(l10 (2510 3010) (180 180)) + rect(l13 (-250 -250) (320 320)) + rect(l14 (-260 -260) (200 200)) + rect(l15 (-101 -101) (2 2)) + rect(l15 (-201 -201) (400 400)) + ) + net(15 name(VSS) + rect(l10 (1110 1610) (180 180)) + rect(l10 (-180 -1280) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l10 (23220 370) (180 180)) + rect(l10 (-180 -1280) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l13 (-21741 -391) (2 2)) + rect(l13 (-1901 -401) (300 1400)) + rect(l13 (-750 -1450) (1200 800)) + rect(l13 (-551 -401) (2 2)) + rect(l13 (-1251 -401) (600 800)) + rect(l13 (23850 -750) (300 1400)) + rect(l13 (-750 -1450) (1200 800)) + rect(l13 (-551 -401) (2 2)) + rect(l13 (549 -401) (600 800)) + rect(l12 (-24850 -800) (500 1500)) + rect(l12 (22900 -1500) (500 1500)) + ) + + # Outgoing pins and their connections to nets + pin(11 name(FB)) + pin(12 name(VDD)) + pin(13 name(OUT)) + pin(14 name(ENABLE)) + pin(15 name(VSS)) + + # Subcircuits and their connections + circuit(1 ND2X1 location(1800 0) + pin(0 12) + pin(1 1) + pin(2 15) + pin(3 12) + pin(4 11) + pin(5 14) + pin(6 15) + ) + circuit(2 INVX1 location(4200 0) + pin(0 12) + pin(1 2) + pin(2 15) + pin(3 12) + pin(4 1) + pin(5 15) + ) + circuit(3 INVX1 location(6000 0) + pin(0 12) + pin(1 3) + pin(2 15) + pin(3 12) + pin(4 2) + pin(5 15) + ) + circuit(4 INVX1 location(7800 0) + pin(0 12) + pin(1 4) + pin(2 15) + pin(3 12) + pin(4 3) + pin(5 15) + ) + circuit(5 INVX1 location(9600 0) + pin(0 12) + pin(1 5) + pin(2 15) + pin(3 12) + pin(4 4) + pin(5 15) + ) + circuit(6 INVX1 location(11400 0) + pin(0 12) + pin(1 6) + pin(2 15) + pin(3 12) + pin(4 5) + pin(5 15) + ) + circuit(7 INVX1 location(13200 0) + pin(0 12) + pin(1 7) + pin(2 15) + pin(3 12) + pin(4 6) + pin(5 15) + ) + circuit(8 INVX1 location(15000 0) + pin(0 12) + pin(1 8) + pin(2 15) + pin(3 12) + pin(4 7) + pin(5 15) + ) + circuit(9 INVX1 location(16800 0) + pin(0 12) + pin(1 9) + pin(2 15) + pin(3 12) + pin(4 8) + pin(5 15) + ) + circuit(10 INVX1 location(18600 0) + pin(0 12) + pin(1 10) + pin(2 15) + pin(3 12) + pin(4 9) + pin(5 15) + ) + circuit(11 INVX1 location(20400 0) + pin(0 12) + pin(1 11) + pin(2 15) + pin(3 12) + pin(4 10) + pin(5 15) + ) + circuit(12 INVX1 location(22200 0) + pin(0 12) + pin(1 13) + pin(2 15) + pin(3 12) + pin(4 11) + pin(5 15) + ) + + ) +) + +# Reference netlist +reference( + + # Device class section + class(PMOS MOS4) + class(NMOS MOS4) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(ND2X1 + + # Nets + net(1 name(VDD)) + net(2 name(OUT)) + net(3 name(VSS)) + net(4 name(NWELL)) + net(5 name(B)) + net(6 name(A)) + net(7 name(BULK)) + net(8 name('1')) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4 name(NWELL)) + pin(5 name(B)) + pin(6 name(A)) + pin(7 name(BULK)) + + # Devices and their connections + device(1 PMOS + name($1) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 2) + terminal(G 6) + terminal(D 1) + terminal(B 4) + ) + device(2 PMOS + name($2) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(3 NMOS + name($3) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 3) + terminal(G 6) + terminal(D 8) + terminal(B 7) + ) + device(4 NMOS + name($4) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 8) + terminal(G 5) + terminal(D 2) + terminal(B 7) + ) + + ) + circuit(INVX1 + + # Nets + net(1 name(VDD)) + net(2 name(OUT)) + net(3 name(VSS)) + net(4 name(NWELL)) + net(5 name(IN)) + net(6 name(BULK)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4 name(NWELL)) + pin(5 name(IN)) + pin(6 name(BULK)) + + # Devices and their connections + device(1 PMOS + name($1) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(2 NMOS + name($2) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 3) + terminal(G 5) + terminal(D 2) + terminal(B 6) + ) + + ) + circuit(RINGO + + # Nets + net(1 name(VSS)) + net(2 name(VDD)) + net(3 name(FB)) + net(4 name(ENABLE)) + net(5 name(OUT)) + net(6 name('1')) + net(7 name('2')) + net(8 name('3')) + net(9 name('4')) + net(10 name('5')) + net(11 name('6')) + net(12 name('7')) + net(13 name('8')) + net(14 name('9')) + net(15 name('10')) + + # Outgoing pins and their connections to nets + pin(1 name(VSS)) + pin(2 name(VDD)) + pin(3 name(FB)) + pin(4 name(ENABLE)) + pin(5 name(OUT)) + + # Subcircuits and their connections + circuit(1 ND2X1 name($1) + pin(0 2) + pin(1 6) + pin(2 1) + pin(3 2) + pin(4 3) + pin(5 4) + pin(6 1) + ) + circuit(2 INVX1 name($2) + pin(0 2) + pin(1 7) + pin(2 1) + pin(3 2) + pin(4 6) + pin(5 1) + ) + circuit(3 INVX1 name($3) + pin(0 2) + pin(1 8) + pin(2 1) + pin(3 2) + pin(4 7) + pin(5 1) + ) + circuit(4 INVX1 name($4) + pin(0 2) + pin(1 9) + pin(2 1) + pin(3 2) + pin(4 8) + pin(5 1) + ) + circuit(5 INVX1 name($5) + pin(0 2) + pin(1 10) + pin(2 1) + pin(3 2) + pin(4 9) + pin(5 1) + ) + circuit(6 INVX1 name($6) + pin(0 2) + pin(1 11) + pin(2 1) + pin(3 2) + pin(4 10) + pin(5 1) + ) + circuit(7 INVX1 name($7) + pin(0 2) + pin(1 12) + pin(2 1) + pin(3 2) + pin(4 11) + pin(5 1) + ) + circuit(8 INVX1 name($8) + pin(0 2) + pin(1 13) + pin(2 1) + pin(3 2) + pin(4 12) + pin(5 1) + ) + circuit(9 INVX1 name($9) + pin(0 2) + pin(1 14) + pin(2 1) + pin(3 2) + pin(4 13) + pin(5 1) + ) + circuit(10 INVX1 name($10) + pin(0 2) + pin(1 15) + pin(2 1) + pin(3 2) + pin(4 14) + pin(5 1) + ) + circuit(11 INVX1 name($11) + pin(0 2) + pin(1 3) + pin(2 1) + pin(3 2) + pin(4 15) + pin(5 1) + ) + circuit(12 INVX1 name($12) + pin(0 2) + pin(1 5) + pin(2 1) + pin(3 2) + pin(4 3) + pin(5 1) + ) + + ) +) + +# Cross reference +xref( + circuit(INVX1 INVX1 match + xref( + net(4 4 match) + net(5 5 match) + net(2 2 match) + net(6 6 match) + net(1 1 match) + net(3 3 match) + pin(3 3 match) + pin(4 4 match) + pin(1 1 match) + pin(5 5 match) + pin(0 0 match) + pin(2 2 match) + device(2 2 match) + device(1 1 match) + ) + ) + circuit(ND2X1 ND2X1 nomatch + xref( + net(4 8 mismatch) + net(5 4 mismatch) + net(7 6 match) + net(6 5 match) + net(2 2 mismatch) + net(8 7 mismatch) + net(1 1 mismatch) + net(3 3 mismatch) + pin(3 3 match) + pin(5 5 match) + pin(4 4 match) + pin(1 1 match) + pin(6 6 match) + pin(0 0 match) + pin(2 2 match) + device(4 4 match) + device(3 3 mismatch) + device(2 2 match) + device(1 1 mismatch) + ) + ) + circuit(RINGO RINGO match + xref( + net(1 6 match) + net(10 15 match) + net(2 7 match) + net(3 8 match) + net(4 9 match) + net(5 10 match) + net(6 11 match) + net(7 12 match) + net(8 13 match) + net(9 14 match) + net(14 4 match) + net(11 3 match) + net(13 5 match) + net(12 2 match) + net(15 1 match) + pin(3 3 match) + pin(0 2 match) + pin(2 4 match) + pin(1 1 match) + pin(4 0 match) + circuit(2 2 match) + circuit(3 3 match) + circuit(4 4 match) + circuit(5 5 match) + circuit(6 6 match) + circuit(7 7 match) + circuit(8 8 match) + circuit(9 9 match) + circuit(10 10 match) + circuit(11 11 match) + circuit(12 12 match) + circuit(1 1 match) + ) + ) +) diff --git a/testdata/ruby/dbNetlist.rb b/testdata/ruby/dbNetlist.rb index 43f2f3a09..13665f01a 100644 --- a/testdata/ruby/dbNetlist.rb +++ b/testdata/ruby/dbNetlist.rb @@ -115,6 +115,10 @@ class DBNetlist_TestClass < TestBase assert_equal(nl.device_class_by_name("UVW") == cc, true) assert_equal(nl.device_class_by_name("doesntexist") == nil, true) + assert_equal(cc.strict?, false) + cc.strict = true + assert_equal(cc.strict?, true) + names = [] nl.each_device_class { |i| names << i.name } assert_equal(names, [ c.name, cc.name ]) From b0aa9b6540a61d6475f352f370f8bf28ca52b63b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 21 Aug 2019 23:03:24 +0200 Subject: [PATCH 08/27] Spice reader test compatible with Windows (three-digit exponential) --- src/db/unit_tests/dbNetlistReaderTests.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/db/unit_tests/dbNetlistReaderTests.cc b/src/db/unit_tests/dbNetlistReaderTests.cc index 149bc22f6..045090a59 100644 --- a/src/db/unit_tests/dbNetlistReaderTests.cc +++ b/src/db/unit_tests/dbNetlistReaderTests.cc @@ -343,7 +343,11 @@ TEST(9_DeviceMultipliers) tl::InputStream is (path); reader.read (is, nl); - EXPECT_EQ (nl.to_string (), + std::string nl_string = nl.to_string (); + // normalization of exponential representation: + nl_string = tl::replaced (nl_string, "e-009", "e-09"); + + EXPECT_EQ (nl_string, "circuit .TOP ();\n" " device RES $1 (A='1',B='2') (R=850,L=0,W=0,A=0,P=0);\n" " device RES $2 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n" From 3ae848bff4a144daf14d4ba7e1c77c0ad07ba5fa Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 23 Aug 2019 23:13:04 +0200 Subject: [PATCH 09/27] Provide test case for spice reader with delegate for devices as subcircuits. Small bugfix in spice reader: wrong line number in warning. --- src/db/db/dbNetlistSpiceReader.cc | 2 +- src/lvs/unit_tests/lvsSimpleTests.cc | 4 + testdata/lvs/ringo_device_subcircuits.cir | 83 ++ testdata/lvs/ringo_device_subcircuits.lvs | 126 +++ testdata/lvs/ringo_device_subcircuits.lvsdb.1 | 971 ++++++++++++++++++ testdata/lvs/ringo_device_subcircuits.lvsdb.2 | 971 ++++++++++++++++++ testdata/lvs/ringo_xdevice.cir | 35 + 7 files changed, 2191 insertions(+), 1 deletion(-) create mode 100644 testdata/lvs/ringo_device_subcircuits.cir create mode 100644 testdata/lvs/ringo_device_subcircuits.lvs create mode 100644 testdata/lvs/ringo_device_subcircuits.lvsdb.1 create mode 100644 testdata/lvs/ringo_device_subcircuits.lvsdb.2 create mode 100644 testdata/lvs/ringo_xdevice.cir diff --git a/src/db/db/dbNetlistSpiceReader.cc b/src/db/db/dbNetlistSpiceReader.cc index 928aba2aa..9234570c7 100644 --- a/src/db/db/dbNetlistSpiceReader.cc +++ b/src/db/db/dbNetlistSpiceReader.cc @@ -478,7 +478,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 ()); + std::string fmt_msg = tl::sprintf ("%s in %s, line %d", msg, mp_stream->source (), mp_stream->line_number () - 1); tl::warn << fmt_msg; } diff --git a/src/lvs/unit_tests/lvsSimpleTests.cc b/src/lvs/unit_tests/lvsSimpleTests.cc index 1a7c9143c..20d8dbc9a 100644 --- a/src/lvs/unit_tests/lvsSimpleTests.cc +++ b/src/lvs/unit_tests/lvsSimpleTests.cc @@ -134,3 +134,7 @@ TEST(12_simple_dmos) run_test (_this, "ringo_simple_dmos", "ringo.gds"); } +TEST(13_simple_ringo_device_subcircuits) +{ + run_test (_this, "ringo_device_subcircuits", "ringo.gds"); +} diff --git a/testdata/lvs/ringo_device_subcircuits.cir b/testdata/lvs/ringo_device_subcircuits.cir new file mode 100644 index 000000000..761afb771 --- /dev/null +++ b/testdata/lvs/ringo_device_subcircuits.cir @@ -0,0 +1,83 @@ +* Extracted by KLayout + +* cell RINGO +* pin FB +* pin VDD +* pin OUT +* pin ENABLE +* pin VSS +.SUBCKT RINGO 11 12 13 14 15 +* net 11 FB +* net 12 VDD +* net 13 OUT +* net 14 ENABLE +* net 15 VSS +* cell instance $1 r0 *1 1.8,0 +X$1 12 1 15 12 11 14 15 ND2X1 +* cell instance $2 r0 *1 4.2,0 +X$2 12 2 15 12 1 15 INVX1 +* cell instance $3 r0 *1 6,0 +X$3 12 3 15 12 2 15 INVX1 +* cell instance $4 r0 *1 7.8,0 +X$4 12 4 15 12 3 15 INVX1 +* cell instance $5 r0 *1 9.6,0 +X$5 12 5 15 12 4 15 INVX1 +* cell instance $6 r0 *1 11.4,0 +X$6 12 6 15 12 5 15 INVX1 +* cell instance $7 r0 *1 13.2,0 +X$7 12 7 15 12 6 15 INVX1 +* cell instance $8 r0 *1 15,0 +X$8 12 8 15 12 7 15 INVX1 +* cell instance $9 r0 *1 16.8,0 +X$9 12 9 15 12 8 15 INVX1 +* cell instance $10 r0 *1 18.6,0 +X$10 12 10 15 12 9 15 INVX1 +* cell instance $11 r0 *1 20.4,0 +X$11 12 11 15 12 10 15 INVX1 +* cell instance $12 r0 *1 22.2,0 +X$12 12 13 15 12 11 15 INVX1 +.ENDS RINGO + +* cell INVX1 +* pin VDD +* pin OUT +* pin VSS +* pin +* pin IN +* pin SUBSTRATE +.SUBCKT INVX1 1 2 3 4 5 6 +* net 1 VDD +* net 2 OUT +* net 3 VSS +* net 5 IN +* net 6 SUBSTRATE +* device instance $1 r0 *1 0.85,5.8 PMOS +M$1 1 5 2 4 PMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U +* device instance $2 r0 *1 0.85,2.135 NMOS +M$2 3 5 2 6 NMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U +.ENDS INVX1 + +* cell ND2X1 +* pin VDD +* pin OUT +* pin VSS +* pin +* pin B +* pin A +* pin SUBSTRATE +.SUBCKT ND2X1 1 2 3 4 5 6 7 +* net 1 VDD +* net 2 OUT +* net 3 VSS +* net 5 B +* net 6 A +* net 7 SUBSTRATE +* device instance $1 r0 *1 0.85,5.8 PMOS +M$1 2 6 1 4 PMOS L=0.25U W=1.5U AS=0.6375P AD=0.3375P PS=3.85U PD=1.95U +* device instance $2 r0 *1 1.55,5.8 PMOS +M$2 1 5 2 4 PMOS L=0.25U W=1.5U AS=0.3375P AD=0.6375P PS=1.95U PD=3.85U +* device instance $3 r0 *1 0.85,2.135 NMOS +M$3 3 6 8 7 NMOS L=0.25U W=0.95U AS=0.40375P AD=0.21375P PS=2.75U PD=1.4U +* device instance $4 r0 *1 1.55,2.135 NMOS +M$4 8 5 2 7 NMOS L=0.25U W=0.95U AS=0.21375P AD=0.40375P PS=1.4U PD=2.75U +.ENDS ND2X1 diff --git a/testdata/lvs/ringo_device_subcircuits.lvs b/testdata/lvs/ringo_device_subcircuits.lvs new file mode 100644 index 000000000..cf54ddc71 --- /dev/null +++ b/testdata/lvs/ringo_device_subcircuits.lvs @@ -0,0 +1,126 @@ + +source($lvs_test_source, "RINGO") + +report_lvs($lvs_test_target_lvsdb, true) + +target_netlist($lvs_test_target_cir, write_spice, "Extracted by KLayout") + + +# Provide a special reader +class SubcircuitModelsReader < RBA::NetlistSpiceReaderDelegate + + # says we want to catch these subcircuits as devices + def wants_subcircuit(name) + name == "NMOS" || name == "XPMOS" + end + + # translate the element + def element(circuit, el, name, model, value, nets, params) + + if el != "X" + # all other elements are left to the standard implementation + return super + end + + if nets.size != 4 + error("Subcircuit #{model} needs four nodes") + end + + # provide a device class + cls = circuit.netlist.device_class_by_name(model) + if ! cls + cls = RBA::DeviceClassMOS4Transistor::new + cls.name = model + circuit.netlist.add(cls) + end + + # create a device + device = circuit.create_device(cls, name) + + # and configure the device + [ "S", "G", "D", "B" ].each_with_index do |t,index| + device.connect_terminal(t, nets[index]) + end + + # parameters in the model are given in micrometer units, so + # we need to translate the parameter values from SI to um values: + device.set_parameter("W", (params["W"] || 1.0e-6) * 1e6) + device.set_parameter("L", (params["L"] || 1.0e-6) * 1e6) + + return true + + end + +end + + +schematic("ringo_xdevice.cir", RBA::NetlistSpiceReader::new(SubcircuitModelsReader::new)) + +deep + +# Drawing layers + +nwell = input(1, 0) +active = input(2, 0) +pplus = input(3, 0) +nplus = input(4, 0) +poly = input(5, 0) +contact = input(8, 0) +metal1 = input(9, 0) +via1 = input(10, 0) +metal2 = input(11, 0) + +# Bulk layer for terminal provisioning + +bulk = polygon_layer + +# Computed layers + +active_in_nwell = active & nwell +pactive = active_in_nwell & pplus +pgate = pactive & poly +psd = pactive - pgate +ntie = active_in_nwell & nplus + +active_outside_nwell = active - nwell +nactive = active_outside_nwell & nplus +ngate = nactive & poly +nsd = nactive - ngate +ptie = active_outside_nwell & pplus + +# Device extraction + +# PMOS transistor device extraction +extract_devices(mos4("PMOS"), { "SD" => psd, "G" => pgate, "W" => nwell, + "tS" => psd, "tD" => psd, "tG" => poly, "tW" => nwell }) + +# NMOS transistor device extraction +extract_devices(mos4("NMOS"), { "SD" => nsd, "G" => ngate, "W" => bulk, + "tS" => nsd, "tD" => nsd, "tG" => poly, "tW" => bulk }) + +# Define connectivity for netlist extraction + +# Inter-layer +connect(psd, contact) +connect(nsd, contact) +connect(poly, contact) +connect(ntie, contact) +connect(nwell, ntie) +connect(ptie, contact) +connect(contact, metal1) +connect(metal1, via1) +connect(via1, metal2) + +# Global +connect_global(bulk, "SUBSTRATE") +connect_global(ptie, "SUBSTRATE") + +# Test same_device_classes +same_device_classes("PMOS", "XPMOS") + +# Compare section + +netlist.simplify + +compare + diff --git a/testdata/lvs/ringo_device_subcircuits.lvsdb.1 b/testdata/lvs/ringo_device_subcircuits.lvsdb.1 new file mode 100644 index 000000000..46d09231c --- /dev/null +++ b/testdata/lvs/ringo_device_subcircuits.lvsdb.1 @@ -0,0 +1,971 @@ +#%lvsdb-klayout + +# Layout +layout( + top(RINGO) + unit(0.001) + + # Layer section + # This section lists the mask layers (drawing or derived) and their connections. + + # Mask layers + layer(l3 '1/0') + layer(l4 '5/0') + layer(l8 '8/0') + layer(l11 '9/0') + layer(l12 '10/0') + layer(l13 '11/0') + layer(l7) + layer(l2) + layer(l9) + layer(l6) + layer(l10) + + # Mask layer connectivity + connect(l3 l3 l9) + connect(l4 l4 l8) + connect(l8 l4 l8 l11 l2 l9 l6 l10) + connect(l11 l8 l11 l12) + connect(l12 l11 l12 l13) + connect(l13 l12 l13) + connect(l7 l7) + connect(l2 l8 l2) + connect(l9 l3 l8 l9) + connect(l6 l8 l6) + connect(l10 l8 l10) + + # Global nets and connectivity + global(l7 SUBSTRATE) + global(l10 SUBSTRATE) + + # Device class section + class(PMOS MOS4) + class(NMOS MOS4) + + # Device abstracts section + # Device abstracts list the pin shapes of the devices. + device(D$PMOS PMOS + terminal(S + rect(l2 (-550 -750) (425 1500)) + ) + terminal(G + rect(l4 (-125 -750) (250 1500)) + ) + terminal(D + rect(l2 (125 -750) (450 1500)) + ) + terminal(B + rect(l3 (-125 -750) (250 1500)) + ) + ) + device(D$PMOS$1 PMOS + terminal(S + rect(l2 (-575 -750) (450 1500)) + ) + terminal(G + rect(l4 (-125 -750) (250 1500)) + ) + terminal(D + rect(l2 (125 -750) (425 1500)) + ) + terminal(B + rect(l3 (-125 -750) (250 1500)) + ) + ) + device(D$PMOS$2 PMOS + terminal(S + rect(l2 (-550 -750) (425 1500)) + ) + terminal(G + rect(l4 (-125 -750) (250 1500)) + ) + terminal(D + rect(l2 (125 -750) (425 1500)) + ) + terminal(B + rect(l3 (-125 -750) (250 1500)) + ) + ) + device(D$NMOS NMOS + terminal(S + rect(l6 (-550 -475) (425 950)) + ) + terminal(G + rect(l4 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (450 950)) + ) + terminal(B + rect(l7 (-125 -475) (250 950)) + ) + ) + device(D$NMOS$1 NMOS + terminal(S + rect(l6 (-575 -475) (450 950)) + ) + terminal(G + rect(l4 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (425 950)) + ) + terminal(B + rect(l7 (-125 -475) (250 950)) + ) + ) + device(D$NMOS$2 NMOS + terminal(S + rect(l6 (-550 -475) (425 950)) + ) + terminal(G + rect(l4 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (425 950)) + ) + terminal(B + rect(l7 (-125 -475) (250 950)) + ) + ) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(ND2X1 + + # Circuit boundary + rect((-100 400) (2600 7600)) + + # Nets with their geometries + net(1 name(VDD) + rect(l8 (1110 5160) (180 180)) + rect(l8 (-180 920) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l11 (-240 -790) (300 1700)) + rect(l11 (-1350 0) (2400 800)) + rect(l11 (-1151 -401) (2 2)) + rect(l2 (-276 -2151) (425 1500)) + rect(l2 (-400 -1500) (425 1500)) + ) + net(2 name(OUT) + rect(l8 (1810 1770) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (-1580 3760) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (1220 920) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (-180 370) (180 180)) + polygon(l11 (-240 -4180) (0 1390) (490 0) (0 -300) (-190 0) (0 -1090)) + rect(l11 (-110 1390) (300 1400)) + polygon(l11 (-1890 0) (0 600) (300 0) (0 -300) (1590 0) (0 -300)) + rect(l11 (-141 -501) (2 2)) + rect(l11 (-1751 1099) (300 1400)) + rect(l11 (1100 -1700) (300 300)) + rect(l11 (-300 0) (300 1400)) + rect(l2 (-1750 -1450) (425 1500)) + rect(l2 (950 -1500) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(3 name(VSS) + rect(l8 (410 1770) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-240 -1300) (300 1360)) + rect(l11 (-650 -2160) (2400 800)) + rect(l11 (-1151 -401) (2 2)) + rect(l6 (-951 859) (425 950)) + ) + net(4 + rect(l3 (-100 4500) (2600 3500)) + ) + net(5 name(B) + rect(l4 (1425 2860) (250 1940)) + rect(l4 (-345 -950) (300 300)) + rect(l4 (-205 650) (250 2000)) + rect(l4 (-250 -2000) (250 2000)) + rect(l4 (-250 -5390) (250 1450)) + rect(l8 (-285 1050) (180 180)) + rect(l11 (-71 -91) (2 2)) + rect(l11 (-171 -151) (300 300)) + ) + net(6 name(A) + rect(l4 (725 2860) (250 1940)) + rect(l4 (-325 -1850) (300 300)) + rect(l4 (-225 1550) (250 2000)) + rect(l4 (-250 -2000) (250 2000)) + rect(l4 (-250 -5390) (250 1450)) + rect(l8 (-265 150) (180 180)) + rect(l11 (-91 -91) (2 2)) + rect(l11 (-151 -151) (300 300)) + ) + net(7 name(SUBSTRATE)) + net(8 + rect(l6 (975 1660) (425 950)) + rect(l6 (-400 -950) (425 950)) + ) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4) + pin(5 name(B)) + pin(6 name(A)) + pin(7 name(SUBSTRATE)) + + # Devices and their connections + device(1 D$PMOS + location(850 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.6375) + param(AD 0.3375) + param(PS 3.85) + param(PD 1.95) + terminal(S 2) + terminal(G 6) + terminal(D 1) + terminal(B 4) + ) + device(2 D$PMOS$1 + location(1550 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.3375) + param(AD 0.6375) + param(PS 1.95) + param(PD 3.85) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(3 D$NMOS + location(850 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.40375) + param(AD 0.21375) + param(PS 2.75) + param(PD 1.4) + terminal(S 3) + terminal(G 6) + terminal(D 8) + terminal(B 7) + ) + device(4 D$NMOS$1 + location(1550 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.21375) + param(AD 0.40375) + param(PS 1.4) + param(PD 2.75) + terminal(S 8) + terminal(G 5) + terminal(D 2) + terminal(B 7) + ) + + ) + circuit(INVX1 + + # Circuit boundary + rect((-100 400) (2000 7600)) + + # Nets with their geometries + net(1 name(VDD) + rect(l8 (410 6260) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l11 (-240 -240) (300 1400)) + rect(l11 (-650 300) (1800 800)) + rect(l11 (-1450 -1100) (300 300)) + rect(l11 (299 399) (2 2)) + rect(l2 (-651 -2151) (425 1500)) + ) + net(2 name(OUT) + rect(l8 (1110 5160) (180 180)) + rect(l8 (-180 920) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (-180 -4120) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-240 -790) (300 4790)) + rect(l11 (-151 -2501) (2 2)) + rect(l2 (-226 1049) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(3 name(VSS) + rect(l8 (410 1770) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-240 -1300) (300 1360)) + rect(l11 (-650 -2160) (1800 800)) + rect(l11 (-851 -401) (2 2)) + rect(l6 (-651 859) (425 950)) + ) + net(4 + rect(l3 (-100 4500) (2000 3500)) + ) + net(5 name(IN) + rect(l4 (725 2860) (250 1940)) + rect(l4 (-525 -1850) (300 300)) + rect(l4 (-25 1550) (250 2000)) + rect(l4 (-250 -2000) (250 2000)) + rect(l4 (-250 -5390) (250 1450)) + rect(l8 (-465 150) (180 180)) + rect(l11 (-91 -91) (2 2)) + rect(l11 (-151 -151) (300 300)) + ) + net(6 name(SUBSTRATE)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4) + pin(5 name(IN)) + pin(6 name(SUBSTRATE)) + + # Devices and their connections + device(1 D$PMOS$2 + location(850 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.6375) + param(AD 0.6375) + param(PS 3.85) + param(PD 3.85) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(2 D$NMOS$2 + location(850 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.40375) + param(AD 0.40375) + param(PS 2.75) + param(PD 2.75) + terminal(S 3) + terminal(G 5) + terminal(D 2) + terminal(B 6) + ) + + ) + circuit(RINGO + + # Circuit boundary + rect((0 350) (25800 7650)) + + # Nets with their geometries + net(1 + rect(l8 (4710 3010) (180 180)) + rect(l11 (-850 -240) (610 300)) + rect(l2 (-2550 1800) (425 1500)) + rect(l2 (950 -1500) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(2 + rect(l8 (6510 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(3 + rect(l8 (8310 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(4 + rect(l8 (10110 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(5 + rect(l8 (11910 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(6 + rect(l8 (13710 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(7 + rect(l8 (15510 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(8 + rect(l8 (17310 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(9 + rect(l8 (19110 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(10 + rect(l8 (20910 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(11 name(FB) + rect(l8 (22710 3010) (180 180)) + rect(l8 (-19700 720) (180 180)) + rect(l11 (18380 -1140) (900 300)) + rect(l11 (-19530 590) (320 320)) + rect(l11 (17820 -320) (320 320)) + rect(l12 (-18400 -260) (200 200)) + rect(l12 (17940 -200) (200 200)) + rect(l13 (-18040 -300) (17740 400)) + rect(l13 (-17921 -201) (2 2)) + rect(l13 (-221 -201) (400 400)) + rect(l13 (17740 -400) (400 400)) + rect(l2 (-245 850) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(12 name(VDD) + rect(l3 (500 4500) (1400 3500)) + rect(l3 (-1900 -3500) (600 3500)) + rect(l3 (23300 -3500) (1400 3500)) + rect(l3 (-100 -3500) (600 3500)) + rect(l8 (-24690 -1240) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (23220 370) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l11 (-21741 859) (2 2)) + rect(l11 (-2351 -451) (1200 800)) + rect(l11 (-750 -1450) (300 1400)) + rect(l11 (-101 -351) (2 2)) + rect(l11 (-1251 -401) (600 800)) + rect(l11 (23400 -800) (1200 800)) + rect(l11 (-750 -1450) (300 1400)) + rect(l11 (-101 -351) (2 2)) + rect(l11 (549 -401) (600 800)) + rect(l2 (-23025 -2550) (425 1500)) + rect(l2 (-400 -1500) (425 1500)) + rect(l2 (1275 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l9 (-21975 -450) (500 1500)) + rect(l9 (22900 -1500) (500 1500)) + ) + net(13 name(OUT) + rect(l11 (23440 3840) (320 320)) + rect(l12 (-260 -260) (200 200)) + rect(l13 (-101 -101) (2 2)) + rect(l13 (-201 -201) (400 400)) + rect(l2 (-625 850) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(14 name(ENABLE) + rect(l8 (2510 3010) (180 180)) + rect(l11 (-250 -250) (320 320)) + rect(l12 (-260 -260) (200 200)) + rect(l13 (-101 -101) (2 2)) + rect(l13 (-201 -201) (400 400)) + ) + net(15 name(VSS) + rect(l8 (1110 1610) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (23220 370) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-21741 -391) (2 2)) + rect(l11 (-1901 -401) (300 1400)) + rect(l11 (-750 -1450) (1200 800)) + rect(l11 (-551 -401) (2 2)) + rect(l11 (-1251 -401) (600 800)) + rect(l11 (23850 -750) (300 1400)) + rect(l11 (-750 -1450) (1200 800)) + rect(l11 (-551 -401) (2 2)) + rect(l11 (549 -401) (600 800)) + rect(l6 (-23700 460) (425 950)) + rect(l6 (1975 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l10 (-21975 -2210) (500 1500)) + rect(l10 (22900 -1500) (500 1500)) + ) + + # Outgoing pins and their connections to nets + pin(11 name(FB)) + pin(12 name(VDD)) + pin(13 name(OUT)) + pin(14 name(ENABLE)) + pin(15 name(VSS)) + + # Subcircuits and their connections + circuit(1 ND2X1 location(1800 0) + pin(0 12) + pin(1 1) + pin(2 15) + pin(3 12) + pin(4 11) + pin(5 14) + pin(6 15) + ) + circuit(2 INVX1 location(4200 0) + pin(0 12) + pin(1 2) + pin(2 15) + pin(3 12) + pin(4 1) + pin(5 15) + ) + circuit(3 INVX1 location(6000 0) + pin(0 12) + pin(1 3) + pin(2 15) + pin(3 12) + pin(4 2) + pin(5 15) + ) + circuit(4 INVX1 location(7800 0) + pin(0 12) + pin(1 4) + pin(2 15) + pin(3 12) + pin(4 3) + pin(5 15) + ) + circuit(5 INVX1 location(9600 0) + pin(0 12) + pin(1 5) + pin(2 15) + pin(3 12) + pin(4 4) + pin(5 15) + ) + circuit(6 INVX1 location(11400 0) + pin(0 12) + pin(1 6) + pin(2 15) + pin(3 12) + pin(4 5) + pin(5 15) + ) + circuit(7 INVX1 location(13200 0) + pin(0 12) + pin(1 7) + pin(2 15) + pin(3 12) + pin(4 6) + pin(5 15) + ) + circuit(8 INVX1 location(15000 0) + pin(0 12) + pin(1 8) + pin(2 15) + pin(3 12) + pin(4 7) + pin(5 15) + ) + circuit(9 INVX1 location(16800 0) + pin(0 12) + pin(1 9) + pin(2 15) + pin(3 12) + pin(4 8) + pin(5 15) + ) + circuit(10 INVX1 location(18600 0) + pin(0 12) + pin(1 10) + pin(2 15) + pin(3 12) + pin(4 9) + pin(5 15) + ) + circuit(11 INVX1 location(20400 0) + pin(0 12) + pin(1 11) + pin(2 15) + pin(3 12) + pin(4 10) + pin(5 15) + ) + circuit(12 INVX1 location(22200 0) + pin(0 12) + pin(1 13) + pin(2 15) + pin(3 12) + pin(4 11) + pin(5 15) + ) + + ) +) + +# Reference netlist +reference( + + # Device class section + class(XPMOS MOS4) + class(NMOS MOS4) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(ND2X1 + + # Nets + net(1 name(VDD)) + net(2 name(OUT)) + net(3 name(VSS)) + net(4 name(NWELL)) + net(5 name(B)) + net(6 name(A)) + net(7 name(BULK)) + net(8 name('1')) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4 name(NWELL)) + pin(5 name(B)) + pin(6 name(A)) + pin(7 name(BULK)) + + # Devices and their connections + device(1 XPMOS + name($1) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 2) + terminal(G 6) + terminal(D 1) + terminal(B 4) + ) + device(2 XPMOS + name($2) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(3 NMOS + name($3) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 3) + terminal(G 6) + terminal(D 8) + terminal(B 7) + ) + device(4 NMOS + name($4) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 8) + terminal(G 5) + terminal(D 2) + terminal(B 7) + ) + + ) + circuit(INVX1 + + # Nets + net(1 name(VDD)) + net(2 name(OUT)) + net(3 name(VSS)) + net(4 name(NWELL)) + net(5 name(IN)) + net(6 name(BULK)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4 name(NWELL)) + pin(5 name(IN)) + pin(6 name(BULK)) + + # Devices and their connections + device(1 XPMOS + name($1) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(2 NMOS + name($2) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 3) + terminal(G 5) + terminal(D 2) + terminal(B 6) + ) + + ) + circuit(RINGO + + # Nets + net(1 name(VSS)) + net(2 name(VDD)) + net(3 name(FB)) + net(4 name(ENABLE)) + net(5 name(OUT)) + net(6 name('1')) + net(7 name('2')) + net(8 name('3')) + net(9 name('4')) + net(10 name('5')) + net(11 name('6')) + net(12 name('7')) + net(13 name('8')) + net(14 name('9')) + net(15 name('10')) + + # Outgoing pins and their connections to nets + pin(1 name(VSS)) + pin(2 name(VDD)) + pin(3 name(FB)) + pin(4 name(ENABLE)) + pin(5 name(OUT)) + + # Subcircuits and their connections + circuit(1 ND2X1 name($1) + pin(0 2) + pin(1 6) + pin(2 1) + pin(3 2) + pin(4 3) + pin(5 4) + pin(6 1) + ) + circuit(2 INVX1 name($2) + pin(0 2) + pin(1 7) + pin(2 1) + pin(3 2) + pin(4 6) + pin(5 1) + ) + circuit(3 INVX1 name($3) + pin(0 2) + pin(1 8) + pin(2 1) + pin(3 2) + pin(4 7) + pin(5 1) + ) + circuit(4 INVX1 name($4) + pin(0 2) + pin(1 9) + pin(2 1) + pin(3 2) + pin(4 8) + pin(5 1) + ) + circuit(5 INVX1 name($5) + pin(0 2) + pin(1 10) + pin(2 1) + pin(3 2) + pin(4 9) + pin(5 1) + ) + circuit(6 INVX1 name($6) + pin(0 2) + pin(1 11) + pin(2 1) + pin(3 2) + pin(4 10) + pin(5 1) + ) + circuit(7 INVX1 name($7) + pin(0 2) + pin(1 12) + pin(2 1) + pin(3 2) + pin(4 11) + pin(5 1) + ) + circuit(8 INVX1 name($8) + pin(0 2) + pin(1 13) + pin(2 1) + pin(3 2) + pin(4 12) + pin(5 1) + ) + circuit(9 INVX1 name($9) + pin(0 2) + pin(1 14) + pin(2 1) + pin(3 2) + pin(4 13) + pin(5 1) + ) + circuit(10 INVX1 name($10) + pin(0 2) + pin(1 15) + pin(2 1) + pin(3 2) + pin(4 14) + pin(5 1) + ) + circuit(11 INVX1 name($11) + pin(0 2) + pin(1 3) + pin(2 1) + pin(3 2) + pin(4 15) + pin(5 1) + ) + circuit(12 INVX1 name($12) + pin(0 2) + pin(1 5) + pin(2 1) + pin(3 2) + pin(4 3) + pin(5 1) + ) + + ) +) + +# Cross reference +xref( + circuit(INVX1 INVX1 match + xref( + net(4 4 match) + net(5 5 match) + net(2 2 match) + net(6 6 match) + net(1 1 match) + net(3 3 match) + pin(3 3 match) + pin(4 4 match) + pin(1 1 match) + pin(5 5 match) + pin(0 0 match) + pin(2 2 match) + device(2 2 match) + device(1 1 match) + ) + ) + circuit(ND2X1 ND2X1 match + xref( + net(8 8 match) + net(4 4 match) + net(6 6 match) + net(5 5 match) + net(2 2 match) + net(7 7 match) + net(1 1 match) + net(3 3 match) + pin(3 3 match) + pin(5 5 match) + pin(4 4 match) + pin(1 1 match) + pin(6 6 match) + pin(0 0 match) + pin(2 2 match) + device(3 3 match) + device(4 4 match) + device(1 1 match) + device(2 2 match) + ) + ) + circuit(RINGO RINGO match + xref( + net(1 6 match) + net(10 15 match) + net(2 7 match) + net(3 8 match) + net(4 9 match) + net(5 10 match) + net(6 11 match) + net(7 12 match) + net(8 13 match) + net(9 14 match) + net(14 4 match) + net(11 3 match) + net(13 5 match) + net(12 2 match) + net(15 1 match) + pin(3 3 match) + pin(0 2 match) + pin(2 4 match) + pin(1 1 match) + pin(4 0 match) + circuit(2 2 match) + circuit(3 3 match) + circuit(4 4 match) + circuit(5 5 match) + circuit(6 6 match) + circuit(7 7 match) + circuit(8 8 match) + circuit(9 9 match) + circuit(10 10 match) + circuit(11 11 match) + circuit(12 12 match) + circuit(1 1 match) + ) + ) +) diff --git a/testdata/lvs/ringo_device_subcircuits.lvsdb.2 b/testdata/lvs/ringo_device_subcircuits.lvsdb.2 new file mode 100644 index 000000000..834cc43fe --- /dev/null +++ b/testdata/lvs/ringo_device_subcircuits.lvsdb.2 @@ -0,0 +1,971 @@ +#%lvsdb-klayout + +# Layout +layout( + top(RINGO) + unit(0.001) + + # Layer section + # This section lists the mask layers (drawing or derived) and their connections. + + # Mask layers + layer(l3 '1/0') + layer(l4 '5/0') + layer(l8 '8/0') + layer(l11 '9/0') + layer(l12 '10/0') + layer(l13 '11/0') + layer(l7) + layer(l2) + layer(l9) + layer(l6) + layer(l10) + + # Mask layer connectivity + connect(l3 l3 l9) + connect(l4 l4 l8) + connect(l8 l4 l8 l11 l2 l9 l6 l10) + connect(l11 l8 l11 l12) + connect(l12 l11 l12 l13) + connect(l13 l12 l13) + connect(l7 l7) + connect(l2 l8 l2) + connect(l9 l3 l8 l9) + connect(l6 l8 l6) + connect(l10 l8 l10) + + # Global nets and connectivity + global(l7 SUBSTRATE) + global(l10 SUBSTRATE) + + # Device class section + class(PMOS MOS4) + class(NMOS MOS4) + + # Device abstracts section + # Device abstracts list the pin shapes of the devices. + device(D$PMOS PMOS + terminal(S + rect(l2 (-550 -750) (425 1500)) + ) + terminal(G + rect(l4 (-125 -750) (250 1500)) + ) + terminal(D + rect(l2 (125 -750) (450 1500)) + ) + terminal(B + rect(l3 (-125 -750) (250 1500)) + ) + ) + device(D$PMOS$1 PMOS + terminal(S + rect(l2 (-575 -750) (450 1500)) + ) + terminal(G + rect(l4 (-125 -750) (250 1500)) + ) + terminal(D + rect(l2 (125 -750) (425 1500)) + ) + terminal(B + rect(l3 (-125 -750) (250 1500)) + ) + ) + device(D$PMOS$2 PMOS + terminal(S + rect(l2 (-550 -750) (425 1500)) + ) + terminal(G + rect(l4 (-125 -750) (250 1500)) + ) + terminal(D + rect(l2 (125 -750) (425 1500)) + ) + terminal(B + rect(l3 (-125 -750) (250 1500)) + ) + ) + device(D$NMOS NMOS + terminal(S + rect(l6 (-550 -475) (425 950)) + ) + terminal(G + rect(l4 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (450 950)) + ) + terminal(B + rect(l7 (-125 -475) (250 950)) + ) + ) + device(D$NMOS$1 NMOS + terminal(S + rect(l6 (-575 -475) (450 950)) + ) + terminal(G + rect(l4 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (425 950)) + ) + terminal(B + rect(l7 (-125 -475) (250 950)) + ) + ) + device(D$NMOS$2 NMOS + terminal(S + rect(l6 (-550 -475) (425 950)) + ) + terminal(G + rect(l4 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (425 950)) + ) + terminal(B + rect(l7 (-125 -475) (250 950)) + ) + ) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(ND2X1 + + # Circuit boundary + rect((-100 400) (2600 7600)) + + # Nets with their geometries + net(1 name(VDD) + rect(l8 (1110 5160) (180 180)) + rect(l8 (-180 920) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l11 (-240 -790) (300 1700)) + rect(l11 (-1350 0) (2400 800)) + rect(l11 (-1151 -401) (2 2)) + rect(l2 (-276 -2151) (425 1500)) + rect(l2 (-400 -1500) (425 1500)) + ) + net(2 name(OUT) + rect(l8 (1810 1770) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (-1580 3760) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (1220 920) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (-180 370) (180 180)) + polygon(l11 (-240 -4180) (0 1390) (490 0) (0 -300) (-190 0) (0 -1090)) + rect(l11 (-110 1390) (300 1400)) + polygon(l11 (-1890 0) (0 600) (300 0) (0 -300) (1590 0) (0 -300)) + rect(l11 (-141 -501) (2 2)) + rect(l11 (-1751 1099) (300 1400)) + rect(l11 (1100 -1700) (300 300)) + rect(l11 (-300 0) (300 1400)) + rect(l2 (-375 -1450) (425 1500)) + rect(l2 (-1800 -1500) (425 1500)) + rect(l6 (950 -4890) (425 950)) + ) + net(3 name(VSS) + rect(l8 (410 1770) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-240 -1300) (300 1360)) + rect(l11 (-650 -2160) (2400 800)) + rect(l11 (-1151 -401) (2 2)) + rect(l6 (-951 859) (425 950)) + ) + net(4 + rect(l3 (-100 4500) (2600 3500)) + ) + net(5 name(B) + rect(l4 (1425 2860) (250 1940)) + rect(l4 (-345 -950) (300 300)) + rect(l4 (-205 650) (250 2000)) + rect(l4 (-250 -2000) (250 2000)) + rect(l4 (-250 -5390) (250 1450)) + rect(l8 (-285 1050) (180 180)) + rect(l11 (-71 -91) (2 2)) + rect(l11 (-171 -151) (300 300)) + ) + net(6 name(A) + rect(l4 (725 2860) (250 1940)) + rect(l4 (-325 -1850) (300 300)) + rect(l4 (-225 1550) (250 2000)) + rect(l4 (-250 -2000) (250 2000)) + rect(l4 (-250 -5390) (250 1450)) + rect(l8 (-265 150) (180 180)) + rect(l11 (-91 -91) (2 2)) + rect(l11 (-151 -151) (300 300)) + ) + net(7 name(SUBSTRATE)) + net(8 + rect(l6 (975 1660) (425 950)) + rect(l6 (-400 -950) (425 950)) + ) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4) + pin(5 name(B)) + pin(6 name(A)) + pin(7 name(SUBSTRATE)) + + # Devices and their connections + device(1 D$PMOS + location(850 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.6375) + param(AD 0.3375) + param(PS 3.85) + param(PD 1.95) + terminal(S 2) + terminal(G 6) + terminal(D 1) + terminal(B 4) + ) + device(2 D$PMOS$1 + location(1550 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.3375) + param(AD 0.6375) + param(PS 1.95) + param(PD 3.85) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(3 D$NMOS + location(850 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.40375) + param(AD 0.21375) + param(PS 2.75) + param(PD 1.4) + terminal(S 3) + terminal(G 6) + terminal(D 8) + terminal(B 7) + ) + device(4 D$NMOS$1 + location(1550 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.21375) + param(AD 0.40375) + param(PS 1.4) + param(PD 2.75) + terminal(S 8) + terminal(G 5) + terminal(D 2) + terminal(B 7) + ) + + ) + circuit(INVX1 + + # Circuit boundary + rect((-100 400) (2000 7600)) + + # Nets with their geometries + net(1 name(VDD) + rect(l8 (410 6260) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l11 (-240 -240) (300 1400)) + rect(l11 (-650 300) (1800 800)) + rect(l11 (-1450 -1100) (300 300)) + rect(l11 (299 399) (2 2)) + rect(l2 (-651 -2151) (425 1500)) + ) + net(2 name(OUT) + rect(l8 (1110 5160) (180 180)) + rect(l8 (-180 920) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (-180 -4120) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-240 -790) (300 4790)) + rect(l11 (-151 -2501) (2 2)) + rect(l2 (-226 1049) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(3 name(VSS) + rect(l8 (410 1770) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-240 -1300) (300 1360)) + rect(l11 (-650 -2160) (1800 800)) + rect(l11 (-851 -401) (2 2)) + rect(l6 (-651 859) (425 950)) + ) + net(4 + rect(l3 (-100 4500) (2000 3500)) + ) + net(5 name(IN) + rect(l4 (725 2860) (250 1940)) + rect(l4 (-525 -1850) (300 300)) + rect(l4 (-25 1550) (250 2000)) + rect(l4 (-250 -2000) (250 2000)) + rect(l4 (-250 -5390) (250 1450)) + rect(l8 (-465 150) (180 180)) + rect(l11 (-91 -91) (2 2)) + rect(l11 (-151 -151) (300 300)) + ) + net(6 name(SUBSTRATE)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4) + pin(5 name(IN)) + pin(6 name(SUBSTRATE)) + + # Devices and their connections + device(1 D$PMOS$2 + location(850 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.6375) + param(AD 0.6375) + param(PS 3.85) + param(PD 3.85) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(2 D$NMOS$2 + location(850 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.40375) + param(AD 0.40375) + param(PS 2.75) + param(PD 2.75) + terminal(S 3) + terminal(G 5) + terminal(D 2) + terminal(B 6) + ) + + ) + circuit(RINGO + + # Circuit boundary + rect((0 350) (25800 7650)) + + # Nets with their geometries + net(1 + rect(l8 (4710 3010) (180 180)) + rect(l11 (-850 -240) (610 300)) + rect(l2 (-1175 1800) (425 1500)) + rect(l2 (-1800 -1500) (425 1500)) + rect(l6 (950 -4890) (425 950)) + ) + net(2 + rect(l8 (6510 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(3 + rect(l8 (8310 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(4 + rect(l8 (10110 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(5 + rect(l8 (11910 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(6 + rect(l8 (13710 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(7 + rect(l8 (15510 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(8 + rect(l8 (17310 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(9 + rect(l8 (19110 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(10 + rect(l8 (20910 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(11 name(FB) + rect(l8 (22710 3010) (180 180)) + rect(l8 (-19700 720) (180 180)) + rect(l11 (18380 -1140) (900 300)) + rect(l11 (-19530 590) (320 320)) + rect(l11 (17820 -320) (320 320)) + rect(l12 (-18400 -260) (200 200)) + rect(l12 (17940 -200) (200 200)) + rect(l13 (-18040 -300) (17740 400)) + rect(l13 (-17921 -201) (2 2)) + rect(l13 (-221 -201) (400 400)) + rect(l13 (17740 -400) (400 400)) + rect(l2 (-245 850) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(12 name(VDD) + rect(l3 (500 4500) (1400 3500)) + rect(l3 (-1900 -3500) (600 3500)) + rect(l3 (23300 -3500) (1400 3500)) + rect(l3 (-100 -3500) (600 3500)) + rect(l8 (-24690 -1240) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (23220 370) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l11 (-21741 859) (2 2)) + rect(l11 (-2351 -451) (1200 800)) + rect(l11 (-750 -1450) (300 1400)) + rect(l11 (-101 -351) (2 2)) + rect(l11 (-1251 -401) (600 800)) + rect(l11 (23400 -800) (1200 800)) + rect(l11 (-750 -1450) (300 1400)) + rect(l11 (-101 -351) (2 2)) + rect(l11 (549 -401) (600 800)) + rect(l2 (-23025 -2550) (425 1500)) + rect(l2 (-400 -1500) (425 1500)) + rect(l2 (1275 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l9 (-21975 -450) (500 1500)) + rect(l9 (22900 -1500) (500 1500)) + ) + net(13 name(OUT) + rect(l11 (23440 3840) (320 320)) + rect(l12 (-260 -260) (200 200)) + rect(l13 (-101 -101) (2 2)) + rect(l13 (-201 -201) (400 400)) + rect(l2 (-625 850) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(14 name(ENABLE) + rect(l8 (2510 3010) (180 180)) + rect(l11 (-250 -250) (320 320)) + rect(l12 (-260 -260) (200 200)) + rect(l13 (-101 -101) (2 2)) + rect(l13 (-201 -201) (400 400)) + ) + net(15 name(VSS) + rect(l8 (1110 1610) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (23220 370) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-21741 -391) (2 2)) + rect(l11 (-1901 -401) (300 1400)) + rect(l11 (-750 -1450) (1200 800)) + rect(l11 (-551 -401) (2 2)) + rect(l11 (-1251 -401) (600 800)) + rect(l11 (23850 -750) (300 1400)) + rect(l11 (-750 -1450) (1200 800)) + rect(l11 (-551 -401) (2 2)) + rect(l11 (549 -401) (600 800)) + rect(l6 (-23700 460) (425 950)) + rect(l6 (1975 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l10 (-21975 -2210) (500 1500)) + rect(l10 (22900 -1500) (500 1500)) + ) + + # Outgoing pins and their connections to nets + pin(11 name(FB)) + pin(12 name(VDD)) + pin(13 name(OUT)) + pin(14 name(ENABLE)) + pin(15 name(VSS)) + + # Subcircuits and their connections + circuit(1 ND2X1 location(1800 0) + pin(0 12) + pin(1 1) + pin(2 15) + pin(3 12) + pin(4 11) + pin(5 14) + pin(6 15) + ) + circuit(2 INVX1 location(4200 0) + pin(0 12) + pin(1 2) + pin(2 15) + pin(3 12) + pin(4 1) + pin(5 15) + ) + circuit(3 INVX1 location(6000 0) + pin(0 12) + pin(1 3) + pin(2 15) + pin(3 12) + pin(4 2) + pin(5 15) + ) + circuit(4 INVX1 location(7800 0) + pin(0 12) + pin(1 4) + pin(2 15) + pin(3 12) + pin(4 3) + pin(5 15) + ) + circuit(5 INVX1 location(9600 0) + pin(0 12) + pin(1 5) + pin(2 15) + pin(3 12) + pin(4 4) + pin(5 15) + ) + circuit(6 INVX1 location(11400 0) + pin(0 12) + pin(1 6) + pin(2 15) + pin(3 12) + pin(4 5) + pin(5 15) + ) + circuit(7 INVX1 location(13200 0) + pin(0 12) + pin(1 7) + pin(2 15) + pin(3 12) + pin(4 6) + pin(5 15) + ) + circuit(8 INVX1 location(15000 0) + pin(0 12) + pin(1 8) + pin(2 15) + pin(3 12) + pin(4 7) + pin(5 15) + ) + circuit(9 INVX1 location(16800 0) + pin(0 12) + pin(1 9) + pin(2 15) + pin(3 12) + pin(4 8) + pin(5 15) + ) + circuit(10 INVX1 location(18600 0) + pin(0 12) + pin(1 10) + pin(2 15) + pin(3 12) + pin(4 9) + pin(5 15) + ) + circuit(11 INVX1 location(20400 0) + pin(0 12) + pin(1 11) + pin(2 15) + pin(3 12) + pin(4 10) + pin(5 15) + ) + circuit(12 INVX1 location(22200 0) + pin(0 12) + pin(1 13) + pin(2 15) + pin(3 12) + pin(4 11) + pin(5 15) + ) + + ) +) + +# Reference netlist +reference( + + # Device class section + class(PMOS MOS4) + class(NMOS MOS4) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(ND2X1 + + # Nets + net(1 name(VDD)) + net(2 name(OUT)) + net(3 name(VSS)) + net(4 name(NWELL)) + net(5 name(B)) + net(6 name(A)) + net(7 name(BULK)) + net(8 name('1')) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4 name(NWELL)) + pin(5 name(B)) + pin(6 name(A)) + pin(7 name(BULK)) + + # Devices and their connections + device(1 PMOS + name($1) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 2) + terminal(G 6) + terminal(D 1) + terminal(B 4) + ) + device(2 PMOS + name($2) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(3 NMOS + name($3) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 3) + terminal(G 6) + terminal(D 8) + terminal(B 7) + ) + device(4 NMOS + name($4) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 8) + terminal(G 5) + terminal(D 2) + terminal(B 7) + ) + + ) + circuit(INVX1 + + # Nets + net(1 name(VDD)) + net(2 name(OUT)) + net(3 name(VSS)) + net(4 name(NWELL)) + net(5 name(IN)) + net(6 name(BULK)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4 name(NWELL)) + pin(5 name(IN)) + pin(6 name(BULK)) + + # Devices and their connections + device(1 PMOS + name($1) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(2 NMOS + name($2) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 3) + terminal(G 5) + terminal(D 2) + terminal(B 6) + ) + + ) + circuit(RINGO + + # Nets + net(1 name(VSS)) + net(2 name(VDD)) + net(3 name(FB)) + net(4 name(ENABLE)) + net(5 name(OUT)) + net(6 name('1')) + net(7 name('2')) + net(8 name('3')) + net(9 name('4')) + net(10 name('5')) + net(11 name('6')) + net(12 name('7')) + net(13 name('8')) + net(14 name('9')) + net(15 name('10')) + + # Outgoing pins and their connections to nets + pin(1 name(VSS)) + pin(2 name(VDD)) + pin(3 name(FB)) + pin(4 name(ENABLE)) + pin(5 name(OUT)) + + # Subcircuits and their connections + circuit(1 ND2X1 name($1) + pin(0 2) + pin(1 6) + pin(2 1) + pin(3 2) + pin(4 3) + pin(5 4) + pin(6 1) + ) + circuit(2 INVX1 name($2) + pin(0 2) + pin(1 7) + pin(2 1) + pin(3 2) + pin(4 6) + pin(5 1) + ) + circuit(3 INVX1 name($3) + pin(0 2) + pin(1 8) + pin(2 1) + pin(3 2) + pin(4 7) + pin(5 1) + ) + circuit(4 INVX1 name($4) + pin(0 2) + pin(1 9) + pin(2 1) + pin(3 2) + pin(4 8) + pin(5 1) + ) + circuit(5 INVX1 name($5) + pin(0 2) + pin(1 10) + pin(2 1) + pin(3 2) + pin(4 9) + pin(5 1) + ) + circuit(6 INVX1 name($6) + pin(0 2) + pin(1 11) + pin(2 1) + pin(3 2) + pin(4 10) + pin(5 1) + ) + circuit(7 INVX1 name($7) + pin(0 2) + pin(1 12) + pin(2 1) + pin(3 2) + pin(4 11) + pin(5 1) + ) + circuit(8 INVX1 name($8) + pin(0 2) + pin(1 13) + pin(2 1) + pin(3 2) + pin(4 12) + pin(5 1) + ) + circuit(9 INVX1 name($9) + pin(0 2) + pin(1 14) + pin(2 1) + pin(3 2) + pin(4 13) + pin(5 1) + ) + circuit(10 INVX1 name($10) + pin(0 2) + pin(1 15) + pin(2 1) + pin(3 2) + pin(4 14) + pin(5 1) + ) + circuit(11 INVX1 name($11) + pin(0 2) + pin(1 3) + pin(2 1) + pin(3 2) + pin(4 15) + pin(5 1) + ) + circuit(12 INVX1 name($12) + pin(0 2) + pin(1 5) + pin(2 1) + pin(3 2) + pin(4 3) + pin(5 1) + ) + + ) +) + +# Cross reference +xref( + circuit(INVX1 INVX1 match + xref( + net(4 4 match) + net(5 5 match) + net(2 2 match) + net(6 6 match) + net(1 1 match) + net(3 3 match) + pin(3 3 match) + pin(4 4 match) + pin(1 1 match) + pin(5 5 match) + pin(0 0 match) + pin(2 2 match) + device(2 2 match) + device(1 1 match) + ) + ) + circuit(ND2X1 ND2X1 match + xref( + net(8 8 match) + net(4 4 match) + net(6 6 match) + net(5 5 match) + net(2 2 match) + net(7 7 match) + net(1 1 match) + net(3 3 match) + pin(3 3 match) + pin(5 5 match) + pin(4 4 match) + pin(1 1 match) + pin(6 6 match) + pin(0 0 match) + pin(2 2 match) + device(3 3 match) + device(4 4 match) + device(1 1 match) + device(2 2 match) + ) + ) + circuit(RINGO RINGO match + xref( + net(1 6 match) + net(10 15 match) + net(2 7 match) + net(3 8 match) + net(4 9 match) + net(5 10 match) + net(6 11 match) + net(7 12 match) + net(8 13 match) + net(9 14 match) + net(14 4 match) + net(11 3 match) + net(13 5 match) + net(12 2 match) + net(15 1 match) + pin(3 3 match) + pin(0 2 match) + pin(2 4 match) + pin(1 1 match) + pin(4 0 match) + circuit(2 2 match) + circuit(3 3 match) + circuit(4 4 match) + circuit(5 5 match) + circuit(6 6 match) + circuit(7 7 match) + circuit(8 8 match) + circuit(9 9 match) + circuit(10 10 match) + circuit(11 11 match) + circuit(12 12 match) + circuit(1 1 match) + ) + ) +) diff --git a/testdata/lvs/ringo_xdevice.cir b/testdata/lvs/ringo_xdevice.cir new file mode 100644 index 000000000..b3129f54e --- /dev/null +++ b/testdata/lvs/ringo_xdevice.cir @@ -0,0 +1,35 @@ + +.SUBCKT XPMOS S G D B PARAMS: L=1U W=1U + M$1 S G D B PMOS L=L W=W +.ENDS PMOS + +.SUBCKT NMOS S G D B PARAMS: L=1U W=1U + M$1 S G D B NMOS L=L W=W +.ENDS NMOS + +.SUBCKT RINGO VSS VDD FB ENABLE OUT +X$1 VDD 1 VSS VDD FB ENABLE VSS ND2X1 +X$2 VDD 2 VSS VDD 1 VSS INVX1 +X$3 VDD 3 VSS VDD 2 VSS INVX1 +X$4 VDD 4 VSS VDD 3 VSS INVX1 +X$5 VDD 5 VSS VDD 4 VSS INVX1 +X$6 VDD 6 VSS VDD 5 VSS INVX1 +X$7 VDD 7 VSS VDD 6 VSS INVX1 +X$8 VDD 8 VSS VDD 7 VSS INVX1 +X$9 VDD 9 VSS VDD 8 VSS INVX1 +X$10 VDD 10 VSS VDD 9 VSS INVX1 +X$11 VDD FB VSS VDD 10 VSS INVX1 +X$12 VDD OUT VSS VDD FB VSS INVX1 +.ENDS RINGO + +.SUBCKT ND2X1 VDD OUT VSS NWELL B A BULK +X$1 OUT A VDD NWELL XPMOS L=0.25U W=1.5U +X$2 VDD B OUT NWELL XPMOS L=0.25U W=1.5U +X$3 VSS A 1 BULK NMOS L=0.25U W=0.95U +X$4 1 B OUT BULK NMOS L=0.25U W=0.95U +.ENDS ND2X1 + +.SUBCKT INVX1 VDD OUT VSS NWELL IN BULK +X$1 VDD IN OUT NWELL XPMOS L=0.25U W=1.5U +X$2 VSS IN OUT BULK NMOS L=0.25U W=0.95U +.ENDS INVX1 From 3a93bc2162c64d1fb3616e1e0cafe34134663291 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 24 Aug 2019 00:13:38 +0200 Subject: [PATCH 10/27] Added test for mixed-hierarchy LVS case. --- src/lay/lay/doc/manual/lvs_io.xml | 14 +- src/lvs/unit_tests/lvsSimpleTests.cc | 5 + testdata/lvs/ringo_device_subcircuits.lvs | 4 +- testdata/lvs/ringo_mixed_hierarchy.cir | 64 ++ testdata/lvs/ringo_mixed_hierarchy.gds | Bin 0 -> 13222 bytes testdata/lvs/ringo_mixed_hierarchy.lvs | 76 ++ testdata/lvs/ringo_mixed_hierarchy.lvsdb | 872 ++++++++++++++++++++++ 7 files changed, 1029 insertions(+), 6 deletions(-) create mode 100644 testdata/lvs/ringo_mixed_hierarchy.cir create mode 100644 testdata/lvs/ringo_mixed_hierarchy.gds create mode 100644 testdata/lvs/ringo_mixed_hierarchy.lvs create mode 100644 testdata/lvs/ringo_mixed_hierarchy.lvsdb diff --git a/src/lay/lay/doc/manual/lvs_io.xml b/src/lay/lay/doc/manual/lvs_io.xml index 37ab399e0..3e66a3624 100644 --- a/src/lay/lay/doc/manual/lvs_io.xml +++ b/src/lay/lay/doc/manual/lvs_io.xml @@ -189,12 +189,14 @@ X$2 VSS IN OUT SUBSTRATE NMOS PARAMS: L=0.25 W=0.9 AS=0.405 AD=0.405 PS=2.7 class SubcircuitModelsReader < RBA::NetlistSpiceReaderDelegate + # implements the delegate interface: # says we want to catch these subcircuits as devices def wants_subcircuit(name) name == "NMOS" || name == "PMOS" end - # translate the element + # implements the delegate interface: + # take and translate the element def element(circuit, el, name, model, value, nets, params) if el != "X" @@ -221,9 +223,13 @@ class SubcircuitModelsReader < RBA::NetlistSpiceReaderDelegate [ "S", "G", "D", "B" ].each_with_index do |t,index| device.connect_terminal(t, nets[index]) end - params.each do |p,value| - device.set_parameter(p, value) - end + + # parameters in the model are given in micrometer units, so + # we need to translate the parameter values from SI to um values: + device.set_parameter("W", (params["W"] || 0.0) * 1e6) + device.set_parameter("L", (params["L"] || 0.0) * 1e6) + + return true end diff --git a/src/lvs/unit_tests/lvsSimpleTests.cc b/src/lvs/unit_tests/lvsSimpleTests.cc index 20d8dbc9a..64b405f05 100644 --- a/src/lvs/unit_tests/lvsSimpleTests.cc +++ b/src/lvs/unit_tests/lvsSimpleTests.cc @@ -138,3 +138,8 @@ TEST(13_simple_ringo_device_subcircuits) { run_test (_this, "ringo_device_subcircuits", "ringo.gds"); } + +TEST(14_simple_ringo_mixed_hierarchy) +{ + run_test (_this, "ringo_mixed_hierarchy", "ringo_mixed_hierarchy.gds"); +} diff --git a/testdata/lvs/ringo_device_subcircuits.lvs b/testdata/lvs/ringo_device_subcircuits.lvs index cf54ddc71..83b63cec8 100644 --- a/testdata/lvs/ringo_device_subcircuits.lvs +++ b/testdata/lvs/ringo_device_subcircuits.lvs @@ -44,8 +44,8 @@ class SubcircuitModelsReader < RBA::NetlistSpiceReaderDelegate # parameters in the model are given in micrometer units, so # we need to translate the parameter values from SI to um values: - device.set_parameter("W", (params["W"] || 1.0e-6) * 1e6) - device.set_parameter("L", (params["L"] || 1.0e-6) * 1e6) + device.set_parameter("W", (params["W"] || 0.0) * 1e6) + device.set_parameter("L", (params["L"] || 0.0) * 1e6) return true diff --git a/testdata/lvs/ringo_mixed_hierarchy.cir b/testdata/lvs/ringo_mixed_hierarchy.cir new file mode 100644 index 000000000..8e98d778a --- /dev/null +++ b/testdata/lvs/ringo_mixed_hierarchy.cir @@ -0,0 +1,64 @@ +* Extracted by KLayout + +* cell RINGO +* pin B,FB +* pin A,ENABLE +* pin VDD +* pin OUT +* pin VSS +.SUBCKT RINGO 1 2 3 14 16 +* net 1 B,FB +* net 2 A,ENABLE +* net 3 VDD +* net 14 OUT +* net 16 VSS +* cell instance $1 r0 *1 22.2,0 +X$1 3 14 16 3 1 16 INVX1 +* cell instance $2 r0 *1 20.4,0 +X$2 3 1 16 3 13 16 INVX1 +* cell instance $8 r0 *1 4.2,0 +X$8 3 5 16 3 4 16 INVX1 +* cell instance $9 r0 *1 6,0 +X$9 3 6 16 3 5 16 INVX1 +* cell instance $10 r0 *1 7.8,0 +X$10 3 7 16 3 6 16 INVX1 +* cell instance $11 r0 *1 9.6,0 +X$11 3 8 16 3 7 16 INVX1 +* cell instance $12 r0 *1 11.4,0 +X$12 3 9 16 3 8 16 INVX1 +* cell instance $13 r0 *1 13.2,0 +X$13 3 10 16 3 9 16 INVX1 +* cell instance $14 r0 *1 15,0 +X$14 3 11 16 3 10 16 INVX1 +* cell instance $15 r0 *1 16.8,0 +X$15 3 12 16 3 11 16 INVX1 +* cell instance $16 r0 *1 18.6,0 +X$16 3 13 16 3 12 16 INVX1 +* device instance $1 r0 *1 2.65,5.8 PMOS +M$1 4 2 3 3 PMOS L=0.25U W=1.5U AS=0.6375P AD=0.3375P PS=3.85U PD=1.95U +* device instance $2 r0 *1 3.35,5.8 PMOS +M$2 3 1 4 3 PMOS L=0.25U W=1.5U AS=0.3375P AD=0.6375P PS=1.95U PD=3.85U +* device instance $3 r0 *1 2.65,2.135 NMOS +M$3 16 2 15 16 NMOS L=0.25U W=0.95U AS=0.40375P AD=0.21375P PS=2.75U PD=1.4U +* device instance $4 r0 *1 3.35,2.135 NMOS +M$4 15 1 4 16 NMOS L=0.25U W=0.95U AS=0.21375P AD=0.40375P PS=1.4U PD=2.75U +.ENDS RINGO + +* cell INVX1 +* pin VDD +* pin OUT +* pin VSS +* pin +* pin IN +* pin SUBSTRATE +.SUBCKT INVX1 1 2 3 4 5 6 +* net 1 VDD +* net 2 OUT +* net 3 VSS +* net 5 IN +* net 6 SUBSTRATE +* device instance $1 r0 *1 0.85,2.135 NMOS +M$1 3 5 2 6 NMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U +* device instance $2 r0 *1 0.85,5.8 PMOS +M$2 1 5 2 4 PMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U +.ENDS INVX1 diff --git a/testdata/lvs/ringo_mixed_hierarchy.gds b/testdata/lvs/ringo_mixed_hierarchy.gds new file mode 100644 index 0000000000000000000000000000000000000000..e498a3028b17e8ab4fd943ac4a072f9af288f866 GIT binary patch literal 13222 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 psd, "G" => pgate, "W" => nwell, + "tS" => psd, "tD" => psd, "tG" => poly, "tW" => nwell }) + +# NMOS transistor device extraction +extract_devices(mos4("NMOS"), { "SD" => nsd, "G" => ngate, "W" => bulk, + "tS" => nsd, "tD" => nsd, "tG" => poly, "tW" => bulk }) + +# Define connectivity for netlist extraction + +# Inter-layer +connect(psd, contact) +connect(nsd, contact) +connect(poly, contact) +connect(ntie, contact) +connect(nwell, ntie) +connect(ptie, contact) +connect(contact, metal1) +connect(metal1, via1) +connect(via1, metal2) + +# Global +connect_global(bulk, "SUBSTRATE") +connect_global(ptie, "SUBSTRATE") + +# Compare section + +netlist.simplify + +align + +compare + diff --git a/testdata/lvs/ringo_mixed_hierarchy.lvsdb b/testdata/lvs/ringo_mixed_hierarchy.lvsdb new file mode 100644 index 000000000..796a8d02b --- /dev/null +++ b/testdata/lvs/ringo_mixed_hierarchy.lvsdb @@ -0,0 +1,872 @@ +#%lvsdb-klayout + +# Layout +layout( + top(RINGO) + unit(0.001) + + # Layer section + # This section lists the mask layers (drawing or derived) and their connections. + + # Mask layers + layer(l3 '1/0') + layer(l4 '5/0') + layer(l8 '8/0') + layer(l11 '9/0') + layer(l12 '10/0') + layer(l13 '11/0') + layer(l7) + layer(l2) + layer(l9) + layer(l6) + layer(l10) + + # Mask layer connectivity + connect(l3 l3 l9) + connect(l4 l4 l8) + connect(l8 l4 l8 l11 l2 l9 l6 l10) + connect(l11 l8 l11 l12) + connect(l12 l11 l12 l13) + connect(l13 l12 l13) + connect(l7 l7) + connect(l2 l8 l2) + connect(l9 l3 l8 l9) + connect(l6 l8 l6) + connect(l10 l8 l10) + + # Global nets and connectivity + global(l7 SUBSTRATE) + global(l10 SUBSTRATE) + + # Device class section + class(PMOS MOS4) + class(NMOS MOS4) + + # Device abstracts section + # Device abstracts list the pin shapes of the devices. + device(D$PMOS PMOS + terminal(S + rect(l2 (-550 -750) (425 1500)) + ) + terminal(G + rect(l4 (-125 -750) (250 1500)) + ) + terminal(D + rect(l2 (125 -750) (450 1500)) + ) + terminal(B + rect(l3 (-125 -750) (250 1500)) + ) + ) + device(D$PMOS$1 PMOS + terminal(S + rect(l2 (-575 -750) (450 1500)) + ) + terminal(G + rect(l4 (-125 -750) (250 1500)) + ) + terminal(D + rect(l2 (125 -750) (425 1500)) + ) + terminal(B + rect(l3 (-125 -750) (250 1500)) + ) + ) + device(D$PMOS$2 PMOS + terminal(S + rect(l2 (-550 -750) (425 1500)) + ) + terminal(G + rect(l4 (-125 -750) (250 1500)) + ) + terminal(D + rect(l2 (125 -750) (425 1500)) + ) + terminal(B + rect(l3 (-125 -750) (250 1500)) + ) + ) + device(D$NMOS NMOS + terminal(S + rect(l6 (-550 -475) (425 950)) + ) + terminal(G + rect(l4 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (450 950)) + ) + terminal(B + rect(l7 (-125 -475) (250 950)) + ) + ) + device(D$NMOS$1 NMOS + terminal(S + rect(l6 (-575 -475) (450 950)) + ) + terminal(G + rect(l4 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (425 950)) + ) + terminal(B + rect(l7 (-125 -475) (250 950)) + ) + ) + device(D$NMOS$2 NMOS + terminal(S + rect(l6 (-550 -475) (425 950)) + ) + terminal(G + rect(l4 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (425 950)) + ) + terminal(B + rect(l7 (-125 -475) (250 950)) + ) + ) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(INVX1 + + # Circuit boundary + rect((-100 400) (2000 7600)) + + # Nets with their geometries + net(1 name(VDD) + rect(l8 (410 6260) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l11 (-240 -240) (300 1400)) + rect(l11 (-650 300) (1800 800)) + rect(l11 (-1450 -1100) (300 300)) + rect(l11 (299 399) (2 2)) + rect(l2 (-651 -2151) (425 1500)) + ) + net(2 name(OUT) + rect(l8 (1110 5160) (180 180)) + rect(l8 (-180 920) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (-180 -4120) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-240 -790) (300 4790)) + rect(l11 (-151 -2501) (2 2)) + rect(l2 (-226 1049) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(3 name(VSS) + rect(l8 (410 1770) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-240 -1300) (300 1360)) + rect(l11 (-650 -2160) (1800 800)) + rect(l11 (-851 -401) (2 2)) + rect(l6 (-651 859) (425 950)) + ) + net(4 + rect(l3 (-100 4500) (2000 3500)) + ) + net(5 name(IN) + rect(l4 (725 2860) (250 1940)) + rect(l4 (-525 -1850) (300 300)) + rect(l4 (-25 -1840) (250 1450)) + rect(l4 (-250 1940) (250 2000)) + rect(l4 (-250 -2000) (250 2000)) + rect(l8 (-465 -3790) (180 180)) + rect(l11 (-91 -91) (2 2)) + rect(l11 (-151 -151) (300 300)) + ) + net(6 name(SUBSTRATE)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4) + pin(5 name(IN)) + pin(6 name(SUBSTRATE)) + + # Devices and their connections + device(1 D$NMOS$2 + location(850 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.40375) + param(AD 0.40375) + param(PS 2.75) + param(PD 2.75) + terminal(S 3) + terminal(G 5) + terminal(D 2) + terminal(B 6) + ) + device(2 D$PMOS$2 + location(850 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.6375) + param(AD 0.6375) + param(PS 3.85) + param(PD 3.85) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + + ) + circuit(RINGO + + # Circuit boundary + rect((0 350) (25800 7650)) + + # Nets with their geometries + net(1 name('B,FB') + rect(l4 (3225 2860) (250 1940)) + rect(l4 (-345 -950) (300 300)) + rect(l4 (-205 650) (250 2000)) + rect(l4 (-250 -2000) (250 2000)) + rect(l4 (-250 -5390) (250 1450)) + rect(l8 (-285 1050) (180 180)) + rect(l8 (19340 -1080) (180 180)) + rect(l11 (-19760 660) (300 300)) + rect(l11 (-131 -151) (2 2)) + rect(l11 (18449 -1051) (900 300)) + rect(l11 (-1390 590) (320 320)) + rect(l11 (-18460 -320) (320 320)) + rect(l12 (17880 -260) (200 200)) + rect(l12 (-18340 -200) (200 200)) + rect(l13 (100 -300) (17740 400)) + rect(l13 (-17921 -201) (2 2)) + rect(l13 (17919 -201) (400 400)) + rect(l13 (-18540 -400) (400 400)) + rect(l2 (17895 850) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(2 name('A,ENABLE') + rect(l4 (2525 2860) (250 1940)) + rect(l4 (-325 -1850) (300 300)) + rect(l4 (-225 -1840) (250 1450)) + rect(l4 (-250 1940) (250 2000)) + rect(l4 (-250 -2000) (250 2000)) + rect(l8 (-265 -3790) (180 180)) + rect(l11 (-240 -240) (300 300)) + rect(l11 (-151 -151) (2 2)) + rect(l11 (-161 -161) (320 320)) + rect(l12 (-260 -260) (200 200)) + rect(l13 (-101 -101) (2 2)) + rect(l13 (-201 -201) (400 400)) + ) + net(3 name(VDD) + rect(l3 (1700 4500) (2600 3500)) + rect(l3 (-3800 -3500) (1400 3500)) + rect(l3 (-1900 -3500) (600 3500)) + rect(l3 (23300 -3500) (1400 3500)) + rect(l3 (-100 -3500) (600 3500)) + rect(l8 (-22890 -2840) (180 180)) + rect(l8 (-180 920) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (-1980 870) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (23220 370) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l11 (-21840 -1290) (300 1700)) + rect(l11 (-1350 0) (2400 800)) + rect(l11 (-1151 -401) (2 2)) + rect(l11 (-102 48) (2 2)) + rect(l11 (-2351 -451) (1200 800)) + rect(l11 (-750 -1450) (300 1400)) + rect(l11 (-101 -351) (2 2)) + rect(l11 (-1251 -401) (600 800)) + rect(l11 (23400 -800) (1200 800)) + rect(l11 (-750 -1450) (300 1400)) + rect(l11 (-101 -351) (2 2)) + rect(l11 (549 -401) (600 800)) + rect(l2 (-23025 -2550) (450 1500)) + rect(l2 (1275 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (3175 -1500) (425 1500)) + rect(l2 (-2225 -1500) (425 1500)) + rect(l9 (-20175 -450) (500 1500)) + rect(l9 (22900 -1500) (500 1500)) + ) + net(4 + rect(l8 (3610 1770) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (-1580 3760) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (1220 920) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (920 -2880) (180 180)) + polygon(l11 (-1340 -1480) (0 1390) (490 0) (0 -300) (-190 0) (0 -1090)) + rect(l11 (-110 1390) (300 1400)) + rect(l11 (0 -1550) (610 300)) + polygon(l11 (-2500 1250) (0 600) (300 0) (0 -300) (1590 0) (0 -300)) + rect(l11 (-1890 600) (300 1400)) + rect(l11 (1100 -1700) (300 300)) + rect(l11 (-300 0) (300 1400)) + rect(l2 (-1750 -1450) (425 1500)) + rect(l2 (950 -1500) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(5 + rect(l8 (6510 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(6 + rect(l8 (8310 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(7 + rect(l8 (10110 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(8 + rect(l8 (11910 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(9 + rect(l8 (13710 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(10 + rect(l8 (15510 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(11 + rect(l8 (17310 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(12 + rect(l8 (19110 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(13 + rect(l8 (20910 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(14 name(OUT) + rect(l11 (23440 3840) (320 320)) + rect(l12 (-260 -260) (200 200)) + rect(l13 (-101 -101) (2 2)) + rect(l13 (-201 -201) (400 400)) + rect(l2 (-625 850) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(15 + rect(l6 (2775 1660) (450 950)) + ) + net(16 name(VSS) + rect(l8 (2210 1770) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (-1280 -890) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (23220 370) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-22540 -40) (300 1360)) + rect(l11 (-650 -2160) (2400 800)) + rect(l11 (-1151 -401) (2 2)) + rect(l11 (-102 48) (2 2)) + rect(l11 (-1901 -401) (300 1400)) + rect(l11 (-750 -1450) (1200 800)) + rect(l11 (-551 -401) (2 2)) + rect(l11 (-1251 -401) (600 800)) + rect(l11 (23850 -750) (300 1400)) + rect(l11 (-750 -1450) (1200 800)) + rect(l11 (-551 -401) (2 2)) + rect(l11 (549 -401) (600 800)) + rect(l6 (-23700 460) (425 950)) + rect(l6 (1975 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (3175 -950) (425 950)) + rect(l6 (-2225 -950) (425 950)) + rect(l10 (-20175 -2210) (500 1500)) + rect(l10 (22900 -1500) (500 1500)) + ) + + # Outgoing pins and their connections to nets + pin(1 name('B,FB')) + pin(2 name('A,ENABLE')) + pin(3 name(VDD)) + pin(14 name(OUT)) + pin(16 name(VSS)) + + # Devices and their connections + device(1 D$PMOS + location(2650 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.6375) + param(AD 0.3375) + param(PS 3.85) + param(PD 1.95) + terminal(S 4) + terminal(G 2) + terminal(D 3) + terminal(B 3) + ) + device(2 D$PMOS$1 + location(3350 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.3375) + param(AD 0.6375) + param(PS 1.95) + param(PD 3.85) + terminal(S 3) + terminal(G 1) + terminal(D 4) + terminal(B 3) + ) + device(3 D$NMOS + location(2650 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.40375) + param(AD 0.21375) + param(PS 2.75) + param(PD 1.4) + terminal(S 16) + terminal(G 2) + terminal(D 15) + terminal(B 16) + ) + device(4 D$NMOS$1 + location(3350 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.21375) + param(AD 0.40375) + param(PS 1.4) + param(PD 2.75) + terminal(S 15) + terminal(G 1) + terminal(D 4) + terminal(B 16) + ) + + # Subcircuits and their connections + circuit(1 INVX1 location(22200 0) + pin(0 3) + pin(1 14) + pin(2 16) + pin(3 3) + pin(4 1) + pin(5 16) + ) + circuit(2 INVX1 location(20400 0) + pin(0 3) + pin(1 1) + pin(2 16) + pin(3 3) + pin(4 13) + pin(5 16) + ) + circuit(8 INVX1 location(4200 0) + pin(0 3) + pin(1 5) + pin(2 16) + pin(3 3) + pin(4 4) + pin(5 16) + ) + circuit(9 INVX1 location(6000 0) + pin(0 3) + pin(1 6) + pin(2 16) + pin(3 3) + pin(4 5) + pin(5 16) + ) + circuit(10 INVX1 location(7800 0) + pin(0 3) + pin(1 7) + pin(2 16) + pin(3 3) + pin(4 6) + pin(5 16) + ) + circuit(11 INVX1 location(9600 0) + pin(0 3) + pin(1 8) + pin(2 16) + pin(3 3) + pin(4 7) + pin(5 16) + ) + circuit(12 INVX1 location(11400 0) + pin(0 3) + pin(1 9) + pin(2 16) + pin(3 3) + pin(4 8) + pin(5 16) + ) + circuit(13 INVX1 location(13200 0) + pin(0 3) + pin(1 10) + pin(2 16) + pin(3 3) + pin(4 9) + pin(5 16) + ) + circuit(14 INVX1 location(15000 0) + pin(0 3) + pin(1 11) + pin(2 16) + pin(3 3) + pin(4 10) + pin(5 16) + ) + circuit(15 INVX1 location(16800 0) + pin(0 3) + pin(1 12) + pin(2 16) + pin(3 3) + pin(4 11) + pin(5 16) + ) + circuit(16 INVX1 location(18600 0) + pin(0 3) + pin(1 13) + pin(2 16) + pin(3 3) + pin(4 12) + pin(5 16) + ) + + ) +) + +# Reference netlist +reference( + + # Device class section + class(PMOS MOS4) + class(NMOS MOS4) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(INVX1 + + # Nets + net(1 name(VDD)) + net(2 name(OUT)) + net(3 name(VSS)) + net(4 name(NWELL)) + net(5 name(IN)) + net(6 name(BULK)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4 name(NWELL)) + pin(5 name(IN)) + pin(6 name(BULK)) + + # Devices and their connections + device(1 PMOS + name($1) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(2 NMOS + name($2) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 3) + terminal(G 5) + terminal(D 2) + terminal(B 6) + ) + + ) + circuit(RINGO + + # Nets + net(1 name(VSS)) + net(2 name(VDD)) + net(3 name(FB)) + net(4 name(ENABLE)) + net(5 name(OUT)) + net(6 name('1')) + net(7 name('2')) + net(8 name('3')) + net(9 name('4')) + net(10 name('5')) + net(11 name('6')) + net(12 name('7')) + net(13 name('8')) + net(14 name('9')) + net(15 name('10')) + net(16 name($1.1)) + + # Outgoing pins and their connections to nets + pin(1 name(VSS)) + pin(2 name(VDD)) + pin(3 name(FB)) + pin(4 name(ENABLE)) + pin(5 name(OUT)) + + # Devices and their connections + device(1 PMOS + name($1.$1) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 6) + terminal(G 4) + terminal(D 2) + terminal(B 2) + ) + device(2 PMOS + name($1.$2) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 2) + terminal(G 3) + terminal(D 6) + terminal(B 2) + ) + device(3 NMOS + name($1.$3) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G 4) + terminal(D 16) + terminal(B 1) + ) + device(4 NMOS + name($1.$4) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 16) + terminal(G 3) + terminal(D 6) + terminal(B 1) + ) + + # Subcircuits and their connections + circuit(2 INVX1 name($2) + pin(0 2) + pin(1 7) + pin(2 1) + pin(3 2) + pin(4 6) + pin(5 1) + ) + circuit(3 INVX1 name($3) + pin(0 2) + pin(1 8) + pin(2 1) + pin(3 2) + pin(4 7) + pin(5 1) + ) + circuit(4 INVX1 name($4) + pin(0 2) + pin(1 9) + pin(2 1) + pin(3 2) + pin(4 8) + pin(5 1) + ) + circuit(5 INVX1 name($5) + pin(0 2) + pin(1 10) + pin(2 1) + pin(3 2) + pin(4 9) + pin(5 1) + ) + circuit(6 INVX1 name($6) + pin(0 2) + pin(1 11) + pin(2 1) + pin(3 2) + pin(4 10) + pin(5 1) + ) + circuit(7 INVX1 name($7) + pin(0 2) + pin(1 12) + pin(2 1) + pin(3 2) + pin(4 11) + pin(5 1) + ) + circuit(8 INVX1 name($8) + pin(0 2) + pin(1 13) + pin(2 1) + pin(3 2) + pin(4 12) + pin(5 1) + ) + circuit(9 INVX1 name($9) + pin(0 2) + pin(1 14) + pin(2 1) + pin(3 2) + pin(4 13) + pin(5 1) + ) + circuit(10 INVX1 name($10) + pin(0 2) + pin(1 15) + pin(2 1) + pin(3 2) + pin(4 14) + pin(5 1) + ) + circuit(11 INVX1 name($11) + pin(0 2) + pin(1 3) + pin(2 1) + pin(3 2) + pin(4 15) + pin(5 1) + ) + circuit(12 INVX1 name($12) + pin(0 2) + pin(1 5) + pin(2 1) + pin(3 2) + pin(4 3) + pin(5 1) + ) + + ) +) + +# Cross reference +xref( + circuit(INVX1 INVX1 match + xref( + net(4 4 match) + net(5 5 match) + net(2 2 match) + net(6 6 match) + net(1 1 match) + net(3 3 match) + pin(3 3 match) + pin(4 4 match) + pin(1 1 match) + pin(5 5 match) + pin(0 0 match) + pin(2 2 match) + device(1 2 match) + device(2 1 match) + ) + ) + circuit(RINGO RINGO match + xref( + net(15 16 match) + net(4 6 match) + net(13 15 match) + net(5 7 match) + net(6 8 match) + net(7 9 match) + net(8 10 match) + net(9 11 match) + net(10 12 match) + net(11 13 match) + net(12 14 match) + net(2 4 match) + net(1 3 match) + net(14 5 match) + net(3 2 match) + net(16 1 match) + pin(1 3 match) + pin(0 2 match) + pin(3 4 match) + pin(2 1 match) + pin(4 0 match) + device(3 3 match) + device(4 4 match) + device(1 1 match) + device(2 2 match) + circuit(8 2 match) + circuit(9 3 match) + circuit(10 4 match) + circuit(11 5 match) + circuit(12 6 match) + circuit(13 7 match) + circuit(14 8 match) + circuit(15 9 match) + circuit(16 10 match) + circuit(2 11 match) + circuit(1 12 match) + ) + ) +) From 1b6e42d70a9b0dfc686e2717641b2431192abf56 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 24 Aug 2019 08:53:19 +0200 Subject: [PATCH 11/27] Fixed a segfault in the LVS result browser. --- src/laybasic/laybasic/layNetlistBrowserModel.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/laybasic/laybasic/layNetlistBrowserModel.cc b/src/laybasic/laybasic/layNetlistBrowserModel.cc index 6c7741aef..b1bd0e5e3 100644 --- a/src/laybasic/laybasic/layNetlistBrowserModel.cc +++ b/src/laybasic/laybasic/layNetlistBrowserModel.cc @@ -824,6 +824,9 @@ static std::string device_parameter_string (const db::Device *device) { std::string s; + if (! device || ! device->device_class ()) { + return s; + } bool first = true; const std::vector &pd = device->device_class ()->parameter_definitions (); From a9a2cb69c874646235eb3a7edfdea531534b43ba Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 24 Aug 2019 09:58:08 +0200 Subject: [PATCH 12/27] Avoiding one assertion by not considering floating device terminals --- src/db/db/dbNetlistCompare.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index f76bb6235..499bc4041 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -732,7 +732,14 @@ public: // .. nothing yet .. } + /** + * @brief Builds a node for a net + */ NetGraphNode (const db::Net *net, DeviceCategorizer &device_categorizer, CircuitCategorizer &circuit_categorizer, const DeviceFilter &device_filter, const std::map *circuit_map, const CircuitPinMapper *pin_map); + + /** + * @brief Builds a virtual node for a subcircuit + */ NetGraphNode (const db::SubCircuit *sc, CircuitCategorizer &circuit_categorizer, const std::map *circuit_map, const CircuitPinMapper *pin_map); void expand_subcircuit_nodes (NetGraph *graph); @@ -1102,6 +1109,9 @@ NetGraphNode::NetGraphNode (const db::Net *net, DeviceCategorizer &device_catego Transition ed2 (d, device_cat, terminal1_id, terminal2_id); const db::Net *net2 = d->net_for_terminal (it->id ()); + if (! net2) { + continue; + } std::map::const_iterator in = n2entry.find ((const void *) net2); if (in == n2entry.end ()) { @@ -1138,6 +1148,9 @@ NetGraphNode::NetGraphNode (const db::SubCircuit *sc, CircuitCategorizer &circui size_t pin_id = p->id (); const db::Net *net_at_pin = sc->net_for_pin (pin_id); + if (! net_at_pin) { + continue; + } // A pin assignment may be missing because there is no net for a pin -> skip this From c543fe7a44c1f138c038a422307fe1565919d384 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 24 Aug 2019 19:42:00 +0200 Subject: [PATCH 13/27] Added test for floating device terminals. --- src/lvs/unit_tests/lvsSimpleTests.cc | 5 + testdata/lvs/ringo_dummy_device.cir | 28 + testdata/lvs/ringo_dummy_device.gds | Bin 0 -> 10838 bytes testdata/lvs/ringo_simple_dummy_device.cir | 85 ++ testdata/lvs/ringo_simple_dummy_device.lvs | 74 ++ testdata/lvs/ringo_simple_dummy_device.lvsdb | 1019 ++++++++++++++++++ 6 files changed, 1211 insertions(+) create mode 100644 testdata/lvs/ringo_dummy_device.cir create mode 100644 testdata/lvs/ringo_dummy_device.gds create mode 100644 testdata/lvs/ringo_simple_dummy_device.cir create mode 100644 testdata/lvs/ringo_simple_dummy_device.lvs create mode 100644 testdata/lvs/ringo_simple_dummy_device.lvsdb diff --git a/src/lvs/unit_tests/lvsSimpleTests.cc b/src/lvs/unit_tests/lvsSimpleTests.cc index 64b405f05..1d3111fe7 100644 --- a/src/lvs/unit_tests/lvsSimpleTests.cc +++ b/src/lvs/unit_tests/lvsSimpleTests.cc @@ -143,3 +143,8 @@ TEST(14_simple_ringo_mixed_hierarchy) { run_test (_this, "ringo_mixed_hierarchy", "ringo_mixed_hierarchy.gds"); } + +TEST(15_simple_dummy_device) +{ + run_test (_this, "ringo_simple_dummy_device", "ringo_dummy_device.gds"); +} diff --git a/testdata/lvs/ringo_dummy_device.cir b/testdata/lvs/ringo_dummy_device.cir new file mode 100644 index 000000000..276b8d847 --- /dev/null +++ b/testdata/lvs/ringo_dummy_device.cir @@ -0,0 +1,28 @@ + +.SUBCKT RINGO VSS VDD FB ENABLE OUT +X$1 VDD 1 VSS VDD FB ENABLE VSS ND2X1 +X$2 VDD 2 VSS VDD 1 VSS INVX1 +X$3 VDD 3 VSS VDD 2 VSS INVX1 +X$4 VDD 4 VSS VDD 3 VSS INVX1 +X$5 VDD 5 VSS VDD 4 VSS INVX1 +X$6 VDD 6 VSS VDD 5 VSS INVX1 +X$7 VDD 7 VSS VDD 6 VSS INVX1 +X$8 VDD 8 VSS VDD 7 VSS INVX1 +X$9 VDD 9 VSS VDD 8 VSS INVX1 +X$10 VDD 10 VSS VDD 9 VSS INVX1 +X$11 VDD FB VSS VDD 10 VSS INVX1 +X$12 VDD OUT VSS VDD FB VSS INVX1 +M$1 VSS DUMMY VSS VSS NMOS L=0.25U W=0.95U +.ENDS RINGO + +.SUBCKT ND2X1 VDD OUT VSS NWELL B A BULK +M$1 OUT A VDD NWELL PMOS L=0.25U W=1.5U +M$2 VDD B OUT NWELL PMOS L=0.25U W=1.5U +M$3 VSS A 1 BULK NMOS L=0.25U W=0.95U +M$4 1 B OUT BULK NMOS L=0.25U W=0.95U +.ENDS ND2X1 + +.SUBCKT INVX1 VDD OUT VSS NWELL IN BULK +M$1 VDD IN OUT NWELL PMOS L=0.25U W=1.5U +M$2 VSS IN OUT BULK NMOS L=0.25U W=0.95U +.ENDS INVX1 diff --git a/testdata/lvs/ringo_dummy_device.gds b/testdata/lvs/ringo_dummy_device.gds new file mode 100644 index 0000000000000000000000000000000000000000..5ff716ea41c17b48f607e15126dd86206a0ddc43 GIT binary patch literal 10838 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 psd, "G" => pgate, "W" => nwell, + "tS" => psd, "tD" => psd, "tG" => poly, "tW" => nwell }) + +# NMOS transistor device extraction +extract_devices(mos4("NMOS"), { "SD" => nsd, "G" => ngate, "W" => bulk, + "tS" => nsd, "tD" => nsd, "tG" => poly, "tW" => bulk }) + +# Define connectivity for netlist extraction + +# Inter-layer +connect(psd, contact) +connect(nsd, contact) +connect(poly, contact) +connect(ntie, contact) +connect(nwell, ntie) +connect(ptie, contact) +connect(contact, metal1) +connect(metal1, via1) +connect(via1, metal2) + +# Global +connect_global(bulk, "SUBSTRATE") +connect_global(ptie, "SUBSTRATE") + +# Compare section + +netlist.simplify + +compare + diff --git a/testdata/lvs/ringo_simple_dummy_device.lvsdb b/testdata/lvs/ringo_simple_dummy_device.lvsdb new file mode 100644 index 000000000..08f01f7fb --- /dev/null +++ b/testdata/lvs/ringo_simple_dummy_device.lvsdb @@ -0,0 +1,1019 @@ +#%lvsdb-klayout + +# Layout +layout( + top(RINGO) + unit(0.001) + + # Layer section + # This section lists the mask layers (drawing or derived) and their connections. + + # Mask layers + layer(l3 '1/0') + layer(l4 '5/0') + layer(l8 '8/0') + layer(l11 '9/0') + layer(l12 '10/0') + layer(l13 '11/0') + layer(l7) + layer(l2) + layer(l9) + layer(l6) + layer(l10) + + # Mask layer connectivity + connect(l3 l3 l9) + connect(l4 l4 l8) + connect(l8 l4 l8 l11 l2 l9 l6 l10) + connect(l11 l8 l11 l12) + connect(l12 l11 l12 l13) + connect(l13 l12 l13) + connect(l7 l7) + connect(l2 l8 l2) + connect(l9 l3 l8 l9) + connect(l6 l8 l6) + connect(l10 l8 l10) + + # Global nets and connectivity + global(l7 SUBSTRATE) + global(l10 SUBSTRATE) + + # Device class section + class(PMOS MOS4) + class(NMOS MOS4) + + # Device abstracts section + # Device abstracts list the pin shapes of the devices. + device(D$PMOS PMOS + terminal(S + rect(l2 (-550 -750) (425 1500)) + ) + terminal(G + rect(l4 (-125 -750) (250 1500)) + ) + terminal(D + rect(l2 (125 -750) (450 1500)) + ) + terminal(B + rect(l3 (-125 -750) (250 1500)) + ) + ) + device(D$PMOS$1 PMOS + terminal(S + rect(l2 (-575 -750) (450 1500)) + ) + terminal(G + rect(l4 (-125 -750) (250 1500)) + ) + terminal(D + rect(l2 (125 -750) (425 1500)) + ) + terminal(B + rect(l3 (-125 -750) (250 1500)) + ) + ) + device(D$PMOS$2 PMOS + terminal(S + rect(l2 (-550 -750) (425 1500)) + ) + terminal(G + rect(l4 (-125 -750) (250 1500)) + ) + terminal(D + rect(l2 (125 -750) (425 1500)) + ) + terminal(B + rect(l3 (-125 -750) (250 1500)) + ) + ) + device(D$NMOS NMOS + terminal(S + rect(l6 (-550 -475) (425 950)) + ) + terminal(G + rect(l4 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (425 950)) + ) + terminal(B + rect(l7 (-125 -475) (250 950)) + ) + ) + device(D$NMOS$1 NMOS + terminal(S + rect(l6 (-550 -475) (425 950)) + ) + terminal(G + rect(l4 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (450 950)) + ) + terminal(B + rect(l7 (-125 -475) (250 950)) + ) + ) + device(D$NMOS$2 NMOS + terminal(S + rect(l6 (-575 -475) (450 950)) + ) + terminal(G + rect(l4 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (425 950)) + ) + terminal(B + rect(l7 (-125 -475) (250 950)) + ) + ) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(ND2X1 + + # Circuit boundary + rect((-100 400) (2600 7600)) + + # Nets with their geometries + net(1 name(VDD) + rect(l8 (1110 5160) (180 180)) + rect(l8 (-180 920) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l11 (-240 -790) (300 1700)) + rect(l11 (-1350 0) (2400 800)) + rect(l11 (-1151 -401) (2 2)) + rect(l2 (-276 -2151) (425 1500)) + rect(l2 (-400 -1500) (425 1500)) + ) + net(2 name(OUT) + rect(l8 (1810 1770) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (-1580 3760) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (1220 920) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (-180 370) (180 180)) + polygon(l11 (-240 -4180) (0 1390) (490 0) (0 -300) (-190 0) (0 -1090)) + rect(l11 (-110 1390) (300 1400)) + polygon(l11 (-1890 0) (0 600) (300 0) (0 -300) (1590 0) (0 -300)) + rect(l11 (-141 -501) (2 2)) + rect(l11 (-1751 1099) (300 1400)) + rect(l11 (1100 -1700) (300 300)) + rect(l11 (-300 0) (300 1400)) + rect(l2 (-1750 -1450) (425 1500)) + rect(l2 (950 -1500) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(3 name(VSS) + rect(l8 (410 1770) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-240 -1300) (300 1360)) + rect(l11 (-650 -2160) (2400 800)) + rect(l11 (-1151 -401) (2 2)) + rect(l6 (-951 859) (425 950)) + ) + net(4 + rect(l3 (-100 4500) (2600 3500)) + ) + net(5 name(B) + rect(l4 (1425 2860) (250 1940)) + rect(l4 (-345 -950) (300 300)) + rect(l4 (-205 650) (250 2000)) + rect(l4 (-250 -2000) (250 2000)) + rect(l4 (-250 -5390) (250 1450)) + rect(l8 (-285 1050) (180 180)) + rect(l11 (-71 -91) (2 2)) + rect(l11 (-171 -151) (300 300)) + ) + net(6 name(A) + rect(l4 (725 2860) (250 1940)) + rect(l4 (-325 -1850) (300 300)) + rect(l4 (-225 1550) (250 2000)) + rect(l4 (-250 -2000) (250 2000)) + rect(l4 (-250 -5390) (250 1450)) + rect(l8 (-265 150) (180 180)) + rect(l11 (-91 -91) (2 2)) + rect(l11 (-151 -151) (300 300)) + ) + net(7 name(SUBSTRATE)) + net(8 + rect(l6 (975 1660) (425 950)) + rect(l6 (-400 -950) (425 950)) + ) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4) + pin(5 name(B)) + pin(6 name(A)) + pin(7 name(SUBSTRATE)) + + # Devices and their connections + device(1 D$PMOS + location(850 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.6375) + param(AD 0.3375) + param(PS 3.85) + param(PD 1.95) + terminal(S 2) + terminal(G 6) + terminal(D 1) + terminal(B 4) + ) + device(2 D$PMOS$1 + location(1550 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.3375) + param(AD 0.6375) + param(PS 1.95) + param(PD 3.85) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(3 D$NMOS$1 + location(850 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.40375) + param(AD 0.21375) + param(PS 2.75) + param(PD 1.4) + terminal(S 3) + terminal(G 6) + terminal(D 8) + terminal(B 7) + ) + device(4 D$NMOS$2 + location(1550 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.21375) + param(AD 0.40375) + param(PS 1.4) + param(PD 2.75) + terminal(S 8) + terminal(G 5) + terminal(D 2) + terminal(B 7) + ) + + ) + circuit(INVX1 + + # Circuit boundary + rect((-100 400) (2000 7600)) + + # Nets with their geometries + net(1 name(VDD) + rect(l8 (410 6260) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l11 (-240 -240) (300 1400)) + rect(l11 (-650 300) (1800 800)) + rect(l11 (-1450 -1100) (300 300)) + rect(l11 (299 399) (2 2)) + rect(l2 (-651 -2151) (425 1500)) + ) + net(2 name(OUT) + rect(l8 (1110 5160) (180 180)) + rect(l8 (-180 920) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (-180 -4120) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-240 -790) (300 4790)) + rect(l11 (-151 -2501) (2 2)) + rect(l2 (-226 1049) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(3 name(VSS) + rect(l8 (410 1770) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-240 -1300) (300 1360)) + rect(l11 (-650 -2160) (1800 800)) + rect(l11 (-851 -401) (2 2)) + rect(l6 (-651 859) (425 950)) + ) + net(4 + rect(l3 (-100 4500) (2000 3500)) + ) + net(5 name(IN) + rect(l4 (725 2860) (250 1940)) + rect(l4 (-525 -1850) (300 300)) + rect(l4 (-25 1550) (250 2000)) + rect(l4 (-250 -2000) (250 2000)) + rect(l4 (-250 -5390) (250 1450)) + rect(l8 (-465 150) (180 180)) + rect(l11 (-91 -91) (2 2)) + rect(l11 (-151 -151) (300 300)) + ) + net(6 name(SUBSTRATE)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4) + pin(5 name(IN)) + pin(6 name(SUBSTRATE)) + + # Devices and their connections + device(1 D$PMOS$2 + location(850 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.6375) + param(AD 0.6375) + param(PS 3.85) + param(PD 3.85) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(2 D$NMOS + location(850 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.40375) + param(AD 0.40375) + param(PS 2.75) + param(PD 2.75) + terminal(S 3) + terminal(G 5) + terminal(D 2) + terminal(B 6) + ) + + ) + circuit(RINGO + + # Circuit boundary + rect((0 350) (27600 7650)) + + # Nets with their geometries + net(1 + rect(l8 (4710 3010) (180 180)) + rect(l11 (-850 -240) (610 300)) + rect(l2 (-2550 1800) (425 1500)) + rect(l2 (950 -1500) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(2 + rect(l8 (6510 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(3 + rect(l8 (8310 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(4 + rect(l8 (10110 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(5 + rect(l8 (11910 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(6 + rect(l8 (13710 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(7 + rect(l8 (15510 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(8 + rect(l8 (17310 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(9 + rect(l8 (19110 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(10 + rect(l8 (20910 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(11 name(FB) + rect(l8 (22710 3010) (180 180)) + rect(l8 (-19700 720) (180 180)) + rect(l11 (18380 -1140) (900 300)) + rect(l11 (-19530 590) (320 320)) + rect(l11 (17820 -320) (320 320)) + rect(l12 (-18400 -260) (200 200)) + rect(l12 (17940 -200) (200 200)) + rect(l13 (-18040 -300) (17740 400)) + rect(l13 (-17921 -201) (2 2)) + rect(l13 (-221 -201) (400 400)) + rect(l13 (17740 -400) (400 400)) + rect(l2 (-245 850) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(12 name(VDD) + rect(l3 (500 4500) (1400 3500)) + rect(l3 (-1900 -3500) (600 3500)) + rect(l3 (23300 -3500) (1400 3500)) + rect(l3 (-100 -3500) (600 3500)) + rect(l3 (0 -3500) (600 3500)) + rect(l3 (0 -3500) (600 3500)) + rect(l3 (0 -3500) (600 3500)) + rect(l8 (-26490 -1240) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (23220 370) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l11 (-21741 859) (2 2)) + rect(l11 (-2351 -451) (1200 800)) + rect(l11 (-750 -1450) (300 1400)) + rect(l11 (-101 -351) (2 2)) + rect(l11 (-1251 -401) (600 800)) + rect(l11 (23400 -800) (1200 800)) + rect(l11 (-750 -1450) (300 1400)) + rect(l11 (-101 -351) (2 2)) + rect(l11 (549 -401) (600 800)) + rect(l11 (0 -800) (600 800)) + rect(l11 (0 -800) (600 800)) + rect(l11 (0 -800) (600 800)) + rect(l2 (-24825 -2550) (425 1500)) + rect(l2 (-400 -1500) (425 1500)) + rect(l2 (1275 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l9 (-21975 -450) (500 1500)) + rect(l9 (22900 -1500) (500 1500)) + ) + net(13 name(OUT) + rect(l11 (23440 3840) (320 320)) + rect(l12 (-260 -260) (200 200)) + rect(l13 (-101 -101) (2 2)) + rect(l13 (-201 -201) (400 400)) + rect(l2 (-625 850) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(14 name(ENABLE) + rect(l8 (2510 3010) (180 180)) + rect(l11 (-250 -250) (320 320)) + rect(l12 (-260 -260) (200 200)) + rect(l13 (-101 -101) (2 2)) + rect(l13 (-201 -201) (400 400)) + ) + net(15 name(VSS) + rect(l8 (26010 1770) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (520 -730) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (-25780 -890) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (23220 370) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (1260 -40) (300 1360)) + rect(l11 (400 -1360) (300 1360)) + rect(l11 (-24001 -1711) (2 2)) + rect(l11 (-1901 -401) (300 1400)) + rect(l11 (-750 -1450) (1200 800)) + rect(l11 (-551 -401) (2 2)) + rect(l11 (-1251 -401) (600 800)) + rect(l11 (23850 -750) (300 1400)) + rect(l11 (-750 -1450) (1200 800)) + rect(l11 (-551 -401) (2 2)) + rect(l11 (549 -401) (600 800)) + rect(l11 (0 -800) (600 800)) + rect(l11 (0 -800) (600 800)) + rect(l11 (0 -800) (600 800)) + rect(l6 (-25500 460) (425 950)) + rect(l6 (1975 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (2975 -1010) (425 950)) + rect(l6 (250 -950) (425 950)) + rect(l10 (-26050 -2150) (500 1500)) + rect(l10 (22900 -1500) (500 1500)) + ) + + # Outgoing pins and their connections to nets + pin(11 name(FB)) + pin(12 name(VDD)) + pin(13 name(OUT)) + pin(14 name(ENABLE)) + pin(15 name(VSS)) + + # Devices and their connections + device(1 D$NMOS + location(26450 2075) + param(L 0.25) + param(W 0.95) + param(AS 0.40375) + param(AD 0.40375) + param(PS 2.75) + param(PD 2.75) + terminal(S 15) + terminal(G) + terminal(D 15) + terminal(B 15) + ) + + # Subcircuits and their connections + circuit(3 ND2X1 location(1800 0) + pin(0 12) + pin(1 1) + pin(2 15) + pin(3 12) + pin(4 11) + pin(5 14) + pin(6 15) + ) + circuit(4 INVX1 location(4200 0) + pin(0 12) + pin(1 2) + pin(2 15) + pin(3 12) + pin(4 1) + pin(5 15) + ) + circuit(5 INVX1 location(6000 0) + pin(0 12) + pin(1 3) + pin(2 15) + pin(3 12) + pin(4 2) + pin(5 15) + ) + circuit(6 INVX1 location(7800 0) + pin(0 12) + pin(1 4) + pin(2 15) + pin(3 12) + pin(4 3) + pin(5 15) + ) + circuit(7 INVX1 location(9600 0) + pin(0 12) + pin(1 5) + pin(2 15) + pin(3 12) + pin(4 4) + pin(5 15) + ) + circuit(8 INVX1 location(11400 0) + pin(0 12) + pin(1 6) + pin(2 15) + pin(3 12) + pin(4 5) + pin(5 15) + ) + circuit(9 INVX1 location(13200 0) + pin(0 12) + pin(1 7) + pin(2 15) + pin(3 12) + pin(4 6) + pin(5 15) + ) + circuit(10 INVX1 location(15000 0) + pin(0 12) + pin(1 8) + pin(2 15) + pin(3 12) + pin(4 7) + pin(5 15) + ) + circuit(11 INVX1 location(16800 0) + pin(0 12) + pin(1 9) + pin(2 15) + pin(3 12) + pin(4 8) + pin(5 15) + ) + circuit(12 INVX1 location(18600 0) + pin(0 12) + pin(1 10) + pin(2 15) + pin(3 12) + pin(4 9) + pin(5 15) + ) + circuit(13 INVX1 location(20400 0) + pin(0 12) + pin(1 11) + pin(2 15) + pin(3 12) + pin(4 10) + pin(5 15) + ) + circuit(14 INVX1 location(22200 0) + pin(0 12) + pin(1 13) + pin(2 15) + pin(3 12) + pin(4 11) + pin(5 15) + ) + + ) +) + +# Reference netlist +reference( + + # Device class section + class(NMOS MOS4) + class(PMOS MOS4) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(ND2X1 + + # Nets + net(1 name(VDD)) + net(2 name(OUT)) + net(3 name(VSS)) + net(4 name(NWELL)) + net(5 name(B)) + net(6 name(A)) + net(7 name(BULK)) + net(8 name('1')) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4 name(NWELL)) + pin(5 name(B)) + pin(6 name(A)) + pin(7 name(BULK)) + + # Devices and their connections + device(1 PMOS + name($1) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 2) + terminal(G 6) + terminal(D 1) + terminal(B 4) + ) + device(2 PMOS + name($2) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(3 NMOS + name($3) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 3) + terminal(G 6) + terminal(D 8) + terminal(B 7) + ) + device(4 NMOS + name($4) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 8) + terminal(G 5) + terminal(D 2) + terminal(B 7) + ) + + ) + circuit(INVX1 + + # Nets + net(1 name(VDD)) + net(2 name(OUT)) + net(3 name(VSS)) + net(4 name(NWELL)) + net(5 name(IN)) + net(6 name(BULK)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4 name(NWELL)) + pin(5 name(IN)) + pin(6 name(BULK)) + + # Devices and their connections + device(1 PMOS + name($1) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(2 NMOS + name($2) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 3) + terminal(G 5) + terminal(D 2) + terminal(B 6) + ) + + ) + circuit(RINGO + + # Nets + net(1 name(VSS)) + net(2 name(VDD)) + net(3 name(FB)) + net(4 name(ENABLE)) + net(5 name(OUT)) + net(6 name('1')) + net(7 name('2')) + net(8 name('3')) + net(9 name('4')) + net(10 name('5')) + net(11 name('6')) + net(12 name('7')) + net(13 name('8')) + net(14 name('9')) + net(15 name('10')) + + # Outgoing pins and their connections to nets + pin(1 name(VSS)) + pin(2 name(VDD)) + pin(3 name(FB)) + pin(4 name(ENABLE)) + pin(5 name(OUT)) + + # Devices and their connections + device(1 NMOS + name($1) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G) + terminal(D 1) + terminal(B 1) + ) + + # Subcircuits and their connections + circuit(1 ND2X1 name($1) + pin(0 2) + pin(1 6) + pin(2 1) + pin(3 2) + pin(4 3) + pin(5 4) + pin(6 1) + ) + circuit(2 INVX1 name($2) + pin(0 2) + pin(1 7) + pin(2 1) + pin(3 2) + pin(4 6) + pin(5 1) + ) + circuit(3 INVX1 name($3) + pin(0 2) + pin(1 8) + pin(2 1) + pin(3 2) + pin(4 7) + pin(5 1) + ) + circuit(4 INVX1 name($4) + pin(0 2) + pin(1 9) + pin(2 1) + pin(3 2) + pin(4 8) + pin(5 1) + ) + circuit(5 INVX1 name($5) + pin(0 2) + pin(1 10) + pin(2 1) + pin(3 2) + pin(4 9) + pin(5 1) + ) + circuit(6 INVX1 name($6) + pin(0 2) + pin(1 11) + pin(2 1) + pin(3 2) + pin(4 10) + pin(5 1) + ) + circuit(7 INVX1 name($7) + pin(0 2) + pin(1 12) + pin(2 1) + pin(3 2) + pin(4 11) + pin(5 1) + ) + circuit(8 INVX1 name($8) + pin(0 2) + pin(1 13) + pin(2 1) + pin(3 2) + pin(4 12) + pin(5 1) + ) + circuit(9 INVX1 name($9) + pin(0 2) + pin(1 14) + pin(2 1) + pin(3 2) + pin(4 13) + pin(5 1) + ) + circuit(10 INVX1 name($10) + pin(0 2) + pin(1 15) + pin(2 1) + pin(3 2) + pin(4 14) + pin(5 1) + ) + circuit(11 INVX1 name($11) + pin(0 2) + pin(1 3) + pin(2 1) + pin(3 2) + pin(4 15) + pin(5 1) + ) + circuit(12 INVX1 name($12) + pin(0 2) + pin(1 5) + pin(2 1) + pin(3 2) + pin(4 3) + pin(5 1) + ) + + ) +) + +# Cross reference +xref( + circuit(INVX1 INVX1 match + xref( + net(4 4 match) + net(5 5 match) + net(2 2 match) + net(6 6 match) + net(1 1 match) + net(3 3 match) + pin(3 3 match) + pin(4 4 match) + pin(1 1 match) + pin(5 5 match) + pin(0 0 match) + pin(2 2 match) + device(2 2 match) + device(1 1 match) + ) + ) + circuit(ND2X1 ND2X1 match + xref( + net(8 8 match) + net(4 4 match) + net(6 6 match) + net(5 5 match) + net(2 2 match) + net(7 7 match) + net(1 1 match) + net(3 3 match) + pin(3 3 match) + pin(5 5 match) + pin(4 4 match) + pin(1 1 match) + pin(6 6 match) + pin(0 0 match) + pin(2 2 match) + device(3 3 match) + device(4 4 match) + device(1 1 match) + device(2 2 match) + ) + ) + circuit(RINGO RINGO match + xref( + net(1 6 match) + net(10 15 match) + net(2 7 match) + net(3 8 match) + net(4 9 match) + net(5 10 match) + net(6 11 match) + net(7 12 match) + net(8 13 match) + net(9 14 match) + net(14 4 match) + net(11 3 match) + net(13 5 match) + net(12 2 match) + net(15 1 match) + pin(3 3 match) + pin(0 2 match) + pin(2 4 match) + pin(1 1 match) + pin(4 0 match) + device(1 1 match) + circuit(4 2 match) + circuit(5 3 match) + circuit(6 4 match) + circuit(7 5 match) + circuit(8 6 match) + circuit(9 7 match) + circuit(10 8 match) + circuit(11 9 match) + circuit(12 10 match) + circuit(13 11 match) + circuit(14 12 match) + circuit(3 1 match) + ) + ) +) From 444e10d32f93ec631f59eb009ca0cc2c75c17890 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 24 Aug 2019 22:56:20 +0200 Subject: [PATCH 14/27] WIP: rerun LVS, partial LVS Rerun LVS: a button is provided which allows re-running the LVS or netlist extraction from the netlist browser. TODO: a generic concept for triggering the generators "Partial LVS" is a feature where it's possible to select a layout subcell - running LVS then will only compare against the corresponding schematic subcell, not the whole tree. The magic is done by "align" which will remove the upper hierarchy part. --- src/db/db/dbLayoutToNetlist.cc | 11 +++++-- src/db/db/dbLayoutToNetlist.h | 14 +++++++++ src/db/db/dbLayoutVsSchematic.cc | 4 +-- src/db/db/dbNetlistCompare.cc | 4 +-- src/db/db/gsiDeclDbLayoutToNetlist.cc | 7 +++++ src/db/db/gsiDeclDbNetlist.cc | 6 ++-- src/db/db/gsiDeclDbNetlistCompare.cc | 2 -- src/drc/drc/built-in-macros/_drc_netter.rb | 2 ++ .../drc/built-in-macros/drc_interpreters.lym | 1 + src/klayout.pro | 6 ++-- src/laybasic/laybasic/NetlistBrowserPage.ui | 14 +++++++++ .../laybasic/layNetlistBrowserPage.cc | 31 +++++++++++++++++++ src/laybasic/laybasic/layNetlistBrowserPage.h | 3 ++ src/laybasic/laybasic/laybasic.pro | 6 ++-- src/lvs/lvs/built-in-macros/_lvs_netter.rb | 12 ++++++- .../lvs/built-in-macros/lvs_interpreters.lym | 1 + 16 files changed, 105 insertions(+), 19 deletions(-) diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index bb7399b35..b30dfb26a 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -1148,7 +1148,7 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, const db::Reg } -void db::LayoutToNetlist::save (const std::string &path, bool short_format) +void LayoutToNetlist::save (const std::string &path, bool short_format) { tl::OutputStream stream (path); db::LayoutToNetlistStandardWriter writer (stream, short_format); @@ -1156,7 +1156,7 @@ void db::LayoutToNetlist::save (const std::string &path, bool short_format) writer.write (this); } -void db::LayoutToNetlist::load (const std::string &path) +void LayoutToNetlist::load (const std::string &path) { tl::InputStream stream (path); db::LayoutToNetlistStandardReader reader (stream); @@ -1165,7 +1165,7 @@ void db::LayoutToNetlist::load (const std::string &path) reader.read (this); } -db::LayoutToNetlist *db::LayoutToNetlist::create_from_file (const std::string &path) +db::LayoutToNetlist *LayoutToNetlist::create_from_file (const std::string &path) { std::auto_ptr db; @@ -1189,4 +1189,9 @@ db::LayoutToNetlist *db::LayoutToNetlist::create_from_file (const std::string &p return db.release (); } +void LayoutToNetlist::set_generator (const std::string &g) +{ + m_generator = g; +} + } diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index e2287a301..3b31ddff3 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -254,6 +254,19 @@ public: */ std::string name (unsigned int) const; + /** + * @brief Sets the generator string + */ + void set_generator (const std::string &g); + + /** + * @brief Gets the generator string + */ + const std::string &generator () const + { + return m_generator; + } + /** * @brief Returns true, if the region is a persisted region * Persisted regions have a name and are kept inside the LayoutToNetlist @@ -730,6 +743,7 @@ private: bool m_is_flat; double m_device_scaling; db::DeepLayer m_dummy_layer; + std::string m_generator; struct CellReuseTableKey { diff --git a/src/db/db/dbLayoutVsSchematic.cc b/src/db/db/dbLayoutVsSchematic.cc index e6c092795..fc054d6f5 100644 --- a/src/db/db/dbLayoutVsSchematic.cc +++ b/src/db/db/dbLayoutVsSchematic.cc @@ -86,7 +86,7 @@ db::NetlistCrossReference *LayoutVsSchematic::make_cross_ref () } -void db::LayoutVsSchematic::save (const std::string &path, bool short_format) +void LayoutVsSchematic::save (const std::string &path, bool short_format) { tl::OutputStream stream (path); db::LayoutVsSchematicStandardWriter writer (stream, short_format); @@ -94,7 +94,7 @@ void db::LayoutVsSchematic::save (const std::string &path, bool short_format) writer.write (this); } -void db::LayoutVsSchematic::load (const std::string &path) +void LayoutVsSchematic::load (const std::string &path) { tl::InputStream stream (path); db::LayoutVsSchematicStandardReader reader (stream); diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 499bc4041..9222cee38 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -2138,14 +2138,14 @@ NetlistComparer::unmatched_circuits (db::Netlist *a, db::Netlist *b, std::vector for (db::Netlist::circuit_iterator i = a->begin_circuits (); i != a->end_circuits (); ++i) { size_t cat = circuit_categorizer.cat_for_circuit (i.operator-> ()); - if (cat && i->begin_refs () != i->end_refs ()) { + if (cat) { cat2circuits[cat].first = i.operator-> (); } } for (db::Netlist::circuit_iterator i = b->begin_circuits (); i != b->end_circuits (); ++i) { size_t cat = circuit_categorizer.cat_for_circuit (i.operator-> ()); - if (cat && i->begin_refs () != i->end_refs ()) { + if (cat) { cat2circuits[cat].second = i.operator-> (); } } diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index 02ba6b3c9..c8256b0c7 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -169,6 +169,13 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "The database unit is mandatory because the physical parameter extraction " "for devices requires this unit for translation of layout to physical dimensions.\n" ) + + gsi::method ("generator", &db::LayoutToNetlist::generator, + "@brief Gets the generator string.\n" + "The generator is the script that created this database.\n" + ) + + gsi::method ("generator=", &db::LayoutToNetlist::set_generator, gsi::arg ("generator"), + "@brief Sets the generator string.\n" + ) + gsi::method ("dss", (db::DeepShapeStore &(db::LayoutToNetlist::*) ()) &db::LayoutToNetlist::dss, "@brief Gets a reference to the internal DSS object.\n" ) + diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index 2b5d4b559..f229dafb1 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -1106,7 +1106,7 @@ Class decl_dbCircuit ("db", "Circuit", "@brief Iterates over the parent circuits of this circuit\n" "Child circuits are the ones that are referencing this circuit via subcircuits." ) + - gsi::method ("has_refs", &db::Circuit::has_refs, + gsi::method ("has_refs?", &db::Circuit::has_refs, "@brief Returns a value indicating whether the circuit has references\n" "A circuit has references if there is at least one subcircuit referring to it." ) + @@ -1379,13 +1379,13 @@ Class decl_dbNetlist ("db", "Netlist", gsi::method ("remove", &db::Netlist::remove_circuit, gsi::arg ("circuit"), "@brief Removes the given circuit object from the netlist\n" "After the circuit has been removed, the object becomes invalid and cannot be used further. " - "A circuit with references (see \\has_refs) should not be removed as the " + "A circuit with references (see \\has_refs?) should not be removed as the " "subcircuits calling it would afterwards point to nothing." ) + gsi::method ("purge_circuit", &db::Netlist::purge_circuit, gsi::arg ("circuit"), "@brief Removes the given circuit object and all child circuits which are not used otherwise from the netlist\n" "After the circuit has been removed, the object becomes invalid and cannot be used further. " - "A circuit with references (see \\has_refs) should not be removed as the " + "A circuit with references (see \\has_refs?) should not be removed as the " "subcircuits calling it would afterwards point to nothing." ) + gsi::method ("flatten_circuit", &db::Netlist::flatten_circuit, gsi::arg ("circuit"), diff --git a/src/db/db/gsiDeclDbNetlistCompare.cc b/src/db/db/gsiDeclDbNetlistCompare.cc index 0afaf06de..900df9d78 100644 --- a/src/db/db/gsiDeclDbNetlistCompare.cc +++ b/src/db/db/gsiDeclDbNetlistCompare.cc @@ -541,12 +541,10 @@ Class decl_dbNetlistComparer ("db", "NetlistComparer", gsi::method_ext ("unmatched_circuits_a", &unmatched_circuits_a, gsi::arg ("a"), gsi::arg ("b"), "@brief Returns a list of circuits in A for which there is not corresponding circuit in B\n" "This list can be used to flatten these circuits so they do not participate in the compare process.\n" - "Top level circuits are not included as they cannot be flattened.\n" ) + gsi::method_ext ("unmatched_circuits_b", &unmatched_circuits_b, gsi::arg ("a"), gsi::arg ("b"), "@brief Returns a list of circuits in B for which there is not corresponding circuit in A\n" "This list can be used to flatten these circuits so they do not participate in the compare process.\n" - "Top level circuits are not included as they cannot be flattened.\n" ) + gsi::method ("compare", (bool (db::NetlistComparer::*) (const db::Netlist *, const db::Netlist *) const) &db::NetlistComparer::compare, gsi::arg ("netlist_a"), gsi::arg ("netlist_b"), "@brief Compares two netlists.\n" diff --git a/src/drc/drc/built-in-macros/_drc_netter.rb b/src/drc/drc/built-in-macros/_drc_netter.rb index 400acd91b..0763d6e54 100644 --- a/src/drc/drc/built-in-macros/_drc_netter.rb +++ b/src/drc/drc/built-in-macros/_drc_netter.rb @@ -407,6 +407,8 @@ module DRC @l2n = RBA::LayoutToNetlist::new(layout.top_cell.name, layout.dbu) end + @l2n.generator = $0 + end def register_layer(data) diff --git a/src/drc/drc/built-in-macros/drc_interpreters.lym b/src/drc/drc/built-in-macros/drc_interpreters.lym index 3445c815a..5818c23d7 100644 --- a/src/drc/drc/built-in-macros/drc_interpreters.lym +++ b/src/drc/drc/built-in-macros/drc_interpreters.lym @@ -74,6 +74,7 @@ module DRC # Implements the execute method def execute(macro) + $0 = macro.path DRC::execute_drc(macro) end diff --git a/src/klayout.pro b/src/klayout.pro index fbf20df44..bf978a92d 100644 --- a/src/klayout.pro +++ b/src/klayout.pro @@ -89,12 +89,12 @@ plugins.depends += lib rdb db plugins.depends += lay ant - laybasic.depends += rdb + lym.depends += gsi $$LANG_DEPENDS + laybasic.depends += rdb lym ant.depends += laybasic img.depends += laybasic edt.depends += laybasic - lym.depends += gsi $$LANG_DEPENDS - lay.depends += laybasic ant img edt lym + lay.depends += laybasic ant img edt klayout_main.depends += plugins $$MAIN_DEPENDS } diff --git a/src/laybasic/laybasic/NetlistBrowserPage.ui b/src/laybasic/laybasic/NetlistBrowserPage.ui index 84373f842..e341345cd 100644 --- a/src/laybasic/laybasic/NetlistBrowserPage.ui +++ b/src/laybasic/laybasic/NetlistBrowserPage.ui @@ -132,6 +132,20 @@ + + + + ... + + + + :/run.png:/run.png + + + true + + + diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index ee0474460..c078a9e38 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -30,6 +30,7 @@ #include "layMarker.h" #include "layNetInfoDialog.h" #include "layNetExportDialog.h" +#include "lymMacro.h" #include "tlProgress.h" #include "tlExceptions.h" #include "dbLayoutToNetlist.h" @@ -124,6 +125,7 @@ NetlistBrowserPage::NetlistBrowserPage (QWidget * /*parent*/) m_update_needed (true), mp_info_dialog (0), dm_update_highlights (this, &NetlistBrowserPage::update_highlights), + dm_rerun_macro (this, &NetlistBrowserPage::rerun_macro), m_cell_context_cache (0) { Ui::NetlistBrowserPage::setupUi (this); @@ -188,6 +190,7 @@ NetlistBrowserPage::NetlistBrowserPage (QWidget * /*parent*/) connect (m_show_all_action, SIGNAL (triggered ()), this, SLOT (show_all_clicked ())); connect (info_button, SIGNAL (pressed ()), this, SLOT (info_button_pressed ())); + connect (rerun_button, SIGNAL (pressed ()), this, SLOT (rerun_button_pressed ())); connect (find_button, SIGNAL (pressed ()), this, SLOT (find_button_pressed ())); connect (forward, SIGNAL (clicked ()), this, SLOT (navigate_forward ())); connect (backward, SIGNAL (clicked ()), this, SLOT (navigate_back ())); @@ -585,6 +588,27 @@ NetlistBrowserPage::navigate_forward () } } +void +NetlistBrowserPage::rerun_button_pressed () +{ + // NOTE: we use deferred execution, because otherwise the button won't get repainted properly + dm_rerun_macro (); +} + +void +NetlistBrowserPage::rerun_macro () +{ + if (! mp_database->generator ().empty ()) { + + lym::Macro *generator = lym::MacroCollection::root ().find_macro (mp_database->generator ()); + if (! generator) { + throw tl::Exception (tl::sprintf (tl::to_string (tr ("Cannot find generator script: %s")), mp_database->generator())); + } else { + generator->run (); + } + + } +} void NetlistBrowserPage::info_button_pressed () { @@ -741,6 +765,13 @@ NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb) db::LayoutVsSchematic *lvsdb = dynamic_cast (l2ndb); mp_database.reset (l2ndb); + rerun_button->setEnabled (mp_database.get () && ! mp_database->generator ().empty ()); + if (rerun_button->isEnabled ()) { + rerun_button->setToolTip (tl::to_qstring (tl::to_string (tr ("Run ")) + mp_database->generator ())); + } else { + rerun_button->setToolTip (QString ()); + } + show_netlist->setVisible (lvsdb != 0); show_xref->setVisible (lvsdb != 0); diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.h b/src/laybasic/laybasic/layNetlistBrowserPage.h index 2bde27cec..1440a13b0 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.h +++ b/src/laybasic/laybasic/layNetlistBrowserPage.h @@ -169,6 +169,7 @@ public slots: private slots: void show_all_clicked (); void info_button_pressed (); + void rerun_button_pressed (); void find_button_pressed (); void anchor_clicked (const QString &url); void navigate_back (); @@ -212,6 +213,7 @@ private: std::vector m_current_circuits; lay::NetInfoDialog *mp_info_dialog; tl::DeferredMethod dm_update_highlights; + tl::DeferredMethod dm_rerun_macro; db::ContextCache m_cell_context_cache; void set_db (db::LayoutToNetlist *l2ndb); @@ -233,6 +235,7 @@ private: bool produce_highlights_for_subcircuit (const db::SubCircuit *subcircuit, size_t &n_markers, const std::vector &tv); bool produce_highlights_for_circuit (const db::Circuit *circuit, size_t &n_markers, const std::vector &tv); void configure_marker (lay::Marker *marker, bool with_fill); + void rerun_macro (); void export_nets (const std::vector *nets); }; diff --git a/src/laybasic/laybasic/laybasic.pro b/src/laybasic/laybasic/laybasic.pro index 5d59bd3af..443343ce1 100644 --- a/src/laybasic/laybasic/laybasic.pro +++ b/src/laybasic/laybasic/laybasic.pro @@ -275,9 +275,9 @@ HEADERS = \ layNetlistBrowserTreeModel.h \ layLibrariesView.h -INCLUDEPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC -DEPENDPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC -LIBS += -L$$DESTDIR -lklayout_tl -lklayout_gsi -lklayout_db -lklayout_rdb +INCLUDEPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC $$LYM_INC +DEPENDPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC $$LYM_INC +LIBS += -L$$DESTDIR -lklayout_tl -lklayout_gsi -lklayout_db -lklayout_rdb -lklayout_lym INCLUDEPATH += $$QTBASIC_INC DEPENDPATH += $$QTBASIC_INC diff --git a/src/lvs/lvs/built-in-macros/_lvs_netter.rb b/src/lvs/lvs/built-in-macros/_lvs_netter.rb index 3e68b3d1c..a0b0b2cf8 100644 --- a/src/lvs/lvs/built-in-macros/_lvs_netter.rb +++ b/src/lvs/lvs/built-in-macros/_lvs_netter.rb @@ -61,6 +61,8 @@ module LVS @lvs = RBA::LayoutVsSchematic::new(cell.name, layout.dbu) end + @lvs.generator = $0 + @l2n = @lvs @comparer = RBA::NetlistComparer::new @@ -117,8 +119,16 @@ module LVS nl = _ensure_two_netlists + unmatched_a = @comparer.unmatched_circuits_a(*nl) + + # check whether we're about to flatten away the internal top cell - that's bad + top_cell = l2n_data.internal_top_cell.name + if unmatched_a.find { |c| c.name == top_cell } + raise("Can't find a schematic counterpart for the top cell #{top_cell} - use 'same_circuit' to establish a correspondence") + end + # flatten layout cells for which there is no corresponding schematic circuit - @comparer.unmatched_circuits_a(*nl).each do |c| + unmatched_a.each do |c| @engine.info("Flatten layout cell (no schematic): #{c.name}") nl[0].flatten_circuit(c) end diff --git a/src/lvs/lvs/built-in-macros/lvs_interpreters.lym b/src/lvs/lvs/built-in-macros/lvs_interpreters.lym index 24a1d0d84..b72af993b 100644 --- a/src/lvs/lvs/built-in-macros/lvs_interpreters.lym +++ b/src/lvs/lvs/built-in-macros/lvs_interpreters.lym @@ -80,6 +80,7 @@ module LVS # Implements the execute method def execute(macro) + $0 = macro.path LVS::execute_lvs(macro) end From 515b68b76f097117540a7534b32f4e2aac4c4e94 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 25 Aug 2019 18:03:27 +0200 Subject: [PATCH 15/27] WIP: provide a recipe registration facility for LVS rerun --- src/gsi/gsi/gsiDeclTl.cc | 80 +++++++++++++++++ src/tl/tl/tl.pro | 6 +- src/tl/tl/tlRecipe.cc | 87 +++++++++++++++++++ src/tl/tl/tlRecipe.h | 132 +++++++++++++++++++++++++++++ src/tl/unit_tests/tlRecipeTests.cc | 58 +++++++++++++ src/tl/unit_tests/unit_tests.pro | 3 +- testdata/ruby/tlTest.rb | 36 ++++++++ 7 files changed, 399 insertions(+), 3 deletions(-) create mode 100644 src/tl/tl/tlRecipe.cc create mode 100644 src/tl/tl/tlRecipe.h create mode 100644 src/tl/unit_tests/tlRecipeTests.cc diff --git a/src/gsi/gsi/gsiDeclTl.cc b/src/gsi/gsi/gsiDeclTl.cc index c282c33c8..27f98a315 100644 --- a/src/gsi/gsi/gsiDeclTl.cc +++ b/src/gsi/gsi/gsiDeclTl.cc @@ -27,6 +27,7 @@ #include "tlProgress.h" #include "tlExpression.h" #include "tlGlobPattern.h" +#include "tlRecipe.h" // ---------------------------------------------------------------- // Logger binding @@ -640,4 +641,83 @@ Class decl_GlobPattern ("tl", "GlobPattern", "This class has been introduced in version 0.26." ); +class Recipe_Impl + : public tl::Recipe +{ +public: + Recipe_Impl (const std::string &name, const std::string &description) + : tl::Recipe (name, description) + { + // .. nothing yet .. + } + + virtual tl::Variant execute (const std::map ¶ms) const + { + if (execute_cb.can_issue ()) { + return execute_cb.issue &> (&tl::Recipe::execute, params); + } else { + return tl::Variant (); + } + } + + gsi::Callback execute_cb; +}; + +} + +namespace tl +{ + template <> struct type_traits : public type_traits { }; +} + +namespace gsi +{ + +static Recipe_Impl *make_recipe (const std::string &name, const std::string &description) +{ + return new Recipe_Impl (name, description); +} + +Class decl_Recipe_Impl ("tl", "Recipe", + gsi::constructor ("new", &make_recipe, gsi::arg ("name"), gsi::arg ("description", std::string ()), + "@brief Creates a new recipe object with the given name and (optional) description" + ) + + gsi::method ("name", &Recipe_Impl::name, + "@brief Gets the name of the recipe." + ) + + gsi::method ("description", &Recipe_Impl::description, + "@brief Gets the description of the recipe." + ) + + gsi::method ("make", &Recipe_Impl::make, gsi::arg ("generator"), + "@brief Executes the recipe given by the generator string.\n" + "The generator string is the one delivered with \\generator." + ) + + gsi::method ("generator", &Recipe_Impl::generator, gsi::arg ("params"), + "@brief Delivers the generator string from the given parameters.\n" + "The generator string can be used with \\make to re-run the recipe." + ) + + gsi::callback ("execute", &Recipe_Impl::execute, &Recipe_Impl::execute_cb, + "@brief Reimplement this method to provide the functionality of the recipe.\n" + "This method is supposed to re-run the recipe with the given parameters and deliver the " + "the intended output object." + ), + "@brief A facility for providing reproducable recipes\n" + "The idea of this facility is to provide a service by which an object\n" + "can be reproduced in a parametrized way. The intended use case is a \n" + "DRC report for example, where the DRC script is the generator.\n" + "\n" + "In this use case, the DRC engine will register a recipe. It will \n" + "put the serialized version of the recipe into the DRC report. If the \n" + "user requests a re-run of the DRC, the recipe will be called and \n" + "the implementation is supposed to deliver a new database.\n" + "\n" + "To register a recipe, reimplement tl::Recipe and create a singleton\n" + "instance. To serialize a recipe, use \"generator\", to execute the\n" + "recipe, use \"make\". \n" + "\n" + "Parameters are kept as a generic key/value map.\n" + "\n" + "This class has been introduced in version 0.26." +); + } diff --git a/src/tl/tl/tl.pro b/src/tl/tl/tl.pro index b481592d9..39184f182 100644 --- a/src/tl/tl/tl.pro +++ b/src/tl/tl/tl.pro @@ -45,7 +45,8 @@ SOURCES = \ tlUniqueId.cc \ tlList.cc \ tlEquivalenceClusters.cc \ - tlUniqueName.cc + tlUniqueName.cc \ + tlRecipe.cc HEADERS = \ tlAlgorithm.h \ @@ -100,7 +101,8 @@ HEADERS = \ tlUniqueId.h \ tlList.h \ tlEquivalenceClusters.h \ - tlUniqueName.h + tlUniqueName.h \ + tlRecipe.h equals(HAVE_CURL, "1") { diff --git a/src/tl/tl/tlRecipe.cc b/src/tl/tl/tlRecipe.cc new file mode 100644 index 000000000..3d02bb8ac --- /dev/null +++ b/src/tl/tl/tlRecipe.cc @@ -0,0 +1,87 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2019 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "tlRecipe.h" +#include "tlString.h" + +namespace tl +{ + +Recipe::Recipe (const std::string &name, const std::string &description) + : tl::RegisteredClass (this, 0, name.c_str (), false) +{ + m_name = name; + m_description = description; +} + +std::string Recipe::generator (const std::map ¶ms) +{ + std::string g; + g += tl::to_word_or_quoted_string (name ()); + g += ": "; + + for (std::map::const_iterator p = params.begin (); p != params.end (); ++p) { + if (p != params.begin ()) { + g += ","; + } + g += tl::to_word_or_quoted_string (p->first); + g += "="; + g += p->second.to_parsable_string (); + } + + return g; +} + +tl::Variant Recipe::make (const std::string &generator) +{ + tl::Extractor ex (generator.c_str ()); + + std::string recipe; + ex.read_word_or_quoted (recipe); + ex.test (":"); + + std::map params; + while (! ex.at_end ()) { + std::string key; + ex.read_word_or_quoted (key); + ex.test ("="); + tl::Variant v; + ex.read (v); + ex.test (","); + params.insert (std::make_pair (key, v)); + } + + tl::Recipe *recipe_obj = 0; + for (tl::Registrar::iterator r = tl::Registrar::begin (); r != tl::Registrar::end (); ++r) { + if (r->name () == recipe) { + recipe_obj = r.operator-> (); + } + } + + if (! recipe_obj) { + return tl::Variant (); + } else { + return recipe_obj->execute (params); + } +} + +} // namespace tl diff --git a/src/tl/tl/tlRecipe.h b/src/tl/tl/tlRecipe.h new file mode 100644 index 000000000..700df550e --- /dev/null +++ b/src/tl/tl/tlRecipe.h @@ -0,0 +1,132 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2019 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#ifndef HDR_tlRecipe +#define HDR_tlRecipe + +#include "tlCommon.h" +#include "tlVariant.h" +#include "tlTypeTraits.h" +#include "tlClassRegistry.h" + +namespace tl +{ + +/** + * @brief A facility for providing reproducable recipes + * + * The idea of this facility is to provide a service by which an object + * can be reproduced in a parametrized way. The intended use case is a + * DRC report for example, where the DRC script is the generator. + * + * In this use case, the DRC engine will register a recipe. It will + * put the serialized version of the recipe into the DRC report. If the + * user requests a re-run of the DRC, the recipe will be called and + * the implementation is supposed to deliver a new database. + * + * To register a recipe, reimplement tl::Recipe and create a singleton + * instance. To serialize a recipe, use "generator", to execute the + * recipe, use "make". + * + * Parameters are kept as a generic key/value map. + */ +class TL_PUBLIC Recipe + : public tl::RegisteredClass +{ +public: + /** + * @brief @brief Creates a new recipe object + */ + Recipe (const std::string &name, const std::string &description = std::string ()); + + /** + * @brief Destructor + */ + virtual ~Recipe () { } + + /** + * @brief Gets the recipes name (a unique identifier) + */ + const std::string &name () const + { + return m_name; + } + + /** + * @brief Gets the description text + */ + const std::string &description () const + { + return m_description; + } + + /** + * @brief An utility function to get a parameters + */ + template + static T get_value (const std::map ¶ms, const std::string &pname, const T &def_value) + { + std::map::const_iterator p = params.find (pname); + if (p != params.end ()) { + const tl::Variant &v = p->second; + return v.to (); + } else { + return def_value; + } + } + + /** + * @brief Serializes the given recipe + */ + std::string generator (const std::map ¶ms); + + /** + * @brief Executes the recipe from the generator + * + * Returns nil if the recipe can't be executed, e.g. because the recipe isn't known. + */ + static tl::Variant make (const std::string &generator); + + /** + * @brief Recipe interface: executes the recipe with the given parameters + */ + virtual tl::Variant execute (const std::map ¶ms) const = 0; + +private: + Recipe (const Recipe &) : tl::RegisteredClass (this) { } + Recipe &operator= (const Recipe &) { return *this; } + + std::string m_name; + std::string m_description; +}; + +template<> struct type_traits : public type_traits +{ + typedef tl::false_tag has_copy_constructor; + typedef tl::false_tag has_default_constructor; +}; + +} // namespace tl + +#endif + diff --git a/src/tl/unit_tests/tlRecipeTests.cc b/src/tl/unit_tests/tlRecipeTests.cc new file mode 100644 index 000000000..bf16eba78 --- /dev/null +++ b/src/tl/unit_tests/tlRecipeTests.cc @@ -0,0 +1,58 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2019 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "tlRecipe.h" +#include "tlUnitTest.h" + +#include + +namespace { + + class MyRecipe : public tl::Recipe + { + public: + MyRecipe () : tl::Recipe ("test_recipe", "description") { } + + tl::Variant execute (const std::map ¶ms) const + { + int a = get_value (params, "A", 0); + double b = get_value (params, "B", 0.0); + return tl::Variant (b * a); + } + }; + + static MyRecipe my_recipe; + +} + +// basic abilities +TEST(1) +{ + std::map params; + params["A"] = tl::Variant (7); + params["B"] = tl::Variant (6.0); + std::string g = my_recipe.generator (params); + EXPECT_EQ (g, "test_recipe: A=#7,B=##6"); + + tl::Variant res = tl::Recipe::make (g); + EXPECT_EQ (res.to_double (), 42.0); +} diff --git a/src/tl/unit_tests/unit_tests.pro b/src/tl/unit_tests/unit_tests.pro index 092699eef..989902872 100644 --- a/src/tl/unit_tests/unit_tests.pro +++ b/src/tl/unit_tests/unit_tests.pro @@ -38,7 +38,8 @@ SOURCES = \ tlListTests.cc \ tlEquivalenceClustersTests.cc \ tlUniqueNameTests.cc \ - tlGlobPatternTests.cc + tlGlobPatternTests.cc \ + tlRecipeTests.cc !equals(HAVE_QT, "0") { diff --git a/testdata/ruby/tlTest.rb b/testdata/ruby/tlTest.rb index eb439b1bd..e0369a353 100644 --- a/testdata/ruby/tlTest.rb +++ b/testdata/ruby/tlTest.rb @@ -262,6 +262,42 @@ class Tl_TestClass < TestBase end + class MyRecipe < RBA::Recipe + + def initialize + super("test_recipe", "description") + end + + def execute(params) + a = params["A"] || 0 + b = params["B"] || 0.0 + b * a + end + + end + + # Recipe + def test_4_Recipe + + # make sure there isn't a second instance + GC.start + + my_recipe = MyRecipe::new + my_recipe._create # makes debugging easier + + assert_equal(my_recipe.name, "test_recipe") + assert_equal(my_recipe.description, "description") + + g = my_recipe.generator("A" => 6, "B" => 7.0) + assert_equal(g, "test_recipe: A=#6,B=##7") + assert_equal("%g" % RBA::Recipe::make(g).to_s, "42") + + my_recipe._destroy + my_recipe = nil + GC.start + + end + end load("test_epilogue.rb") From 441f946f433dc69f2e257583c27a115d8b0705e0 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 25 Aug 2019 21:55:48 +0200 Subject: [PATCH 16/27] WIP: LVS rerun feature --- src/drc/drc/built-in-macros/_drc_engine.rb | 37 +++++++++- src/drc/drc/built-in-macros/_drc_netter.rb | 2 +- src/gsi/gsi/gsiDeclTl.cc | 16 +++-- src/laybasic/laybasic/NetlistBrowserPage.ui | 3 + src/laybasic/laybasic/gsiDeclLayLayoutView.cc | 28 +++++++- src/laybasic/laybasic/layLayoutView.cc | 31 +++++++++ src/laybasic/laybasic/layLayoutView.h | 11 +++ .../laybasic/layNetlistBrowserPage.cc | 22 ++++-- src/lvs/lvs/built-in-macros/_lvs_netter.rb | 2 +- .../lvs/built-in-macros/lvs_interpreters.lym | 69 ++++++++++++++----- src/lym/lym/gsiDeclLymMacro.cc | 45 ++++++------ src/rba/rba/rbaMarshal.cc | 13 ++++ src/tl/tl/tlRecipe.cc | 6 +- src/tl/tl/tlRecipe.h | 4 +- src/tl/unit_tests/tlRecipeTests.cc | 8 ++- testdata/ruby/tlTest.rb | 10 +-- 16 files changed, 239 insertions(+), 68 deletions(-) diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index ab1373625..5cd9fec55 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -20,6 +20,9 @@ module DRC cv = RBA::CellView::active + @generator = "" + @rdb_index = nil + @l2ndb_index = nil @def_layout = cv && cv.layout @def_cell = cv && cv.cell @def_path = cv && cv.filename @@ -780,7 +783,7 @@ module DRC cn || raise("No cell name specified - either the source was not specified before 'report' or there is no default source. In the latter case, specify a cell name as the third parameter of 'report'") @output_rdb_cell = @output_rdb.create_cell(cn) - @output_rdb.generator = $0 + @output_rdb.generator = self._generator @output_rdb.top_cell_name = cn @output_rdb.description = description @@ -1466,7 +1469,11 @@ CODE # NOTE: to prevent the netter destroying the database, we need to take it l2ndb = _take_data - l2ndb_index = view.add_l2ndb(l2ndb) + if self._l2ndb_index + l2ndb_index = view.replace_l2ndb(self._l2ndb_index, l2ndb) + else + l2ndb_index = view.add_l2ndb(l2ndb) + end view.show_l2ndb(l2ndb_index, view.active_cellview_index) end @@ -1551,6 +1558,30 @@ CODE end end + def _generator + @generator + end + + def _generator=(g) + @generator = g + end + + def _rdb_index + @rdb_index + end + + def _rdb_index=(i) + @rdb_index = i + end + + def _l2ndb_index + @l2ndb_index + end + + def _l2ndb_index=(i) + @l2ndb_index = i + end + private def _make_string(v) @@ -1717,7 +1748,7 @@ CODE @layout_sources[name] = src src end - + end end diff --git a/src/drc/drc/built-in-macros/_drc_netter.rb b/src/drc/drc/built-in-macros/_drc_netter.rb index 0763d6e54..a449ba5b1 100644 --- a/src/drc/drc/built-in-macros/_drc_netter.rb +++ b/src/drc/drc/built-in-macros/_drc_netter.rb @@ -407,7 +407,7 @@ module DRC @l2n = RBA::LayoutToNetlist::new(layout.top_cell.name, layout.dbu) end - @l2n.generator = $0 + @l2n.generator = @engine._generator end diff --git a/src/gsi/gsi/gsiDeclTl.cc b/src/gsi/gsi/gsiDeclTl.cc index 27f98a315..2874f388f 100644 --- a/src/gsi/gsi/gsiDeclTl.cc +++ b/src/gsi/gsi/gsiDeclTl.cc @@ -642,13 +642,15 @@ Class decl_GlobPattern ("tl", "GlobPattern", ); class Recipe_Impl - : public tl::Recipe + : public tl::Recipe, public gsi::ObjectBase { public: Recipe_Impl (const std::string &name, const std::string &description) : tl::Recipe (name, description) { - // .. nothing yet .. + // makes the object owned by the C++ side (registrar). This way we don't need to keep a + // singleton instance. + keep (); } virtual tl::Variant execute (const std::map ¶ms) const @@ -688,9 +690,11 @@ Class decl_Recipe_Impl ("tl", "Recipe", gsi::method ("description", &Recipe_Impl::description, "@brief Gets the description of the recipe." ) + - gsi::method ("make", &Recipe_Impl::make, gsi::arg ("generator"), + gsi::method ("make", &Recipe_Impl::make, gsi::arg ("generator"), gsi::arg ("add_params", std::map ()), "@brief Executes the recipe given by the generator string.\n" - "The generator string is the one delivered with \\generator." + "The generator string is the one delivered with \\generator.\n" + "Additional parameters can be passed in \"add_params\". They have lower priority than the parameters " + "kept inside the generator string." ) + gsi::method ("generator", &Recipe_Impl::generator, gsi::arg ("params"), "@brief Delivers the generator string from the given parameters.\n" @@ -711,9 +715,9 @@ Class decl_Recipe_Impl ("tl", "Recipe", "user requests a re-run of the DRC, the recipe will be called and \n" "the implementation is supposed to deliver a new database.\n" "\n" - "To register a recipe, reimplement tl::Recipe and create a singleton\n" + "To register a recipe, reimplement the Recipe class and create an\n" "instance. To serialize a recipe, use \"generator\", to execute the\n" - "recipe, use \"make\". \n" + "recipe, use \"make\".\n" "\n" "Parameters are kept as a generic key/value map.\n" "\n" diff --git a/src/laybasic/laybasic/NetlistBrowserPage.ui b/src/laybasic/laybasic/NetlistBrowserPage.ui index e341345cd..19d7438c1 100644 --- a/src/laybasic/laybasic/NetlistBrowserPage.ui +++ b/src/laybasic/laybasic/NetlistBrowserPage.ui @@ -141,6 +141,9 @@ :/run.png:/run.png + + F5 + true diff --git a/src/laybasic/laybasic/gsiDeclLayLayoutView.cc b/src/laybasic/laybasic/gsiDeclLayLayoutView.cc index 129ca2851..9dc052808 100644 --- a/src/laybasic/laybasic/gsiDeclLayLayoutView.cc +++ b/src/laybasic/laybasic/gsiDeclLayLayoutView.cc @@ -218,11 +218,17 @@ static db::LayoutVsSchematic *get_lvsdb (lay::LayoutView *view, unsigned int ind return dynamic_cast (db); } -static void add_lvsdb (lay::LayoutView *view, db::LayoutVsSchematic *lvsdb) +static unsigned int add_lvsdb (lay::LayoutView *view, db::LayoutVsSchematic *lvsdb) { - view->add_l2ndb (lvsdb); + return view->add_l2ndb (lvsdb); } +static unsigned int replace_lvsdb (lay::LayoutView *view, unsigned int db_index, db::LayoutVsSchematic *lvsdb) +{ + return view->replace_l2ndb (db_index, lvsdb); +} + + // this binding returns a const pointer which is not converted into a copy by RBA static lay::LayerPropertiesNodeRef insert_layer1 (lay::LayoutView *view, const lay::LayerPropertiesConstIterator &iter, const lay::LayerProperties &props) { @@ -1499,6 +1505,15 @@ Class decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou "\n" "This method has been added in version 0.26." ) + + gsi::method ("replace_l2ndb", &lay::LayoutView::replace_l2ndb, gsi::arg ("db_index"), gsi::arg ("db"), + "@brief Replaces the database with the given index\n" + "\n" + "If the index is not valid, the database will be added to the view (see \\add_lvsdb).\n" + "\n" + "@return The index of the database within the view (see \\lvsdb)\n" + "\n" + "This method has been added in version 0.26." + ) + gsi::method_ext ("create_l2ndb", &create_l2ndb, gsi::arg ("name"), "@brief Creates a new netlist database and returns the index of the new database\n" "@param name The name of the new netlist database\n" @@ -1532,6 +1547,15 @@ Class decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou "\n" "This method has been added in version 0.26." ) + + gsi::method_ext ("replace_lvsdb", &replace_lvsdb, gsi::arg ("db_index"), gsi::arg ("db"), + "@brief Replaces the database with the given index\n" + "\n" + "If the index is not valid, the database will be added to the view (see \\add_lvsdb).\n" + "\n" + "@return The index of the database within the view (see \\lvsdb)\n" + "\n" + "This method has been added in version 0.26." + ) + gsi::method_ext ("create_lvsdb", &create_lvsdb, gsi::arg ("name"), "@brief Creates a new netlist database and returns the index of the new database\n" "@param name The name of the new netlist database\n" diff --git a/src/laybasic/laybasic/layLayoutView.cc b/src/laybasic/laybasic/layLayoutView.cc index 3930c678c..3a2b0dbf2 100644 --- a/src/laybasic/laybasic/layLayoutView.cc +++ b/src/laybasic/laybasic/layLayoutView.cc @@ -7207,6 +7207,37 @@ LayoutView::add_l2ndb (db::LayoutToNetlist *l2ndb) return (unsigned int)(m_l2ndbs.size () - 1); } +unsigned int +LayoutView::replace_l2ndb (unsigned int db_index, db::LayoutToNetlist *l2ndb) +{ + if (db_index < m_l2ndbs.size ()) { + + std::string n = m_l2ndbs [db_index]->name (); + + delete m_l2ndbs [db_index]; + m_l2ndbs.erase (m_l2ndbs.begin () + db_index); + + // keep old name if possible + if (l2ndb->name ().empty ()) { + l2ndb->set_name (n); + } else { + make_unique_name (l2ndb, m_l2ndbs.begin (), m_l2ndbs.end ()); + } + + m_l2ndbs.insert (m_l2ndbs.begin () + db_index, l2ndb); + + // Mark this object as owned by us (for GSI) + l2ndb->keep (); + + l2ndb_list_changed_event (); + + return db_index; + + } else { + return add_l2ndb (l2ndb); + } +} + db::LayoutToNetlist * LayoutView::get_l2ndb (int index) { diff --git a/src/laybasic/laybasic/layLayoutView.h b/src/laybasic/laybasic/layLayoutView.h index cf5cbc8b9..548dd499d 100644 --- a/src/laybasic/laybasic/layLayoutView.h +++ b/src/laybasic/laybasic/layLayoutView.h @@ -2340,6 +2340,17 @@ public: */ unsigned int add_l2ndb (db::LayoutToNetlist *l2ndb); + /** + * @brief Replaces a Netlist database + * + * The layout view will become owner of the database. + * If the index is not valid, the database will be added and the new index will be returned. + * + * @param db_index The index of the database to replace + * @param l2ndb The database to add + */ + unsigned int replace_l2ndb (unsigned int db_index, db::LayoutToNetlist *l2ndb); + /** * @brief Get the netlist database by index * diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index c078a9e38..22d8e06db 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -30,9 +30,9 @@ #include "layMarker.h" #include "layNetInfoDialog.h" #include "layNetExportDialog.h" -#include "lymMacro.h" #include "tlProgress.h" #include "tlExceptions.h" +#include "tlRecipe.h" #include "dbLayoutToNetlist.h" #include "dbNetlistDeviceClasses.h" #include "dbCellMapping.h" @@ -600,13 +600,17 @@ NetlistBrowserPage::rerun_macro () { if (! mp_database->generator ().empty ()) { - lym::Macro *generator = lym::MacroCollection::root ().find_macro (mp_database->generator ()); - if (! generator) { - throw tl::Exception (tl::sprintf (tl::to_string (tr ("Cannot find generator script: %s")), mp_database->generator())); - } else { - generator->run (); + std::map add_pars; + + for (unsigned int i = 0; i < mp_view->num_l2ndbs (); ++i) { + if (mp_view->get_l2ndb (i) == mp_database.get ()) { + add_pars["l2ndb_index"] = tl::Variant (int (i)); + break; + } } + tl::Recipe::make (mp_database->generator (), add_pars); + } } void @@ -767,7 +771,11 @@ NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb) rerun_button->setEnabled (mp_database.get () && ! mp_database->generator ().empty ()); if (rerun_button->isEnabled ()) { - rerun_button->setToolTip (tl::to_qstring (tl::to_string (tr ("Run ")) + mp_database->generator ())); + QString shortcut; + if (! rerun_button->shortcut ().isEmpty ()) { + shortcut = QString::fromUtf8 (" (%1)").arg (rerun_button->shortcut ().toString ()); + } + rerun_button->setToolTip (tl::to_qstring (tl::to_string (tr ("Run ")) + mp_database->generator ()) + shortcut); } else { rerun_button->setToolTip (QString ()); } diff --git a/src/lvs/lvs/built-in-macros/_lvs_netter.rb b/src/lvs/lvs/built-in-macros/_lvs_netter.rb index a0b0b2cf8..9649cb49e 100644 --- a/src/lvs/lvs/built-in-macros/_lvs_netter.rb +++ b/src/lvs/lvs/built-in-macros/_lvs_netter.rb @@ -61,7 +61,7 @@ module LVS @lvs = RBA::LayoutVsSchematic::new(cell.name, layout.dbu) end - @lvs.generator = $0 + @lvs.generator = @engine._generator @l2n = @lvs @comparer = RBA::NetlistComparer::new diff --git a/src/lvs/lvs/built-in-macros/lvs_interpreters.lym b/src/lvs/lvs/built-in-macros/lvs_interpreters.lym index b72af993b..5c6e36eca 100644 --- a/src/lvs/lvs/built-in-macros/lvs_interpreters.lym +++ b/src/lvs/lvs/built-in-macros/lvs_interpreters.lym @@ -17,37 +17,39 @@ module LVS - def LVS.execute_lvs(_macro) + def self.execute_lvs(macro, generator, l2ndb_index = nil) - _timer = RBA::Timer::new - _timer.start - _lvs = LVSEngine::new + timer = RBA::Timer::new + timer.start + lvs = LVSEngine::new + lvs._l2ndb_index = l2ndb_index + lvs._generator = generator begin # Set a debugger scope so that our errors end up with the debugger set to the LVS's line - RBA::MacroExecutionContext::set_debugger_scope(_macro.path) + RBA::MacroExecutionContext::set_debugger_scope(macro.path) # No verbosity set in lvs engine - we cannot use the engine's logger - RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{_macro.path}") - _lvs.instance_eval(_macro.text, _macro.path) + RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{macro.path}") + lvs.instance_eval(macro.text, macro.path) # Remove the debugger scope RBA::MacroExecutionContext::remove_debugger_scope rescue => ex - _lvs.error("In #{_macro.path}: #{ex.to_s}") + lvs.error("In #{macro.path}: #{ex.to_s}") RBA::MacroExecutionContext::ignore_next_exception raise ex ensure # cleans up and creates layout and report views - _lvs._finish + lvs._finish end - _timer.stop - _lvs.info("Total run time: #{'%.3f'%(_timer.sys+_timer.user)}s") + timer.stop + lvs.info("Total run time: #{'%.3f'%(timer.sys+timer.user)}s") end @@ -55,7 +57,9 @@ module LVS class LVSInterpreter < RBA::MacroInterpreter # Constructor - def initialize + def initialize(recipe) + + @recipe = recipe # Make the DSL use ruby syntax highlighting self.syntax_scheme = "ruby" @@ -80,8 +84,7 @@ module LVS # Implements the execute method def execute(macro) - $0 = macro.path - LVS::execute_lvs(macro) + LVS::execute_lvs(macro, @recipe.generator("script" => macro.path)) end end @@ -90,7 +93,9 @@ module LVS class LVSPlainTextInterpreter < RBA::MacroInterpreter # Constructor - def initialize + def initialize(recipe) + + @recipe = recipe # Make the DSL use ruby syntax highlighting self.syntax_scheme = "ruby" @@ -106,15 +111,41 @@ module LVS # Implements the execute method def execute(macro) - LVS::execute_lvs(macro) + LVS::execute_lvs(macro, @recipe.generator("script" => macro.path)) end end + + # A recipe implementation allowing the LVS run to be redone + class LVSRecipe < RBA::Recipe + + def initialize + super("lvs", "LVS recipe") + end + + def execute(params) + + script = params["script"] + if ! script + return + end + + macro = RBA::Macro::macro_by_path(script) + macro || raise("Can't find LVS script #{script} - unable to re-run") + + LVS::execute_lvs(macro, self.generator("script" => script), params["l2ndb_index"]) + + end + + end - # Register the new interpreters - LVSInterpreter::new - LVSPlainTextInterpreter::new + # Register the recipe + lvs_recipe = LVSRecipe::new + # Register the new interpreters + LVSInterpreter::new(lvs_recipe) + LVSPlainTextInterpreter::new(lvs_recipe) + end diff --git a/src/lym/lym/gsiDeclLymMacro.cc b/src/lym/lym/gsiDeclLymMacro.cc index bf2bd56b7..6416bba2a 100644 --- a/src/lym/lym/gsiDeclLymMacro.cc +++ b/src/lym/lym/gsiDeclLymMacro.cc @@ -73,9 +73,8 @@ public: }; Class decl_MacroExecutionContext ("lay", "MacroExecutionContext", - gsi::method ("set_debugger_scope", &gsi::MacroExecutionContext::set_debugger_scope, + gsi::method ("set_debugger_scope", &gsi::MacroExecutionContext::set_debugger_scope, gsi::arg ("filename"), "@brief Sets a debugger scope (file level which shall appear in the debugger)\n" - "@args filename\n" "If a debugger scope is set, back traces will be produced starting from that scope. " "Setting a scope is useful for implementing DSL interpreters and giving a proper hint about " "the original location of an error." @@ -277,9 +276,8 @@ Class decl_MacroInterpreter ("lay", "MacroInterpreter", gsi::method ("NoDebugger", &const_NoDebugger, "@brief Indicates no debugging for \\debugger_scheme\n" ) + - gsi::method ("register", &MacroInterpreter::register_gsi, + gsi::method ("register", &MacroInterpreter::register_gsi, gsi::arg ("name"), "@brief Registers the macro interpreter\n" - "@args name\n" "@param name The interpreter name. This is an arbitrary string which should be unique.\n" "\n" "Registration of the interpreter makes the object known to the system. After registration, macros whose interpreter " @@ -351,9 +349,8 @@ Class decl_MacroInterpreter ("lay", "MacroInterpreter", "Before version 0.25 this attribute was a reimplementable method. It has been turned into an attribute for " "performance reasons in version 0.25.\n" ) + - gsi::callback ("execute", &gsi::MacroInterpreter::execute, &gsi::MacroInterpreter::f_execute, + gsi::callback ("execute", &gsi::MacroInterpreter::execute, &gsi::MacroInterpreter::f_execute, gsi::arg ("macro"), "@brief Gets called to execute a macro\n" - "@args macro\n" "This method must be reimplemented to execute the macro. " "The system will call this script when a macro with interpreter type 'dsl' and the " "name of this interpreter is run." @@ -424,6 +421,11 @@ Class decl_MacroInterpreter ("lay", "MacroInterpreter", "This class has been introduced in version 0.23.\n" ); +static lym::Macro *macro_by_path (const std::string &path) +{ + return lym::MacroCollection::root ().find_macro (path); +} + Class decl_Macro ("lay", "Macro", gsi::method ("path", &lym::Macro::path, "@brief Gets the path of the macro\n" @@ -431,6 +433,13 @@ Class decl_Macro ("lay", "Macro", "The path is the path where the macro is stored, starting with an abstract group identifier. " "The path is used to identify the macro in the debugger for example." ) + + gsi::method ("macro_by_path", ¯o_by_path, gsi::arg ("path"), + "@brief Finds the macro by installation path\n" + "\n" + "Returns nil if no macro with this path can be found.\n" + "\n" + "This method has been added in version 0.26." + ) + gsi::method ("name", &lym::Macro::name, "@brief Gets the name of the macro\n" "\n" @@ -443,9 +452,8 @@ Class decl_Macro ("lay", "Macro", "the description text can have the format \"Group;;Description\". In that case, the macro " "will appear in a group with title \"Group\"." ) + - gsi::method ("description=", &lym::Macro::set_description, + gsi::method ("description=", &lym::Macro::set_description, gsi::arg ("description"), "@brief Sets the description text\n" - "@args description\n" "@param description The description text.\n" "See \\description for details.\n" ) + @@ -455,9 +463,8 @@ Class decl_Macro ("lay", "Macro", "The prolog is executed before the actual code is executed. Interpretation depends on the " "implementation of the DSL interpreter for DSL macros." ) + - gsi::method ("prolog=", &lym::Macro::set_prolog, + gsi::method ("prolog=", &lym::Macro::set_prolog, gsi::arg ("string"), "@brief Sets the prolog\n" - "@args string\n" "See \\prolog for details.\n" ) + gsi::method ("epilog", &lym::Macro::epilog, @@ -466,9 +473,8 @@ Class decl_Macro ("lay", "Macro", "The epilog is executed after the actual code is executed. Interpretation depends on the " "implementation of the DSL interpreter for DSL macros." ) + - gsi::method ("epilog=", &lym::Macro::set_epilog, + gsi::method ("epilog=", &lym::Macro::set_epilog, gsi::arg ("string"), "@brief Sets the epilog\n" - "@args string\n" "See \\epilog for details.\n" ) + gsi::method ("category", &lym::Macro::category, @@ -477,9 +483,8 @@ Class decl_Macro ("lay", "Macro", "The category tags string indicates to which categories a macro will belong to. This string " "is only used for templates currently and is a comma-separated list of category names." ) + - gsi::method ("category=", &lym::Macro::set_category, + gsi::method ("category=", &lym::Macro::set_category, gsi::arg ("string"), "@brief Sets the category tags string\n" - "@args string\n" "See \\category for details.\n" ) + gsi::method ("text", &lym::Macro::text, @@ -488,17 +493,15 @@ Class decl_Macro ("lay", "Macro", "The text is the code executed by the macro interpreter. " "Depending on the DSL interpreter, the text can be any kind of code." ) + - gsi::method ("text=", &lym::Macro::set_text, + gsi::method ("text=", &lym::Macro::set_text, gsi::arg ("string"), "@brief Sets the macro text\n" - "@args string\n" "See \\text for details.\n" ) + gsi::method ("show_in_menu?", &lym::Macro::show_in_menu, "@brief Gets a value indicating whether the macro shall be shown in the menu\n" ) + - gsi::method ("show_in_menu=", &lym::Macro::set_show_in_menu, + gsi::method ("show_in_menu=", &lym::Macro::set_show_in_menu, gsi::arg ("flag"), "@brief Sets a value indicating whether the macro shall be shown in the menu\n" - "@args flag\n" ) + gsi::method ("group_name", &lym::Macro::group_name, "@brief Gets the menu group name\n" @@ -506,9 +509,8 @@ Class decl_Macro ("lay", "Macro", "If a group name is specified and \\show_in_menu? is true, the macro will appear in " "a separate group (separated by a separator) together with other macros sharing the same group." ) + - gsi::method ("group_name=", &lym::Macro::set_group_name, + gsi::method ("group_name=", &lym::Macro::set_group_name, gsi::arg ("string"), "@brief Sets the menu group name\n" - "@args string\n" "See \\group_name for details.\n" ) + gsi::method ("menu_path", &lym::Macro::menu_path, @@ -517,9 +519,8 @@ Class decl_Macro ("lay", "Macro", "If a menu path is specified and \\show_in_menu? is true, the macro will appear in " "the menu at the specified position." ) + - gsi::method ("menu_path=", &lym::Macro::set_menu_path, + gsi::method ("menu_path=", &lym::Macro::set_menu_path, gsi::arg ("string"), "@brief Sets the menu path\n" - "@args string\n" "See \\menu_path for details.\n" ), "@brief A macro class\n" diff --git a/src/rba/rba/rbaMarshal.cc b/src/rba/rba/rbaMarshal.cc index 7b0b0d9ad..df03434fe 100644 --- a/src/rba/rba/rbaMarshal.cc +++ b/src/rba/rba/rbaMarshal.cc @@ -350,8 +350,14 @@ struct writer aa->write ((void *)0); } } else { + + if (TYPE (arg) != T_ARRAY) { + throw tl::Exception (tl::sprintf (tl::to_string (tr ("Unexpected object type (expected array, got %s)")), rba_class_name (arg).c_str ())); + } + tl_assert (atype.inner () != 0); aa->write ((void *)new RubyBasedVectorAdaptor (arg, atype.inner ())); + } } }; @@ -370,10 +376,17 @@ struct writer } else { aa->write ((void *)0); } + } else { + + if (TYPE (arg) != T_HASH) { + throw tl::Exception (tl::sprintf (tl::to_string (tr ("Unexpected object type (expected hash, got %s)")), rba_class_name (arg).c_str ())); + } + tl_assert (atype.inner () != 0); tl_assert (atype.inner_k () != 0); aa->write ((void *)new RubyBasedMapAdaptor (arg, atype.inner (), atype.inner_k ())); + } } }; diff --git a/src/tl/tl/tlRecipe.cc b/src/tl/tl/tlRecipe.cc index 3d02bb8ac..157280a32 100644 --- a/src/tl/tl/tlRecipe.cc +++ b/src/tl/tl/tlRecipe.cc @@ -51,7 +51,7 @@ std::string Recipe::generator (const std::map ¶ms) return g; } -tl::Variant Recipe::make (const std::string &generator) +tl::Variant Recipe::make (const std::string &generator, const std::map &padd) { tl::Extractor ex (generator.c_str ()); @@ -70,6 +70,10 @@ tl::Variant Recipe::make (const std::string &generator) params.insert (std::make_pair (key, v)); } + for (std::map::const_iterator p = padd.begin (); p != padd.end (); ++p) { + params.insert (*p); + } + tl::Recipe *recipe_obj = 0; for (tl::Registrar::iterator r = tl::Registrar::begin (); r != tl::Registrar::end (); ++r) { if (r->name () == recipe) { diff --git a/src/tl/tl/tlRecipe.h b/src/tl/tl/tlRecipe.h index 700df550e..900b48ed1 100644 --- a/src/tl/tl/tlRecipe.h +++ b/src/tl/tl/tlRecipe.h @@ -104,8 +104,10 @@ public: * @brief Executes the recipe from the generator * * Returns nil if the recipe can't be executed, e.g. because the recipe isn't known. + * Additional parameters can be passed in the second argument. + * They have lower priority than the parameters kept in the generator argument. */ - static tl::Variant make (const std::string &generator); + static tl::Variant make (const std::string &generator, const std::map ¶ms = std::map ()); /** * @brief Recipe interface: executes the recipe with the given parameters diff --git a/src/tl/unit_tests/tlRecipeTests.cc b/src/tl/unit_tests/tlRecipeTests.cc index bf16eba78..21bbc3f50 100644 --- a/src/tl/unit_tests/tlRecipeTests.cc +++ b/src/tl/unit_tests/tlRecipeTests.cc @@ -36,7 +36,8 @@ namespace { { int a = get_value (params, "A", 0); double b = get_value (params, "B", 0.0); - return tl::Variant (b * a); + double c = get_value (params, "C", 1.0); + return tl::Variant (b * a * c); } }; @@ -55,4 +56,9 @@ TEST(1) tl::Variant res = tl::Recipe::make (g); EXPECT_EQ (res.to_double (), 42.0); + + std::map padd; + padd["C"] = tl::Variant(1.5); + res = tl::Recipe::make (g, padd); + EXPECT_EQ (res.to_double (), 63.0); } diff --git a/testdata/ruby/tlTest.rb b/testdata/ruby/tlTest.rb index e0369a353..bb55b9ea5 100644 --- a/testdata/ruby/tlTest.rb +++ b/testdata/ruby/tlTest.rb @@ -265,13 +265,14 @@ class Tl_TestClass < TestBase class MyRecipe < RBA::Recipe def initialize - super("test_recipe", "description") + super("rba_test_recipe", "description") end def execute(params) a = params["A"] || 0 b = params["B"] || 0.0 - b * a + c = params["C"] || 1.0 + b * a * c end end @@ -285,12 +286,13 @@ class Tl_TestClass < TestBase my_recipe = MyRecipe::new my_recipe._create # makes debugging easier - assert_equal(my_recipe.name, "test_recipe") + assert_equal(my_recipe.name, "rba_test_recipe") assert_equal(my_recipe.description, "description") g = my_recipe.generator("A" => 6, "B" => 7.0) - assert_equal(g, "test_recipe: A=#6,B=##7") + assert_equal(g, "rba_test_recipe: A=#6,B=##7") assert_equal("%g" % RBA::Recipe::make(g).to_s, "42") + assert_equal("%g" % RBA::Recipe::make(g, "C" => 1.5).to_s, "63") my_recipe._destroy my_recipe = nil From db9ea273248d80f87893133c7569fb10fd5598a1 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 25 Aug 2019 23:47:55 +0200 Subject: [PATCH 17/27] Re-run feature for DRC too. --- src/drc/drc/built-in-macros/_drc_engine.rb | 15 +- src/drc/drc/built-in-macros/_drc_netter.rb | 1 + .../drc/built-in-macros/drc_interpreters.lym | 67 +++-- src/laybasic/laybasic/MarkerBrowserDialog.ui | 283 ++++++++++-------- src/laybasic/laybasic/MarkerBrowserPage.ui | 195 ++++++++---- src/laybasic/laybasic/gsiDeclLayLayoutView.cc | 15 +- src/laybasic/laybasic/layLayoutView.cc | 43 ++- src/laybasic/laybasic/layLayoutView.h | 11 + .../laybasic/layNetlistBrowserPage.cc | 1 + .../laybasic/rdbMarkerBrowserDialog.cc | 1 + src/laybasic/laybasic/rdbMarkerBrowserPage.cc | 42 ++- src/laybasic/laybasic/rdbMarkerBrowserPage.h | 4 + src/lvs/lvs/built-in-macros/_lvs_netter.rb | 1 + 13 files changed, 450 insertions(+), 229 deletions(-) diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index 5cd9fec55..f513aef6d 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -763,10 +763,17 @@ module DRC name = filename && File::basename(filename) name ||= "DRC" - lv = RBA::LayoutView::current - if lv - @output_rdb_index = lv.create_rdb(name) - @output_rdb = lv.rdb(@output_rdb_index) + @output_rdb_index = nil + + view = RBA::LayoutView::current + if view + if self._rdb_index + @output_rdb = RBA::ReportDatabase::new("") # reuse existing name + @output_rdb_index = view.replace_rdb(self._rdb_index, @output_rdb) + else + @output_rdb = RBA::ReportDatabase::new(name) + @output_rdb_index = view.add_rdb(@output_rdb) + end else @output_rdb = RBA::ReportDatabase::new(name) end diff --git a/src/drc/drc/built-in-macros/_drc_netter.rb b/src/drc/drc/built-in-macros/_drc_netter.rb index a449ba5b1..1a7f70ef6 100644 --- a/src/drc/drc/built-in-macros/_drc_netter.rb +++ b/src/drc/drc/built-in-macros/_drc_netter.rb @@ -407,6 +407,7 @@ module DRC @l2n = RBA::LayoutToNetlist::new(layout.top_cell.name, layout.dbu) end + @l2n.name = "DRC" @l2n.generator = @engine._generator end diff --git a/src/drc/drc/built-in-macros/drc_interpreters.lym b/src/drc/drc/built-in-macros/drc_interpreters.lym index 5818c23d7..6ada00b60 100644 --- a/src/drc/drc/built-in-macros/drc_interpreters.lym +++ b/src/drc/drc/built-in-macros/drc_interpreters.lym @@ -17,37 +17,39 @@ module DRC - def DRC.execute_drc(_macro) + def DRC.execute_drc(macro, generator, rdb_index = nil) - _timer = RBA::Timer::new - _timer.start - _drc = DRCEngine::new + timer = RBA::Timer::new + timer.start + drc = DRCEngine::new + drc._rdb_index = rdb_index + drc._generator = generator begin # Set a debugger scope so that our errors end up with the debugger set to the DRC's line - RBA::MacroExecutionContext::set_debugger_scope(_macro.path) + RBA::MacroExecutionContext::set_debugger_scope(macro.path) # No verbosity set in drc engine - we cannot use the engine's logger - RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{_macro.path}") - _drc.instance_eval(_macro.text, _macro.path) + RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{macro.path}") + drc.instance_eval(macro.text, macro.path) # Remove the debugger scope RBA::MacroExecutionContext::remove_debugger_scope rescue => ex - _drc.error("In #{_macro.path}: #{ex.to_s}") + drc.error("In #{macro.path}: #{ex.to_s}") RBA::MacroExecutionContext::ignore_next_exception raise ex ensure # cleans up and creates layout and report views - _drc._finish + drc._finish end - _timer.stop - _drc.info("Total run time: #{'%.3f'%(_timer.sys+_timer.user)}s") + timer.stop + drc.info("Total run time: #{'%.3f'%(timer.sys+timer.user)}s") end @@ -55,7 +57,9 @@ module DRC class DRCInterpreter < RBA::MacroInterpreter # Constructor - def initialize + def initialize(recipe) + + @recipe = recipe # Make the DSL use ruby syntax highlighting self.syntax_scheme = "ruby" @@ -74,8 +78,7 @@ module DRC # Implements the execute method def execute(macro) - $0 = macro.path - DRC::execute_drc(macro) + DRC::execute_drc(macro, @recipe.generator("script" => macro.path)) end end @@ -84,7 +87,9 @@ module DRC class DRCPlainTextInterpreter < RBA::MacroInterpreter # Constructor - def initialize + def initialize(recipe) + + @recipe = recipe # Make the DSL use ruby syntax highlighting self.syntax_scheme = "ruby" @@ -100,14 +105,40 @@ module DRC # Implements the execute method def execute(macro) - DRC::execute_drc(macro) + DRC::execute_drc(macro, @recipe.generator("script" => macro.path)) end end + # A recipe implementation allowing the LVS run to be redone + class DRCRecipe < RBA::Recipe + + def initialize + super("drc", "DRC recipe") + end + + def execute(params) + + script = params["script"] + if ! script + return + end + + macro = RBA::Macro::macro_by_path(script) + macro || raise("Can't find DRC script #{script} - unable to re-run") + + DRC::execute_drc(macro, self.generator("script" => script), params["rdb_index"]) + + end + + end + + # Register the recipe + drc_recipe = DRCRecipe::new + # Register the new interpreters - DRCInterpreter::new - DRCPlainTextInterpreter::new + DRCInterpreter::new(drc_recipe) + DRCPlainTextInterpreter::new(drc_recipe) end diff --git a/src/laybasic/laybasic/MarkerBrowserDialog.ui b/src/laybasic/laybasic/MarkerBrowserDialog.ui index d7c11abb5..1a7dc53d0 100644 --- a/src/laybasic/laybasic/MarkerBrowserDialog.ui +++ b/src/laybasic/laybasic/MarkerBrowserDialog.ui @@ -1,7 +1,8 @@ - + + MarkerBrowserDialog - - + + 0 0 @@ -9,40 +10,75 @@ 553 - + Marker Database Browser - - - 9 - - + + 6 + + 9 + + + 9 + + + 9 + + + 9 + - - + + QFrame::NoFrame - + QFrame::Raised - - + + 0 - + + 0 + + + 0 + + + 0 + + 6 - + + + + File ... + + + QToolButton::InstantPopup + + + + + + + ... on layout + + + + - + Qt::Horizontal - + QSizePolicy::Fixed - + 20 20 @@ -50,152 +86,133 @@ - - - - - 7 - 0 + + + + 1 0 - + QComboBox::AdjustToContentsOnFirstShow - - - + + + Database - - - - ... on layout - - - - - - - - 7 - 0 + + + + 1 0 - + QComboBox::AdjustToContentsOnFirstShow - - - - File ... - - - QToolButton::InstantPopup - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 10 - - - - - - - Qt::Horizontal - - - - - - + + QFrame::NoFrame - + QFrame::Raised - - - 0 - - + + 6 + + 0 + + + 0 + + + 0 + + + 0 + - - + + 1 - - - - 0 - - + + + 6 + + 0 + + + 0 + + + 0 + + + 0 + - - - - 13 - 13 + + + 0 0 - + QFrame::NoFrame - + QFrame::Raised - - - - 0 - - + + + 6 + + 0 + + + 0 + + + 0 + + + 0 + - - - Choose "Open" from the "File ..." menu + + + Choose "Open" from the "File ..." menu to load a marker database - + Qt::AlignCenter - + true @@ -208,40 +225,49 @@ to load a marker database - - + + Qt::Horizontal - - + + QFrame::NoFrame - + QFrame::Raised - - - 0 - - + + 6 + + 0 + + + 0 + + + 0 + + + 0 + - - + + Configure - + Qt::Horizontal - + 40 20 @@ -250,8 +276,8 @@ to load a marker database - - + + Close @@ -266,6 +292,7 @@ to load a marker database rdb::MarkerBrowserPage QFrame

rdbMarkerBrowserPage.h
+ 1 @@ -282,11 +309,11 @@ to load a marker database MarkerBrowserDialog accept() - + 837 441 - + 881 387 diff --git a/src/laybasic/laybasic/MarkerBrowserPage.ui b/src/laybasic/laybasic/MarkerBrowserPage.ui index 682d9ae9c..d352c1916 100644 --- a/src/laybasic/laybasic/MarkerBrowserPage.ui +++ b/src/laybasic/laybasic/MarkerBrowserPage.ui @@ -13,7 +13,7 @@ Form - + 6 @@ -29,6 +29,73 @@ 0 + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + ... + + + + :/run.png:/run.png + + + F5 + + + true + + + + + + + Qt::Vertical + + + + 20 + 11 + + + + + + + + Qt::Horizontal + + + + + + @@ -63,69 +130,6 @@ 6 - - - - ... - - - - :/down.png:/down.png - - - - - - - ... - - - - :/up.png:/up.png - - - - - - - - 0 - 0 - - - - - 0 - 4 - - - - Qt::ActionsContextMenu - - - QAbstractItemView::ExtendedSelection - - - QAbstractItemView::SelectRows - - - true - - - true - - - true - - - - - - - Directory - - - @@ -237,6 +241,69 @@ + + + + ... + + + + :/down.png:/down.png + + + + + + + ... + + + + :/up.png:/up.png + + + + + + + + 0 + 0 + + + + + 0 + 4 + + + + Qt::ActionsContextMenu + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows + + + true + + + true + + + true + + + + + + + Directory + + + diff --git a/src/laybasic/laybasic/gsiDeclLayLayoutView.cc b/src/laybasic/laybasic/gsiDeclLayLayoutView.cc index 9dc052808..2e0b3d44c 100644 --- a/src/laybasic/laybasic/gsiDeclLayLayoutView.cc +++ b/src/laybasic/laybasic/gsiDeclLayLayoutView.cc @@ -1448,7 +1448,7 @@ Class decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou "@return The \\ReportDatabase object or nil if the index is not valid" ) + gsi::method ("add_rdb", &lay::LayoutView::add_rdb, gsi::arg ("db"), - "@brief Adds the given database to the view\n" + "@brief Adds the given report database to the view\n" "\n" "This method will add an existing database to the view. It will then appear in the marker database browser.\n" "A similar method is \\create_rdb which will create a new database within the view.\n" @@ -1457,6 +1457,15 @@ Class decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou "\n" "This method has been added in version 0.26." ) + + gsi::method ("replace_rdb", &lay::LayoutView::replace_rdb, gsi::arg ("db_index"), gsi::arg ("db"), + "@brief Replaces the report database with the given index\n" + "\n" + "If the index is not valid, the database will be added to the view (see \\add_rdb).\n" + "\n" + "@return The index of the database within the view (see \\rdb)\n" + "\n" + "This method has been added in version 0.26." + ) + gsi::method_ext ("create_rdb", &create_rdb, gsi::arg ("name"), "@brief Creates a new report database and returns the index of the new database\n" "@param name The name of the new report database\n" @@ -1496,7 +1505,7 @@ Class decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou "This method has been added in version 0.26." ) + gsi::method ("add_l2ndb", &lay::LayoutView::add_l2ndb, gsi::arg ("db"), - "@brief Adds the given database to the view\n" + "@brief Adds the given netlist database to the view\n" "\n" "This method will add an existing database to the view. It will then appear in the netlist database browser.\n" "A similar method is \\create_l2ndb which will create a new database within the view.\n" @@ -1506,7 +1515,7 @@ Class decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou "This method has been added in version 0.26." ) + gsi::method ("replace_l2ndb", &lay::LayoutView::replace_l2ndb, gsi::arg ("db_index"), gsi::arg ("db"), - "@brief Replaces the database with the given index\n" + "@brief Replaces the netlist database with the given index\n" "\n" "If the index is not valid, the database will be added to the view (see \\add_lvsdb).\n" "\n" diff --git a/src/laybasic/laybasic/layLayoutView.cc b/src/laybasic/laybasic/layLayoutView.cc index 3a2b0dbf2..b6d2f791a 100644 --- a/src/laybasic/laybasic/layLayoutView.cc +++ b/src/laybasic/laybasic/layLayoutView.cc @@ -7210,21 +7210,16 @@ LayoutView::add_l2ndb (db::LayoutToNetlist *l2ndb) unsigned int LayoutView::replace_l2ndb (unsigned int db_index, db::LayoutToNetlist *l2ndb) { + tl_assert (l2ndb != 0); + if (db_index < m_l2ndbs.size ()) { + // keep the name as it is used for reference in the browser for example std::string n = m_l2ndbs [db_index]->name (); + l2ndb->set_name (n); delete m_l2ndbs [db_index]; - m_l2ndbs.erase (m_l2ndbs.begin () + db_index); - - // keep old name if possible - if (l2ndb->name ().empty ()) { - l2ndb->set_name (n); - } else { - make_unique_name (l2ndb, m_l2ndbs.begin (), m_l2ndbs.end ()); - } - - m_l2ndbs.insert (m_l2ndbs.begin () + db_index, l2ndb); + m_l2ndbs [db_index] = l2ndb; // Mark this object as owned by us (for GSI) l2ndb->keep (); @@ -7280,7 +7275,7 @@ LayoutView::remove_l2ndb (unsigned int index) unsigned int LayoutView::add_rdb (rdb::Database *rdb) { - make_unique_name (rdb, m_l2ndbs.begin (), m_l2ndbs.end ()); + make_unique_name (rdb, m_rdbs.begin (), m_rdbs.end ()); m_rdbs.push_back (rdb); // Mark this object as owned by us (for GSI) @@ -7291,6 +7286,32 @@ LayoutView::add_rdb (rdb::Database *rdb) return (unsigned int)(m_rdbs.size () - 1); } +unsigned int +LayoutView::replace_rdb (unsigned int db_index, rdb::Database *rdb) +{ + tl_assert (rdb != 0); + + if (db_index < m_rdbs.size ()) { + + // keep name because it's used for reference in the browser for example + std::string n = m_rdbs [db_index]->name (); + rdb->set_name (n); + + delete m_rdbs [db_index]; + m_rdbs [db_index] = rdb; + + // Mark this object as owned by us (for GSI) + rdb->keep (); + + rdb_list_changed_event (); + + return db_index; + + } else { + return add_rdb (rdb); + } +} + rdb::Database * LayoutView::get_rdb (int index) { diff --git a/src/laybasic/laybasic/layLayoutView.h b/src/laybasic/laybasic/layLayoutView.h index 548dd499d..d562d74ca 100644 --- a/src/laybasic/laybasic/layLayoutView.h +++ b/src/laybasic/laybasic/layLayoutView.h @@ -2285,6 +2285,17 @@ public: */ unsigned int add_rdb (rdb::Database *rdb); + /** + * @brief Replaces a marker database + * + * The layout view will become owner of the database. + * If the index is not valid, the database will be added and the new index will be returned. + * + * @param db_index The index of the database to replace + * @param rdb The database to add + */ + unsigned int replace_rdb (unsigned int db_index, rdb::Database *rdb); + /** * @brief Get the marker database by index * diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index 22d8e06db..b47b7fd09 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -613,6 +613,7 @@ NetlistBrowserPage::rerun_macro () } } + void NetlistBrowserPage::info_button_pressed () { diff --git a/src/laybasic/laybasic/rdbMarkerBrowserDialog.cc b/src/laybasic/laybasic/rdbMarkerBrowserDialog.cc index 680540389..b599eeb58 100644 --- a/src/laybasic/laybasic/rdbMarkerBrowserDialog.cc +++ b/src/laybasic/laybasic/rdbMarkerBrowserDialog.cc @@ -671,6 +671,7 @@ MarkerBrowserDialog::update_content () m_reload_action->setEnabled (rdb != 0); browser_frame->enable_updates (false); // Avoid building the internal lists several times ... + browser_frame->set_rdb (0); // force update browser_frame->set_rdb (rdb); browser_frame->set_max_marker_count (m_max_marker_count); browser_frame->set_marker_style (m_marker_color, m_marker_line_width, m_marker_vertex_size, m_marker_halo, m_marker_dither_pattern); diff --git a/src/laybasic/laybasic/rdbMarkerBrowserPage.cc b/src/laybasic/laybasic/rdbMarkerBrowserPage.cc index 1948b6f95..ef268bb1b 100644 --- a/src/laybasic/laybasic/rdbMarkerBrowserPage.cc +++ b/src/laybasic/laybasic/rdbMarkerBrowserPage.cc @@ -26,6 +26,7 @@ #include "dbLayoutUtils.h" +#include "tlRecipe.h" #include "layLayoutView.h" #include "layMarker.h" @@ -1463,7 +1464,8 @@ MarkerBrowserPage::MarkerBrowserPage (QWidget * /*parent*/) m_marker_list_sort_order (Qt::DescendingOrder), m_directory_tree_sorted_section (-1), m_directory_tree_sort_order (Qt::DescendingOrder), - mp_plugin_root (0) + mp_plugin_root (0), + dm_rerun_macro (this, &MarkerBrowserPage::rerun_macro) { Ui::MarkerBrowserPage::setupUi (this); @@ -1514,6 +1516,7 @@ MarkerBrowserPage::MarkerBrowserPage (QWidget * /*parent*/) connect (info_text, SIGNAL (anchorClicked (const QUrl &)), this, SLOT (info_anchor_clicked (const QUrl &))); connect (cat_filter, SIGNAL (textEdited (const QString &)), this, SLOT (filter_changed ())); connect (cell_filter, SIGNAL (textEdited (const QString &)), this, SLOT (filter_changed ())); + connect (rerun_button, SIGNAL (pressed ()), this, SLOT (rerun_button_pressed ())); m_show_all_action = new QAction (QObject::tr ("Show All"), this); m_show_all_action->setCheckable (true); @@ -1678,6 +1681,17 @@ MarkerBrowserPage::set_rdb (rdb::Database *database) mp_database = database; + rerun_button->setEnabled (mp_database && ! mp_database->generator ().empty ()); + if (rerun_button->isEnabled ()) { + QString shortcut; + if (! rerun_button->shortcut ().isEmpty ()) { + shortcut = QString::fromUtf8 (" (%1)").arg (rerun_button->shortcut ().toString ()); + } + rerun_button->setToolTip (tl::to_qstring (tl::to_string (tr ("Run ")) + mp_database->generator ()) + shortcut); + } else { + rerun_button->setToolTip (QString ()); + } + QAbstractItemModel *tree_model = directory_tree->model (); MarkerBrowserTreeViewModel *new_model = new MarkerBrowserTreeViewModel (); @@ -2643,6 +2657,32 @@ MarkerBrowserPage::flag_button_clicked () list_model->mark_data_changed (); } +void +MarkerBrowserPage::rerun_button_pressed () +{ + // NOTE: we use deferred execution, because otherwise the button won't get repainted properly + dm_rerun_macro (); +} + +void +MarkerBrowserPage::rerun_macro () +{ + if (! mp_database->generator ().empty ()) { + + std::map add_pars; + + for (unsigned int i = 0; i < mp_view->num_rdbs (); ++i) { + if (mp_view->get_rdb (i) == mp_database) { + add_pars["rdb_index"] = tl::Variant (int (i)); + break; + } + } + + tl::Recipe::make (mp_database->generator (), add_pars); + + } +} + void MarkerBrowserPage::flag_menu_selected () { diff --git a/src/laybasic/laybasic/rdbMarkerBrowserPage.h b/src/laybasic/laybasic/rdbMarkerBrowserPage.h index 66cd279a9..508bbf050 100644 --- a/src/laybasic/laybasic/rdbMarkerBrowserPage.h +++ b/src/laybasic/laybasic/rdbMarkerBrowserPage.h @@ -26,6 +26,7 @@ #include "ui_MarkerBrowserPage.h" #include "rdbMarkerBrowser.h" +#include "tlDeferredExecution.h" #include "dbBox.h" #include @@ -155,6 +156,7 @@ public slots: void dir_down_clicked (); void list_up_clicked (); void list_down_clicked (); + void rerun_button_pressed (); void flag_button_clicked (); void flag_menu_selected (); void important_button_clicked (); @@ -205,6 +207,7 @@ private: int m_directory_tree_sorted_section; Qt::SortOrder m_directory_tree_sort_order; lay::PluginRoot *mp_plugin_root; + tl::DeferredMethod dm_rerun_macro; void release_markers (); void update_marker_list (int selection_mode); @@ -214,6 +217,7 @@ private: void mark_visited (bool visited); void do_update_markers (); void update_info_text (); + void rerun_macro (); }; } // namespace rdb diff --git a/src/lvs/lvs/built-in-macros/_lvs_netter.rb b/src/lvs/lvs/built-in-macros/_lvs_netter.rb index 9649cb49e..26f45bb00 100644 --- a/src/lvs/lvs/built-in-macros/_lvs_netter.rb +++ b/src/lvs/lvs/built-in-macros/_lvs_netter.rb @@ -61,6 +61,7 @@ module LVS @lvs = RBA::LayoutVsSchematic::new(cell.name, layout.dbu) end + @lvs.name = "LVS" @lvs.generator = @engine._generator @l2n = @lvs From 3a1271459338e686350129ac4ff079eb2910bc97 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 26 Aug 2019 18:55:35 +0200 Subject: [PATCH 18/27] Fixed some doc issues, added doc for hierarchical compare. --- src/db/db/gsiDeclDbCell.cc | 2 +- src/gsi/gsi/gsiDeclTl.cc | 6 ++-- src/lay/lay/doc/manual/lvs_compare.xml | 48 ++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/db/db/gsiDeclDbCell.cc b/src/db/db/gsiDeclDbCell.cc index a68571bfe..fa1031472 100644 --- a/src/db/db/gsiDeclDbCell.cc +++ b/src/db/db/gsiDeclDbCell.cc @@ -3960,7 +3960,7 @@ Class decl_Instance ("db", "Instance", "\n" "If the instance is a PCell instance, this method will convert the cell into a static cell and " "remove the PCell variant if required. A new cell will be created containing the PCell content " - "but begin a static cell. If the instance is not a PCell instance, this method will not do anything.\n" + "but being a static cell. If the instance is not a PCell instance, this method won't do anything.\n" "\n" "This method has been introduced in version 0.24." ) + diff --git a/src/gsi/gsi/gsiDeclTl.cc b/src/gsi/gsi/gsiDeclTl.cc index 2874f388f..9243cbcfb 100644 --- a/src/gsi/gsi/gsiDeclTl.cc +++ b/src/gsi/gsi/gsiDeclTl.cc @@ -681,7 +681,7 @@ static Recipe_Impl *make_recipe (const std::string &name, const std::string &des } Class decl_Recipe_Impl ("tl", "Recipe", - gsi::constructor ("new", &make_recipe, gsi::arg ("name"), gsi::arg ("description", std::string ()), + gsi::constructor ("new", &make_recipe, gsi::arg ("name"), gsi::arg ("description", std::string (), "\"\""), "@brief Creates a new recipe object with the given name and (optional) description" ) + gsi::method ("name", &Recipe_Impl::name, @@ -690,7 +690,7 @@ Class decl_Recipe_Impl ("tl", "Recipe", gsi::method ("description", &Recipe_Impl::description, "@brief Gets the description of the recipe." ) + - gsi::method ("make", &Recipe_Impl::make, gsi::arg ("generator"), gsi::arg ("add_params", std::map ()), + gsi::method ("make", &Recipe_Impl::make, gsi::arg ("generator"), gsi::arg ("add_params", std::map (), "{}"), "@brief Executes the recipe given by the generator string.\n" "The generator string is the one delivered with \\generator.\n" "Additional parameters can be passed in \"add_params\". They have lower priority than the parameters " @@ -700,7 +700,7 @@ Class decl_Recipe_Impl ("tl", "Recipe", "@brief Delivers the generator string from the given parameters.\n" "The generator string can be used with \\make to re-run the recipe." ) + - gsi::callback ("execute", &Recipe_Impl::execute, &Recipe_Impl::execute_cb, + gsi::callback ("execute", &Recipe_Impl::execute, &Recipe_Impl::execute_cb, gsi::arg ("params"), "@brief Reimplement this method to provide the functionality of the recipe.\n" "This method is supposed to re-run the recipe with the given parameters and deliver the " "the intended output object." diff --git a/src/lay/lay/doc/manual/lvs_compare.xml b/src/lay/lay/doc/manual/lvs_compare.xml index 1908fd2a1..72e60825e 100644 --- a/src/lay/lay/doc/manual/lvs_compare.xml +++ b/src/lay/lay/doc/manual/lvs_compare.xml @@ -125,6 +125,54 @@ same_device_classes("NMOS_IN_LAYOUT", "NMOS_IN_SCHEMATIC")
min_caps(1e-16)
+

Compare and netlist hierarchy

+ +

+ Good layouts are built hierarchically and the netlist compare can make use + of hierarchy. "Hierarchically" means that a circuit is built from cells + which itself map to subcircuits of the schematic netlist. The netlist + extractor tries hard to maintain the hierarchy and the netlist compare + will utilize the hierarchy to provide more meaningful reports and enable + a bottom-up design approach. +

+ +

+ Given a hierarchical layout and schematic netlist, the compare algorithm + will work bottom-up: it will first compare the leaf circuits (circuits without + subcircuit calls) and if those match, it will continue with the calling + circuits. This approach is more efficient and fosters a clean relationship + between layout and schematic netlist. +

+ +
+ +

+ The second useful feature is "align" (align). + This statement will remove circuits from the layout or schematic netlist which are + unknown in the other netlist. Often, layouts contain helper cells which are not + corresponding to a circuit (e.g. via cells). These are removed in this step. Eventually, + this step will also flatten the schematic netlist if the layout has been extracted + in a flat way. +

+ +

+ In general, it's a good idea to include "align" before the "compare" step. +

+ +

+ A very useful side effect of "align" is this: it will remove circuits above the + top level circuit of either side. So it will eventually render a sub-tree from + the circuit tree and use that for compare. This enables subcell verification: + by selecting a subcell in the layout hierarchy, an "align"-enabled LVS script will + compare this cell against the corresponding subcircuit in the schematic netlist. + It will ignore the parent hierarchy of this subcircuit. This way, you can work yourself + upwards in the hierarchy and fix LVS errors cell by cell with the same schematic netlist. +

+

How the compare algorithm works

From ef66becfdbe9bae01d07a9477401b4b236296c38 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 26 Aug 2019 19:02:38 +0200 Subject: [PATCH 19/27] Fixed LVS test golden data for MSVC --- testdata/lvs/ringo_device_subcircuits.lvsdb.2 | 8 +- ...e_dmos.lvsdb => ringo_simple_dmos.lvsdb.1} | 0 testdata/lvs/ringo_simple_dmos.lvsdb.2 | 925 +++++++++++++++ ...vsdb => ringo_simple_dummy_device.lvsdb.1} | 0 .../lvs/ringo_simple_dummy_device.lvsdb.2 | 1019 +++++++++++++++++ 5 files changed, 1948 insertions(+), 4 deletions(-) rename testdata/lvs/{ringo_simple_dmos.lvsdb => ringo_simple_dmos.lvsdb.1} (100%) create mode 100644 testdata/lvs/ringo_simple_dmos.lvsdb.2 rename testdata/lvs/{ringo_simple_dummy_device.lvsdb => ringo_simple_dummy_device.lvsdb.1} (100%) create mode 100644 testdata/lvs/ringo_simple_dummy_device.lvsdb.2 diff --git a/testdata/lvs/ringo_device_subcircuits.lvsdb.2 b/testdata/lvs/ringo_device_subcircuits.lvsdb.2 index 834cc43fe..5f01d5105 100644 --- a/testdata/lvs/ringo_device_subcircuits.lvsdb.2 +++ b/testdata/lvs/ringo_device_subcircuits.lvsdb.2 @@ -633,7 +633,7 @@ layout( reference( # Device class section - class(PMOS MOS4) + class(XPMOS MOS4) class(NMOS MOS4) # Circuit section @@ -660,7 +660,7 @@ reference( pin(7 name(BULK)) # Devices and their connections - device(1 PMOS + device(1 XPMOS name($1) param(L 0.25) param(W 1.5) @@ -673,7 +673,7 @@ reference( terminal(D 1) terminal(B 4) ) - device(2 PMOS + device(2 XPMOS name($2) param(L 0.25) param(W 1.5) @@ -733,7 +733,7 @@ reference( pin(6 name(BULK)) # Devices and their connections - device(1 PMOS + device(1 XPMOS name($1) param(L 0.25) param(W 1.5) diff --git a/testdata/lvs/ringo_simple_dmos.lvsdb b/testdata/lvs/ringo_simple_dmos.lvsdb.1 similarity index 100% rename from testdata/lvs/ringo_simple_dmos.lvsdb rename to testdata/lvs/ringo_simple_dmos.lvsdb.1 diff --git a/testdata/lvs/ringo_simple_dmos.lvsdb.2 b/testdata/lvs/ringo_simple_dmos.lvsdb.2 new file mode 100644 index 000000000..4256ead4a --- /dev/null +++ b/testdata/lvs/ringo_simple_dmos.lvsdb.2 @@ -0,0 +1,925 @@ +#%lvsdb-klayout + +# Layout +layout( + top(RINGO) + unit(0.001) + + # Layer section + # This section lists the mask layers (drawing or derived) and their connections. + + # Mask layers + layer(l4 '1/0') + layer(l5 '5/0') + layer(l10 '8/0') + layer(l13 '9/0') + layer(l14 '10/0') + layer(l15 '11/0') + layer(l9) + layer(l3) + layer(l1) + layer(l11) + layer(l8) + layer(l6) + layer(l12) + + # Mask layer connectivity + connect(l4 l4 l11) + connect(l5 l5 l10) + connect(l10 l5 l10 l13 l3 l1 l11 l8 l6 l12) + connect(l13 l10 l13 l14) + connect(l14 l13 l14 l15) + connect(l15 l14 l15) + connect(l9 l9) + connect(l3 l10 l3) + connect(l1 l10 l1) + connect(l11 l4 l10 l11) + connect(l8 l10 l8) + connect(l6 l10 l6) + connect(l12 l10 l12) + + # Global nets and connectivity + global(l9 SUBSTRATE) + global(l12 SUBSTRATE) + + # Device class section + class(PMOS MOS4) + class(NMOS MOS4) + + # Device abstracts section + # Device abstracts list the pin shapes of the devices. + device(D$PMOS PMOS + terminal(S + rect(l3 (125 -750) (450 1500)) + ) + terminal(G + rect(l5 (-125 -750) (250 1500)) + ) + terminal(D + rect(l1 (-550 -750) (425 1500)) + ) + terminal(B + rect(l4 (-125 -750) (250 1500)) + ) + ) + device(D$PMOS$1 PMOS + terminal(S + rect(l3 (-575 -750) (450 1500)) + ) + terminal(G + rect(l5 (-125 -750) (250 1500)) + ) + terminal(D + rect(l1 (125 -750) (425 1500)) + ) + terminal(B + rect(l4 (-125 -750) (250 1500)) + ) + ) + device(D$PMOS$2 PMOS + terminal(S + rect(l3 (-550 -750) (425 1500)) + ) + terminal(G + rect(l5 (-125 -750) (250 1500)) + ) + terminal(D + rect(l1 (125 -750) (425 1500)) + ) + terminal(B + rect(l4 (-125 -750) (250 1500)) + ) + ) + device(D$NMOS NMOS + terminal(S + rect(l8 (125 -475) (450 950)) + ) + terminal(G + rect(l5 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (-550 -475) (425 950)) + ) + terminal(B + rect(l9 (-125 -475) (250 950)) + ) + ) + device(D$NMOS$1 NMOS + terminal(S + rect(l8 (-575 -475) (450 950)) + ) + terminal(G + rect(l5 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (425 950)) + ) + terminal(B + rect(l9 (-125 -475) (250 950)) + ) + ) + device(D$NMOS$2 NMOS + terminal(S + rect(l8 (-550 -475) (425 950)) + ) + terminal(G + rect(l5 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (425 950)) + ) + terminal(B + rect(l9 (-125 -475) (250 950)) + ) + ) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(ND2X1 + + # Circuit boundary + rect((-100 400) (2600 7600)) + + # Nets with their geometries + net(1 name(VDD) + rect(l10 (1110 5160) (180 180)) + rect(l10 (-180 920) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l13 (-240 -790) (300 1700)) + rect(l13 (-1350 0) (2400 800)) + rect(l13 (-1151 -401) (2 2)) + rect(l3 (-251 -2151) (425 1500)) + rect(l3 (-450 -1500) (425 1500)) + ) + net(2 name(OUT) + rect(l10 (1810 1770) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l10 (-1580 3760) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l10 (1220 920) (180 180)) + rect(l10 (-180 -1280) (180 180)) + rect(l10 (-180 370) (180 180)) + polygon(l13 (-240 -4180) (0 1390) (490 0) (0 -300) (-190 0) (0 -1090)) + rect(l13 (-110 1390) (300 1400)) + polygon(l13 (-1890 0) (0 600) (300 0) (0 -300) (1590 0) (0 -300)) + rect(l13 (-141 -501) (2 2)) + rect(l13 (-1751 1099) (300 1400)) + rect(l13 (1100 -1700) (300 300)) + rect(l13 (-300 0) (300 1400)) + rect(l1 (-1750 -1450) (425 1500)) + rect(l1 (950 -1500) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(3 name(VSS) + rect(l10 (410 1770) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l13 (-240 -1300) (300 1360)) + rect(l13 (-650 -2160) (2400 800)) + rect(l13 (-1151 -401) (2 2)) + rect(l6 (-951 859) (425 950)) + ) + net(4 + rect(l8 (1000 1660) (425 950)) + rect(l8 (-450 -950) (425 950)) + ) + net(5 + rect(l4 (-100 4500) (2600 3500)) + ) + net(6 name(B) + rect(l5 (1425 2860) (250 1940)) + rect(l5 (-345 -950) (300 300)) + rect(l5 (-205 650) (250 2000)) + rect(l5 (-250 -2000) (250 2000)) + rect(l5 (-250 -5390) (250 1450)) + rect(l10 (-285 1050) (180 180)) + rect(l13 (-71 -91) (2 2)) + rect(l13 (-171 -151) (300 300)) + ) + net(7 name(A) + rect(l5 (725 2860) (250 1940)) + rect(l5 (-325 -1850) (300 300)) + rect(l5 (-225 1550) (250 2000)) + rect(l5 (-250 -2000) (250 2000)) + rect(l5 (-250 -5390) (250 1450)) + rect(l10 (-265 150) (180 180)) + rect(l13 (-91 -91) (2 2)) + rect(l13 (-151 -151) (300 300)) + ) + net(8 name(SUBSTRATE)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(5) + pin(6 name(B)) + pin(7 name(A)) + pin(8 name(SUBSTRATE)) + + # Devices and their connections + device(1 D$PMOS + location(850 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.3375) + param(AD 0.6375) + param(PS 1.95) + param(PD 3.85) + terminal(S 1) + terminal(G 7) + terminal(D 2) + terminal(B 5) + ) + device(2 D$PMOS$1 + location(1550 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.3375) + param(AD 0.6375) + param(PS 1.95) + param(PD 3.85) + terminal(S 1) + terminal(G 6) + terminal(D 2) + terminal(B 5) + ) + device(3 D$NMOS + location(850 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.21375) + param(AD 0.40375) + param(PS 1.4) + param(PD 2.75) + terminal(S 4) + terminal(G 7) + terminal(D 3) + terminal(B 8) + ) + device(4 D$NMOS$1 + location(1550 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.21375) + param(AD 0.40375) + param(PS 1.4) + param(PD 2.75) + terminal(S 4) + terminal(G 6) + terminal(D 2) + terminal(B 8) + ) + + ) + circuit(INVX1 + + # Circuit boundary + rect((-100 400) (2000 7600)) + + # Nets with their geometries + net(1 name(VDD) + rect(l10 (410 6260) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l13 (-240 -240) (300 1400)) + rect(l13 (-650 300) (1800 800)) + rect(l13 (-1450 -1100) (300 300)) + rect(l13 (299 399) (2 2)) + rect(l3 (-651 -2151) (425 1500)) + ) + net(2 name(OUT) + rect(l10 (1110 5160) (180 180)) + rect(l10 (-180 920) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l10 (-180 -4120) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l13 (-240 -790) (300 4790)) + rect(l13 (-151 -2501) (2 2)) + rect(l1 (-226 1049) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(3 name(VSS) + rect(l10 (410 1770) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l13 (-240 -1300) (300 1360)) + rect(l13 (-650 -2160) (1800 800)) + rect(l13 (-851 -401) (2 2)) + rect(l8 (-651 859) (425 950)) + ) + net(4 + rect(l4 (-100 4500) (2000 3500)) + ) + net(5 name(IN) + rect(l5 (725 2860) (250 1940)) + rect(l5 (-525 -1850) (300 300)) + rect(l5 (-25 1550) (250 2000)) + rect(l5 (-250 -2000) (250 2000)) + rect(l5 (-250 -5390) (250 1450)) + rect(l10 (-465 150) (180 180)) + rect(l13 (-91 -91) (2 2)) + rect(l13 (-151 -151) (300 300)) + ) + net(6 name(SUBSTRATE)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4) + pin(5 name(IN)) + pin(6 name(SUBSTRATE)) + + # Devices and their connections + device(1 D$PMOS$2 + location(850 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.6375) + param(AD 0.6375) + param(PS 3.85) + param(PD 3.85) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(2 D$NMOS$2 + location(850 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.40375) + param(AD 0.40375) + param(PS 2.75) + param(PD 2.75) + terminal(S 3) + terminal(G 5) + terminal(D 2) + terminal(B 6) + ) + + ) + circuit(RINGO + + # Circuit boundary + rect((0 350) (25800 7650)) + + # Nets with their geometries + net(1 + rect(l10 (4710 3010) (180 180)) + rect(l13 (-850 -240) (610 300)) + ) + net(2 + rect(l10 (6510 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(3 + rect(l10 (8310 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(4 + rect(l10 (10110 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(5 + rect(l10 (11910 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(6 + rect(l10 (13710 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(7 + rect(l10 (15510 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(8 + rect(l10 (17310 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(9 + rect(l10 (19110 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(10 + rect(l10 (20910 3010) (180 180)) + rect(l13 (-1140 -240) (900 300)) + ) + net(11 name(FB) + rect(l10 (22710 3010) (180 180)) + rect(l10 (-19700 720) (180 180)) + rect(l13 (18380 -1140) (900 300)) + rect(l13 (-19530 590) (320 320)) + rect(l13 (17820 -320) (320 320)) + rect(l14 (-18400 -260) (200 200)) + rect(l14 (17940 -200) (200 200)) + rect(l15 (-18040 -300) (17740 400)) + rect(l15 (-17921 -201) (2 2)) + rect(l15 (-221 -201) (400 400)) + rect(l15 (17740 -400) (400 400)) + ) + net(12 name(VDD) + rect(l4 (500 4500) (1400 3500)) + rect(l4 (-1900 -3500) (600 3500)) + rect(l4 (23300 -3500) (1400 3500)) + rect(l4 (-100 -3500) (600 3500)) + rect(l10 (-24690 -1240) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l10 (-180 -1280) (180 180)) + rect(l10 (23220 370) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l10 (-180 -1280) (180 180)) + rect(l13 (-21741 859) (2 2)) + rect(l13 (-2351 -451) (1200 800)) + rect(l13 (-750 -1450) (300 1400)) + rect(l13 (-101 -351) (2 2)) + rect(l13 (-1251 -401) (600 800)) + rect(l13 (23400 -800) (1200 800)) + rect(l13 (-750 -1450) (300 1400)) + rect(l13 (-101 -351) (2 2)) + rect(l13 (549 -401) (600 800)) + rect(l11 (-24850 -1500) (500 1500)) + rect(l11 (22900 -1500) (500 1500)) + ) + net(13 name(OUT) + rect(l13 (23440 3840) (320 320)) + rect(l14 (-260 -260) (200 200)) + rect(l15 (-101 -101) (2 2)) + rect(l15 (-201 -201) (400 400)) + ) + net(14 name(ENABLE) + rect(l10 (2510 3010) (180 180)) + rect(l13 (-250 -250) (320 320)) + rect(l14 (-260 -260) (200 200)) + rect(l15 (-101 -101) (2 2)) + rect(l15 (-201 -201) (400 400)) + ) + net(15 name(VSS) + rect(l10 (1110 1610) (180 180)) + rect(l10 (-180 -1280) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l10 (23220 370) (180 180)) + rect(l10 (-180 -1280) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l13 (-21741 -391) (2 2)) + rect(l13 (-1901 -401) (300 1400)) + rect(l13 (-750 -1450) (1200 800)) + rect(l13 (-551 -401) (2 2)) + rect(l13 (-1251 -401) (600 800)) + rect(l13 (23850 -750) (300 1400)) + rect(l13 (-750 -1450) (1200 800)) + rect(l13 (-551 -401) (2 2)) + rect(l13 (549 -401) (600 800)) + rect(l12 (-24850 -800) (500 1500)) + rect(l12 (22900 -1500) (500 1500)) + ) + + # Outgoing pins and their connections to nets + pin(11 name(FB)) + pin(12 name(VDD)) + pin(13 name(OUT)) + pin(14 name(ENABLE)) + pin(15 name(VSS)) + + # Subcircuits and their connections + circuit(1 ND2X1 location(1800 0) + pin(0 12) + pin(1 1) + pin(2 15) + pin(3 12) + pin(4 11) + pin(5 14) + pin(6 15) + ) + circuit(2 INVX1 location(4200 0) + pin(0 12) + pin(1 2) + pin(2 15) + pin(3 12) + pin(4 1) + pin(5 15) + ) + circuit(3 INVX1 location(6000 0) + pin(0 12) + pin(1 3) + pin(2 15) + pin(3 12) + pin(4 2) + pin(5 15) + ) + circuit(4 INVX1 location(7800 0) + pin(0 12) + pin(1 4) + pin(2 15) + pin(3 12) + pin(4 3) + pin(5 15) + ) + circuit(5 INVX1 location(9600 0) + pin(0 12) + pin(1 5) + pin(2 15) + pin(3 12) + pin(4 4) + pin(5 15) + ) + circuit(6 INVX1 location(11400 0) + pin(0 12) + pin(1 6) + pin(2 15) + pin(3 12) + pin(4 5) + pin(5 15) + ) + circuit(7 INVX1 location(13200 0) + pin(0 12) + pin(1 7) + pin(2 15) + pin(3 12) + pin(4 6) + pin(5 15) + ) + circuit(8 INVX1 location(15000 0) + pin(0 12) + pin(1 8) + pin(2 15) + pin(3 12) + pin(4 7) + pin(5 15) + ) + circuit(9 INVX1 location(16800 0) + pin(0 12) + pin(1 9) + pin(2 15) + pin(3 12) + pin(4 8) + pin(5 15) + ) + circuit(10 INVX1 location(18600 0) + pin(0 12) + pin(1 10) + pin(2 15) + pin(3 12) + pin(4 9) + pin(5 15) + ) + circuit(11 INVX1 location(20400 0) + pin(0 12) + pin(1 11) + pin(2 15) + pin(3 12) + pin(4 10) + pin(5 15) + ) + circuit(12 INVX1 location(22200 0) + pin(0 12) + pin(1 13) + pin(2 15) + pin(3 12) + pin(4 11) + pin(5 15) + ) + + ) +) + +# Reference netlist +reference( + + # Device class section + class(PMOS MOS4) + class(NMOS MOS4) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(ND2X1 + + # Nets + net(1 name(VDD)) + net(2 name(OUT)) + net(3 name(VSS)) + net(4 name(NWELL)) + net(5 name(B)) + net(6 name(A)) + net(7 name(BULK)) + net(8 name('1')) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4 name(NWELL)) + pin(5 name(B)) + pin(6 name(A)) + pin(7 name(BULK)) + + # Devices and their connections + device(1 PMOS + name($1) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 2) + terminal(G 6) + terminal(D 1) + terminal(B 4) + ) + device(2 PMOS + name($2) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(3 NMOS + name($3) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 3) + terminal(G 6) + terminal(D 8) + terminal(B 7) + ) + device(4 NMOS + name($4) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 8) + terminal(G 5) + terminal(D 2) + terminal(B 7) + ) + + ) + circuit(INVX1 + + # Nets + net(1 name(VDD)) + net(2 name(OUT)) + net(3 name(VSS)) + net(4 name(NWELL)) + net(5 name(IN)) + net(6 name(BULK)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4 name(NWELL)) + pin(5 name(IN)) + pin(6 name(BULK)) + + # Devices and their connections + device(1 PMOS + name($1) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(2 NMOS + name($2) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 3) + terminal(G 5) + terminal(D 2) + terminal(B 6) + ) + + ) + circuit(RINGO + + # Nets + net(1 name(VSS)) + net(2 name(VDD)) + net(3 name(FB)) + net(4 name(ENABLE)) + net(5 name(OUT)) + net(6 name('1')) + net(7 name('2')) + net(8 name('3')) + net(9 name('4')) + net(10 name('5')) + net(11 name('6')) + net(12 name('7')) + net(13 name('8')) + net(14 name('9')) + net(15 name('10')) + + # Outgoing pins and their connections to nets + pin(1 name(VSS)) + pin(2 name(VDD)) + pin(3 name(FB)) + pin(4 name(ENABLE)) + pin(5 name(OUT)) + + # Subcircuits and their connections + circuit(1 ND2X1 name($1) + pin(0 2) + pin(1 6) + pin(2 1) + pin(3 2) + pin(4 3) + pin(5 4) + pin(6 1) + ) + circuit(2 INVX1 name($2) + pin(0 2) + pin(1 7) + pin(2 1) + pin(3 2) + pin(4 6) + pin(5 1) + ) + circuit(3 INVX1 name($3) + pin(0 2) + pin(1 8) + pin(2 1) + pin(3 2) + pin(4 7) + pin(5 1) + ) + circuit(4 INVX1 name($4) + pin(0 2) + pin(1 9) + pin(2 1) + pin(3 2) + pin(4 8) + pin(5 1) + ) + circuit(5 INVX1 name($5) + pin(0 2) + pin(1 10) + pin(2 1) + pin(3 2) + pin(4 9) + pin(5 1) + ) + circuit(6 INVX1 name($6) + pin(0 2) + pin(1 11) + pin(2 1) + pin(3 2) + pin(4 10) + pin(5 1) + ) + circuit(7 INVX1 name($7) + pin(0 2) + pin(1 12) + pin(2 1) + pin(3 2) + pin(4 11) + pin(5 1) + ) + circuit(8 INVX1 name($8) + pin(0 2) + pin(1 13) + pin(2 1) + pin(3 2) + pin(4 12) + pin(5 1) + ) + circuit(9 INVX1 name($9) + pin(0 2) + pin(1 14) + pin(2 1) + pin(3 2) + pin(4 13) + pin(5 1) + ) + circuit(10 INVX1 name($10) + pin(0 2) + pin(1 15) + pin(2 1) + pin(3 2) + pin(4 14) + pin(5 1) + ) + circuit(11 INVX1 name($11) + pin(0 2) + pin(1 3) + pin(2 1) + pin(3 2) + pin(4 15) + pin(5 1) + ) + circuit(12 INVX1 name($12) + pin(0 2) + pin(1 5) + pin(2 1) + pin(3 2) + pin(4 3) + pin(5 1) + ) + + ) +) + +# Cross reference +xref( + circuit(INVX1 INVX1 match + xref( + net(4 4 match) + net(5 5 match) + net(2 2 match) + net(6 6 match) + net(1 1 match) + net(3 3 match) + pin(3 3 match) + pin(4 4 match) + pin(1 1 match) + pin(5 5 match) + pin(0 0 match) + pin(2 2 match) + device(2 2 match) + device(1 1 match) + ) + ) + circuit(ND2X1 ND2X1 nomatch + xref( + net(4 8 mismatch) + net(5 4 mismatch) + net(7 6 match) + net(6 5 match) + net(2 2 mismatch) + net(8 7 mismatch) + net(1 1 mismatch) + net(3 3 mismatch) + pin(3 3 match) + pin(5 5 match) + pin(4 4 match) + pin(1 1 match) + pin(6 6 match) + pin(0 0 match) + pin(2 2 match) + device(4 4 match) + device(3 3 mismatch) + device(2 2 match) + device(1 1 mismatch) + ) + ) + circuit(RINGO RINGO match + xref( + net(1 6 match) + net(10 15 match) + net(2 7 match) + net(3 8 match) + net(4 9 match) + net(5 10 match) + net(6 11 match) + net(7 12 match) + net(8 13 match) + net(9 14 match) + net(14 4 match) + net(11 3 match) + net(13 5 match) + net(12 2 match) + net(15 1 match) + pin(3 3 match) + pin(0 2 match) + pin(2 4 match) + pin(1 1 match) + pin(4 0 match) + circuit(2 2 match) + circuit(3 3 match) + circuit(4 4 match) + circuit(5 5 match) + circuit(6 6 match) + circuit(7 7 match) + circuit(8 8 match) + circuit(9 9 match) + circuit(10 10 match) + circuit(11 11 match) + circuit(12 12 match) + circuit(1 1 match) + ) + ) +) diff --git a/testdata/lvs/ringo_simple_dummy_device.lvsdb b/testdata/lvs/ringo_simple_dummy_device.lvsdb.1 similarity index 100% rename from testdata/lvs/ringo_simple_dummy_device.lvsdb rename to testdata/lvs/ringo_simple_dummy_device.lvsdb.1 diff --git a/testdata/lvs/ringo_simple_dummy_device.lvsdb.2 b/testdata/lvs/ringo_simple_dummy_device.lvsdb.2 new file mode 100644 index 000000000..e0c48421a --- /dev/null +++ b/testdata/lvs/ringo_simple_dummy_device.lvsdb.2 @@ -0,0 +1,1019 @@ +#%lvsdb-klayout + +# Layout +layout( + top(RINGO) + unit(0.001) + + # Layer section + # This section lists the mask layers (drawing or derived) and their connections. + + # Mask layers + layer(l3 '1/0') + layer(l4 '5/0') + layer(l8 '8/0') + layer(l11 '9/0') + layer(l12 '10/0') + layer(l13 '11/0') + layer(l7) + layer(l2) + layer(l9) + layer(l6) + layer(l10) + + # Mask layer connectivity + connect(l3 l3 l9) + connect(l4 l4 l8) + connect(l8 l4 l8 l11 l2 l9 l6 l10) + connect(l11 l8 l11 l12) + connect(l12 l11 l12 l13) + connect(l13 l12 l13) + connect(l7 l7) + connect(l2 l8 l2) + connect(l9 l3 l8 l9) + connect(l6 l8 l6) + connect(l10 l8 l10) + + # Global nets and connectivity + global(l7 SUBSTRATE) + global(l10 SUBSTRATE) + + # Device class section + class(PMOS MOS4) + class(NMOS MOS4) + + # Device abstracts section + # Device abstracts list the pin shapes of the devices. + device(D$PMOS PMOS + terminal(S + rect(l2 (-550 -750) (425 1500)) + ) + terminal(G + rect(l4 (-125 -750) (250 1500)) + ) + terminal(D + rect(l2 (125 -750) (450 1500)) + ) + terminal(B + rect(l3 (-125 -750) (250 1500)) + ) + ) + device(D$PMOS$1 PMOS + terminal(S + rect(l2 (-575 -750) (450 1500)) + ) + terminal(G + rect(l4 (-125 -750) (250 1500)) + ) + terminal(D + rect(l2 (125 -750) (425 1500)) + ) + terminal(B + rect(l3 (-125 -750) (250 1500)) + ) + ) + device(D$PMOS$2 PMOS + terminal(S + rect(l2 (-550 -750) (425 1500)) + ) + terminal(G + rect(l4 (-125 -750) (250 1500)) + ) + terminal(D + rect(l2 (125 -750) (425 1500)) + ) + terminal(B + rect(l3 (-125 -750) (250 1500)) + ) + ) + device(D$NMOS NMOS + terminal(S + rect(l6 (-550 -475) (425 950)) + ) + terminal(G + rect(l4 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (425 950)) + ) + terminal(B + rect(l7 (-125 -475) (250 950)) + ) + ) + device(D$NMOS$1 NMOS + terminal(S + rect(l6 (-550 -475) (425 950)) + ) + terminal(G + rect(l4 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (450 950)) + ) + terminal(B + rect(l7 (-125 -475) (250 950)) + ) + ) + device(D$NMOS$2 NMOS + terminal(S + rect(l6 (-575 -475) (450 950)) + ) + terminal(G + rect(l4 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (425 950)) + ) + terminal(B + rect(l7 (-125 -475) (250 950)) + ) + ) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(ND2X1 + + # Circuit boundary + rect((-100 400) (2600 7600)) + + # Nets with their geometries + net(1 name(VDD) + rect(l8 (1110 5160) (180 180)) + rect(l8 (-180 920) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l11 (-240 -790) (300 1700)) + rect(l11 (-1350 0) (2400 800)) + rect(l11 (-1151 -401) (2 2)) + rect(l2 (-276 -2151) (425 1500)) + rect(l2 (-400 -1500) (425 1500)) + ) + net(2 name(OUT) + rect(l8 (1810 1770) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (-1580 3760) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (1220 920) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (-180 370) (180 180)) + polygon(l11 (-240 -4180) (0 1390) (490 0) (0 -300) (-190 0) (0 -1090)) + rect(l11 (-110 1390) (300 1400)) + polygon(l11 (-1890 0) (0 600) (300 0) (0 -300) (1590 0) (0 -300)) + rect(l11 (-141 -501) (2 2)) + rect(l11 (-1751 1099) (300 1400)) + rect(l11 (1100 -1700) (300 300)) + rect(l11 (-300 0) (300 1400)) + rect(l2 (-375 -1450) (425 1500)) + rect(l2 (-1800 -1500) (425 1500)) + rect(l6 (950 -4890) (425 950)) + ) + net(3 name(VSS) + rect(l8 (410 1770) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-240 -1300) (300 1360)) + rect(l11 (-650 -2160) (2400 800)) + rect(l11 (-1151 -401) (2 2)) + rect(l6 (-951 859) (425 950)) + ) + net(4 + rect(l3 (-100 4500) (2600 3500)) + ) + net(5 name(B) + rect(l4 (1425 2860) (250 1940)) + rect(l4 (-345 -950) (300 300)) + rect(l4 (-205 650) (250 2000)) + rect(l4 (-250 -2000) (250 2000)) + rect(l4 (-250 -5390) (250 1450)) + rect(l8 (-285 1050) (180 180)) + rect(l11 (-71 -91) (2 2)) + rect(l11 (-171 -151) (300 300)) + ) + net(6 name(A) + rect(l4 (725 2860) (250 1940)) + rect(l4 (-325 -1850) (300 300)) + rect(l4 (-225 1550) (250 2000)) + rect(l4 (-250 -2000) (250 2000)) + rect(l4 (-250 -5390) (250 1450)) + rect(l8 (-265 150) (180 180)) + rect(l11 (-91 -91) (2 2)) + rect(l11 (-151 -151) (300 300)) + ) + net(7 name(SUBSTRATE)) + net(8 + rect(l6 (975 1660) (425 950)) + rect(l6 (-400 -950) (425 950)) + ) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4) + pin(5 name(B)) + pin(6 name(A)) + pin(7 name(SUBSTRATE)) + + # Devices and their connections + device(1 D$PMOS + location(850 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.6375) + param(AD 0.3375) + param(PS 3.85) + param(PD 1.95) + terminal(S 2) + terminal(G 6) + terminal(D 1) + terminal(B 4) + ) + device(2 D$PMOS$1 + location(1550 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.3375) + param(AD 0.6375) + param(PS 1.95) + param(PD 3.85) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(3 D$NMOS$1 + location(850 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.40375) + param(AD 0.21375) + param(PS 2.75) + param(PD 1.4) + terminal(S 3) + terminal(G 6) + terminal(D 8) + terminal(B 7) + ) + device(4 D$NMOS$2 + location(1550 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.21375) + param(AD 0.40375) + param(PS 1.4) + param(PD 2.75) + terminal(S 8) + terminal(G 5) + terminal(D 2) + terminal(B 7) + ) + + ) + circuit(INVX1 + + # Circuit boundary + rect((-100 400) (2000 7600)) + + # Nets with their geometries + net(1 name(VDD) + rect(l8 (410 6260) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l11 (-240 -240) (300 1400)) + rect(l11 (-650 300) (1800 800)) + rect(l11 (-1450 -1100) (300 300)) + rect(l11 (299 399) (2 2)) + rect(l2 (-651 -2151) (425 1500)) + ) + net(2 name(OUT) + rect(l8 (1110 5160) (180 180)) + rect(l8 (-180 920) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (-180 -4120) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-240 -790) (300 4790)) + rect(l11 (-151 -2501) (2 2)) + rect(l2 (-226 1049) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(3 name(VSS) + rect(l8 (410 1770) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-240 -1300) (300 1360)) + rect(l11 (-650 -2160) (1800 800)) + rect(l11 (-851 -401) (2 2)) + rect(l6 (-651 859) (425 950)) + ) + net(4 + rect(l3 (-100 4500) (2000 3500)) + ) + net(5 name(IN) + rect(l4 (725 2860) (250 1940)) + rect(l4 (-525 -1850) (300 300)) + rect(l4 (-25 1550) (250 2000)) + rect(l4 (-250 -2000) (250 2000)) + rect(l4 (-250 -5390) (250 1450)) + rect(l8 (-465 150) (180 180)) + rect(l11 (-91 -91) (2 2)) + rect(l11 (-151 -151) (300 300)) + ) + net(6 name(SUBSTRATE)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4) + pin(5 name(IN)) + pin(6 name(SUBSTRATE)) + + # Devices and their connections + device(1 D$PMOS$2 + location(850 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.6375) + param(AD 0.6375) + param(PS 3.85) + param(PD 3.85) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(2 D$NMOS + location(850 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.40375) + param(AD 0.40375) + param(PS 2.75) + param(PD 2.75) + terminal(S 3) + terminal(G 5) + terminal(D 2) + terminal(B 6) + ) + + ) + circuit(RINGO + + # Circuit boundary + rect((0 350) (27600 7650)) + + # Nets with their geometries + net(1 + rect(l8 (4710 3010) (180 180)) + rect(l11 (-850 -240) (610 300)) + rect(l2 (-1175 1800) (425 1500)) + rect(l2 (-1800 -1500) (425 1500)) + rect(l6 (950 -4890) (425 950)) + ) + net(2 + rect(l8 (6510 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(3 + rect(l8 (8310 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(4 + rect(l8 (10110 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(5 + rect(l8 (11910 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(6 + rect(l8 (13710 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(7 + rect(l8 (15510 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(8 + rect(l8 (17310 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(9 + rect(l8 (19110 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(10 + rect(l8 (20910 3010) (180 180)) + rect(l11 (-1140 -240) (900 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(11 name(FB) + rect(l8 (22710 3010) (180 180)) + rect(l8 (-19700 720) (180 180)) + rect(l11 (18380 -1140) (900 300)) + rect(l11 (-19530 590) (320 320)) + rect(l11 (17820 -320) (320 320)) + rect(l12 (-18400 -260) (200 200)) + rect(l12 (17940 -200) (200 200)) + rect(l13 (-18040 -300) (17740 400)) + rect(l13 (-17921 -201) (2 2)) + rect(l13 (-221 -201) (400 400)) + rect(l13 (17740 -400) (400 400)) + rect(l2 (-245 850) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(12 name(VDD) + rect(l3 (500 4500) (1400 3500)) + rect(l3 (-1900 -3500) (600 3500)) + rect(l3 (23300 -3500) (1400 3500)) + rect(l3 (-100 -3500) (600 3500)) + rect(l3 (0 -3500) (600 3500)) + rect(l3 (0 -3500) (600 3500)) + rect(l3 (0 -3500) (600 3500)) + rect(l8 (-26490 -1240) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (23220 370) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l11 (-21741 859) (2 2)) + rect(l11 (-2351 -451) (1200 800)) + rect(l11 (-750 -1450) (300 1400)) + rect(l11 (-101 -351) (2 2)) + rect(l11 (-1251 -401) (600 800)) + rect(l11 (23400 -800) (1200 800)) + rect(l11 (-750 -1450) (300 1400)) + rect(l11 (-101 -351) (2 2)) + rect(l11 (549 -401) (600 800)) + rect(l11 (0 -800) (600 800)) + rect(l11 (0 -800) (600 800)) + rect(l11 (0 -800) (600 800)) + rect(l2 (-24825 -2550) (425 1500)) + rect(l2 (-400 -1500) (425 1500)) + rect(l2 (1275 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l2 (1375 -1500) (425 1500)) + rect(l9 (-21975 -450) (500 1500)) + rect(l9 (22900 -1500) (500 1500)) + ) + net(13 name(OUT) + rect(l11 (23440 3840) (320 320)) + rect(l12 (-260 -260) (200 200)) + rect(l13 (-101 -101) (2 2)) + rect(l13 (-201 -201) (400 400)) + rect(l2 (-625 850) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(14 name(ENABLE) + rect(l8 (2510 3010) (180 180)) + rect(l11 (-250 -250) (320 320)) + rect(l12 (-260 -260) (200 200)) + rect(l13 (-101 -101) (2 2)) + rect(l13 (-201 -201) (400 400)) + ) + net(15 name(VSS) + rect(l8 (26010 1770) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (520 -730) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (-25780 -890) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (23220 370) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (1260 -40) (300 1360)) + rect(l11 (400 -1360) (300 1360)) + rect(l11 (-24001 -1711) (2 2)) + rect(l11 (-1901 -401) (300 1400)) + rect(l11 (-750 -1450) (1200 800)) + rect(l11 (-551 -401) (2 2)) + rect(l11 (-1251 -401) (600 800)) + rect(l11 (23850 -750) (300 1400)) + rect(l11 (-750 -1450) (1200 800)) + rect(l11 (-551 -401) (2 2)) + rect(l11 (549 -401) (600 800)) + rect(l11 (0 -800) (600 800)) + rect(l11 (0 -800) (600 800)) + rect(l11 (0 -800) (600 800)) + rect(l6 (-25500 460) (425 950)) + rect(l6 (1975 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (1375 -950) (425 950)) + rect(l6 (3650 -1010) (425 950)) + rect(l6 (-1100 -950) (425 950)) + rect(l10 (-25375 -2150) (500 1500)) + rect(l10 (22900 -1500) (500 1500)) + ) + + # Outgoing pins and their connections to nets + pin(11 name(FB)) + pin(12 name(VDD)) + pin(13 name(OUT)) + pin(14 name(ENABLE)) + pin(15 name(VSS)) + + # Devices and their connections + device(1 D$NMOS + location(26450 2075) + param(L 0.25) + param(W 0.95) + param(AS 0.40375) + param(AD 0.40375) + param(PS 2.75) + param(PD 2.75) + terminal(S 15) + terminal(G) + terminal(D 15) + terminal(B 15) + ) + + # Subcircuits and their connections + circuit(3 ND2X1 location(1800 0) + pin(0 12) + pin(1 1) + pin(2 15) + pin(3 12) + pin(4 11) + pin(5 14) + pin(6 15) + ) + circuit(4 INVX1 location(4200 0) + pin(0 12) + pin(1 2) + pin(2 15) + pin(3 12) + pin(4 1) + pin(5 15) + ) + circuit(5 INVX1 location(6000 0) + pin(0 12) + pin(1 3) + pin(2 15) + pin(3 12) + pin(4 2) + pin(5 15) + ) + circuit(6 INVX1 location(7800 0) + pin(0 12) + pin(1 4) + pin(2 15) + pin(3 12) + pin(4 3) + pin(5 15) + ) + circuit(7 INVX1 location(9600 0) + pin(0 12) + pin(1 5) + pin(2 15) + pin(3 12) + pin(4 4) + pin(5 15) + ) + circuit(8 INVX1 location(11400 0) + pin(0 12) + pin(1 6) + pin(2 15) + pin(3 12) + pin(4 5) + pin(5 15) + ) + circuit(9 INVX1 location(13200 0) + pin(0 12) + pin(1 7) + pin(2 15) + pin(3 12) + pin(4 6) + pin(5 15) + ) + circuit(10 INVX1 location(15000 0) + pin(0 12) + pin(1 8) + pin(2 15) + pin(3 12) + pin(4 7) + pin(5 15) + ) + circuit(11 INVX1 location(16800 0) + pin(0 12) + pin(1 9) + pin(2 15) + pin(3 12) + pin(4 8) + pin(5 15) + ) + circuit(12 INVX1 location(18600 0) + pin(0 12) + pin(1 10) + pin(2 15) + pin(3 12) + pin(4 9) + pin(5 15) + ) + circuit(13 INVX1 location(20400 0) + pin(0 12) + pin(1 11) + pin(2 15) + pin(3 12) + pin(4 10) + pin(5 15) + ) + circuit(14 INVX1 location(22200 0) + pin(0 12) + pin(1 13) + pin(2 15) + pin(3 12) + pin(4 11) + pin(5 15) + ) + + ) +) + +# Reference netlist +reference( + + # Device class section + class(NMOS MOS4) + class(PMOS MOS4) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(ND2X1 + + # Nets + net(1 name(VDD)) + net(2 name(OUT)) + net(3 name(VSS)) + net(4 name(NWELL)) + net(5 name(B)) + net(6 name(A)) + net(7 name(BULK)) + net(8 name('1')) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4 name(NWELL)) + pin(5 name(B)) + pin(6 name(A)) + pin(7 name(BULK)) + + # Devices and their connections + device(1 PMOS + name($1) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 2) + terminal(G 6) + terminal(D 1) + terminal(B 4) + ) + device(2 PMOS + name($2) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(3 NMOS + name($3) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 3) + terminal(G 6) + terminal(D 8) + terminal(B 7) + ) + device(4 NMOS + name($4) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 8) + terminal(G 5) + terminal(D 2) + terminal(B 7) + ) + + ) + circuit(INVX1 + + # Nets + net(1 name(VDD)) + net(2 name(OUT)) + net(3 name(VSS)) + net(4 name(NWELL)) + net(5 name(IN)) + net(6 name(BULK)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4 name(NWELL)) + pin(5 name(IN)) + pin(6 name(BULK)) + + # Devices and their connections + device(1 PMOS + name($1) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(2 NMOS + name($2) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 3) + terminal(G 5) + terminal(D 2) + terminal(B 6) + ) + + ) + circuit(RINGO + + # Nets + net(1 name(VSS)) + net(2 name(VDD)) + net(3 name(FB)) + net(4 name(ENABLE)) + net(5 name(OUT)) + net(6 name('1')) + net(7 name('2')) + net(8 name('3')) + net(9 name('4')) + net(10 name('5')) + net(11 name('6')) + net(12 name('7')) + net(13 name('8')) + net(14 name('9')) + net(15 name('10')) + + # Outgoing pins and their connections to nets + pin(1 name(VSS)) + pin(2 name(VDD)) + pin(3 name(FB)) + pin(4 name(ENABLE)) + pin(5 name(OUT)) + + # Devices and their connections + device(1 NMOS + name($1) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G) + terminal(D 1) + terminal(B 1) + ) + + # Subcircuits and their connections + circuit(1 ND2X1 name($1) + pin(0 2) + pin(1 6) + pin(2 1) + pin(3 2) + pin(4 3) + pin(5 4) + pin(6 1) + ) + circuit(2 INVX1 name($2) + pin(0 2) + pin(1 7) + pin(2 1) + pin(3 2) + pin(4 6) + pin(5 1) + ) + circuit(3 INVX1 name($3) + pin(0 2) + pin(1 8) + pin(2 1) + pin(3 2) + pin(4 7) + pin(5 1) + ) + circuit(4 INVX1 name($4) + pin(0 2) + pin(1 9) + pin(2 1) + pin(3 2) + pin(4 8) + pin(5 1) + ) + circuit(5 INVX1 name($5) + pin(0 2) + pin(1 10) + pin(2 1) + pin(3 2) + pin(4 9) + pin(5 1) + ) + circuit(6 INVX1 name($6) + pin(0 2) + pin(1 11) + pin(2 1) + pin(3 2) + pin(4 10) + pin(5 1) + ) + circuit(7 INVX1 name($7) + pin(0 2) + pin(1 12) + pin(2 1) + pin(3 2) + pin(4 11) + pin(5 1) + ) + circuit(8 INVX1 name($8) + pin(0 2) + pin(1 13) + pin(2 1) + pin(3 2) + pin(4 12) + pin(5 1) + ) + circuit(9 INVX1 name($9) + pin(0 2) + pin(1 14) + pin(2 1) + pin(3 2) + pin(4 13) + pin(5 1) + ) + circuit(10 INVX1 name($10) + pin(0 2) + pin(1 15) + pin(2 1) + pin(3 2) + pin(4 14) + pin(5 1) + ) + circuit(11 INVX1 name($11) + pin(0 2) + pin(1 3) + pin(2 1) + pin(3 2) + pin(4 15) + pin(5 1) + ) + circuit(12 INVX1 name($12) + pin(0 2) + pin(1 5) + pin(2 1) + pin(3 2) + pin(4 3) + pin(5 1) + ) + + ) +) + +# Cross reference +xref( + circuit(INVX1 INVX1 match + xref( + net(4 4 match) + net(5 5 match) + net(2 2 match) + net(6 6 match) + net(1 1 match) + net(3 3 match) + pin(3 3 match) + pin(4 4 match) + pin(1 1 match) + pin(5 5 match) + pin(0 0 match) + pin(2 2 match) + device(2 2 match) + device(1 1 match) + ) + ) + circuit(ND2X1 ND2X1 match + xref( + net(8 8 match) + net(4 4 match) + net(6 6 match) + net(5 5 match) + net(2 2 match) + net(7 7 match) + net(1 1 match) + net(3 3 match) + pin(3 3 match) + pin(5 5 match) + pin(4 4 match) + pin(1 1 match) + pin(6 6 match) + pin(0 0 match) + pin(2 2 match) + device(3 3 match) + device(4 4 match) + device(1 1 match) + device(2 2 match) + ) + ) + circuit(RINGO RINGO match + xref( + net(1 6 match) + net(10 15 match) + net(2 7 match) + net(3 8 match) + net(4 9 match) + net(5 10 match) + net(6 11 match) + net(7 12 match) + net(8 13 match) + net(9 14 match) + net(14 4 match) + net(11 3 match) + net(13 5 match) + net(12 2 match) + net(15 1 match) + pin(3 3 match) + pin(0 2 match) + pin(2 4 match) + pin(1 1 match) + pin(4 0 match) + device(1 1 match) + circuit(4 2 match) + circuit(5 3 match) + circuit(6 4 match) + circuit(7 5 match) + circuit(8 6 match) + circuit(9 7 match) + circuit(10 8 match) + circuit(11 9 match) + circuit(12 10 match) + circuit(13 11 match) + circuit(14 12 match) + circuit(3 1 match) + ) + ) +) From 9a69d106fde569e6bd9cdf2d6c047f3d3b496e00 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 29 Aug 2019 00:19:24 +0200 Subject: [PATCH 20/27] Fixed some small issues in the netlist compare --- src/db/db/dbNetlistCompare.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 9222cee38..47d44d7bc 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -3043,14 +3043,12 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph ++i; } - if (i == unmatched_a.end () && j == unmatched_b.end ()) { + if (i == unmatched_a.end () || j == unmatched_b.end ()) { break; } unmatched_list::iterator ii = i, jj = j; ++i, ++j; - size_t n = ii->first.size (); - tl_assert (n == jj->first.size ()); while (i != unmatched_a.end () && cmp.equals (*i, *ii)) { ++i; @@ -3211,7 +3209,7 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG ++i; } - if (i == unmatched_a.end () && j == unmatched_b.end ()) { + if (i == unmatched_a.end () || j == unmatched_b.end ()) { break; } From b1acfe95870cd005936f385b447fbf18ae47b18d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 29 Aug 2019 22:25:59 +0200 Subject: [PATCH 21/27] Tried a better deal with floating pins 1.) is_floating is now only true if there is no device and no subcircuit on a net. This means we only purge nets if they are really floating. So far we purged nets without pins which lead to the mismatch: Before purge: Layout: (net) <--> DEVICE.TERMINAL Schematic: PIN <--> DEVICE.TERMINAL After purge: Layout: (null) <--> DEVICE.TERMINAL Schematic: PIN <--> DEVICE.TERMINAL (null does not match any net) 2.) circuit pin matching was a bit picky. Only when one circuit did not have pins, matching was sloppy. In real cases however, circuits may have unconnected pins: - top level pins without a counterpart (no label) - subcircuits pins which are not used We catch both cases by refining the match: if a pin is not used, it does not need to match against any other pin. It's reported as "matching against null" though. --- src/db/db/dbNet.h | 4 +- src/db/db/dbNetlistCompare.cc | 264 +++++++++++++--------------- src/db/db/dbNetlistCompare.h | 1 + src/db/unit_tests/dbNetlistTests.cc | 2 +- 4 files changed, 128 insertions(+), 143 deletions(-) diff --git a/src/db/db/dbNet.h b/src/db/db/dbNet.h index ada3e98e2..dd476652a 100644 --- a/src/db/db/dbNet.h +++ b/src/db/db/dbNet.h @@ -603,11 +603,11 @@ public: } /** - * @brief Returns true, if the net is floating (has no or only a single connection) + * @brief Returns true, if the net is floating (there is no active element on the net) */ bool is_floating () const { - return (m_pins.size () + m_subcircuit_pins.size () + m_terminals.size ()) < 2; + return (m_subcircuit_pins.size () + m_terminals.size ()) < 1; } /** diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 47d44d7bc..a4dfd9c79 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -2710,186 +2710,170 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, return good; } +void +NetlistComparer::handle_pin_mismatch (const db::Circuit *c1, const db::Pin *pin1, const db::Circuit *c2, const db::Pin *pin2, bool &good, bool &pin_mismatch) const +{ + // Determine whether the pin in question is used - only in this case we will report an error. + // Otherwise, the report will be "match" against 0. + + const db::Circuit *c = pin1 ? c1 : c2; + const db::Pin *pin = pin1 ? pin1 : pin2; + + bool is_not_connected = true; + for (db::Circuit::const_refs_iterator r = c->begin_refs (); r != c->end_refs () && is_not_connected; ++r) { + const db::SubCircuit *sc = r.operator-> (); + const db::Net *net = sc->net_for_pin (pin->id ()); + if (net && ((net->terminal_count () + net->pin_count ()) > 0 || net->subcircuit_pin_count () > 1)) { + is_not_connected = false; + } + } + + if (is_not_connected) { + if (mp_logger) { + mp_logger->match_pins (pin1, pin2); + } + } else { + if (mp_logger) { + mp_logger->pin_mismatch (pin1, pin2); + } + good = false; + pin_mismatch = true; + } +} + void NetlistComparer::do_pin_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping, bool &pin_mismatch, bool &good) const { // Report pin assignment // This step also does the pin identity mapping. - if (c1->pin_count () > 0 && c2->pin_count () > 0) { + // try to assign floating pins by name with higher prio + std::map > floating_pins_by_name; - // try to assign floating pins by name with higher prio - std::map > floating_pins_by_name; - - for (db::Circuit::const_pin_iterator p = c2->begin_pins (); p != c2->end_pins (); ++p) { - const db::Net *net = c2->net_for_pin (p->id ()); - if (!net && !p->name ().empty ()) { - floating_pins_by_name.insert (std::make_pair (normalize_name (p->name ()), std::make_pair ((const db::Pin *) 0, (const db::Pin *) 0))).first->second.second = p.operator-> (); - } + for (db::Circuit::const_pin_iterator p = c2->begin_pins (); p != c2->end_pins (); ++p) { + const db::Net *net = c2->net_for_pin (p->id ()); + if (!net && !p->name ().empty ()) { + floating_pins_by_name.insert (std::make_pair (normalize_name (p->name ()), std::make_pair ((const db::Pin *) 0, (const db::Pin *) 0))).first->second.second = p.operator-> (); } + } - for (db::Circuit::const_pin_iterator p = c1->begin_pins (); p != c1->end_pins (); ++p) { - const db::Net *net = c1->net_for_pin (p->id ()); - if (!net && !p->name ().empty ()) { - floating_pins_by_name.insert (std::make_pair (normalize_name (p->name ()), std::make_pair ((const db::Pin *) 0, (const db::Pin *) 0))).first->second.first = p.operator-> (); - } + for (db::Circuit::const_pin_iterator p = c1->begin_pins (); p != c1->end_pins (); ++p) { + const db::Net *net = c1->net_for_pin (p->id ()); + if (!net && !p->name ().empty ()) { + floating_pins_by_name.insert (std::make_pair (normalize_name (p->name ()), std::make_pair ((const db::Pin *) 0, (const db::Pin *) 0))).first->second.first = p.operator-> (); } + } - std::map floating_pin_name_mapping; - for (std::map >::const_iterator i = floating_pins_by_name.begin (); i != floating_pins_by_name.end (); ++i) { - if (i->second.first && i->second.second) { - floating_pin_name_mapping [i->second.first] = i->second.second; - floating_pin_name_mapping [i->second.second] = i->second.first; - } + std::map floating_pin_name_mapping; + for (std::map >::const_iterator i = floating_pins_by_name.begin (); i != floating_pins_by_name.end (); ++i) { + if (i->second.first && i->second.second) { + floating_pin_name_mapping [i->second.first] = i->second.second; + floating_pin_name_mapping [i->second.second] = i->second.first; } + } - std::vector floating_pins; - std::multimap net2pin; - for (db::Circuit::const_pin_iterator p = c2->begin_pins (); p != c2->end_pins (); ++p) { - const db::Net *net = c2->net_for_pin (p->id ()); - if (net) { - net2pin.insert (std::make_pair (g2.node_index_for_net (net), p.operator-> ())); - } else if (floating_pin_name_mapping.find (p.operator-> ()) == floating_pin_name_mapping.end ()) { - floating_pins.push_back (p.operator-> ()); - } + std::vector floating_pins; + std::multimap net2pin; + for (db::Circuit::const_pin_iterator p = c2->begin_pins (); p != c2->end_pins (); ++p) { + const db::Net *net = c2->net_for_pin (p->id ()); + if (net) { + net2pin.insert (std::make_pair (g2.node_index_for_net (net), p.operator-> ())); + } else if (floating_pin_name_mapping.find (p.operator-> ()) == floating_pin_name_mapping.end ()) { + floating_pins.push_back (p.operator-> ()); } + } - std::vector::iterator next_float = floating_pins.begin (); + std::vector::iterator next_float = floating_pins.begin (); - CircuitMapper &c12_pin_mapping = c12_circuit_and_pin_mapping [c1]; - c12_pin_mapping.set_other (c2); + CircuitMapper &c12_pin_mapping = c12_circuit_and_pin_mapping [c1]; + c12_pin_mapping.set_other (c2); - // dummy mapping: we show this circuit is used. - CircuitMapper &c22_pin_mapping = c22_circuit_and_pin_mapping [c2]; - c22_pin_mapping.set_other (c2); + // dummy mapping: we show this circuit is used. + CircuitMapper &c22_pin_mapping = c22_circuit_and_pin_mapping [c2]; + c22_pin_mapping.set_other (c2); - for (db::Circuit::const_pin_iterator p = c1->begin_pins (); p != c1->end_pins (); ++p) { + for (db::Circuit::const_pin_iterator p = c1->begin_pins (); p != c1->end_pins (); ++p) { - const db::Net *net = c1->net_for_pin (p->id ()); - if (! net) { + const db::Net *net = c1->net_for_pin (p->id ()); + if (! net) { - std::map::const_iterator fp = floating_pin_name_mapping.find (p.operator-> ()); - if (fp != floating_pin_name_mapping.end ()) { - - // assign a floating pin - this is a dummy assignment which is mitigated - // by declaring the pins equivalent in derive_pin_equivalence - if (mp_logger) { - mp_logger->match_pins (p.operator-> (), fp->second); - } - c12_pin_mapping.map_pin (p->id (), fp->second->id ()); - c22_pin_mapping.map_pin (fp->second->id (), p->id ()); - - } else if (next_float != floating_pins.end ()) { - - // assign a floating pin - this is a dummy assignment which is mitigated - // by declaring the pins equivalent in derive_pin_equivalence - if (mp_logger) { - mp_logger->match_pins (p.operator-> (), *next_float); - } - c12_pin_mapping.map_pin (p->id (), (*next_float)->id ()); - c22_pin_mapping.map_pin ((*next_float)->id (), p->id ()); - - ++next_float; - - } else { - - // otherwise this is an error - if (mp_logger) { - mp_logger->pin_mismatch (p.operator-> (), 0); - } - - pin_mismatch = true; - good = false; + std::map::const_iterator fp = floating_pin_name_mapping.find (p.operator-> ()); + if (fp != floating_pin_name_mapping.end ()) { + // assign a floating pin - this is a dummy assignment which is mitigated + // by declaring the pins equivalent in derive_pin_equivalence + if (mp_logger) { + mp_logger->match_pins (p.operator-> (), fp->second); } + c12_pin_mapping.map_pin (p->id (), fp->second->id ()); + c22_pin_mapping.map_pin (fp->second->id (), p->id ()); - continue; + } else if (next_float != floating_pins.end ()) { + + // assign a floating pin - this is a dummy assignment which is mitigated + // by declaring the pins equivalent in derive_pin_equivalence + if (mp_logger) { + mp_logger->match_pins (p.operator-> (), *next_float); + } + c12_pin_mapping.map_pin (p->id (), (*next_float)->id ()); + c22_pin_mapping.map_pin ((*next_float)->id (), p->id ()); + + ++next_float; + + } else { + + // otherwise this is an error for subcircuits or worth a report for top-level circuits + handle_pin_mismatch (c1, p.operator-> (), c2, 0, good, pin_mismatch); } - const db::NetGraphNode &n = *(g1.begin () + g1.node_index_for_net (net)); + continue; - if (! n.has_other ()) { + } + + const db::NetGraphNode &n = *(g1.begin () + g1.node_index_for_net (net)); + + if (! n.has_other ()) { + + handle_pin_mismatch (c1, p.operator-> (), c2, 0, good, pin_mismatch); + + continue; + + } + + std::multimap::iterator np = net2pin.find (n.other_net_index ()); + for (db::Net::const_pin_iterator pi = net->begin_pins (); pi != net->end_pins (); ++pi) { + + if (np != net2pin.end () && np->first == n.other_net_index ()) { if (mp_logger) { - mp_logger->pin_mismatch (p.operator-> (), 0); + mp_logger->match_pins (pi->pin (), np->second); } + c12_pin_mapping.map_pin (pi->pin ()->id (), np->second->id ()); + // dummy mapping: we show this pin is used. + c22_pin_mapping.map_pin (np->second->id (), np->second->id ()); - pin_mismatch = true; - good = false; + std::multimap::iterator np_delete = np; + ++np; + net2pin.erase (np_delete); - continue; + } else { - } - - std::multimap::iterator np = net2pin.find (n.other_net_index ()); - for (db::Net::const_pin_iterator pi = net->begin_pins (); pi != net->end_pins (); ++pi) { - - if (np != net2pin.end () && np->first == n.other_net_index ()) { - - if (mp_logger) { - mp_logger->match_pins (pi->pin (), np->second); - } - c12_pin_mapping.map_pin (pi->pin ()->id (), np->second->id ()); - // dummy mapping: we show this pin is used. - c22_pin_mapping.map_pin (np->second->id (), np->second->id ()); - - std::multimap::iterator np_delete = np; - ++np; - net2pin.erase (np_delete); - - } else { - - if (mp_logger) { - mp_logger->pin_mismatch (pi->pin (), 0); - } - pin_mismatch = true; - good = false; - - } + handle_pin_mismatch (c1, pi->pin (), c2, 0, good, pin_mismatch); } } - for (std::multimap::iterator np = net2pin.begin (); np != net2pin.end (); ++np) { - if (mp_logger) { - mp_logger->pin_mismatch (0, np->second); - } - pin_mismatch = true; - good = false; - } + } - while (next_float != floating_pins.end ()) { - if (mp_logger) { - mp_logger->pin_mismatch (0, *next_float); - } - pin_mismatch = true; - good = false; - ++next_float; - } - - } else { - - // skip pin mapping in case one circuit does not feature pins - // This is often the case for top-level circuits. We don't necessarily need pins for them. - // We still report those circuits with "pin mismatch" so they don't get considered within - // subcircuits. Plus we report the pins so they get listed in the cross-ref (but with a - // "match" - this is important to cover the cases which are found when analyzing the nets). - - if (mp_logger) { - for (db::Circuit::const_pin_iterator p = c1->begin_pins (); p != c1->end_pins (); ++p) { - mp_logger->match_pins (p.operator-> (), 0); - } - for (db::Circuit::const_pin_iterator p = c2->begin_pins (); p != c2->end_pins (); ++p) { - mp_logger->match_pins (0, p.operator-> ()); - } - } - - if (c1->pin_count () != c2->pin_count ()) { - pin_mismatch = true; - } + for (std::multimap::iterator np = net2pin.begin (); np != net2pin.end (); ++np) { + handle_pin_mismatch (c1, 0, c2, np->second, good, pin_mismatch); + } + while (next_float != floating_pins.end ()) { + handle_pin_mismatch (c1, 0, c2, *next_float, good, pin_mismatch); + ++next_float; } } diff --git a/src/db/db/dbNetlistCompare.h b/src/db/db/dbNetlistCompare.h index 774936442..46f4dcb56 100644 --- a/src/db/db/dbNetlistCompare.h +++ b/src/db/db/dbNetlistCompare.h @@ -297,6 +297,7 @@ protected: void do_pin_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping, bool &pin_mismatch, bool &good) const; void do_device_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, const db::DeviceFilter &device_filter, DeviceCategorizer &device_categorizer, bool &good) const; void do_subcircuit_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, CircuitCategorizer &circuit_categorizer, const db::CircuitPinMapper &circuit_pin_mapper, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping, bool &good) const; + void handle_pin_mismatch (const db::Circuit *c1, const db::Pin *pin1, const db::Circuit *c2, const db::Pin *p2, bool &good, bool &pin_mismatch) const; mutable NetlistCompareLogger *mp_logger; std::map, std::vector > > m_same_nets; diff --git a/src/db/unit_tests/dbNetlistTests.cc b/src/db/unit_tests/dbNetlistTests.cc index fdffed627..a4db90bb7 100644 --- a/src/db/unit_tests/dbNetlistTests.cc +++ b/src/db/unit_tests/dbNetlistTests.cc @@ -780,7 +780,7 @@ TEST(7_NetTerminalsEditing) EXPECT_EQ (n1->terminal_count (), size_t (1)); EXPECT_EQ (n1->pin_count (), size_t (0)); - EXPECT_EQ (n1->is_floating (), true); + EXPECT_EQ (n1->is_floating (), false); EXPECT_EQ (n1->is_internal (), false); d2->connect_terminal (1, n1); From 60ed0cdc89f2f4160cb19d55f965802cb1fe54e0 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 29 Aug 2019 23:26:03 +0200 Subject: [PATCH 22/27] Updated test golden data (mainly: nets are not purged when there is a subcircuit pin on it) --- src/db/unit_tests/dbLayoutToNetlistTests.cc | 64 ++--- src/db/unit_tests/dbNetlistCompareTests.cc | 8 +- src/db/unit_tests/dbNetlistExtractorTests.cc | 36 +-- src/db/unit_tests/dbNetlistReaderTests.cc | 10 +- testdata/algo/l2n_writer_au.txt | 115 +++++++-- testdata/algo/l2n_writer_au_2.gds | Bin 14582 -> 13334 bytes testdata/algo/l2n_writer_au_2.txt | 91 ++++--- testdata/algo/l2n_writer_au_2s.txt | 91 ++++--- testdata/algo/l2n_writer_au_s.txt | 115 +++++++-- testdata/algo/lvs_test1_au.lvsdb.1 | 134 ++++++++-- testdata/algo/lvs_test1b_au.lvsdb.1 | 134 ++++++++-- testdata/algo/lvs_test2_au.lvsdb.1 | 116 +++++++-- testdata/algo/lvs_test2b_au.lvsdb.1 | 116 +++++++-- testdata/lvs/ringo_simple_dummy_device.cir | 38 +-- .../lvs/ringo_simple_dummy_device.lvsdb.1 | 233 +++++++++--------- testdata/python/dbLayoutToNetlist.py | 10 +- testdata/ruby/dbLayoutToNetlist.rb | 10 +- testdata/ruby/dbNetlist.rb | 4 +- testdata/ruby/dbNetlistReaderTests.rb | 2 +- 19 files changed, 936 insertions(+), 391 deletions(-) diff --git a/src/db/unit_tests/dbLayoutToNetlistTests.cc b/src/db/unit_tests/dbLayoutToNetlistTests.cc index 640552385..c4b7ca373 100644 --- a/src/db/unit_tests/dbLayoutToNetlistTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistTests.cc @@ -554,15 +554,15 @@ TEST(1_BasicExtraction) db::compare_netlist (_this, *l2n.netlist (), "circuit RINGO (FB=FB,OSC=OSC,VSS=VSS,VDD=VDD);\n" " subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $2 (IN=FB,$2=(null),OUT=$I19,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $3 (IN=$I19,$2=(null),OUT=$I1,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $4 (IN=$I1,$2=(null),OUT=$I2,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $5 (IN=$I2,$2=(null),OUT=$I3,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $6 (IN=$I3,$2=(null),OUT=$I4,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $7 (IN=$I4,$2=(null),OUT=$I5,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $8 (IN=$I5,$2=(null),OUT=$I6,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $9 (IN=$I6,$2=(null),OUT=$I7,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $10 (IN=$I7,$2=(null),OUT=$I8,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $3 (IN=$I19,$2=$I39,OUT=$I1,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $4 (IN=$I1,$2=$I40,OUT=$I2,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $5 (IN=$I2,$2=$I41,OUT=$I3,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $6 (IN=$I3,$2=$I42,OUT=$I4,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $7 (IN=$I4,$2=$I43,OUT=$I5,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $8 (IN=$I5,$2=$I44,OUT=$I6,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $9 (IN=$I6,$2=$I45,OUT=$I7,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $10 (IN=$I7,$2=$I46,OUT=$I8,$4=VSS,$5=VDD);\n" "end;\n" "circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n" " device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" @@ -583,7 +583,7 @@ TEST(1_BasicExtraction) // the transistor which supplies this probe target has been optimized away by "purge". EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (5.3, 0.0))), "(null)"); - EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "INV2:$2"); + EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "RINGO:$I39"); EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (6.4, 1.0))), "RINGO:$I2"); } @@ -806,14 +806,14 @@ TEST(2_Probing) db::compare_netlist (_this, *l2n.netlist (), "circuit RINGO (FB=FB,OSC=OSC,VSS=VSS,VDD=VDD);\n" " subcircuit INV2PAIR $1 ($1=FB,$2=VDD,$3=VSS,$4=$I3,$5=OSC);\n" - " subcircuit INV2PAIR $2 ($1=(null),$2=VDD,$3=VSS,$4=FB,$5=$I9);\n" - " subcircuit INV2PAIR $3 ($1=(null),$2=VDD,$3=VSS,$4=$I9,$5=$I1);\n" - " subcircuit INV2PAIR $4 ($1=(null),$2=VDD,$3=VSS,$4=$I1,$5=$I2);\n" - " subcircuit INV2PAIR $5 ($1=(null),$2=VDD,$3=VSS,$4=$I2,$5=$I3);\n" + " subcircuit INV2PAIR $2 ($1=$I18,$2=VDD,$3=VSS,$4=FB,$5=$I9);\n" + " subcircuit INV2PAIR $3 ($1=$I19,$2=VDD,$3=VSS,$4=$I9,$5=$I1);\n" + " subcircuit INV2PAIR $4 ($1=$I20,$2=VDD,$3=VSS,$4=$I1,$5=$I2);\n" + " subcircuit INV2PAIR $5 ($1=$I21,$2=VDD,$3=VSS,$4=$I2,$5=$I3);\n" "end;\n" "circuit INV2PAIR ($1=$I7,$2=$I5,$3=$I4,$4=$I2,$5=$I1);\n" " subcircuit INV2 $1 (IN=$I3,$2=$I7,OUT=$I1,$4=$I4,$5=$I5);\n" - " subcircuit INV2 $2 (IN=$I2,$2=(null),OUT=$I3,$4=$I4,$5=$I5);\n" + " subcircuit INV2 $2 (IN=$I2,$2=$I6,OUT=$I3,$4=$I4,$5=$I5);\n" "end;\n" "circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n" " device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" @@ -834,7 +834,7 @@ TEST(2_Probing) // the transistor which supplies this probe target has been optimized away by "purge". EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (5.3, 0.0))), "(null)"); - EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "INV2PAIR:$I7"); + EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "RINGO:$I18"); EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (6.4, 1.0))), "INV2PAIR:$I3"); } @@ -1087,13 +1087,13 @@ TEST(3_GlobalNetConnections) db::compare_netlist (_this, *l2n.netlist (), "circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,VSS=VSS);\n" " subcircuit INV2PAIR $1 (BULK=VSS,$2=FB,$3=VDD,$4=VSS,$5=$I7,$6=OSC,$7=VDD);\n" - " subcircuit INV2PAIR $2 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=FB,$6=$I13,$7=VDD);\n" - " subcircuit INV2PAIR $3 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=$I13,$6=$I5,$7=VDD);\n" - " subcircuit INV2PAIR $4 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=$I5,$6=$I6,$7=VDD);\n" - " subcircuit INV2PAIR $5 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=$I6,$6=$I7,$7=VDD);\n" + " subcircuit INV2PAIR $2 (BULK=VSS,$2=$I22,$3=VDD,$4=VSS,$5=FB,$6=$I13,$7=VDD);\n" + " subcircuit INV2PAIR $3 (BULK=VSS,$2=$I23,$3=VDD,$4=VSS,$5=$I13,$6=$I5,$7=VDD);\n" + " subcircuit INV2PAIR $4 (BULK=VSS,$2=$I24,$3=VDD,$4=VSS,$5=$I5,$6=$I6,$7=VDD);\n" + " subcircuit INV2PAIR $5 (BULK=VSS,$2=$I25,$3=VDD,$4=VSS,$5=$I6,$6=$I7,$7=VDD);\n" "end;\n" "circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1);\n" - " subcircuit INV2 $1 ($1=$I1,IN=$I3,$3=(null),OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK);\n" + " subcircuit INV2 $1 ($1=$I1,IN=$I3,$3=$I7,OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK);\n" " subcircuit INV2 $2 ($1=$I1,IN=$I4,$3=$I8,OUT=$I2,VSS=$I5,VDD=$I6,BULK=BULK);\n" "end;\n" "circuit INV2 ($1=(null),IN=IN,$3=$3,OUT=OUT,VSS=VSS,VDD=VDD,BULK=(null));\n" @@ -1115,7 +1115,7 @@ TEST(3_GlobalNetConnections) // the transistor which supplies this probe target has been optimized away by "purge". EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (5.3, 0.0))), "(null)"); - EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "INV2PAIR:$I8"); + EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "RINGO:$I22"); EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (6.4, 1.0))), "INV2PAIR:$I4"); } @@ -1374,13 +1374,13 @@ TEST(4_GlobalNetDeviceExtraction) db::compare_netlist (_this, *l2n.netlist (), "circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,VSS=VSS);\n" " subcircuit INV2PAIR $1 (BULK=VSS,$2=FB,$3=VDD,$4=VSS,$5=$I7,$6=OSC,$7=VDD);\n" - " subcircuit INV2PAIR $2 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=FB,$6=$I13,$7=VDD);\n" - " subcircuit INV2PAIR $3 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=$I13,$6=$I5,$7=VDD);\n" - " subcircuit INV2PAIR $4 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=$I5,$6=$I6,$7=VDD);\n" - " subcircuit INV2PAIR $5 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=$I6,$6=$I7,$7=VDD);\n" + " subcircuit INV2PAIR $2 (BULK=VSS,$2=$I22,$3=VDD,$4=VSS,$5=FB,$6=$I13,$7=VDD);\n" + " subcircuit INV2PAIR $3 (BULK=VSS,$2=$I23,$3=VDD,$4=VSS,$5=$I13,$6=$I5,$7=VDD);\n" + " subcircuit INV2PAIR $4 (BULK=VSS,$2=$I24,$3=VDD,$4=VSS,$5=$I5,$6=$I6,$7=VDD);\n" + " subcircuit INV2PAIR $5 (BULK=VSS,$2=$I25,$3=VDD,$4=VSS,$5=$I6,$6=$I7,$7=VDD);\n" "end;\n" "circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1);\n" - " subcircuit INV2 $1 ($1=$I1,IN=$I3,$3=(null),OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK);\n" + " subcircuit INV2 $1 ($1=$I1,IN=$I3,$3=$I7,OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK);\n" " subcircuit INV2 $2 ($1=$I1,IN=$I4,$3=$I8,OUT=$I2,VSS=$I5,VDD=$I6,BULK=BULK);\n" "end;\n" "circuit INV2 ($1=$1,IN=IN,$3=$3,OUT=OUT,VSS=VSS,VDD=VDD,BULK=BULK);\n" @@ -1402,7 +1402,7 @@ TEST(4_GlobalNetDeviceExtraction) // the transistor which supplies this probe target has been optimized away by "purge". EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (5.3, 0.0))), "(null)"); - EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "INV2PAIR:$I8"); + EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "RINGO:$I22"); EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (6.4, 1.0))), "INV2PAIR:$I4"); } @@ -1658,10 +1658,10 @@ TEST(5_DeviceExtractionWithDeviceCombination) db::compare_netlist (_this, *l2n.netlist (), "circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,VSS=VSS);\n" " subcircuit INV2PAIR $1 (BULK=VSS,$2=VDD,$3=VSS,$4=FB,$5=$I7,$6=OSC,$7=VDD);\n" - " subcircuit INV2PAIR $2 (BULK=VSS,$2=VDD,$3=VSS,$4=(null),$5=FB,$6=$I13,$7=VDD);\n" - " subcircuit INV2PAIR $3 (BULK=VSS,$2=VDD,$3=VSS,$4=(null),$5=$I13,$6=$I5,$7=VDD);\n" - " subcircuit INV2PAIR $4 (BULK=VSS,$2=VDD,$3=VSS,$4=(null),$5=$I5,$6=$I6,$7=VDD);\n" - " subcircuit INV2PAIR $5 (BULK=VSS,$2=VDD,$3=VSS,$4=(null),$5=$I6,$6=$I7,$7=VDD);\n" + " subcircuit INV2PAIR $2 (BULK=VSS,$2=VDD,$3=VSS,$4=$I22,$5=FB,$6=$I13,$7=VDD);\n" + " subcircuit INV2PAIR $3 (BULK=VSS,$2=VDD,$3=VSS,$4=$I23,$5=$I13,$6=$I5,$7=VDD);\n" + " subcircuit INV2PAIR $4 (BULK=VSS,$2=VDD,$3=VSS,$4=$I24,$5=$I5,$6=$I6,$7=VDD);\n" + " subcircuit INV2PAIR $5 (BULK=VSS,$2=VDD,$3=VSS,$4=$I25,$5=$I6,$6=$I7,$7=VDD);\n" "end;\n" "circuit INV2PAIR (BULK=BULK,$2=$I6,$3=$I5,$4=$I4,$5=$I3,$6=$I2,$7=$I1);\n" " subcircuit INV2 $1 ($1=$I1,IN=$I3,OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK);\n" diff --git a/src/db/unit_tests/dbNetlistCompareTests.cc b/src/db/unit_tests/dbNetlistCompareTests.cc index 60267320e..1412d5c9d 100644 --- a/src/db/unit_tests/dbNetlistCompareTests.cc +++ b/src/db/unit_tests/dbNetlistCompareTests.cc @@ -2053,12 +2053,12 @@ TEST(14_Subcircuit2NandMismatchNoSwap) "net_mismatch INT IN1\n" "net_mismatch IN1 INT\n" "net_mismatch IN2 IN2\n" - "pin_mismatch $0 (null)\n" + "match_pins $0 (null)\n" "match_pins $1 $1\n" "match_pins $2 $2\n" "match_pins $3 $3\n" "match_pins $4 $4\n" - "pin_mismatch (null) $0\n" + "match_pins (null) $0\n" "match_subcircuits $2 $1\n" "subcircuit_mismatch $1 $2\n" "end_circuit TOP TOP NOMATCH" @@ -2106,8 +2106,8 @@ TEST(14_Subcircuit2NandMismatchNoSwap) " device $1:$1 [Match]\n" " device $2:$2 [Match]\n" "TOP:TOP [NoMatch]:\n" - " pin (null):$0 [Mismatch]\n" - " pin $0:(null) [Mismatch]\n" + " pin (null):$0 [Match]\n" + " pin $0:(null) [Match]\n" " pin $1:$1 [Match]\n" " pin $2:$2 [Match]\n" " pin $3:$3 [Match]\n" diff --git a/src/db/unit_tests/dbNetlistExtractorTests.cc b/src/db/unit_tests/dbNetlistExtractorTests.cc index 38c2d7789..932334032 100644 --- a/src/db/unit_tests/dbNetlistExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistExtractorTests.cc @@ -354,15 +354,15 @@ TEST(1_DeviceAndNetExtraction) db::compare_netlist (_this, nl, "circuit RINGO (FB=FB,OSC=OSC,VSS=VSS,VDD=VDD);\n" " subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $2 (IN=FB,$2=(null),OUT=$I19,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $3 (IN=$I19,$2=(null),OUT=$I1,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $4 (IN=$I1,$2=(null),OUT=$I2,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $5 (IN=$I2,$2=(null),OUT=$I3,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $6 (IN=$I3,$2=(null),OUT=$I4,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $7 (IN=$I4,$2=(null),OUT=$I5,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $8 (IN=$I5,$2=(null),OUT=$I6,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $9 (IN=$I6,$2=(null),OUT=$I7,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $10 (IN=$I7,$2=(null),OUT=$I8,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $3 (IN=$I19,$2=$I39,OUT=$I1,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $4 (IN=$I1,$2=$I40,OUT=$I2,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $5 (IN=$I2,$2=$I41,OUT=$I3,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $6 (IN=$I3,$2=$I42,OUT=$I4,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $7 (IN=$I4,$2=$I43,OUT=$I5,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $8 (IN=$I5,$2=$I44,OUT=$I6,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $9 (IN=$I6,$2=$I45,OUT=$I7,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $10 (IN=$I7,$2=$I46,OUT=$I8,$4=VSS,$5=VDD);\n" "end;\n" "circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n" " device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" @@ -819,15 +819,15 @@ TEST(3_DeviceAndNetExtractionWithImplicitConnections) db::compare_netlist (_this, nl, "circuit RINGO (FB=FB,OSC=OSC,NEXT=NEXT,'VSSZ,VSS'='VSSZ,VSS','VDDZ,VDD'='VDDZ,VDD');\n" " subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4='VSSZ,VSS',$5='VDDZ,VDD');\n" - " subcircuit INV2 $2 (IN=FB,$2=(null),OUT=$I19,$4='VSSZ,VSS',$5='VDDZ,VDD');\n" - " subcircuit INV2 $3 (IN=NEXT,$2=(null),OUT=$I5,$4='VSSZ,VSS',$5='VDDZ,VDD');\n" - " subcircuit INV2 $4 (IN=$I3,$2=(null),OUT=NEXT,$4='VSSZ,VSS',$5='VDDZ,VDD');\n" - " subcircuit INV2 $5 (IN=$I5,$2=(null),OUT=$I6,$4='VSSZ,VSS',$5='VDDZ,VDD');\n" - " subcircuit INV2 $6 (IN=$I6,$2=(null),OUT=$I7,$4='VSSZ,VSS',$5='VDDZ,VDD');\n" - " subcircuit INV2 $7 (IN=$I7,$2=(null),OUT=$I8,$4='VSSZ,VSS',$5='VDDZ,VDD');\n" - " subcircuit INV2 $8 (IN=$I19,$2=(null),OUT=$I1,$4='VSSZ,VSS',$5='VDDZ,VDD');\n" - " subcircuit INV2 $9 (IN=$I1,$2=(null),OUT=$I2,$4='VSSZ,VSS',$5='VDDZ,VDD');\n" - " subcircuit INV2 $10 (IN=$I2,$2=(null),OUT=$I3,$4='VSSZ,VSS',$5='VDDZ,VDD');\n" + " subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4='VSSZ,VSS',$5='VDDZ,VDD');\n" + " subcircuit INV2 $3 (IN=NEXT,$2=$I43,OUT=$I5,$4='VSSZ,VSS',$5='VDDZ,VDD');\n" + " subcircuit INV2 $4 (IN=$I3,$2=$I42,OUT=NEXT,$4='VSSZ,VSS',$5='VDDZ,VDD');\n" + " subcircuit INV2 $5 (IN=$I5,$2=$I44,OUT=$I6,$4='VSSZ,VSS',$5='VDDZ,VDD');\n" + " subcircuit INV2 $6 (IN=$I6,$2=$I45,OUT=$I7,$4='VSSZ,VSS',$5='VDDZ,VDD');\n" + " subcircuit INV2 $7 (IN=$I7,$2=$I46,OUT=$I8,$4='VSSZ,VSS',$5='VDDZ,VDD');\n" + " subcircuit INV2 $8 (IN=$I19,$2=$I39,OUT=$I1,$4='VSSZ,VSS',$5='VDDZ,VDD');\n" + " subcircuit INV2 $9 (IN=$I1,$2=$I40,OUT=$I2,$4='VSSZ,VSS',$5='VDDZ,VDD');\n" + " subcircuit INV2 $10 (IN=$I2,$2=$I41,OUT=$I3,$4='VSSZ,VSS',$5='VDDZ,VDD');\n" "end;\n" "circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n" " device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" diff --git a/src/db/unit_tests/dbNetlistReaderTests.cc b/src/db/unit_tests/dbNetlistReaderTests.cc index 045090a59..98a6b3491 100644 --- a/src/db/unit_tests/dbNetlistReaderTests.cc +++ b/src/db/unit_tests/dbNetlistReaderTests.cc @@ -137,10 +137,10 @@ TEST(4_ReaderWithUnconnectedPins) EXPECT_EQ (nl.to_string (), "circuit RINGO ('1'='1','2'='2','3'='3','4'='4');\n" " subcircuit INV2PAIR $1 ('1'='4','2'='3','3'='4','4'='1','5'='6','6'='2','7'='3');\n" - " subcircuit INV2PAIR $2 ('1'='4','2'='3','3'='4','4'=(null),'5'='1','6'='5','7'='3');\n" - " subcircuit INV2PAIR $3 ('1'='4','2'='3','3'='4','4'=(null),'5'='5','6'='8','7'='3');\n" - " subcircuit INV2PAIR $4 ('1'='4','2'='3','3'='4','4'=(null),'5'='8','6'='7','7'='3');\n" - " subcircuit INV2PAIR $5 ('1'='4','2'='3','3'='4','4'=(null),'5'='7','6'='6','7'='3');\n" + " subcircuit INV2PAIR $2 ('1'='4','2'='3','3'='4','4'='100','5'='1','6'='5','7'='3');\n" + " subcircuit INV2PAIR $3 ('1'='4','2'='3','3'='4','4'='101','5'='5','6'='8','7'='3');\n" + " subcircuit INV2PAIR $4 ('1'='4','2'='3','3'='4','4'='102','5'='8','6'='7','7'='3');\n" + " subcircuit INV2PAIR $5 ('1'='4','2'='3','3'='4','4'='103','5'='7','6'='6','7'='3');\n" "end;\n" "circuit INV2PAIR ('1'='1','2'='2','3'='3','4'='4','5'='5','6'='6','7'='7');\n" " subcircuit INV2 $1 ('1'='7','2'='5','3'='4','4'='3','5'='2','6'='1');\n" @@ -251,7 +251,7 @@ TEST(6_ReaderWithDelegate) " device RES $1 (A=A,B=Z) (R=100000,L=0,W=0,A=0,P=0);\n" "end;\n" "circuit .TOP ();\n" - " subcircuit SUBCKT SUBCKT ($1=(null),A=(null),VDD=(null),Z=(null),GND=VSS,GND$1=VSS);\n" + " subcircuit SUBCKT SUBCKT ($1=IN,A=OUT,VDD=VDD,Z=Z,GND=VSS,GND$1=VSS);\n" "end;\n" ); } diff --git a/testdata/algo/l2n_writer_au.txt b/testdata/algo/l2n_writer_au.txt index 6a9228b28..3d97644d3 100644 --- a/testdata/algo/l2n_writer_au.txt +++ b/testdata/algo/l2n_writer_au.txt @@ -363,54 +363,108 @@ circuit(RINGO rect(metal2_lbl (-23941 -381) (2 2)) ) net(5 + rect(diff_cont (20210 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(6 + rect(diff_cont (17570 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(7 + rect(diff_cont (14930 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(8 + rect(diff_cont (12290 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(9 + rect(diff_cont (9650 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(10 + rect(diff_cont (7010 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(11 + rect(diff_cont (4370 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(12 + rect(diff_cont (1730 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(13 + rect(diff_cont (-910 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(14 rect(diff_cont (690 2890) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -2620) (220 220)) rect(diff_cont (-220 -620) (220 220)) ) - net(6 + net(15 rect(diff_cont (21810 2890) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -2620) (220 220)) rect(diff_cont (-220 -620) (220 220)) ) - net(7 + net(16 rect(diff_cont (19170 2890) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -2620) (220 220)) rect(diff_cont (-220 -620) (220 220)) ) - net(8 + net(17 rect(diff_cont (16530 2890) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -2620) (220 220)) rect(diff_cont (-220 -620) (220 220)) ) - net(9 + net(18 rect(diff_cont (13890 2890) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -2620) (220 220)) rect(diff_cont (-220 -620) (220 220)) ) - net(10 + net(19 rect(diff_cont (11250 2890) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -2620) (220 220)) rect(diff_cont (-220 -620) (220 220)) ) - net(11 + net(20 rect(diff_cont (8610 2890) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -2620) (220 220)) rect(diff_cont (-220 -620) (220 220)) ) - net(12 + net(21 rect(diff_cont (5970 2890) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -2620) (220 220)) rect(diff_cont (-220 -620) (220 220)) ) - net(13 + net(22 rect(diff_cont (3330 2890) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -2620) (220 220)) @@ -425,7 +479,7 @@ circuit(RINGO # Subcircuits and their connections circuit(1 INV2 location(23760 0) - pin(0 6) + pin(0 15) pin(1 1) pin(2 2) pin(3 3) @@ -433,55 +487,64 @@ circuit(RINGO ) circuit(2 INV2 location(0 0) pin(0 1) - pin(2 5) + pin(1 13) + pin(2 14) pin(3 3) pin(4 4) ) circuit(3 INV2 location(2640 0) - pin(0 5) - pin(2 13) + pin(0 14) + pin(1 12) + pin(2 22) pin(3 3) pin(4 4) ) circuit(4 INV2 location(5280 0) - pin(0 13) - pin(2 12) + pin(0 22) + pin(1 11) + pin(2 21) pin(3 3) pin(4 4) ) circuit(5 INV2 location(7920 0) - pin(0 12) - pin(2 11) + pin(0 21) + pin(1 10) + pin(2 20) pin(3 3) pin(4 4) ) circuit(6 INV2 location(10560 0) - pin(0 11) - pin(2 10) + pin(0 20) + pin(1 9) + pin(2 19) pin(3 3) pin(4 4) ) circuit(7 INV2 location(13200 0) - pin(0 10) - pin(2 9) + pin(0 19) + pin(1 8) + pin(2 18) pin(3 3) pin(4 4) ) circuit(8 INV2 location(15840 0) - pin(0 9) - pin(2 8) + pin(0 18) + pin(1 7) + pin(2 17) pin(3 3) pin(4 4) ) circuit(9 INV2 location(18480 0) - pin(0 8) - pin(2 7) + pin(0 17) + pin(1 6) + pin(2 16) pin(3 3) pin(4 4) ) circuit(10 INV2 location(21120 0) - pin(0 7) - pin(2 6) + pin(0 16) + pin(1 5) + pin(2 15) pin(3 3) pin(4 4) ) diff --git a/testdata/algo/l2n_writer_au_2.gds b/testdata/algo/l2n_writer_au_2.gds index 6ba0a3c82af4c7c64d7d967db31f493519e11b96..ad232c88802491914579fcbfffed27b62957cef4 100644 GIT binary patch delta 2021 zcmexXI4whofsKKQDS|9=puuC_a5g98&Z6ahbRIhmb7}t2TRy z{lsNpgoHe6J=S!}z{AGoqT=W4AFN`?z{1YJAj66?u`_VN)Dlz)HZ=gn)OzH6gUp5) z3sOwbSfB$!f*k#V83?KbI>660BwoeS1gMsafk8-U@^a+>W$aBJjvA#v_}HN8fT)e5Puu8R5`dpyrN4=8T#%cA3p8>cWf)*aHI| za;B3Db)+Wm)N~`H& zER_r>k3xNKir-Lk8?1)nF*7U}l$n4TL<|z5lk0SNH}BLIW5FNkVJk)R-a@VS?uUZSL=hbW5Z%v`TK!ko39zB}jpzH`n!Gjs353*WCL zK?7MHhL|KfKj7L600C&UuBVd?A$wxv3_+}p+7m1%5f=7BqCC50%CjI-o`^zu?kki> zRw>U-lKG;(BX;`ULDeZ}6!S(qNo3pSq?kn~)xo@rsuQlDn8^yFPVsj|ULl$*c)!{+ z#SveNL{N|YRKDVm;C`Z1u`m3SN;n*;b4=KNr{K}FoZf%**r1*U)d>)DkRLm^g?3w| znRQ@G)(Pu>V_oyKhIrew*uc>7uKq#TR_W8U{`}CWp6=AMsCEOee*b}9uNuI=TJAi@y&sgzM2}K-H4NPANO>mi%=cxYTa)Ba_X!h;` z(7ZAzp!sAx(RLYob3R9JisOz?0IsJ10!19r-rr~>xPw`TI69Xw!AD$gAdj=FH8Gu6 zaIbR=wDL*W6fNE?U}7<2f0w7h$E^2COK-FlrYZgEr5aEXNccQDB_3~weKQV z`+K-rpok+{)DjNG$SuF(YJnn-$kpc!m2!)#)dE)w6mdlBC>>i~1y;~zao>o}8@TWJ z5{kGs%WgZODdjF7x`ATY0*#?_-jvF#0Ma=2kLa1fv2~PC#HH~~sUb0>{(D?1P{chm zhP2Pjy1=FC9G41|HsXlpUdx{?>}>p;{b|Tr6Cu`BH(Z8&S%$q_#`ii=E^BXnhVV|+ zA10W!`fhusm`hek4faQ{IIG$__1=yL$!NzB{4dN;8z)+RY#_XC!keA?Z*Nw37b<$1DTy|C1^DLC9^}F%H2$t?4R+ov{_rnGa}mVo&I Lu|y`Ms4Dygd|_m_ diff --git a/testdata/algo/l2n_writer_au_2.txt b/testdata/algo/l2n_writer_au_2.txt index 2c615dffc..c232887a5 100644 --- a/testdata/algo/l2n_writer_au_2.txt +++ b/testdata/algo/l2n_writer_au_2.txt @@ -264,6 +264,12 @@ circuit(INV2PAIR rect(diff_cont (-220 180) (220 220)) ) net(3 + rect(diff_cont (790 3290) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(4 rect(diff_cont (4230 3290) (220 220)) rect(diff_cont (-220 180) (220 220)) rect(diff_cont (-220 -220) (220 220)) @@ -277,7 +283,7 @@ circuit(INV2PAIR rect(metal1 (-3000 -760) (360 760)) rect(metal1 (-360 -760) (360 760)) ) - net(4 + net(5 rect(diff_cont (4230 490) (220 220)) rect(diff_cont (-220 180) (220 220)) rect(diff_cont (-220 -220) (220 220)) @@ -291,46 +297,47 @@ circuit(INV2PAIR rect(metal1 (-3000 -760) (360 760)) rect(metal1 (-360 -760) (360 760)) ) - net(5 + net(6 rect(diff_cont (2390 3690) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -2620) (220 220)) rect(diff_cont (-220 -620) (220 220)) ) - net(6) - net(7 + net(7) + net(8 rect(diff_cont (5030 3690) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -2620) (220 220)) rect(diff_cont (-220 -620) (220 220)) ) - net(8) + net(9) # Outgoing pins and their connections to nets pin(1 name(BULK)) pin(2) - pin(3) pin(4) - pin(6) + pin(5) pin(7) pin(8) + pin(9) # Subcircuits and their connections circuit(1 INV2 location(1700 800) - pin(0 8) - pin(1 6) - pin(3 5) - pin(4 4) - pin(5 3) + pin(0 9) + pin(1 7) + pin(2 3) + pin(3 6) + pin(4 5) + pin(5 4) pin(6 1) ) circuit(2 INV2 location(4340 800) - pin(0 8) - pin(1 5) + pin(0 9) + pin(1 6) pin(2 2) - pin(3 7) - pin(4 4) - pin(5 3) + pin(3 8) + pin(4 5) + pin(5 4) pin(6 1) ) @@ -508,24 +515,48 @@ circuit(RINGO rect(metal2_lbl (-21301 -381) (2 2)) ) net(5 + rect(diff_cont (17570 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(6 + rect(diff_cont (12290 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(7 + rect(diff_cont (7010 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(8 + rect(diff_cont (1730 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(9 rect(diff_cont (3330 2890) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -2620) (220 220)) rect(diff_cont (-220 -620) (220 220)) ) - net(6 + net(10 rect(diff_cont (19170 2890) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -2620) (220 220)) rect(diff_cont (-220 -620) (220 220)) ) - net(7 + net(11 rect(diff_cont (13890 2890) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -2620) (220 220)) rect(diff_cont (-220 -620) (220 220)) ) - net(8 + net(12 rect(diff_cont (8610 2890) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -2620) (220 220)) @@ -544,40 +575,44 @@ circuit(RINGO pin(1 1) pin(2 3) pin(3 4) - pin(4 6) + pin(4 10) pin(5 2) pin(6 3) ) circuit(2 INV2PAIR location(-1700 -800) pin(0 4) + pin(1 8) pin(2 3) pin(3 4) pin(4 1) - pin(5 5) + pin(5 9) pin(6 3) ) circuit(3 INV2PAIR location(3580 -800) pin(0 4) + pin(1 7) pin(2 3) pin(3 4) - pin(4 5) - pin(5 8) + pin(4 9) + pin(5 12) pin(6 3) ) circuit(4 INV2PAIR location(8860 -800) pin(0 4) + pin(1 6) pin(2 3) pin(3 4) - pin(4 8) - pin(5 7) + pin(4 12) + pin(5 11) pin(6 3) ) circuit(5 INV2PAIR location(14140 -800) pin(0 4) + pin(1 5) pin(2 3) pin(3 4) - pin(4 7) - pin(5 6) + pin(4 11) + pin(5 10) pin(6 3) ) diff --git a/testdata/algo/l2n_writer_au_2s.txt b/testdata/algo/l2n_writer_au_2s.txt index 7af0f364f..c12295b2d 100644 --- a/testdata/algo/l2n_writer_au_2s.txt +++ b/testdata/algo/l2n_writer_au_2s.txt @@ -232,6 +232,12 @@ X(INV2PAIR R(diff_cont (-220 180) (220 220)) ) N(3 + R(diff_cont (790 3290) (220 220)) + R(diff_cont (-220 180) (220 220)) + R(diff_cont (-220 -3420) (220 220)) + R(diff_cont (-220 180) (220 220)) + ) + N(4 R(diff_cont (4230 3290) (220 220)) R(diff_cont (-220 180) (220 220)) R(diff_cont (-220 -220) (220 220)) @@ -245,7 +251,7 @@ X(INV2PAIR R(metal1 (-3000 -760) (360 760)) R(metal1 (-360 -760) (360 760)) ) - N(4 + N(5 R(diff_cont (4230 490) (220 220)) R(diff_cont (-220 180) (220 220)) R(diff_cont (-220 -220) (220 220)) @@ -259,42 +265,43 @@ X(INV2PAIR R(metal1 (-3000 -760) (360 760)) R(metal1 (-360 -760) (360 760)) ) - N(5 + N(6 R(diff_cont (2390 3690) (220 220)) R(diff_cont (-220 -620) (220 220)) R(diff_cont (-220 -2620) (220 220)) R(diff_cont (-220 -620) (220 220)) ) - N(6) - N(7 + N(7) + N(8 R(diff_cont (5030 3690) (220 220)) R(diff_cont (-220 -620) (220 220)) R(diff_cont (-220 -2620) (220 220)) R(diff_cont (-220 -620) (220 220)) ) - N(8) + N(9) P(1 I(BULK)) P(2) - P(3) P(4) - P(6) + P(5) P(7) P(8) + P(9) X(1 INV2 Y(1700 800) - P(0 8) - P(1 6) - P(3 5) - P(4 4) - P(5 3) + P(0 9) + P(1 7) + P(2 3) + P(3 6) + P(4 5) + P(5 4) P(6 1) ) X(2 INV2 Y(4340 800) - P(0 8) - P(1 5) + P(0 9) + P(1 6) P(2 2) - P(3 7) - P(4 4) - P(5 3) + P(3 8) + P(4 5) + P(5 4) P(6 1) ) ) @@ -467,24 +474,48 @@ X(RINGO R(metal2_lbl (-21301 -381) (2 2)) ) N(5 + R(diff_cont (17570 2490) (220 220)) + R(diff_cont (-220 180) (220 220)) + R(diff_cont (-220 -3420) (220 220)) + R(diff_cont (-220 180) (220 220)) + ) + N(6 + R(diff_cont (12290 2490) (220 220)) + R(diff_cont (-220 180) (220 220)) + R(diff_cont (-220 -3420) (220 220)) + R(diff_cont (-220 180) (220 220)) + ) + N(7 + R(diff_cont (7010 2490) (220 220)) + R(diff_cont (-220 180) (220 220)) + R(diff_cont (-220 -3420) (220 220)) + R(diff_cont (-220 180) (220 220)) + ) + N(8 + R(diff_cont (1730 2490) (220 220)) + R(diff_cont (-220 180) (220 220)) + R(diff_cont (-220 -3420) (220 220)) + R(diff_cont (-220 180) (220 220)) + ) + N(9 R(diff_cont (3330 2890) (220 220)) R(diff_cont (-220 -620) (220 220)) R(diff_cont (-220 -2620) (220 220)) R(diff_cont (-220 -620) (220 220)) ) - N(6 + N(10 R(diff_cont (19170 2890) (220 220)) R(diff_cont (-220 -620) (220 220)) R(diff_cont (-220 -2620) (220 220)) R(diff_cont (-220 -620) (220 220)) ) - N(7 + N(11 R(diff_cont (13890 2890) (220 220)) R(diff_cont (-220 -620) (220 220)) R(diff_cont (-220 -2620) (220 220)) R(diff_cont (-220 -620) (220 220)) ) - N(8 + N(12 R(diff_cont (8610 2890) (220 220)) R(diff_cont (-220 -620) (220 220)) R(diff_cont (-220 -2620) (220 220)) @@ -499,40 +530,44 @@ X(RINGO P(1 1) P(2 3) P(3 4) - P(4 6) + P(4 10) P(5 2) P(6 3) ) X(2 INV2PAIR Y(-1700 -800) P(0 4) + P(1 8) P(2 3) P(3 4) P(4 1) - P(5 5) + P(5 9) P(6 3) ) X(3 INV2PAIR Y(3580 -800) P(0 4) + P(1 7) P(2 3) P(3 4) - P(4 5) - P(5 8) + P(4 9) + P(5 12) P(6 3) ) X(4 INV2PAIR Y(8860 -800) P(0 4) + P(1 6) P(2 3) P(3 4) - P(4 8) - P(5 7) + P(4 12) + P(5 11) P(6 3) ) X(5 INV2PAIR Y(14140 -800) P(0 4) + P(1 5) P(2 3) P(3 4) - P(4 7) - P(5 6) + P(4 11) + P(5 10) P(6 3) ) ) diff --git a/testdata/algo/l2n_writer_au_s.txt b/testdata/algo/l2n_writer_au_s.txt index 84903d827..5d9d02240 100644 --- a/testdata/algo/l2n_writer_au_s.txt +++ b/testdata/algo/l2n_writer_au_s.txt @@ -333,54 +333,108 @@ X(RINGO R(metal2_lbl (-23941 -381) (2 2)) ) N(5 + R(diff_cont (20210 2490) (220 220)) + R(diff_cont (-220 180) (220 220)) + R(diff_cont (-220 -3420) (220 220)) + R(diff_cont (-220 180) (220 220)) + ) + N(6 + R(diff_cont (17570 2490) (220 220)) + R(diff_cont (-220 180) (220 220)) + R(diff_cont (-220 -3420) (220 220)) + R(diff_cont (-220 180) (220 220)) + ) + N(7 + R(diff_cont (14930 2490) (220 220)) + R(diff_cont (-220 180) (220 220)) + R(diff_cont (-220 -3420) (220 220)) + R(diff_cont (-220 180) (220 220)) + ) + N(8 + R(diff_cont (12290 2490) (220 220)) + R(diff_cont (-220 180) (220 220)) + R(diff_cont (-220 -3420) (220 220)) + R(diff_cont (-220 180) (220 220)) + ) + N(9 + R(diff_cont (9650 2490) (220 220)) + R(diff_cont (-220 180) (220 220)) + R(diff_cont (-220 -3420) (220 220)) + R(diff_cont (-220 180) (220 220)) + ) + N(10 + R(diff_cont (7010 2490) (220 220)) + R(diff_cont (-220 180) (220 220)) + R(diff_cont (-220 -3420) (220 220)) + R(diff_cont (-220 180) (220 220)) + ) + N(11 + R(diff_cont (4370 2490) (220 220)) + R(diff_cont (-220 180) (220 220)) + R(diff_cont (-220 -3420) (220 220)) + R(diff_cont (-220 180) (220 220)) + ) + N(12 + R(diff_cont (1730 2490) (220 220)) + R(diff_cont (-220 180) (220 220)) + R(diff_cont (-220 -3420) (220 220)) + R(diff_cont (-220 180) (220 220)) + ) + N(13 + R(diff_cont (-910 2490) (220 220)) + R(diff_cont (-220 180) (220 220)) + R(diff_cont (-220 -3420) (220 220)) + R(diff_cont (-220 180) (220 220)) + ) + N(14 R(diff_cont (690 2890) (220 220)) R(diff_cont (-220 -620) (220 220)) R(diff_cont (-220 -2620) (220 220)) R(diff_cont (-220 -620) (220 220)) ) - N(6 + N(15 R(diff_cont (21810 2890) (220 220)) R(diff_cont (-220 -620) (220 220)) R(diff_cont (-220 -2620) (220 220)) R(diff_cont (-220 -620) (220 220)) ) - N(7 + N(16 R(diff_cont (19170 2890) (220 220)) R(diff_cont (-220 -620) (220 220)) R(diff_cont (-220 -2620) (220 220)) R(diff_cont (-220 -620) (220 220)) ) - N(8 + N(17 R(diff_cont (16530 2890) (220 220)) R(diff_cont (-220 -620) (220 220)) R(diff_cont (-220 -2620) (220 220)) R(diff_cont (-220 -620) (220 220)) ) - N(9 + N(18 R(diff_cont (13890 2890) (220 220)) R(diff_cont (-220 -620) (220 220)) R(diff_cont (-220 -2620) (220 220)) R(diff_cont (-220 -620) (220 220)) ) - N(10 + N(19 R(diff_cont (11250 2890) (220 220)) R(diff_cont (-220 -620) (220 220)) R(diff_cont (-220 -2620) (220 220)) R(diff_cont (-220 -620) (220 220)) ) - N(11 + N(20 R(diff_cont (8610 2890) (220 220)) R(diff_cont (-220 -620) (220 220)) R(diff_cont (-220 -2620) (220 220)) R(diff_cont (-220 -620) (220 220)) ) - N(12 + N(21 R(diff_cont (5970 2890) (220 220)) R(diff_cont (-220 -620) (220 220)) R(diff_cont (-220 -2620) (220 220)) R(diff_cont (-220 -620) (220 220)) ) - N(13 + N(22 R(diff_cont (3330 2890) (220 220)) R(diff_cont (-220 -620) (220 220)) R(diff_cont (-220 -2620) (220 220)) @@ -391,7 +445,7 @@ X(RINGO P(3 I(VSS)) P(4 I(VDD)) X(1 INV2 Y(23760 0) - P(0 6) + P(0 15) P(1 1) P(2 2) P(3 3) @@ -399,55 +453,64 @@ X(RINGO ) X(2 INV2 Y(0 0) P(0 1) - P(2 5) + P(1 13) + P(2 14) P(3 3) P(4 4) ) X(3 INV2 Y(2640 0) - P(0 5) - P(2 13) + P(0 14) + P(1 12) + P(2 22) P(3 3) P(4 4) ) X(4 INV2 Y(5280 0) - P(0 13) - P(2 12) + P(0 22) + P(1 11) + P(2 21) P(3 3) P(4 4) ) X(5 INV2 Y(7920 0) - P(0 12) - P(2 11) + P(0 21) + P(1 10) + P(2 20) P(3 3) P(4 4) ) X(6 INV2 Y(10560 0) - P(0 11) - P(2 10) + P(0 20) + P(1 9) + P(2 19) P(3 3) P(4 4) ) X(7 INV2 Y(13200 0) - P(0 10) - P(2 9) + P(0 19) + P(1 8) + P(2 18) P(3 3) P(4 4) ) X(8 INV2 Y(15840 0) - P(0 9) - P(2 8) + P(0 18) + P(1 7) + P(2 17) P(3 3) P(4 4) ) X(9 INV2 Y(18480 0) - P(0 8) - P(2 7) + P(0 17) + P(1 6) + P(2 16) P(3 3) P(4 4) ) X(10 INV2 Y(21120 0) - P(0 7) - P(2 6) + P(0 16) + P(1 5) + P(2 15) P(3 3) P(4 4) ) diff --git a/testdata/algo/lvs_test1_au.lvsdb.1 b/testdata/algo/lvs_test1_au.lvsdb.1 index 5f45d3819..add09797d 100644 --- a/testdata/algo/lvs_test1_au.lvsdb.1 +++ b/testdata/algo/lvs_test1_au.lvsdb.1 @@ -655,7 +655,7 @@ layout( rect(metal2_lbl (-21301 -381) (2 2)) ) net(5 - rect(diff_cont (1730 90) (220 220)) + rect(diff_cont (14930 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -673,7 +673,7 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(6 - rect(diff_cont (17570 90) (220 220)) + rect(diff_cont (9650 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -691,7 +691,7 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(7 - rect(diff_cont (12290 90) (220 220)) + rect(diff_cont (4370 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -709,6 +709,78 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(8 + rect(diff_cont (-910 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(9 + rect(diff_cont (1730 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(10 + rect(diff_cont (17570 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(11 + rect(diff_cont (12290 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(12 rect(diff_cont (7010 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -739,7 +811,7 @@ layout( pin(1 3) pin(2 4) pin(3 1) - pin(4 6) + pin(4 10) pin(5 2) pin(6 3) ) @@ -747,32 +819,36 @@ layout( pin(0 4) pin(1 3) pin(2 4) + pin(3 8) pin(4 1) - pin(5 5) + pin(5 9) pin(6 3) ) circuit(3 INV2PAIR location(3580 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 5) - pin(5 8) + pin(3 7) + pin(4 9) + pin(5 12) pin(6 3) ) circuit(4 INV2PAIR location(8860 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 8) - pin(5 7) + pin(3 6) + pin(4 12) + pin(5 11) pin(6 3) ) circuit(5 INV2PAIR location(14140 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 7) - pin(5 6) + pin(3 5) + pin(4 11) + pin(5 10) pin(6 3) ) @@ -882,9 +958,13 @@ reference( net(3 name('3')) net(4 name('4')) net(5 name('6')) - net(6 name('5')) - net(7 name('8')) - net(8 name('7')) + net(6 name('100')) + net(7 name('5')) + net(8 name('101')) + net(9 name('8')) + net(10 name('102')) + net(11 name('7')) + net(12 name('103')) # Outgoing pins and their connections to nets pin(1 name('1')) @@ -906,31 +986,35 @@ reference( pin(0 4) pin(1 3) pin(2 4) + pin(3 6) pin(4 1) - pin(5 6) + pin(5 7) pin(6 3) ) circuit(3 INV2PAIR name($3) pin(0 4) pin(1 3) pin(2 4) - pin(4 6) - pin(5 7) + pin(3 8) + pin(4 7) + pin(5 9) pin(6 3) ) circuit(4 INV2PAIR name($4) pin(0 4) pin(1 3) pin(2 4) - pin(4 7) - pin(5 8) + pin(3 10) + pin(4 9) + pin(5 11) pin(6 3) ) circuit(5 INV2PAIR name($5) pin(0 4) pin(1 3) pin(2 4) - pin(4 8) + pin(3 12) + pin(4 11) pin(5 5) pin(6 3) ) @@ -980,10 +1064,14 @@ xref( ) circuit(RINGO RINGO match xref( - net(5 6 match) - net(6 5 match) + net(8 6 match) net(7 8 match) - net(8 7 match) + net(6 10 match) + net(5 12 match) + net(9 7 match) + net(10 5 match) + net(11 11 match) + net(12 9 match) net(1 1 match) net(2 2 match) net(3 3 match) diff --git a/testdata/algo/lvs_test1b_au.lvsdb.1 b/testdata/algo/lvs_test1b_au.lvsdb.1 index ca44150de..460cae8e7 100644 --- a/testdata/algo/lvs_test1b_au.lvsdb.1 +++ b/testdata/algo/lvs_test1b_au.lvsdb.1 @@ -655,7 +655,7 @@ layout( rect(metal2_lbl (-21301 -381) (2 2)) ) net(5 - rect(diff_cont (1730 90) (220 220)) + rect(diff_cont (14930 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -673,7 +673,7 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(6 - rect(diff_cont (17570 90) (220 220)) + rect(diff_cont (9650 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -691,7 +691,7 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(7 - rect(diff_cont (12290 90) (220 220)) + rect(diff_cont (4370 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -709,6 +709,78 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(8 + rect(diff_cont (-910 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(9 + rect(diff_cont (1730 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(10 + rect(diff_cont (17570 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(11 + rect(diff_cont (12290 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(12 rect(diff_cont (7010 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -739,7 +811,7 @@ layout( pin(1 3) pin(2 4) pin(3 1) - pin(4 6) + pin(4 10) pin(5 2) pin(6 3) ) @@ -747,32 +819,36 @@ layout( pin(0 4) pin(1 3) pin(2 4) + pin(3 8) pin(4 1) - pin(5 5) + pin(5 9) pin(6 3) ) circuit(3 INV2PAIR location(3580 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 5) - pin(5 8) + pin(3 7) + pin(4 9) + pin(5 12) pin(6 3) ) circuit(4 INV2PAIR location(8860 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 8) - pin(5 7) + pin(3 6) + pin(4 12) + pin(5 11) pin(6 3) ) circuit(5 INV2PAIR location(14140 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 7) - pin(5 6) + pin(3 5) + pin(4 11) + pin(5 10) pin(6 3) ) @@ -882,9 +958,13 @@ reference( net(3 name('3')) net(4 name('4')) net(5 name('6')) - net(6 name('5')) - net(7 name('8')) - net(8 name('7')) + net(6 name('100')) + net(7 name('5')) + net(8 name('101')) + net(9 name('8')) + net(10 name('102')) + net(11 name('7')) + net(12 name('103')) # Outgoing pins and their connections to nets pin(1 name('1')) @@ -906,31 +986,35 @@ reference( pin(0 4) pin(1 3) pin(2 4) + pin(3 6) pin(4 1) - pin(5 6) + pin(5 7) pin(6 3) ) circuit(3 INV2PAIR name($3) pin(0 4) pin(1 3) pin(2 4) - pin(4 6) - pin(5 7) + pin(3 8) + pin(4 7) + pin(5 9) pin(6 3) ) circuit(4 INV2PAIR name($4) pin(0 4) pin(1 3) pin(2 4) - pin(4 7) - pin(5 8) + pin(3 10) + pin(4 9) + pin(5 11) pin(6 3) ) circuit(5 INV2PAIR name($5) pin(0 4) pin(1 3) pin(2 4) - pin(4 8) + pin(3 12) + pin(4 11) pin(5 5) pin(6 3) ) @@ -980,10 +1064,14 @@ xref( ) circuit(RINGO RINGO match xref( - net(5 6 match) - net(6 5 match) + net(8 6 match) net(7 8 match) - net(8 7 match) + net(6 10 match) + net(5 12 match) + net(9 7 match) + net(10 5 match) + net(11 11 match) + net(12 9 match) net(1 1 match) net(2 2 match) net(3 3 match) diff --git a/testdata/algo/lvs_test2_au.lvsdb.1 b/testdata/algo/lvs_test2_au.lvsdb.1 index 85ec734bf..5526f557a 100644 --- a/testdata/algo/lvs_test2_au.lvsdb.1 +++ b/testdata/algo/lvs_test2_au.lvsdb.1 @@ -655,7 +655,7 @@ layout( rect(metal2_lbl (-21301 -381) (2 2)) ) net(5 - rect(diff_cont (1730 90) (220 220)) + rect(diff_cont (14930 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -673,7 +673,7 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(6 - rect(diff_cont (17570 90) (220 220)) + rect(diff_cont (9650 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -691,7 +691,7 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(7 - rect(diff_cont (12290 90) (220 220)) + rect(diff_cont (4370 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -709,6 +709,78 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(8 + rect(diff_cont (-910 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(9 + rect(diff_cont (1730 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(10 + rect(diff_cont (17570 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(11 + rect(diff_cont (12290 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(12 rect(diff_cont (7010 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -739,7 +811,7 @@ layout( pin(1 3) pin(2 4) pin(3 1) - pin(4 6) + pin(4 10) pin(5 2) pin(6 3) ) @@ -747,32 +819,36 @@ layout( pin(0 4) pin(1 3) pin(2 4) + pin(3 8) pin(4 1) - pin(5 5) + pin(5 9) pin(6 3) ) circuit(3 INV2PAIR location(3580 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 5) - pin(5 8) + pin(3 7) + pin(4 9) + pin(5 12) pin(6 3) ) circuit(4 INV2PAIR location(8860 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 8) - pin(5 7) + pin(3 6) + pin(4 12) + pin(5 11) pin(6 3) ) circuit(5 INV2PAIR location(14140 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 7) - pin(5 6) + pin(3 5) + pin(4 11) + pin(5 10) pin(6 3) ) @@ -874,8 +950,11 @@ reference( net(4 name('4')) net(5 name('6')) net(6 name('5')) - net(7 name('8')) - net(8 name('7')) + net(7 name('101')) + net(8 name('8')) + net(9 name('102')) + net(10 name('7')) + net(11 name('103')) # Outgoing pins and their connections to nets pin(1 name('1')) @@ -906,23 +985,26 @@ reference( pin(0 4) pin(1 3) pin(2 4) + pin(3 7) pin(4 6) - pin(5 7) + pin(5 8) pin(6 3) ) circuit(4 INV2PAIR name($4) pin(0 4) pin(1 3) pin(2 4) - pin(4 7) - pin(5 8) + pin(3 9) + pin(4 8) + pin(5 10) pin(6 3) ) circuit(5 INV2PAIR name($5) pin(0 4) pin(1 3) pin(2 4) - pin(4 8) + pin(3 11) + pin(4 10) pin(5 5) pin(6 3) ) diff --git a/testdata/algo/lvs_test2b_au.lvsdb.1 b/testdata/algo/lvs_test2b_au.lvsdb.1 index f0a00dfb1..612ed7a51 100644 --- a/testdata/algo/lvs_test2b_au.lvsdb.1 +++ b/testdata/algo/lvs_test2b_au.lvsdb.1 @@ -655,7 +655,7 @@ layout( rect(metal2_lbl (-21301 -381) (2 2)) ) net(5 - rect(diff_cont (1730 90) (220 220)) + rect(diff_cont (14930 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -673,7 +673,7 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(6 - rect(diff_cont (17570 90) (220 220)) + rect(diff_cont (9650 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -691,7 +691,7 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(7 - rect(diff_cont (12290 90) (220 220)) + rect(diff_cont (4370 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -709,6 +709,78 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(8 + rect(diff_cont (-910 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(9 + rect(diff_cont (1730 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(10 + rect(diff_cont (17570 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(11 + rect(diff_cont (12290 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(12 rect(diff_cont (7010 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -739,7 +811,7 @@ layout( pin(1 3) pin(2 4) pin(3 1) - pin(4 6) + pin(4 10) pin(5 2) pin(6 3) ) @@ -747,32 +819,36 @@ layout( pin(0 4) pin(1 3) pin(2 4) + pin(3 8) pin(4 1) - pin(5 5) + pin(5 9) pin(6 3) ) circuit(3 INV2PAIR location(3580 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 5) - pin(5 8) + pin(3 7) + pin(4 9) + pin(5 12) pin(6 3) ) circuit(4 INV2PAIR location(8860 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 8) - pin(5 7) + pin(3 6) + pin(4 12) + pin(5 11) pin(6 3) ) circuit(5 INV2PAIR location(14140 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 7) - pin(5 6) + pin(3 5) + pin(4 11) + pin(5 10) pin(6 3) ) @@ -874,8 +950,11 @@ reference( net(4 name('4')) net(5 name('6')) net(6 name('5')) - net(7 name('8')) - net(8 name('7')) + net(7 name('101')) + net(8 name('8')) + net(9 name('102')) + net(10 name('7')) + net(11 name('103')) # Outgoing pins and their connections to nets pin(1 name('1')) @@ -906,23 +985,26 @@ reference( pin(0 4) pin(1 3) pin(2 4) + pin(3 7) pin(4 6) - pin(5 7) + pin(5 8) pin(6 3) ) circuit(4 INV2PAIR name($4) pin(0 4) pin(1 3) pin(2 4) - pin(4 7) - pin(5 8) + pin(3 9) + pin(4 8) + pin(5 10) pin(6 3) ) circuit(5 INV2PAIR name($5) pin(0 4) pin(1 3) pin(2 4) - pin(4 8) + pin(3 11) + pin(4 10) pin(5 5) pin(6 3) ) diff --git a/testdata/lvs/ringo_simple_dummy_device.cir b/testdata/lvs/ringo_simple_dummy_device.cir index 375af82c0..9b5fe15e2 100644 --- a/testdata/lvs/ringo_simple_dummy_device.cir +++ b/testdata/lvs/ringo_simple_dummy_device.cir @@ -6,38 +6,38 @@ * pin OUT * pin ENABLE * pin VSS -.SUBCKT RINGO 11 12 13 14 15 -* net 11 FB -* net 12 VDD -* net 13 OUT -* net 14 ENABLE -* net 15 VSS +.SUBCKT RINGO 12 13 14 15 16 +* net 12 FB +* net 13 VDD +* net 14 OUT +* net 15 ENABLE +* net 16 VSS * cell instance $3 r0 *1 1.8,0 -X$3 12 1 15 12 11 14 15 ND2X1 +X$3 13 2 16 13 12 15 16 ND2X1 * cell instance $4 r0 *1 4.2,0 -X$4 12 2 15 12 1 15 INVX1 +X$4 13 3 16 13 2 16 INVX1 * cell instance $5 r0 *1 6,0 -X$5 12 3 15 12 2 15 INVX1 +X$5 13 4 16 13 3 16 INVX1 * cell instance $6 r0 *1 7.8,0 -X$6 12 4 15 12 3 15 INVX1 +X$6 13 5 16 13 4 16 INVX1 * cell instance $7 r0 *1 9.6,0 -X$7 12 5 15 12 4 15 INVX1 +X$7 13 6 16 13 5 16 INVX1 * cell instance $8 r0 *1 11.4,0 -X$8 12 6 15 12 5 15 INVX1 +X$8 13 7 16 13 6 16 INVX1 * cell instance $9 r0 *1 13.2,0 -X$9 12 7 15 12 6 15 INVX1 +X$9 13 8 16 13 7 16 INVX1 * cell instance $10 r0 *1 15,0 -X$10 12 8 15 12 7 15 INVX1 +X$10 13 9 16 13 8 16 INVX1 * cell instance $11 r0 *1 16.8,0 -X$11 12 9 15 12 8 15 INVX1 +X$11 13 10 16 13 9 16 INVX1 * cell instance $12 r0 *1 18.6,0 -X$12 12 10 15 12 9 15 INVX1 +X$12 13 11 16 13 10 16 INVX1 * cell instance $13 r0 *1 20.4,0 -X$13 12 11 15 12 10 15 INVX1 +X$13 13 12 16 13 11 16 INVX1 * cell instance $14 r0 *1 22.2,0 -X$14 12 13 15 12 11 15 INVX1 +X$14 13 14 16 13 12 16 INVX1 * device instance $1 r0 *1 26.45,2.075 NMOS -M$1 15 16 15 15 NMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U +M$1 16 1 16 16 NMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U .ENDS RINGO * cell INVX1 diff --git a/testdata/lvs/ringo_simple_dummy_device.lvsdb.1 b/testdata/lvs/ringo_simple_dummy_device.lvsdb.1 index 08f01f7fb..ee46022fe 100644 --- a/testdata/lvs/ringo_simple_dummy_device.lvsdb.1 +++ b/testdata/lvs/ringo_simple_dummy_device.lvsdb.1 @@ -362,67 +362,74 @@ layout( # Nets with their geometries net(1 + rect(l4 (26050 2800) (525 550)) + rect(l4 (-525 -300) (300 300)) + rect(l4 (-25 -2000) (250 1450)) + rect(l8 (-465 310) (180 180)) + rect(l11 (-240 -240) (300 300)) + ) + net(2 rect(l8 (4710 3010) (180 180)) rect(l11 (-850 -240) (610 300)) rect(l2 (-2550 1800) (425 1500)) rect(l2 (950 -1500) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(2 + net(3 rect(l8 (6510 3010) (180 180)) rect(l11 (-1140 -240) (900 300)) rect(l2 (-1275 1800) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(3 + net(4 rect(l8 (8310 3010) (180 180)) rect(l11 (-1140 -240) (900 300)) rect(l2 (-1275 1800) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(4 + net(5 rect(l8 (10110 3010) (180 180)) rect(l11 (-1140 -240) (900 300)) rect(l2 (-1275 1800) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(5 + net(6 rect(l8 (11910 3010) (180 180)) rect(l11 (-1140 -240) (900 300)) rect(l2 (-1275 1800) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(6 + net(7 rect(l8 (13710 3010) (180 180)) rect(l11 (-1140 -240) (900 300)) rect(l2 (-1275 1800) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(7 + net(8 rect(l8 (15510 3010) (180 180)) rect(l11 (-1140 -240) (900 300)) rect(l2 (-1275 1800) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(8 + net(9 rect(l8 (17310 3010) (180 180)) rect(l11 (-1140 -240) (900 300)) rect(l2 (-1275 1800) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(9 + net(10 rect(l8 (19110 3010) (180 180)) rect(l11 (-1140 -240) (900 300)) rect(l2 (-1275 1800) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(10 + net(11 rect(l8 (20910 3010) (180 180)) rect(l11 (-1140 -240) (900 300)) rect(l2 (-1275 1800) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(11 name(FB) + net(12 name(FB) rect(l8 (22710 3010) (180 180)) rect(l8 (-19700 720) (180 180)) rect(l11 (18380 -1140) (900 300)) @@ -437,7 +444,7 @@ layout( rect(l2 (-245 850) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(12 name(VDD) + net(13 name(VDD) rect(l3 (500 4500) (1400 3500)) rect(l3 (-1900 -3500) (600 3500)) rect(l3 (23300 -3500) (1400 3500)) @@ -479,7 +486,7 @@ layout( rect(l9 (-21975 -450) (500 1500)) rect(l9 (22900 -1500) (500 1500)) ) - net(13 name(OUT) + net(14 name(OUT) rect(l11 (23440 3840) (320 320)) rect(l12 (-260 -260) (200 200)) rect(l13 (-101 -101) (2 2)) @@ -487,14 +494,14 @@ layout( rect(l2 (-625 850) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(14 name(ENABLE) + net(15 name(ENABLE) rect(l8 (2510 3010) (180 180)) rect(l11 (-250 -250) (320 320)) rect(l12 (-260 -260) (200 200)) rect(l13 (-101 -101) (2 2)) rect(l13 (-201 -201) (400 400)) ) - net(15 name(VSS) + net(16 name(VSS) rect(l8 (26010 1770) (180 180)) rect(l8 (-180 370) (180 180)) rect(l8 (520 -730) (180 180)) @@ -538,11 +545,11 @@ layout( ) # Outgoing pins and their connections to nets - pin(11 name(FB)) - pin(12 name(VDD)) - pin(13 name(OUT)) - pin(14 name(ENABLE)) - pin(15 name(VSS)) + pin(12 name(FB)) + pin(13 name(VDD)) + pin(14 name(OUT)) + pin(15 name(ENABLE)) + pin(16 name(VSS)) # Devices and their connections device(1 D$NMOS @@ -553,109 +560,109 @@ layout( param(AD 0.40375) param(PS 2.75) param(PD 2.75) - terminal(S 15) - terminal(G) - terminal(D 15) - terminal(B 15) + terminal(S 16) + terminal(G 1) + terminal(D 16) + terminal(B 16) ) # Subcircuits and their connections circuit(3 ND2X1 location(1800 0) - pin(0 12) - pin(1 1) - pin(2 15) - pin(3 12) - pin(4 11) - pin(5 14) - pin(6 15) + pin(0 13) + pin(1 2) + pin(2 16) + pin(3 13) + pin(4 12) + pin(5 15) + pin(6 16) ) circuit(4 INVX1 location(4200 0) - pin(0 12) - pin(1 2) - pin(2 15) - pin(3 12) - pin(4 1) - pin(5 15) + pin(0 13) + pin(1 3) + pin(2 16) + pin(3 13) + pin(4 2) + pin(5 16) ) circuit(5 INVX1 location(6000 0) - pin(0 12) - pin(1 3) - pin(2 15) - pin(3 12) - pin(4 2) - pin(5 15) + pin(0 13) + pin(1 4) + pin(2 16) + pin(3 13) + pin(4 3) + pin(5 16) ) circuit(6 INVX1 location(7800 0) - pin(0 12) - pin(1 4) - pin(2 15) - pin(3 12) - pin(4 3) - pin(5 15) + pin(0 13) + pin(1 5) + pin(2 16) + pin(3 13) + pin(4 4) + pin(5 16) ) circuit(7 INVX1 location(9600 0) - pin(0 12) - pin(1 5) - pin(2 15) - pin(3 12) - pin(4 4) - pin(5 15) + pin(0 13) + pin(1 6) + pin(2 16) + pin(3 13) + pin(4 5) + pin(5 16) ) circuit(8 INVX1 location(11400 0) - pin(0 12) - pin(1 6) - pin(2 15) - pin(3 12) - pin(4 5) - pin(5 15) + pin(0 13) + pin(1 7) + pin(2 16) + pin(3 13) + pin(4 6) + pin(5 16) ) circuit(9 INVX1 location(13200 0) - pin(0 12) - pin(1 7) - pin(2 15) - pin(3 12) - pin(4 6) - pin(5 15) + pin(0 13) + pin(1 8) + pin(2 16) + pin(3 13) + pin(4 7) + pin(5 16) ) circuit(10 INVX1 location(15000 0) - pin(0 12) - pin(1 8) - pin(2 15) - pin(3 12) - pin(4 7) - pin(5 15) + pin(0 13) + pin(1 9) + pin(2 16) + pin(3 13) + pin(4 8) + pin(5 16) ) circuit(11 INVX1 location(16800 0) - pin(0 12) - pin(1 9) - pin(2 15) - pin(3 12) - pin(4 8) - pin(5 15) + pin(0 13) + pin(1 10) + pin(2 16) + pin(3 13) + pin(4 9) + pin(5 16) ) circuit(12 INVX1 location(18600 0) - pin(0 12) - pin(1 10) - pin(2 15) - pin(3 12) - pin(4 9) - pin(5 15) + pin(0 13) + pin(1 11) + pin(2 16) + pin(3 13) + pin(4 10) + pin(5 16) ) circuit(13 INVX1 location(20400 0) - pin(0 12) - pin(1 11) - pin(2 15) - pin(3 12) - pin(4 10) - pin(5 15) + pin(0 13) + pin(1 12) + pin(2 16) + pin(3 13) + pin(4 11) + pin(5 16) ) circuit(14 INVX1 location(22200 0) - pin(0 12) - pin(1 13) - pin(2 15) - pin(3 12) - pin(4 11) - pin(5 15) + pin(0 13) + pin(1 14) + pin(2 16) + pin(3 13) + pin(4 12) + pin(5 16) ) ) @@ -811,6 +818,7 @@ reference( net(13 name('8')) net(14 name('9')) net(15 name('10')) + net(16 name(DUMMY)) # Outgoing pins and their connections to nets pin(1 name(VSS)) @@ -829,7 +837,7 @@ reference( param(PS 0) param(PD 0) terminal(S 1) - terminal(G) + terminal(G 16) terminal(D 1) terminal(B 1) ) @@ -981,21 +989,22 @@ xref( ) circuit(RINGO RINGO match xref( - net(1 6 match) - net(10 15 match) - net(2 7 match) - net(3 8 match) - net(4 9 match) - net(5 10 match) - net(6 11 match) - net(7 12 match) - net(8 13 match) - net(9 14 match) - net(14 4 match) - net(11 3 match) - net(13 5 match) - net(12 2 match) - net(15 1 match) + net(2 6 match) + net(11 15 match) + net(3 7 match) + net(4 8 match) + net(5 9 match) + net(6 10 match) + net(7 11 match) + net(8 12 match) + net(9 13 match) + net(10 14 match) + net(1 16 match) + net(15 4 match) + net(12 3 match) + net(14 5 match) + net(13 2 match) + net(16 1 match) pin(3 3 match) pin(0 2 match) pin(2 4 match) diff --git a/testdata/python/dbLayoutToNetlist.py b/testdata/python/dbLayoutToNetlist.py index ea7df5f46..11e395309 100644 --- a/testdata/python/dbLayoutToNetlist.py +++ b/testdata/python/dbLayoutToNetlist.py @@ -416,13 +416,13 @@ end; self.assertEqual(str(l2n.netlist()), """circuit RINGO (FB=FB,OSC=OSC,VDD=VDD,VSS=VSS); subcircuit INV2PAIR $1 (BULK=VSS,$2=FB,$3=VDD,$4=VSS,$5=$I7,$6=OSC,$7=VDD); - subcircuit INV2PAIR $2 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=FB,$6=$I13,$7=VDD); - subcircuit INV2PAIR $3 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=$I13,$6=$I5,$7=VDD); - subcircuit INV2PAIR $4 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=$I5,$6=$I6,$7=VDD); - subcircuit INV2PAIR $5 (BULK=VSS,$2=(null),$3=VDD,$4=VSS,$5=$I6,$6=$I7,$7=VDD); + subcircuit INV2PAIR $2 (BULK=VSS,$2=$I22,$3=VDD,$4=VSS,$5=FB,$6=$I13,$7=VDD); + subcircuit INV2PAIR $3 (BULK=VSS,$2=$I23,$3=VDD,$4=VSS,$5=$I13,$6=$I5,$7=VDD); + subcircuit INV2PAIR $4 (BULK=VSS,$2=$I24,$3=VDD,$4=VSS,$5=$I5,$6=$I6,$7=VDD); + subcircuit INV2PAIR $5 (BULK=VSS,$2=$I25,$3=VDD,$4=VSS,$5=$I6,$6=$I7,$7=VDD); end; circuit INV2PAIR (BULK=BULK,$2=$I8,$3=$I6,$4=$I5,$5=$I3,$6=$I2,$7=$I1); - subcircuit INV2 $1 ($1=$I1,IN=$I3,$3=(null),OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK); + subcircuit INV2 $1 ($1=$I1,IN=$I3,$3=$I7,OUT=$I4,VSS=$I5,VDD=$I6,BULK=BULK); subcircuit INV2 $2 ($1=$I1,IN=$I4,$3=$I8,OUT=$I2,VSS=$I5,VDD=$I6,BULK=BULK); end; circuit INV2 ($1=$1,IN=IN,$3=$3,OUT=OUT,VSS=VSS,VDD=VDD,BULK=BULK); diff --git a/testdata/ruby/dbLayoutToNetlist.rb b/testdata/ruby/dbLayoutToNetlist.rb index 325e6284d..727ab064a 100644 --- a/testdata/ruby/dbLayoutToNetlist.rb +++ b/testdata/ruby/dbLayoutToNetlist.rb @@ -455,13 +455,13 @@ END assert_equal(l2n.netlist.to_s, < Date: Fri, 30 Aug 2019 10:24:55 +0200 Subject: [PATCH 23/27] Put more amphasis on net names to resolve ambiguities The problem was that with the floating test case, the ambiguity resolution sometimes assigned the wrong pins and floating pins/connected pins were swapped. One option is to make the ambiguity resolver consider the pin connection state when tenatively evaluating nodes. Another option is to put more emphasis on net names and use them for ambiguity resolution. This has helped here. --- src/db/db/dbNetlistCompare.cc | 111 ++++- src/db/db/dbNetlistCompare.h | 18 + src/db/unit_tests/dbNetlistCompareTests.cc | 57 +++ src/lvs/unit_tests/lvsSimpleTests.cc | 10 +- testdata/lvs/floating.cir | 50 +++ testdata/lvs/floating.gds | Bin 0 -> 5258 bytes testdata/lvs/floating.lvs | 75 ++++ testdata/lvs/floating.lvsdb | 454 ++++++++++++++++++++ testdata/lvs/floating_ref.cir | 16 + testdata/lvs/ringo_simple_blackboxing.lvsdb | 8 +- 10 files changed, 785 insertions(+), 14 deletions(-) create mode 100644 testdata/lvs/floating.cir create mode 100644 testdata/lvs/floating.gds create mode 100644 testdata/lvs/floating.lvs create mode 100644 testdata/lvs/floating.lvsdb create mode 100644 testdata/lvs/floating_ref.cir diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index a4dfd9c79..1124dae2d 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -523,12 +523,13 @@ class NetGraph; struct CompareData { CompareData () - : other (0), max_depth (0), max_n_branch (0), logger (0), circuit_pin_mapper (0) + : other (0), max_depth (0), max_n_branch (0), dont_consider_net_names (false), logger (0), circuit_pin_mapper (0) { } NetGraph *other; size_t max_depth; size_t max_n_branch; + bool dont_consider_net_names; NetlistCompareLogger *logger; CircuitPinMapper *circuit_pin_mapper; }; @@ -1009,7 +1010,7 @@ public: * with a proposed identity. With "with_ambiguous", amiguities are resolved by trying * different combinations in tentative mode and deciding for one combination if possible. */ - size_t derive_node_identities_from_node_set (const std::vector &nodes, const std::vector &other_nodes, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, bool with_ambiguous, CompareData *data); + size_t derive_node_identities_from_node_set (std::vector &nodes, std::vector &other_nodes, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, bool with_ambiguous, CompareData *data); private: std::vector m_nodes; @@ -1382,7 +1383,7 @@ NetGraphNode::edge_equal (const db::Net *a, const db::Net *b) */ struct NodeRange { - NodeRange (size_t _num, std::vector::const_iterator _n1, std::vector::const_iterator _nn1, std::vector::const_iterator _n2, std::vector::const_iterator _nn2) + NodeRange (size_t _num, std::vector::iterator _n1, std::vector::iterator _nn1, std::vector::iterator _n2, std::vector::iterator _nn2) : num (_num), n1 (_n1), nn1 (_nn1), n2 (_n2), nn2 (_nn2) { // .. nothing yet .. @@ -1394,7 +1395,7 @@ struct NodeRange } size_t num; - std::vector::const_iterator n1, nn1, n2, nn2; + std::vector::iterator n1, nn1, n2, nn2; }; // -------------------------------------------------------------------------------------------------------------------- @@ -1680,8 +1681,81 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc return new_nodes; } +namespace { + + struct SortNodeByNet + { + public: + bool operator() (const NetGraphNode *a, const NetGraphNode *b) const + { + tl_assert (a->net () && b->net ()); + return a->net ()->name () < b->net ()->name (); + } + }; + +} + +static void sort_node_range_by_best_match (NodeRange &nr) +{ + std::stable_sort (nr.n1, nr.nn1, SortNodeByNet ()); + std::stable_sort (nr.n2, nr.nn2, SortNodeByNet ()); + + std::vector nomatch1, nomatch2; + nomatch1.reserve (nr.nn1 - nr.n1); + nomatch2.reserve (nr.nn2 - nr.n2); + + std::vector::const_iterator i = nr.n1, j = nr.n2; + std::vector::iterator iw = nr.n1, jw = nr.n2; + + SortNodeByNet compare; + + while (i != nr.nn1 || j != nr.nn2) { + if (j == nr.nn2) { + nomatch1.push_back (*i); + ++i; + } else if (i == nr.nn1) { + nomatch2.push_back (*j); + ++j; + } else if (compare (*i, *j)) { + nomatch1.push_back (*i); + ++i; + } else if (compare (*j, *i)) { + nomatch2.push_back (*j); + ++j; + } else { + if (iw != i) { + *iw = *i; + } + ++iw, ++i; + if (jw != j) { + *jw = *j; + } + ++jw, ++j; + } + } + + tl_assert (iw + nomatch1.size () == nr.nn1); + tl_assert (jw + nomatch2.size () == nr.nn2); + + for (i = nomatch1.begin (); i != nomatch1.end (); ++i) { + *iw++ = *i; + } + for (j = nomatch2.begin (); j != nomatch2.end (); ++j) { + *jw++ = *j; + } +} + +static bool net_names_are_different (const db::Net *a, const db::Net *b) +{ + if (! a || ! b || a->name ().empty () || b->name ().empty ()) { + return false; + } else { + return (a->name () != b->name ()); + } +} + size_t -NetGraph::derive_node_identities_from_node_set (const std::vector &nodes, const std::vector &other_nodes, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, bool with_ambiguous, CompareData *data) +NetGraph::derive_node_identities_from_node_set (std::vector &nodes, std::vector &other_nodes, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, bool with_ambiguous, CompareData *data) { #if defined(PRINT_DEBUG_NETCOMPARE) std::string indent; @@ -1757,8 +1831,8 @@ NetGraph::derive_node_identities_from_node_set (const std::vector node_ranges; - std::vector::const_iterator n1 = nodes.begin (); - std::vector::const_iterator n2 = other_nodes.begin (); + std::vector::iterator n1 = nodes.begin (); + std::vector::iterator n2 = other_nodes.begin (); while (n1 != nodes.end () && n2 != other_nodes.end ()) { @@ -1778,7 +1852,7 @@ NetGraph::derive_node_identities_from_node_set (const std::vector::const_iterator nn1 = n1, nn2 = n2; + std::vector::iterator nn1 = n1, nn2 = n2; size_t num = 1; ++nn1; @@ -1853,6 +1927,16 @@ NetGraph::derive_node_identities_from_node_set (const std::vectorn1)->has_other () && ! (*nr->n2)->has_other ()) { + // in tentative mode, reject this choice if both nets are named and + // their names differ -> this favors net matching by name + + if (tentative && ! data->dont_consider_net_names && net_names_are_different ((*nr->n1)->net (), (*nr->n2)->net ())) { +#if defined(PRINT_DEBUG_NETCOMPARE) + tl::info << indent << "rejecting pair as names are not identical: " << (*nr->n1)->net ()->expanded_name () << " vs. " << (*nr->n2)->net ()->expanded_name (); +#endif + return std::numeric_limits::max (); + } + // A single candiate: just take this one -> this may render // inexact matches, but further propagates net pairing @@ -1909,10 +1993,17 @@ NetGraph::derive_node_identities_from_node_set (const std::vectornum << " members"; #endif + + // sort the ambiguity group such that net names + std::vector > pairs; tl::equivalence_clusters equivalent_other_nodes; std::set seen; + if (! data->dont_consider_net_names) { + sort_node_range_by_best_match (*nr); + } + for (std::vector::const_iterator i1 = nr->n1; i1 != nr->nn1; ++i1) { if ((*i1)->has_other ()) { @@ -2061,6 +2152,8 @@ NetlistComparer::NetlistComparer (NetlistCompareLogger *logger) m_max_depth = 8; m_max_n_branch = 100; + + m_dont_consider_net_names = false; } NetlistComparer::~NetlistComparer () @@ -2617,6 +2710,7 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, data.other = &g2; data.max_depth = m_max_depth; data.max_n_branch = m_max_n_branch; + data.dont_consider_net_names = m_dont_consider_net_names; data.circuit_pin_mapper = &circuit_pin_mapper; data.logger = mp_logger; @@ -2669,6 +2763,7 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, data.other = &g2; data.max_depth = m_max_depth; data.max_n_branch = m_max_n_branch; + data.dont_consider_net_names = m_dont_consider_net_names; data.circuit_pin_mapper = &circuit_pin_mapper; data.logger = mp_logger; diff --git a/src/db/db/dbNetlistCompare.h b/src/db/db/dbNetlistCompare.h index 46f4dcb56..bcb6b9f56 100644 --- a/src/db/db/dbNetlistCompare.h +++ b/src/db/db/dbNetlistCompare.h @@ -245,6 +245,23 @@ public: return m_max_depth; } + /** + * @brief Sets a value indicating whether not to consider net names + * This feature is mainly intended for testing. + */ + void set_dont_consider_net_names (bool f) + { + m_dont_consider_net_names = f; + } + + /** + * @brief Gets a value indicating whether not to consider net names + */ + bool dont_consider_net_names () const + { + return m_dont_consider_net_names; + } + /** * @brief Sets the maximum branch complexity * @@ -308,6 +325,7 @@ protected: double m_res_threshold; size_t m_max_n_branch; size_t m_max_depth; + bool m_dont_consider_net_names; }; } diff --git a/src/db/unit_tests/dbNetlistCompareTests.cc b/src/db/unit_tests/dbNetlistCompareTests.cc index 1412d5c9d..7d2443e95 100644 --- a/src/db/unit_tests/dbNetlistCompareTests.cc +++ b/src/db/unit_tests/dbNetlistCompareTests.cc @@ -1661,6 +1661,7 @@ TEST(11_MismatchingSubcircuits) NetlistCompareTestLogger logger; db::NetlistComparer comp (&logger); + comp.set_dont_consider_net_names (true); bool good = comp.compare (&nl1, &nl2); @@ -1696,6 +1697,7 @@ TEST(11_MismatchingSubcircuits) db::NetlistCrossReference xref; db::NetlistComparer comp_xref (&xref); + comp_xref.set_dont_consider_net_names (true); good = comp_xref.compare (&nl1, &nl2); @@ -2521,6 +2523,7 @@ TEST(17_InherentlyAmbiguousDecoder) NetlistCompareTestLogger logger; db::NetlistComparer comp (&logger); comp.equivalent_pins (nl2.circuit_by_name ("NAND"), 0, 1); + comp.set_dont_consider_net_names (true); bool good = comp.compare (&nl1, &nl2); @@ -2572,7 +2575,61 @@ TEST(17_InherentlyAmbiguousDecoder) EXPECT_EQ (good, true); + comp.set_dont_consider_net_names (false); + logger.clear (); + good = comp.compare (&nl1, &nl2); + + EXPECT_EQ (logger.text (), + "begin_circuit NAND NAND\n" + "match_nets VSS VSS\n" + "match_nets INT INT\n" + "match_nets OUT OUT\n" + "match_nets VDD VDD\n" + "match_nets B B\n" + "match_nets A A\n" + "match_pins $0 $0\n" + "match_pins $1 $1\n" + "match_pins $2 $2\n" + "match_pins $3 $3\n" + "match_pins $4 $4\n" + "match_devices $1 $1\n" + "match_devices $2 $2\n" + "match_devices $3 $3\n" + "match_devices $4 $4\n" + "end_circuit NAND NAND MATCH\n" + "begin_circuit DECODER DECODER\n" + "match_nets VSS VSS\n" + "match_nets VDD VDD\n" + "match_nets NQ0 NQ0\n" + "match_nets NQ1 NQ1\n" + "match_nets NQ2 NQ2\n" + "match_nets NQ3 NQ3\n" + "match_ambiguous_nets NA NA\n" + "match_ambiguous_nets NB NB\n" + "match_nets B B\n" + "match_nets A A\n" + "match_pins $0 $1\n" + "match_pins $1 $0\n" + "match_pins $2 $2\n" + "match_pins $3 $3\n" + "match_pins $4 $4\n" + "match_pins $5 $5\n" + "match_pins $6 $6\n" + "match_pins $7 $7\n" + "match_subcircuits $1 $1\n" + "match_subcircuits $2 $2\n" + "match_subcircuits $4 $3\n" + "match_subcircuits $6 $4\n" + "match_subcircuits $3 $5\n" + "match_subcircuits $5 $6\n" + "end_circuit DECODER DECODER MATCH" + ); + + EXPECT_EQ (good, true); + + logger.clear (); + comp.set_dont_consider_net_names (true); comp.same_nets (nl1.circuit_by_name ("DECODER")->net_by_name ("A"), nl2.circuit_by_name ("DECODER")->net_by_name ("A")); good = comp.compare (&nl1, &nl2); diff --git a/src/lvs/unit_tests/lvsSimpleTests.cc b/src/lvs/unit_tests/lvsSimpleTests.cc index 1d3111fe7..2fa9252d2 100644 --- a/src/lvs/unit_tests/lvsSimpleTests.cc +++ b/src/lvs/unit_tests/lvsSimpleTests.cc @@ -28,7 +28,7 @@ #include "lymMacro.h" #include "tlFileUtils.h" -void run_test (tl::TestBase *_this, const std::string &suffix, const std::string &layout, bool with_l2n = false) +void run_test (tl::TestBase *_this, const std::string &suffix, const std::string &layout, bool with_l2n = false, const std::string &top = std::string ()) { std::string rs = tl::testsrc (); rs += "/testdata/lvs/" + suffix + ".lvs"; @@ -57,7 +57,8 @@ void run_test (tl::TestBase *_this, const std::string &suffix, const std::string "$lvs_test_target_lvsdb = '%s'\n" "$lvs_test_target_cir = '%s'\n" "$lvs_test_target_l2n = '%s'\n" - , src, output_lvsdb, output_cir, output_l2n) + "$lvs_test_top = '%s'\n" + , src, output_lvsdb, output_cir, output_l2n, top) ); config.set_interpreter (lym::Macro::Ruby); EXPECT_EQ (config.run (), 0); @@ -148,3 +149,8 @@ TEST(15_simple_dummy_device) { run_test (_this, "ringo_simple_dummy_device", "ringo_dummy_device.gds"); } + +TEST(16_floating) +{ + run_test (_this, "floating", "floating.gds", false, "TOP"); +} diff --git a/testdata/lvs/floating.cir b/testdata/lvs/floating.cir new file mode 100644 index 000000000..ced9a2759 --- /dev/null +++ b/testdata/lvs/floating.cir @@ -0,0 +1,50 @@ +* Extracted by KLayout + +* cell TOP +* pin A +* pin C +* pin SUBSTRATE +.SUBCKT TOP 2 3 4 +* net 2 A +* net 3 C +* net 4 SUBSTRATE +* cell instance $1 r0 *1 0,0 +X$1 2 3 1 6 4 DINV +* cell instance $2 r0 *1 3.6,0 +X$2 5 6 1 4 INVX1 +.ENDS TOP + +* cell DINV +* pin A<1> +* pin A<2> +* pin B<2> +* pin VDD +* pin VSS +.SUBCKT DINV 1 2 3 5 6 +* net 1 A<1> +* net 2 A<2> +* net 3 B<2> +* net 4 B<1> +* net 5 VDD +* net 6 VSS +* cell instance $1 r0 *1 0,0 +X$1 4 5 1 6 INVX1 +* cell instance $2 r0 *1 1.8,0 +X$2 3 5 2 6 INVX1 +.ENDS DINV + +* cell INVX1 +* pin OUT +* pin VDD +* pin IN +* pin VSS +.SUBCKT INVX1 1 2 3 4 +* net 1 OUT +* net 2 VDD +* net 3 IN +* net 4 VSS +* device instance $1 r0 *1 0.85,2.135 NMOS +M$1 4 3 1 4 NMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U +* device instance $2 r0 *1 0.85,5.8 PMOS +M$2 2 3 1 2 PMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U +.ENDS INVX1 diff --git a/testdata/lvs/floating.gds b/testdata/lvs/floating.gds new file mode 100644 index 0000000000000000000000000000000000000000..3329c14d1b9eb2f7b126d6fda2935ac9377839f0 GIT binary patch literal 5258 zcmcJT&1+m$7{=eZcjjg?ndY-3CYks}DMf;kRuG|-BnB~FCH8v)XrY zk)4e7h%fg43EFoBzOTeZcCw%!F6jH{|B&?>sm;qIx5uHu6jKwdr@ymK2oR?J?TyO-+(?a`V{-WQ_#PP zzTZGiFntdGAI&K{SgEI$h1$5t4wmZE$AWLr`Tjj8_2GM^p8aG!_CJMQl)c!0tLO1! zZhusP?heN9O;L8z_rG_hZ6nhzppoNi5>Z8&mi=lj(>&q9WuRjeX?doeOdqdl_`8dd z4w>5c!e^=|dok0Bde%{)ju|S-UesG@rZ#@_nJS`XJ#qa1QIGlT?n!7K*~E-+Sv5eW zGsBco$}my(Vx}GUPv0!@D&f2AU=)8*e?L}A{TpOA;%J}`Tq&aLV5xuhk@ZOG*l$tx zqTW*Lj(=e_!Hl-B(mV^_od4b{ZGCfZe+iAW%vzH=3)|x<=4jun-SKhwuVMdpUu%o- z`bPXUtl93@slpf(*I@FC*$7%7C%?rQ{*+U8(8Vz9&gJeJ${tBDcFi&Lu=b9fW>5Jv z-!mJ+b^-RGLVQl8I8Wwl?9i*gK737`@hY$n)%0gx1v*vO5eq9ixo$R(*&-KkZZRW7 z*}+OZXPbJgm1ytwSwK6!$NDHEL!GmpJhyrNi%GD9u|7IGyly_!TR`8b7i9-yeRNAg z9=vb%z-ykf=g{7!nJ7D0sh@_1?aUy%s261iOZD|VTs+~|5j%3Dg}+7F&z0-xmwHF& z=%0E=*(>z)%Q#8KP5+|oRq<2DI7!A$y(oLH__M#fe&{2w7i9-a$B%Kd9!VYJ7G}k5~Jrp8lz$|1M>((7O}uwm%Wl*ZqkgCczGt#!vlxsMiU4QFbua zN4I>p{c$gJ57!R&K~Z+FQa=~;3qdc+4wmX`SIwsW#`uA=*D!w9bIJ~u>bX~BU!u<- z^^Iq9$_|$5>6h`6EsO&Fi?V~2ditfF@lr3!4wmY9BbAU|twCuBA?0zWfYq=hGrVq^~ zZg@J~D`ukX6NO)HHk#|<;Rj^@8PB;z%-{jCCs1~s`Jw;E^t`{boz^|C7i9;LuySw{Jh_&;4W7QUi@N)eUC57>i%a4E zQ2NQQ;g{U~*6Gg=pdY!V{9L^_h(6En)q(oY@$2~2*AB?}4&|eP>s`_pA(%n;|!_b3GH(7} psd, "G" => pgate, "W" => nwell, + "tS" => psd, "tD" => psd, "tG" => poly, "tW" => nwell }) + +# NMOS transistor device extraction +extract_devices(mos4("NMOS"), { "SD" => nsd, "G" => ngate, "W" => bulk, + "tS" => nsd, "tD" => nsd, "tG" => poly, "tW" => bulk }) + +# Define connectivity for netlist extraction + +# Inter-layer +connect(psd, contact) +connect(nsd, contact) +connect(poly, contact) +connect(ntie, contact) +connect(nwell, ntie) +connect(ptie, contact) +connect(contact, metal1) +connect(metal1, via1) +connect(via1, metal2) + +# Global +connect_global(bulk, "SUBSTRATE") +connect_global(ptie, "SUBSTRATE") + +# Compare section + +netlist.simplify +align + +compare + diff --git a/testdata/lvs/floating.lvsdb b/testdata/lvs/floating.lvsdb new file mode 100644 index 000000000..3775e7da4 --- /dev/null +++ b/testdata/lvs/floating.lvsdb @@ -0,0 +1,454 @@ +#%lvsdb-klayout + +# Layout +layout( + top(TOP) + unit(0.001) + + # Layer section + # This section lists the mask layers (drawing or derived) and their connections. + + # Mask layers + layer(l3 '1/0') + layer(l4 '5/0') + layer(l8 '8/0') + layer(l11 '9/0') + layer(l12 '5/0') + layer(l13 '5/0') + layer(l7) + layer(l2) + layer(l9) + layer(l6) + layer(l10) + + # Mask layer connectivity + connect(l3 l3 l9) + connect(l4 l4 l8) + connect(l8 l4 l8 l11 l2 l9 l6 l10) + connect(l11 l8 l11 l12) + connect(l12 l11 l12 l13) + connect(l13 l12 l13) + connect(l7 l7) + connect(l2 l8 l2) + connect(l9 l3 l8 l9) + connect(l6 l8 l6) + connect(l10 l8 l10) + + # Global nets and connectivity + global(l7 SUBSTRATE) + global(l10 SUBSTRATE) + + # Device class section + class(PMOS MOS4) + class(NMOS MOS4) + + # Device abstracts section + # Device abstracts list the pin shapes of the devices. + device(D$PMOS PMOS + terminal(S + rect(l2 (-550 -750) (425 1500)) + ) + terminal(G + rect(l4 (-125 -750) (250 1500)) + ) + terminal(D + rect(l2 (125 -750) (425 1500)) + ) + terminal(B + rect(l3 (-125 -750) (250 1500)) + ) + ) + device(D$NMOS NMOS + terminal(S + rect(l6 (-550 -475) (425 950)) + ) + terminal(G + rect(l4 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (425 950)) + ) + terminal(B + rect(l7 (-125 -475) (250 950)) + ) + ) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(INVX1 + + # Circuit boundary + rect((-100 400) (2000 7600)) + + # Nets with their geometries + net(1 name(OUT) + rect(l8 (1110 5160) (180 180)) + rect(l8 (-180 920) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (-180 -4120) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-240 -790) (300 4790)) + rect(l11 (-151 -2501) (2 2)) + rect(l2 (-226 1049) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(2 name(VDD) + rect(l3 (-100 4500) (2000 3500)) + rect(l8 (-1090 -890) (180 180)) + rect(l8 (-580 -1030) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l11 (-590 1460) (1800 800)) + rect(l11 (-1050 -550) (300 300)) + rect(l11 (-700 -850) (300 300)) + rect(l11 (299 499) (2 2)) + rect(l11 (-601 -2201) (300 1400)) + rect(l2 (-350 -1450) (425 1500)) + rect(l9 (-75 450) (500 500)) + ) + net(3 name(IN) + rect(l4 (725 2860) (250 1940)) + rect(l4 (-525 -1850) (300 300)) + rect(l4 (-25 -1840) (250 1450)) + rect(l4 (-250 1940) (250 2000)) + rect(l4 (-250 -2000) (250 2000)) + rect(l8 (-465 -3790) (180 180)) + rect(l11 (-91 -91) (2 2)) + rect(l11 (-151 -151) (300 300)) + ) + net(4 name(VSS) + rect(l8 (810 710) (180 180)) + rect(l8 (-580 880) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-590 -2100) (1800 800)) + rect(l11 (-1050 -550) (300 300)) + rect(l11 (-101 -151) (2 2)) + rect(l11 (-601 399) (300 1360)) + rect(l6 (-350 -900) (425 950)) + rect(l10 (-75 -2010) (500 400)) + ) + + # Outgoing pins and their connections to nets + pin(1 name(OUT)) + pin(2 name(VDD)) + pin(3 name(IN)) + pin(4 name(VSS)) + + # Devices and their connections + device(1 D$NMOS + location(850 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.40375) + param(AD 0.40375) + param(PS 2.75) + param(PD 2.75) + terminal(S 4) + terminal(G 3) + terminal(D 1) + terminal(B 4) + ) + device(2 D$PMOS + location(850 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.6375) + param(AD 0.6375) + param(PS 3.85) + param(PD 3.85) + terminal(S 2) + terminal(G 3) + terminal(D 1) + terminal(B 2) + ) + + ) + circuit(DINV + + # Circuit boundary + rect((-100 400) (3800 7600)) + + # Nets with their geometries + net(1 name('A<1>') + rect(l8 (510 3010) (180 180)) + rect(l11 (-91 -91) (2 2)) + ) + net(2 name('A<2>') + rect(l8 (2310 3010) (180 180)) + rect(l11 (-91 -91) (2 2)) + ) + net(3 name('B<2>') + rect(l11 (2999 3999) (2 2)) + rect(l2 (-226 1049) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(4 name('B<1>') + rect(l11 (1199 3999) (2 2)) + rect(l2 (-226 1049) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(5 name(VDD) + rect(l11 (1799 7199) (2 2)) + rect(l2 (299 -2151) (425 1500)) + rect(l2 (-2225 -1500) (425 1500)) + ) + net(6 name(VSS) + rect(l11 (1799 799) (2 2)) + rect(l6 (299 859) (425 950)) + rect(l6 (-2225 -950) (425 950)) + ) + + # Outgoing pins and their connections to nets + pin(1 name('A<1>')) + pin(2 name('A<2>')) + pin(3 name('B<2>')) + pin(5 name(VDD)) + pin(6 name(VSS)) + + # Subcircuits and their connections + circuit(1 INVX1 location(0 0) + pin(0 4) + pin(1 5) + pin(2 1) + pin(3 6) + ) + circuit(2 INVX1 location(1800 0) + pin(0 3) + pin(1 5) + pin(2 2) + pin(3 6) + ) + + ) + circuit(TOP + + # Circuit boundary + rect((-100 400) (5600 7600)) + + # Nets with their geometries + net(1 + rect(l8 (4110 3010) (180 180)) + rect(l11 (-1190 -240) (950 300)) + rect(l2 (-1275 1800) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(2 name(A) + rect(l8 (510 3010) (180 180)) + rect(l11 (-91 -91) (2 2)) + ) + net(3 name(C) + rect(l8 (2310 3010) (180 180)) + rect(l11 (-91 -91) (2 2)) + ) + net(4 name(SUBSTRATE) + rect(l6 (3900 1660) (425 950)) + rect(l6 (-2225 -950) (425 950)) + rect(l6 (-2225 -950) (425 950)) + ) + net(5 + rect(l2 (4575 5050) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(6 + rect(l2 (3900 5050) (425 1500)) + rect(l2 (-2225 -1500) (425 1500)) + rect(l2 (-2225 -1500) (425 1500)) + ) + + # Outgoing pins and their connections to nets + pin(2 name(A)) + pin(3 name(C)) + pin(4 name(SUBSTRATE)) + + # Subcircuits and their connections + circuit(1 DINV location(0 0) + pin(0 2) + pin(1 3) + pin(2 1) + pin(3 6) + pin(4 4) + ) + circuit(2 INVX1 location(3600 0) + pin(0 5) + pin(1 6) + pin(2 1) + pin(3 4) + ) + + ) +) + +# Reference netlist +reference( + + # Device class section + class(NMOS MOS4) + class(PMOS MOS4) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(INVX1 + + # Nets + net(1 name(A)) + net(2 name(Z)) + net(3 name(VDD)) + net(4 name(VSS)) + + # Outgoing pins and their connections to nets + pin(1 name(A)) + pin(2 name(Z)) + pin(3 name(VDD)) + pin(4 name(VSS)) + + # Devices and their connections + device(1 NMOS + name('0') + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 2) + terminal(G 1) + terminal(D 4) + terminal(B 4) + ) + device(2 PMOS + name('1') + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 2) + terminal(G 1) + terminal(D 3) + terminal(B 3) + ) + + ) + circuit(DINV + + # Nets + net(1 name('A<1>')) + net(2 name('A<2>')) + net(3 name('B<1>')) + net(4 name('B<2>')) + net(5 name(VDD)) + net(6 name(VSS)) + + # Outgoing pins and their connections to nets + pin(1 name('A<1>')) + pin(2 name('A<2>')) + pin(3 name('B<1>')) + pin(4 name('B<2>')) + pin(5 name(VDD)) + pin(6 name(VSS)) + + # Subcircuits and their connections + circuit(1 INVX1 name(A) + pin(0 1) + pin(1 3) + pin(2 5) + pin(3 6) + ) + circuit(2 INVX1 name(B) + pin(0 2) + pin(1 4) + pin(2 5) + pin(3 6) + ) + + ) + circuit(TOP + + # Nets + net(1 name(A)) + net(2 name(C)) + net(3 name(D)) + net(4 name(VDD)) + net(5 name(VSS)) + net(6 name(B)) + net(7 name(E)) + + # Outgoing pins and their connections to nets + pin(1 name(A)) + pin(2 name(C)) + pin(3 name(D)) + pin(4 name(VDD)) + pin(5 name(VSS)) + + # Subcircuits and their connections + circuit(1 DINV name('0') + pin(0 1) + pin(1 2) + pin(2 6) + pin(3 7) + pin(4 4) + pin(5 5) + ) + circuit(2 INVX1 name('1') + pin(0 7) + pin(1 3) + pin(2 4) + pin(3 5) + ) + + ) +) + +# Cross reference +xref( + circuit(DINV DINV match + xref( + net(1 1 match) + net(2 2 match) + net(4 3 warning) + net(3 4 warning) + net(5 5 match) + net(6 6 match) + pin(() 2 match) + pin(0 0 match) + pin(1 1 match) + pin(2 3 match) + pin(3 4 match) + pin(4 5 match) + circuit(1 1 match) + circuit(2 2 match) + ) + ) + circuit(INVX1 INVX1 match + xref( + net(3 1 match) + net(1 2 match) + net(2 3 match) + net(4 4 match) + pin(2 0 match) + pin(0 1 match) + pin(1 2 match) + pin(3 3 match) + device(1 1 match) + device(2 2 match) + ) + ) + circuit(TOP TOP match + xref( + net(5 3 match) + net(1 7 match) + net(6 4 match) + net(2 1 match) + net(3 2 match) + net(4 5 match) + pin(() 2 match) + pin(() 3 match) + pin(0 0 match) + pin(1 1 match) + pin(2 4 match) + circuit(1 1 match) + circuit(2 2 match) + ) + ) +) diff --git a/testdata/lvs/floating_ref.cir b/testdata/lvs/floating_ref.cir new file mode 100644 index 000000000..a0f4dc332 --- /dev/null +++ b/testdata/lvs/floating_ref.cir @@ -0,0 +1,16 @@ +.global VDD VSS + +.subckt TOP A C D +X0 A C B E DINV +X1 E D INVX1 +.ends + +.subckt DINV A<1> A<2> B<1> B<2> +XA A<1> B<1> INVX1 +XB A<2> B<2> INVX1 +.ends + +.subckt INVX1 A Z +M0 Z A VSS VSS NMOS W=0.95U L=0.25U +M1 Z A VDD VDD PMOS W=1.5U L=0.25U +.ends diff --git a/testdata/lvs/ringo_simple_blackboxing.lvsdb b/testdata/lvs/ringo_simple_blackboxing.lvsdb index 0e9ead554..0ab36f522 100644 --- a/testdata/lvs/ringo_simple_blackboxing.lvsdb +++ b/testdata/lvs/ringo_simple_blackboxing.lvsdb @@ -530,13 +530,13 @@ xref( net(8 4 match) net(5 3 match) net(7 5 match) - net(6 1 warning) - net(9 2 warning) + net(6 2 warning) + net(9 1 warning) pin(3 3 match) pin(0 2 match) pin(2 4 match) - pin(1 0 match) - pin(4 1 match) + pin(1 1 match) + pin(4 0 match) circuit(2 2 match) circuit(3 3 match) circuit(17 4 match) From 2a8f4c96104cb0fc5d9610a3725defd7db47e70b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 30 Aug 2019 10:52:51 +0200 Subject: [PATCH 24/27] Updated test data. --- .../dbLayoutToNetlistReaderTests.cc | 4 +- testdata/algo/l2n_reader_au_1.gds | Bin 18006 -> 20994 bytes testdata/algo/l2n_reader_au_2.gds | Bin 25780 -> 24930 bytes testdata/algo/l2n_reader_au_2r.gds | Bin 0 -> 25780 bytes testdata/algo/l2n_writer_au_2.txt | 91 ++++++------------ 5 files changed, 30 insertions(+), 65 deletions(-) create mode 100644 testdata/algo/l2n_reader_au_2r.gds diff --git a/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc b/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc index 1b7bb5b4c..cf1b10997 100644 --- a/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc @@ -317,7 +317,7 @@ TEST(2_ReaderWithGlobalNets) std::string au = tl::testsrc (); au = tl::combine_path (au, "testdata"); au = tl::combine_path (au, "algo"); - au = tl::combine_path (au, "l2n_reader_au_2.gds"); + au = tl::combine_path (au, "l2n_reader_au_2r.gds"); db::compare_layouts (_this, ly2, au); } @@ -374,7 +374,7 @@ TEST(3_ReaderAbsoluteCoordinates) std::string au = tl::testsrc (); au = tl::combine_path (au, "testdata"); au = tl::combine_path (au, "algo"); - au = tl::combine_path (au, "l2n_reader_au_2.gds"); + au = tl::combine_path (au, "l2n_reader_au_2r.gds"); db::compare_layouts (_this, ly2, au); } diff --git a/testdata/algo/l2n_reader_au_1.gds b/testdata/algo/l2n_reader_au_1.gds index 95598a9d637889cddcefc0a5fbfe8c03282c822d..2b85b42acbdaebea22df8912a3fc3ee4ec3ecf44 100644 GIT binary patch delta 2956 zcma);KWI}y9LMjyrfHkR+C-B!O`4ZHlm1!aOX&Y%k(v|{O-mFlL8*3i%4mlo4o*^( z19g&Gii3lYW|2)33vGs`yFnX>JU#Pn{fWT*J4^}E{mP_fi5-P&<}k)7J=d|;C_ynN=h(s+xW zobA5f@Uaqy-JXhOuFYL1wl+e7thP z=sgNszePL;ruebkCgOpzR;PslO}B4XDknQgRVtM?NSWkyy5wwU4mrX*)P4j~qOJQuJpn;SitJA`urn@~{2ZWBhY!W(d4|J~bHW(Z2 zpn-ORqTZYijr;XTV2L|`a0pJDghPPlhcuSLtVm&Yqy$-=7KSuEu*4leI0UCn!XdC! zb3hx+3SxG&6BP9(9dft_D z@;dz)M2!1@@GP=dF?hEUwb#4K|BE4b~7O8b+fo)6+ zVtT{`d7W9L*0}`;i}Z>~SX8@JEf#nmOpAV)9{mJGy*Z0NA6X;O1a4O(bI6TA7|oST z!YD%vevPFtI8qQnN|4oQ-mmGIL+%5@XRc%tKAFSXQ$ZWd4Z;KM1Vz0$pJF`ReY)`% zQ89O3y7hSag(CUAQ2Xbbox$5v%w9Z_{KP5Vo*9sBy}a~ZrMqdDI!x$V+UscGJtrKkR5U-a^(hIZx-#fo5l>h($ delta 1118 zcmZo#!g#HRQHg<#fr%-CL57iu{V@X*12Y3JgE)g4GJB$uvM6?ms6-qR7vix?Om<TC{8JC_3%((1fVZo)RiUpURcPz0ue44zP>djo3cAuiAq*lyG=f!^ogFa_@xGp}_Oj>mJn#4Ye&6@3ers$@rFaV=giQ<^hd%jPnYnd zZkMj;PwP7gL)vjO^L{k;W6~4TzlwR%#%#nu{=&ee{DhhxE2N?dk}(ORo)iUR3rk}&_0_hfUD^#G52wy^TZ0q=lsLzKB z2ZZ0rh*%4W*l2G-uTz2^NcR()mh?jEY0;4xwgY=`T@7Mgjo@3SUB9{wHjH-}2@evL z!w0t_Ydled<|8YRnu0jp@yn*-j2ZqRC1EFCpt8t|{uDm1E-D55o`QZ5Yyf^Rvr z0r${T2yT-XD1;Q!5DHD{p==-!LZLkrdh@lHU=j$${fPlMWowQhw*nZKkhkaND{JGYtdx z)Yl2Ts@sy|hI87x0;?lr&@N1n-KRNO^VQ16|J8=T=pGru@0Bcm9VmJ;tQ*>6**k^b zh8}xotXttJNs#&{BJ_LGJA;!w3B0fOVa3pKK9i0^QO3Nd8z*F;eth9% zz1gleTIFI1?SX~+%)_O2-R_XViM~a|cP2#6RE$=PDM?+`D(o=6It<`Kx z5ok9@265FiaJ`VjL-}n1>u_NL2SyWRpH-yi&%LutbM@nReaOI>(J|aAY!|%e7bT=o zYqpD}gT)G5?ny<<0FjtN@46&FG=>}D3~jL>309rIdyMo83?)Yy2L7#SdTB>!GnE{u zI)0<{y)Iv%;b{OHd;bJbzuH9}r%2h))IQT@Nj1h+|6^>9JTBF6Db_y@pxvQFlVNxh zAowEyM;@0=PW}vlG%1;)c8`+(*hL;EO-`oHp)KaD?_u!}q{o$pd@icRgk$fz87JaWaRHXYZSjH+H^RF2Y4oT94JluwV+lkRleG=5^5 zm`f+n$dBR2qoUUTY3z&q%lmfvV6luN*%WPajl4tmYGL}S{qZnlFxu;w=A^81{@s3@Af_&_MRkPt^>GH8Niig%~~6uk$lMeyX5E|U-Fv{ zd1{h6Ps~Uo-eu5Rm+cyTEm$D|D>OMLdbDm;-b#31W!Arkg{dRUKZ^`=AD$Mys@Fa` zhAW*^BpTnn#!&AhFx!4jP{X12goMvJL1`M-I>Q)lCoZ?c_(P}KHE}jdcey$n?hZJ; Q;|@4&NXI4g0H`WF2OTt-V*mgE diff --git a/testdata/algo/l2n_reader_au_2r.gds b/testdata/algo/l2n_reader_au_2r.gds new file mode 100644 index 0000000000000000000000000000000000000000..70dbdd3ded1c774ac0320f749e41007edbc3e4ee GIT binary patch literal 25780 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 BgVq25 literal 0 HcmV?d00001 diff --git a/testdata/algo/l2n_writer_au_2.txt b/testdata/algo/l2n_writer_au_2.txt index c232887a5..2c615dffc 100644 --- a/testdata/algo/l2n_writer_au_2.txt +++ b/testdata/algo/l2n_writer_au_2.txt @@ -264,12 +264,6 @@ circuit(INV2PAIR rect(diff_cont (-220 180) (220 220)) ) net(3 - rect(diff_cont (790 3290) (220 220)) - rect(diff_cont (-220 180) (220 220)) - rect(diff_cont (-220 -3420) (220 220)) - rect(diff_cont (-220 180) (220 220)) - ) - net(4 rect(diff_cont (4230 3290) (220 220)) rect(diff_cont (-220 180) (220 220)) rect(diff_cont (-220 -220) (220 220)) @@ -283,7 +277,7 @@ circuit(INV2PAIR rect(metal1 (-3000 -760) (360 760)) rect(metal1 (-360 -760) (360 760)) ) - net(5 + net(4 rect(diff_cont (4230 490) (220 220)) rect(diff_cont (-220 180) (220 220)) rect(diff_cont (-220 -220) (220 220)) @@ -297,47 +291,46 @@ circuit(INV2PAIR rect(metal1 (-3000 -760) (360 760)) rect(metal1 (-360 -760) (360 760)) ) - net(6 + net(5 rect(diff_cont (2390 3690) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -2620) (220 220)) rect(diff_cont (-220 -620) (220 220)) ) - net(7) - net(8 + net(6) + net(7 rect(diff_cont (5030 3690) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -2620) (220 220)) rect(diff_cont (-220 -620) (220 220)) ) - net(9) + net(8) # Outgoing pins and their connections to nets pin(1 name(BULK)) pin(2) + pin(3) pin(4) - pin(5) + pin(6) pin(7) pin(8) - pin(9) # Subcircuits and their connections circuit(1 INV2 location(1700 800) - pin(0 9) - pin(1 7) - pin(2 3) - pin(3 6) - pin(4 5) - pin(5 4) + pin(0 8) + pin(1 6) + pin(3 5) + pin(4 4) + pin(5 3) pin(6 1) ) circuit(2 INV2 location(4340 800) - pin(0 9) - pin(1 6) + pin(0 8) + pin(1 5) pin(2 2) - pin(3 8) - pin(4 5) - pin(5 4) + pin(3 7) + pin(4 4) + pin(5 3) pin(6 1) ) @@ -515,48 +508,24 @@ circuit(RINGO rect(metal2_lbl (-21301 -381) (2 2)) ) net(5 - rect(diff_cont (17570 2490) (220 220)) - rect(diff_cont (-220 180) (220 220)) - rect(diff_cont (-220 -3420) (220 220)) - rect(diff_cont (-220 180) (220 220)) - ) - net(6 - rect(diff_cont (12290 2490) (220 220)) - rect(diff_cont (-220 180) (220 220)) - rect(diff_cont (-220 -3420) (220 220)) - rect(diff_cont (-220 180) (220 220)) - ) - net(7 - rect(diff_cont (7010 2490) (220 220)) - rect(diff_cont (-220 180) (220 220)) - rect(diff_cont (-220 -3420) (220 220)) - rect(diff_cont (-220 180) (220 220)) - ) - net(8 - rect(diff_cont (1730 2490) (220 220)) - rect(diff_cont (-220 180) (220 220)) - rect(diff_cont (-220 -3420) (220 220)) - rect(diff_cont (-220 180) (220 220)) - ) - net(9 rect(diff_cont (3330 2890) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -2620) (220 220)) rect(diff_cont (-220 -620) (220 220)) ) - net(10 + net(6 rect(diff_cont (19170 2890) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -2620) (220 220)) rect(diff_cont (-220 -620) (220 220)) ) - net(11 + net(7 rect(diff_cont (13890 2890) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -2620) (220 220)) rect(diff_cont (-220 -620) (220 220)) ) - net(12 + net(8 rect(diff_cont (8610 2890) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -2620) (220 220)) @@ -575,44 +544,40 @@ circuit(RINGO pin(1 1) pin(2 3) pin(3 4) - pin(4 10) + pin(4 6) pin(5 2) pin(6 3) ) circuit(2 INV2PAIR location(-1700 -800) pin(0 4) - pin(1 8) pin(2 3) pin(3 4) pin(4 1) - pin(5 9) + pin(5 5) pin(6 3) ) circuit(3 INV2PAIR location(3580 -800) pin(0 4) - pin(1 7) pin(2 3) pin(3 4) - pin(4 9) - pin(5 12) + pin(4 5) + pin(5 8) pin(6 3) ) circuit(4 INV2PAIR location(8860 -800) pin(0 4) - pin(1 6) pin(2 3) pin(3 4) - pin(4 12) - pin(5 11) + pin(4 8) + pin(5 7) pin(6 3) ) circuit(5 INV2PAIR location(14140 -800) pin(0 4) - pin(1 5) pin(2 3) pin(3 4) - pin(4 11) - pin(5 10) + pin(4 7) + pin(5 6) pin(6 3) ) From 5cfadad54f563ece52d256a1d33791aef2b0b51e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 30 Aug 2019 11:01:00 +0200 Subject: [PATCH 25/27] Updated test data. --- .../dbLayoutToNetlistReaderTests.cc | 8 +- .../dbLayoutToNetlistWriterTests.cc | 4 +- ...{l2n_writer_au_2.txt => l2n_reader_au.txt} | 0 ...ter_au_2_abs.txt => l2n_reader_au_abs.txt} | 0 testdata/algo/l2n_writer_au_2b.txt | 619 ++++++++++++++++++ 5 files changed, 625 insertions(+), 6 deletions(-) rename testdata/algo/{l2n_writer_au_2.txt => l2n_reader_au.txt} (100%) rename testdata/algo/{l2n_writer_au_2_abs.txt => l2n_reader_au_abs.txt} (100%) create mode 100644 testdata/algo/l2n_writer_au_2b.txt diff --git a/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc b/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc index cf1b10997..5f637911d 100644 --- a/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc @@ -270,7 +270,7 @@ TEST(2_ReaderWithGlobalNets) { db::LayoutToNetlist l2n; - std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_2.txt"); + std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_reader_au.txt"); tl::InputStream is_in (in_path); db::LayoutToNetlistStandardReader reader (is_in); @@ -285,7 +285,7 @@ TEST(2_ReaderWithGlobalNets) writer.write (&l2n); } - std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_2.txt"); + std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_reader_au.txt"); compare_text_files (path, au_path); @@ -327,7 +327,7 @@ TEST(3_ReaderAbsoluteCoordinates) { db::LayoutToNetlist l2n; - std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_2_abs.txt"); + std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_reader_au_abs.txt"); tl::InputStream is_in (in_path); db::LayoutToNetlistStandardReader reader (is_in); @@ -342,7 +342,7 @@ TEST(3_ReaderAbsoluteCoordinates) writer.write (&l2n); } - std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_2.txt"); + std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_reader_au.txt"); compare_text_files (path, au_path); diff --git a/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc b/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc index f2f12169e..2db34248d 100644 --- a/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc @@ -371,14 +371,14 @@ TEST(2_WriterWithGlobalNets) l2n.netlist ()->make_top_level_pins (); l2n.netlist ()->purge (); - std::string path = tmp_file ("tmp_l2nwriter_2.txt"); + std::string path = tmp_file ("tmp_l2nwriter_2b.txt"); { tl::OutputStream stream (path); db::LayoutToNetlistStandardWriter writer (stream, false); writer.write (&l2n); } - std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_2.txt"); + std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_2b.txt"); compare_text_files (path, au_path); diff --git a/testdata/algo/l2n_writer_au_2.txt b/testdata/algo/l2n_reader_au.txt similarity index 100% rename from testdata/algo/l2n_writer_au_2.txt rename to testdata/algo/l2n_reader_au.txt diff --git a/testdata/algo/l2n_writer_au_2_abs.txt b/testdata/algo/l2n_reader_au_abs.txt similarity index 100% rename from testdata/algo/l2n_writer_au_2_abs.txt rename to testdata/algo/l2n_reader_au_abs.txt diff --git a/testdata/algo/l2n_writer_au_2b.txt b/testdata/algo/l2n_writer_au_2b.txt new file mode 100644 index 000000000..c232887a5 --- /dev/null +++ b/testdata/algo/l2n_writer_au_2b.txt @@ -0,0 +1,619 @@ +#%l2n-klayout +top(RINGO) +unit(0.001) + +# Layer section +# This section lists the mask layers (drawing or derived) and their connections. + +# Mask layers +layer(rbulk) +layer(nwell '1/0') +layer(poly '3/0') +layer(poly_lbl '3/1') +layer(diff_cont '4/0') +layer(poly_cont '5/0') +layer(metal1 '6/0') +layer(metal1_lbl '6/1') +layer(via1 '7/0') +layer(metal2 '8/0') +layer(metal2_lbl '8/1') +layer(ntie) +layer(psd) +layer(ptie) +layer(nsd) + +# Mask layer connectivity +connect(nwell nwell ntie) +connect(poly poly poly_lbl poly_cont) +connect(poly_lbl poly) +connect(diff_cont diff_cont metal1 ntie psd ptie nsd) +connect(poly_cont poly poly_cont metal1) +connect(metal1 diff_cont poly_cont metal1 metal1_lbl via1) +connect(metal1_lbl metal1) +connect(via1 metal1 via1 metal2) +connect(metal2 via1 metal2 metal2_lbl) +connect(metal2_lbl metal2) +connect(ntie nwell diff_cont ntie) +connect(psd diff_cont psd) +connect(ptie diff_cont ptie) +connect(nsd diff_cont nsd) + +# Global nets and connectivity +global(rbulk BULK) +global(ptie BULK) + +# Device class section +class(PMOS MOS4) +class(NMOS MOS4) + +# Device abstracts section +# Device abstracts list the pin shapes of the devices. +device(D$PMOS PMOS + terminal(S + rect(psd (-650 -475) (525 950)) + ) + terminal(G + rect(poly (-125 -475) (250 950)) + ) + terminal(D + rect(psd (125 -475) (550 950)) + ) + terminal(B + rect(nwell (-125 -475) (250 950)) + ) +) +device(D$PMOS$1 PMOS + terminal(S + rect(psd (-675 -475) (550 950)) + ) + terminal(G + rect(poly (-125 -475) (250 950)) + ) + terminal(D + rect(psd (125 -475) (525 950)) + ) + terminal(B + rect(nwell (-125 -475) (250 950)) + ) +) +device(D$NMOS NMOS + terminal(S + rect(nsd (-650 -475) (525 950)) + ) + terminal(G + rect(poly (-125 -475) (250 950)) + ) + terminal(D + rect(nsd (125 -475) (550 950)) + ) + terminal(B + rect(rbulk (-125 -475) (250 950)) + ) +) +device(D$NMOS$1 NMOS + terminal(S + rect(nsd (-675 -475) (550 950)) + ) + terminal(G + rect(poly (-125 -475) (250 950)) + ) + terminal(D + rect(nsd (125 -475) (525 950)) + ) + terminal(B + rect(rbulk (-125 -475) (250 950)) + ) +) + +# Circuit section +# Circuits are the hierarchical building blocks of the netlist. +circuit(INV2 + + # Circuit boundary + rect((-1700 -1640) (3100 6220)) + + # Nets with their geometries + net(1 + rect(nwell (-1400 1800) (2800 2780)) + rect(diff_cont (-1510 -650) (220 220)) + rect(ntie (-510 -450) (800 680)) + ) + net(2 name(IN) + rect(poly (-525 -250) (250 2500)) + rect(poly (-1425 -630) (1300 360)) + rect(poly (-125 -2780) (250 1600)) + rect(poly (-250 1200) (250 1600)) + rect(poly_lbl (-526 -1801) (2 2)) + rect(poly_cont (-831 -111) (220 220)) + ) + net(3 + rect(poly (275 -250) (250 2500)) + rect(poly (-305 -1430) (360 360)) + rect(poly (-305 820) (250 1600)) + rect(poly (-250 -4400) (250 1600)) + rect(diff_cont (-1435 1690) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(poly_cont (980 580) (220 220)) + rect(metal1 (-1310 -290) (1380 360)) + rect(metal1 (-1560 -1600) (360 2840)) + rect(metal1 (-360 0) (360 760)) + rect(metal1 (-360 -3560) (360 760)) + rect(psd (-430 1945) (525 950)) + rect(nsd (-525 -3750) (525 950)) + ) + net(4 name(OUT) + rect(diff_cont (690 2890) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -2620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + polygon(metal1 (-110 110) (0 360) (140 0) (0 1240) (-320 0) (0 800) (360 0) (0 -440) (320 0) (0 -1960)) + rect(metal1 (-680 2400) (360 760)) + rect(metal1 (-360 -3560) (360 760)) + rect(metal1_lbl (-181 1419) (2 2)) + rect(psd (-276 524) (525 950)) + rect(nsd (-525 -3750) (525 950)) + ) + net(5 name(VSS) + rect(diff_cont (-110 -310) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(metal1 (-290 -290) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(via1 (-305 -705) (250 250)) + rect(via1 (-250 150) (250 250)) + rect(metal2 (-1525 -775) (2800 900)) + rect(metal2_lbl (-161 -541) (2 2)) + rect(nsd (-1516 -386) (550 950)) + ) + net(6 name(VDD) + rect(diff_cont (-110 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(metal1 (-290 -290) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(via1 (-305 -705) (250 250)) + rect(via1 (-250 150) (250 250)) + rect(metal2 (-1525 -775) (2800 900)) + rect(metal2_lbl (-151 -451) (2 2)) + rect(psd (-1526 -476) (550 950)) + ) + net(7 name(BULK) + rect(diff_cont (-110 -1360) (220 220)) + rect(ptie (-510 -450) (800 680)) + ) + + # Outgoing pins and their connections to nets + pin(1) + pin(2 name(IN)) + pin(3) + pin(4 name(OUT)) + pin(5 name(VSS)) + pin(6 name(VDD)) + pin(7 name(BULK)) + + # Devices and their connections + device(1 D$PMOS + location(-400 2800) + param(L 0.25) + param(W 0.95) + param(AS 0.49875) + param(AD 0.26125) + param(PS 2.95) + param(PD 1.5) + terminal(S 3) + terminal(G 2) + terminal(D 6) + terminal(B 1) + ) + device(2 D$PMOS$1 + location(400 2800) + param(L 0.25) + param(W 0.95) + param(AS 0.26125) + param(AD 0.49875) + param(PS 1.5) + param(PD 2.95) + terminal(S 6) + terminal(G 3) + terminal(D 4) + terminal(B 1) + ) + device(3 D$NMOS + location(-400 0) + param(L 0.25) + param(W 0.95) + param(AS 0.49875) + param(AD 0.26125) + param(PS 2.95) + param(PD 1.5) + terminal(S 3) + terminal(G 2) + terminal(D 5) + terminal(B 7) + ) + device(4 D$NMOS$1 + location(400 0) + param(L 0.25) + param(W 0.95) + param(AS 0.26125) + param(AD 0.49875) + param(PS 1.5) + param(PD 2.95) + terminal(S 5) + terminal(G 3) + terminal(D 4) + terminal(B 7) + ) + +) +circuit(INV2PAIR + + # Circuit boundary + rect((0 -840) (5740 6220)) + + # Nets with their geometries + net(1 name(BULK)) + net(2 + rect(diff_cont (3430 3290) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(3 + rect(diff_cont (790 3290) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(4 + rect(diff_cont (4230 3290) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-2860 -220) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(metal1 (2350 -290) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(metal1 (-3000 -760) (360 760)) + rect(metal1 (-360 -760) (360 760)) + ) + net(5 + rect(diff_cont (4230 490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-2860 -220) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(metal1 (2350 -290) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(metal1 (-3000 -760) (360 760)) + rect(metal1 (-360 -760) (360 760)) + ) + net(6 + rect(diff_cont (2390 3690) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -2620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + ) + net(7) + net(8 + rect(diff_cont (5030 3690) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -2620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + ) + net(9) + + # Outgoing pins and their connections to nets + pin(1 name(BULK)) + pin(2) + pin(4) + pin(5) + pin(7) + pin(8) + pin(9) + + # Subcircuits and their connections + circuit(1 INV2 location(1700 800) + pin(0 9) + pin(1 7) + pin(2 3) + pin(3 6) + pin(4 5) + pin(5 4) + pin(6 1) + ) + circuit(2 INV2 location(4340 800) + pin(0 9) + pin(1 6) + pin(2 2) + pin(3 8) + pin(4 5) + pin(5 4) + pin(6 1) + ) + +) +circuit(RINGO + + # Circuit boundary + rect((-1720 -1640) (26880 6220)) + + # Nets with their geometries + net(1 name(FB) + rect(diff_cont (22850 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(metal1 (-24770 1310) (360 360)) + rect(via1 (-305 -305) (250 250)) + rect(via1 (24230 -250) (250 250)) + rect(metal2 (-24805 -325) (24880 400)) + rect(metal2_lbl (-23161 -201) (2 2)) + ) + net(2 name(OSC) + rect(diff_cont (24450 2890) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -2620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(via1 (-235 1765) (250 250)) + rect(metal2 (-325 -325) (400 400)) + rect(metal2_lbl (-201 -201) (2 2)) + ) + net(3 name(VDD) + rect(diff_cont (7810 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-2860 -220) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-2860 -220) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-2860 -220) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (12980 -220) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-2860 -220) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (7700 -220) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-2860 -220) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (7700 -220) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-2860 -220) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(metal1 (-21410 390) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (-16200 -1800) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(metal1 (-3000 -760) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(metal1 (-3000 -760) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(metal1 (-3000 -760) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(metal1 (12840 -760) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(metal1 (-3000 -760) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(metal1 (7560 -760) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(metal1 (-3000 -760) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(metal1 (7560 -760) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(metal1 (-3000 -760) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(metal2_lbl (-21301 -381) (2 2)) + ) + net(4 name(VSS) + rect(diff_cont (7810 -310) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-2860 -220) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-2860 -220) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-2860 -220) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (12980 -220) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-2860 -220) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (7700 -220) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-2860 -220) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (7700 -220) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-2860 -220) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(metal1 (-21410 -1330) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (2280 -1120) (360 1120)) + rect(metal1 (-16200 -80) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(metal1 (-3000 -760) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(metal1 (-3000 -760) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(metal1 (-3000 -760) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(metal1 (12840 -760) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(metal1 (-3000 -760) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(metal1 (7560 -760) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(metal1 (-3000 -760) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(metal1 (7560 -760) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(metal1 (-3000 -760) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(metal2_lbl (-21301 -381) (2 2)) + ) + net(5 + rect(diff_cont (17570 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(6 + rect(diff_cont (12290 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(7 + rect(diff_cont (7010 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(8 + rect(diff_cont (1730 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(9 + rect(diff_cont (3330 2890) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -2620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + ) + net(10 + rect(diff_cont (19170 2890) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -2620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + ) + net(11 + rect(diff_cont (13890 2890) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -2620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + ) + net(12 + rect(diff_cont (8610 2890) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -2620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + ) + + # Outgoing pins and their connections to nets + pin(1 name(FB)) + pin(2 name(OSC)) + pin(3 name(VDD)) + pin(4 name(VSS)) + + # Subcircuits and their connections + circuit(1 INV2PAIR location(19420 -800) + pin(0 4) + pin(1 1) + pin(2 3) + pin(3 4) + pin(4 10) + pin(5 2) + pin(6 3) + ) + circuit(2 INV2PAIR location(-1700 -800) + pin(0 4) + pin(1 8) + pin(2 3) + pin(3 4) + pin(4 1) + pin(5 9) + pin(6 3) + ) + circuit(3 INV2PAIR location(3580 -800) + pin(0 4) + pin(1 7) + pin(2 3) + pin(3 4) + pin(4 9) + pin(5 12) + pin(6 3) + ) + circuit(4 INV2PAIR location(8860 -800) + pin(0 4) + pin(1 6) + pin(2 3) + pin(3 4) + pin(4 12) + pin(5 11) + pin(6 3) + ) + circuit(5 INV2PAIR location(14140 -800) + pin(0 4) + pin(1 5) + pin(2 3) + pin(3 4) + pin(4 11) + pin(5 10) + pin(6 3) + ) + +) From ab66186db4a1da83bb7a5a2adc5d3caa0203d34a Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 30 Aug 2019 13:03:37 +0200 Subject: [PATCH 26/27] Updated MSVC test golden data --- testdata/algo/lvs_test1_au.lvsdb.2 | 134 ++++++++-- testdata/algo/lvs_test2_au.lvsdb.2 | 116 +++++++-- .../lvs/ringo_simple_dummy_device.lvsdb.2 | 233 +++++++++--------- 3 files changed, 331 insertions(+), 152 deletions(-) diff --git a/testdata/algo/lvs_test1_au.lvsdb.2 b/testdata/algo/lvs_test1_au.lvsdb.2 index cf52cf8cd..dac6d562b 100644 --- a/testdata/algo/lvs_test1_au.lvsdb.2 +++ b/testdata/algo/lvs_test1_au.lvsdb.2 @@ -655,7 +655,7 @@ layout( rect(metal2_lbl (-21301 -381) (2 2)) ) net(5 - rect(diff_cont (1730 90) (220 220)) + rect(diff_cont (14930 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -673,7 +673,7 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(6 - rect(diff_cont (17570 90) (220 220)) + rect(diff_cont (9650 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -691,7 +691,7 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(7 - rect(diff_cont (12290 90) (220 220)) + rect(diff_cont (4370 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -709,6 +709,78 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(8 + rect(diff_cont (-910 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(9 + rect(diff_cont (1730 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(10 + rect(diff_cont (17570 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(11 + rect(diff_cont (12290 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(12 rect(diff_cont (7010 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -739,7 +811,7 @@ layout( pin(1 3) pin(2 4) pin(3 1) - pin(4 6) + pin(4 10) pin(5 2) pin(6 3) ) @@ -747,32 +819,36 @@ layout( pin(0 4) pin(1 3) pin(2 4) + pin(3 8) pin(4 1) - pin(5 5) + pin(5 9) pin(6 3) ) circuit(3 INV2PAIR location(3580 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 5) - pin(5 8) + pin(3 7) + pin(4 9) + pin(5 12) pin(6 3) ) circuit(4 INV2PAIR location(8860 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 8) - pin(5 7) + pin(3 6) + pin(4 12) + pin(5 11) pin(6 3) ) circuit(5 INV2PAIR location(14140 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 7) - pin(5 6) + pin(3 5) + pin(4 11) + pin(5 10) pin(6 3) ) @@ -882,9 +958,13 @@ reference( net(3 name('3')) net(4 name('4')) net(5 name('6')) - net(6 name('5')) - net(7 name('8')) - net(8 name('7')) + net(6 name('100')) + net(7 name('5')) + net(8 name('101')) + net(9 name('8')) + net(10 name('102')) + net(11 name('7')) + net(12 name('103')) # Outgoing pins and their connections to nets pin(1 name('1')) @@ -906,31 +986,35 @@ reference( pin(0 4) pin(1 3) pin(2 4) + pin(3 6) pin(4 1) - pin(5 6) + pin(5 7) pin(6 3) ) circuit(3 INV2PAIR name($3) pin(0 4) pin(1 3) pin(2 4) - pin(4 6) - pin(5 7) + pin(3 8) + pin(4 7) + pin(5 9) pin(6 3) ) circuit(4 INV2PAIR name($4) pin(0 4) pin(1 3) pin(2 4) - pin(4 7) - pin(5 8) + pin(3 10) + pin(4 9) + pin(5 11) pin(6 3) ) circuit(5 INV2PAIR name($5) pin(0 4) pin(1 3) pin(2 4) - pin(4 8) + pin(3 12) + pin(4 11) pin(5 5) pin(6 3) ) @@ -980,10 +1064,14 @@ xref( ) circuit(RINGO RINGO match xref( - net(5 6 match) - net(6 5 match) + net(8 6 match) net(7 8 match) - net(8 7 match) + net(6 10 match) + net(5 12 match) + net(9 7 match) + net(10 5 match) + net(11 11 match) + net(12 9 match) net(1 1 match) net(2 2 match) net(3 3 match) diff --git a/testdata/algo/lvs_test2_au.lvsdb.2 b/testdata/algo/lvs_test2_au.lvsdb.2 index 9dacebd21..84e349abc 100644 --- a/testdata/algo/lvs_test2_au.lvsdb.2 +++ b/testdata/algo/lvs_test2_au.lvsdb.2 @@ -655,7 +655,7 @@ layout( rect(metal2_lbl (-21301 -381) (2 2)) ) net(5 - rect(diff_cont (1730 90) (220 220)) + rect(diff_cont (14930 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -673,7 +673,7 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(6 - rect(diff_cont (17570 90) (220 220)) + rect(diff_cont (9650 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -691,7 +691,7 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(7 - rect(diff_cont (12290 90) (220 220)) + rect(diff_cont (4370 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -709,6 +709,78 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(8 + rect(diff_cont (-910 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(9 + rect(diff_cont (1730 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(10 + rect(diff_cont (17570 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(11 + rect(diff_cont (12290 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(12 rect(diff_cont (7010 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -739,7 +811,7 @@ layout( pin(1 3) pin(2 4) pin(3 1) - pin(4 6) + pin(4 10) pin(5 2) pin(6 3) ) @@ -747,32 +819,36 @@ layout( pin(0 4) pin(1 3) pin(2 4) + pin(3 8) pin(4 1) - pin(5 5) + pin(5 9) pin(6 3) ) circuit(3 INV2PAIR location(3580 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 5) - pin(5 8) + pin(3 7) + pin(4 9) + pin(5 12) pin(6 3) ) circuit(4 INV2PAIR location(8860 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 8) - pin(5 7) + pin(3 6) + pin(4 12) + pin(5 11) pin(6 3) ) circuit(5 INV2PAIR location(14140 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 7) - pin(5 6) + pin(3 5) + pin(4 11) + pin(5 10) pin(6 3) ) @@ -874,8 +950,11 @@ reference( net(4 name('4')) net(5 name('6')) net(6 name('5')) - net(7 name('8')) - net(8 name('7')) + net(7 name('101')) + net(8 name('8')) + net(9 name('102')) + net(10 name('7')) + net(11 name('103')) # Outgoing pins and their connections to nets pin(1 name('1')) @@ -906,23 +985,26 @@ reference( pin(0 4) pin(1 3) pin(2 4) + pin(3 7) pin(4 6) - pin(5 7) + pin(5 8) pin(6 3) ) circuit(4 INV2PAIR name($4) pin(0 4) pin(1 3) pin(2 4) - pin(4 7) - pin(5 8) + pin(3 9) + pin(4 8) + pin(5 10) pin(6 3) ) circuit(5 INV2PAIR name($5) pin(0 4) pin(1 3) pin(2 4) - pin(4 8) + pin(3 11) + pin(4 10) pin(5 5) pin(6 3) ) diff --git a/testdata/lvs/ringo_simple_dummy_device.lvsdb.2 b/testdata/lvs/ringo_simple_dummy_device.lvsdb.2 index e0c48421a..f4780ff2d 100644 --- a/testdata/lvs/ringo_simple_dummy_device.lvsdb.2 +++ b/testdata/lvs/ringo_simple_dummy_device.lvsdb.2 @@ -362,67 +362,74 @@ layout( # Nets with their geometries net(1 + rect(l4 (26050 2800) (525 550)) + rect(l4 (-525 -300) (300 300)) + rect(l4 (-25 -2000) (250 1450)) + rect(l8 (-465 310) (180 180)) + rect(l11 (-240 -240) (300 300)) + ) + net(2 rect(l8 (4710 3010) (180 180)) rect(l11 (-850 -240) (610 300)) rect(l2 (-1175 1800) (425 1500)) rect(l2 (-1800 -1500) (425 1500)) rect(l6 (950 -4890) (425 950)) ) - net(2 + net(3 rect(l8 (6510 3010) (180 180)) rect(l11 (-1140 -240) (900 300)) rect(l2 (-1275 1800) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(3 + net(4 rect(l8 (8310 3010) (180 180)) rect(l11 (-1140 -240) (900 300)) rect(l2 (-1275 1800) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(4 + net(5 rect(l8 (10110 3010) (180 180)) rect(l11 (-1140 -240) (900 300)) rect(l2 (-1275 1800) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(5 + net(6 rect(l8 (11910 3010) (180 180)) rect(l11 (-1140 -240) (900 300)) rect(l2 (-1275 1800) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(6 + net(7 rect(l8 (13710 3010) (180 180)) rect(l11 (-1140 -240) (900 300)) rect(l2 (-1275 1800) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(7 + net(8 rect(l8 (15510 3010) (180 180)) rect(l11 (-1140 -240) (900 300)) rect(l2 (-1275 1800) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(8 + net(9 rect(l8 (17310 3010) (180 180)) rect(l11 (-1140 -240) (900 300)) rect(l2 (-1275 1800) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(9 + net(10 rect(l8 (19110 3010) (180 180)) rect(l11 (-1140 -240) (900 300)) rect(l2 (-1275 1800) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(10 + net(11 rect(l8 (20910 3010) (180 180)) rect(l11 (-1140 -240) (900 300)) rect(l2 (-1275 1800) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(11 name(FB) + net(12 name(FB) rect(l8 (22710 3010) (180 180)) rect(l8 (-19700 720) (180 180)) rect(l11 (18380 -1140) (900 300)) @@ -437,7 +444,7 @@ layout( rect(l2 (-245 850) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(12 name(VDD) + net(13 name(VDD) rect(l3 (500 4500) (1400 3500)) rect(l3 (-1900 -3500) (600 3500)) rect(l3 (23300 -3500) (1400 3500)) @@ -479,7 +486,7 @@ layout( rect(l9 (-21975 -450) (500 1500)) rect(l9 (22900 -1500) (500 1500)) ) - net(13 name(OUT) + net(14 name(OUT) rect(l11 (23440 3840) (320 320)) rect(l12 (-260 -260) (200 200)) rect(l13 (-101 -101) (2 2)) @@ -487,14 +494,14 @@ layout( rect(l2 (-625 850) (425 1500)) rect(l6 (-425 -4890) (425 950)) ) - net(14 name(ENABLE) + net(15 name(ENABLE) rect(l8 (2510 3010) (180 180)) rect(l11 (-250 -250) (320 320)) rect(l12 (-260 -260) (200 200)) rect(l13 (-101 -101) (2 2)) rect(l13 (-201 -201) (400 400)) ) - net(15 name(VSS) + net(16 name(VSS) rect(l8 (26010 1770) (180 180)) rect(l8 (-180 370) (180 180)) rect(l8 (520 -730) (180 180)) @@ -538,11 +545,11 @@ layout( ) # Outgoing pins and their connections to nets - pin(11 name(FB)) - pin(12 name(VDD)) - pin(13 name(OUT)) - pin(14 name(ENABLE)) - pin(15 name(VSS)) + pin(12 name(FB)) + pin(13 name(VDD)) + pin(14 name(OUT)) + pin(15 name(ENABLE)) + pin(16 name(VSS)) # Devices and their connections device(1 D$NMOS @@ -553,109 +560,109 @@ layout( param(AD 0.40375) param(PS 2.75) param(PD 2.75) - terminal(S 15) - terminal(G) - terminal(D 15) - terminal(B 15) + terminal(S 16) + terminal(G 1) + terminal(D 16) + terminal(B 16) ) # Subcircuits and their connections circuit(3 ND2X1 location(1800 0) - pin(0 12) - pin(1 1) - pin(2 15) - pin(3 12) - pin(4 11) - pin(5 14) - pin(6 15) + pin(0 13) + pin(1 2) + pin(2 16) + pin(3 13) + pin(4 12) + pin(5 15) + pin(6 16) ) circuit(4 INVX1 location(4200 0) - pin(0 12) - pin(1 2) - pin(2 15) - pin(3 12) - pin(4 1) - pin(5 15) + pin(0 13) + pin(1 3) + pin(2 16) + pin(3 13) + pin(4 2) + pin(5 16) ) circuit(5 INVX1 location(6000 0) - pin(0 12) - pin(1 3) - pin(2 15) - pin(3 12) - pin(4 2) - pin(5 15) + pin(0 13) + pin(1 4) + pin(2 16) + pin(3 13) + pin(4 3) + pin(5 16) ) circuit(6 INVX1 location(7800 0) - pin(0 12) - pin(1 4) - pin(2 15) - pin(3 12) - pin(4 3) - pin(5 15) + pin(0 13) + pin(1 5) + pin(2 16) + pin(3 13) + pin(4 4) + pin(5 16) ) circuit(7 INVX1 location(9600 0) - pin(0 12) - pin(1 5) - pin(2 15) - pin(3 12) - pin(4 4) - pin(5 15) + pin(0 13) + pin(1 6) + pin(2 16) + pin(3 13) + pin(4 5) + pin(5 16) ) circuit(8 INVX1 location(11400 0) - pin(0 12) - pin(1 6) - pin(2 15) - pin(3 12) - pin(4 5) - pin(5 15) + pin(0 13) + pin(1 7) + pin(2 16) + pin(3 13) + pin(4 6) + pin(5 16) ) circuit(9 INVX1 location(13200 0) - pin(0 12) - pin(1 7) - pin(2 15) - pin(3 12) - pin(4 6) - pin(5 15) + pin(0 13) + pin(1 8) + pin(2 16) + pin(3 13) + pin(4 7) + pin(5 16) ) circuit(10 INVX1 location(15000 0) - pin(0 12) - pin(1 8) - pin(2 15) - pin(3 12) - pin(4 7) - pin(5 15) + pin(0 13) + pin(1 9) + pin(2 16) + pin(3 13) + pin(4 8) + pin(5 16) ) circuit(11 INVX1 location(16800 0) - pin(0 12) - pin(1 9) - pin(2 15) - pin(3 12) - pin(4 8) - pin(5 15) + pin(0 13) + pin(1 10) + pin(2 16) + pin(3 13) + pin(4 9) + pin(5 16) ) circuit(12 INVX1 location(18600 0) - pin(0 12) - pin(1 10) - pin(2 15) - pin(3 12) - pin(4 9) - pin(5 15) + pin(0 13) + pin(1 11) + pin(2 16) + pin(3 13) + pin(4 10) + pin(5 16) ) circuit(13 INVX1 location(20400 0) - pin(0 12) - pin(1 11) - pin(2 15) - pin(3 12) - pin(4 10) - pin(5 15) + pin(0 13) + pin(1 12) + pin(2 16) + pin(3 13) + pin(4 11) + pin(5 16) ) circuit(14 INVX1 location(22200 0) - pin(0 12) - pin(1 13) - pin(2 15) - pin(3 12) - pin(4 11) - pin(5 15) + pin(0 13) + pin(1 14) + pin(2 16) + pin(3 13) + pin(4 12) + pin(5 16) ) ) @@ -811,6 +818,7 @@ reference( net(13 name('8')) net(14 name('9')) net(15 name('10')) + net(16 name(DUMMY)) # Outgoing pins and their connections to nets pin(1 name(VSS)) @@ -829,7 +837,7 @@ reference( param(PS 0) param(PD 0) terminal(S 1) - terminal(G) + terminal(G 16) terminal(D 1) terminal(B 1) ) @@ -981,21 +989,22 @@ xref( ) circuit(RINGO RINGO match xref( - net(1 6 match) - net(10 15 match) - net(2 7 match) - net(3 8 match) - net(4 9 match) - net(5 10 match) - net(6 11 match) - net(7 12 match) - net(8 13 match) - net(9 14 match) - net(14 4 match) - net(11 3 match) - net(13 5 match) - net(12 2 match) - net(15 1 match) + net(2 6 match) + net(11 15 match) + net(3 7 match) + net(4 8 match) + net(5 9 match) + net(6 10 match) + net(7 11 match) + net(8 12 match) + net(9 13 match) + net(10 14 match) + net(1 16 match) + net(15 4 match) + net(12 3 match) + net(14 5 match) + net(13 2 match) + net(16 1 match) pin(3 3 match) pin(0 2 match) pin(2 4 match) From cd137e6b3e74f27f7f9126a6057cb765eb0831c2 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 30 Aug 2019 14:24:07 +0200 Subject: [PATCH 27/27] Another fix for MSVC golden data. --- testdata/algo/lvs_test1b_au.lvsdb.2 | 134 +++++++++++++++++++++++----- testdata/algo/lvs_test2b_au.lvsdb.2 | 116 ++++++++++++++++++++---- 2 files changed, 210 insertions(+), 40 deletions(-) diff --git a/testdata/algo/lvs_test1b_au.lvsdb.2 b/testdata/algo/lvs_test1b_au.lvsdb.2 index 2db900155..2853d93ef 100644 --- a/testdata/algo/lvs_test1b_au.lvsdb.2 +++ b/testdata/algo/lvs_test1b_au.lvsdb.2 @@ -655,7 +655,7 @@ layout( rect(metal2_lbl (-21301 -381) (2 2)) ) net(5 - rect(diff_cont (1730 90) (220 220)) + rect(diff_cont (14930 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -673,7 +673,7 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(6 - rect(diff_cont (17570 90) (220 220)) + rect(diff_cont (9650 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -691,7 +691,7 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(7 - rect(diff_cont (12290 90) (220 220)) + rect(diff_cont (4370 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -709,6 +709,78 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(8 + rect(diff_cont (-910 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(9 + rect(diff_cont (1730 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(10 + rect(diff_cont (17570 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(11 + rect(diff_cont (12290 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(12 rect(diff_cont (7010 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -739,7 +811,7 @@ layout( pin(1 3) pin(2 4) pin(3 1) - pin(4 6) + pin(4 10) pin(5 2) pin(6 3) ) @@ -747,32 +819,36 @@ layout( pin(0 4) pin(1 3) pin(2 4) + pin(3 8) pin(4 1) - pin(5 5) + pin(5 9) pin(6 3) ) circuit(3 INV2PAIR location(3580 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 5) - pin(5 8) + pin(3 7) + pin(4 9) + pin(5 12) pin(6 3) ) circuit(4 INV2PAIR location(8860 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 8) - pin(5 7) + pin(3 6) + pin(4 12) + pin(5 11) pin(6 3) ) circuit(5 INV2PAIR location(14140 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 7) - pin(5 6) + pin(3 5) + pin(4 11) + pin(5 10) pin(6 3) ) @@ -882,9 +958,13 @@ reference( net(3 name('3')) net(4 name('4')) net(5 name('6')) - net(6 name('5')) - net(7 name('8')) - net(8 name('7')) + net(6 name('100')) + net(7 name('5')) + net(8 name('101')) + net(9 name('8')) + net(10 name('102')) + net(11 name('7')) + net(12 name('103')) # Outgoing pins and their connections to nets pin(1 name('1')) @@ -906,31 +986,35 @@ reference( pin(0 4) pin(1 3) pin(2 4) + pin(3 6) pin(4 1) - pin(5 6) + pin(5 7) pin(6 3) ) circuit(3 INV2PAIR name($3) pin(0 4) pin(1 3) pin(2 4) - pin(4 6) - pin(5 7) + pin(3 8) + pin(4 7) + pin(5 9) pin(6 3) ) circuit(4 INV2PAIR name($4) pin(0 4) pin(1 3) pin(2 4) - pin(4 7) - pin(5 8) + pin(3 10) + pin(4 9) + pin(5 11) pin(6 3) ) circuit(5 INV2PAIR name($5) pin(0 4) pin(1 3) pin(2 4) - pin(4 8) + pin(3 12) + pin(4 11) pin(5 5) pin(6 3) ) @@ -980,10 +1064,14 @@ xref( ) circuit(RINGO RINGO match xref( - net(5 6 match) - net(6 5 match) + net(8 6 match) net(7 8 match) - net(8 7 match) + net(6 10 match) + net(5 12 match) + net(9 7 match) + net(10 5 match) + net(11 11 match) + net(12 9 match) net(1 1 match) net(2 2 match) net(3 3 match) diff --git a/testdata/algo/lvs_test2b_au.lvsdb.2 b/testdata/algo/lvs_test2b_au.lvsdb.2 index 1cf9af670..965381b39 100644 --- a/testdata/algo/lvs_test2b_au.lvsdb.2 +++ b/testdata/algo/lvs_test2b_au.lvsdb.2 @@ -655,7 +655,7 @@ layout( rect(metal2_lbl (-21301 -381) (2 2)) ) net(5 - rect(diff_cont (1730 90) (220 220)) + rect(diff_cont (14930 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -673,7 +673,7 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(6 - rect(diff_cont (17570 90) (220 220)) + rect(diff_cont (9650 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -691,7 +691,7 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(7 - rect(diff_cont (12290 90) (220 220)) + rect(diff_cont (4370 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -709,6 +709,78 @@ layout( rect(diff_cont (-220 180) (220 220)) ) net(8 + rect(diff_cont (-910 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(9 + rect(diff_cont (1730 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(10 + rect(diff_cont (17570 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(11 + rect(diff_cont (12290 90) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (1380 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3820) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-1820 3380) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 180) (220 220)) + ) + net(12 rect(diff_cont (7010 90) (220 220)) rect(diff_cont (-220 -620) (220 220)) rect(diff_cont (-220 -620) (220 220)) @@ -739,7 +811,7 @@ layout( pin(1 3) pin(2 4) pin(3 1) - pin(4 6) + pin(4 10) pin(5 2) pin(6 3) ) @@ -747,32 +819,36 @@ layout( pin(0 4) pin(1 3) pin(2 4) + pin(3 8) pin(4 1) - pin(5 5) + pin(5 9) pin(6 3) ) circuit(3 INV2PAIR location(3580 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 5) - pin(5 8) + pin(3 7) + pin(4 9) + pin(5 12) pin(6 3) ) circuit(4 INV2PAIR location(8860 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 8) - pin(5 7) + pin(3 6) + pin(4 12) + pin(5 11) pin(6 3) ) circuit(5 INV2PAIR location(14140 -800) pin(0 4) pin(1 3) pin(2 4) - pin(4 7) - pin(5 6) + pin(3 5) + pin(4 11) + pin(5 10) pin(6 3) ) @@ -874,8 +950,11 @@ reference( net(4 name('4')) net(5 name('6')) net(6 name('5')) - net(7 name('8')) - net(8 name('7')) + net(7 name('101')) + net(8 name('8')) + net(9 name('102')) + net(10 name('7')) + net(11 name('103')) # Outgoing pins and their connections to nets pin(1 name('1')) @@ -906,23 +985,26 @@ reference( pin(0 4) pin(1 3) pin(2 4) + pin(3 7) pin(4 6) - pin(5 7) + pin(5 8) pin(6 3) ) circuit(4 INV2PAIR name($4) pin(0 4) pin(1 3) pin(2 4) - pin(4 7) - pin(5 8) + pin(3 9) + pin(4 8) + pin(5 10) pin(6 3) ) circuit(5 INV2PAIR name($5) pin(0 4) pin(1 3) pin(2 4) - pin(4 8) + pin(3 11) + pin(4 10) pin(5 5) pin(6 3) )

+ To enable hierarchical extraction, you must use "deep" mode (deep). + If the deep mode statement is missing, the layout netlist will be flat (i.e. without + subcircuits). +