diff --git a/src/db/db/dbEdgePairs.cc b/src/db/db/dbEdgePairs.cc index cd43514b8..de4b3ab24 100644 --- a/src/db/db/dbEdgePairs.cc +++ b/src/db/db/dbEdgePairs.cc @@ -103,6 +103,13 @@ EdgePairs::EdgePairs (DeepShapeStore &dss) mp_delegate = new DeepEdgePairs (DeepLayer (&dss, layout_index, dss.layout (layout_index).insert_layer ())); } +void +EdgePairs::convert_to_deep (const db::DeepLayer &layer) +{ + tl_assert (mp_delegate->deep () == 0); + set_delegate (copy_data_id (new db::DeepEdgePairs (layer))); +} + void EdgePairs::write (const std::string &fn) const { diff --git a/src/db/db/dbEdgePairs.h b/src/db/db/dbEdgePairs.h index 7b2b4ed7f..f75d7d773 100644 --- a/src/db/db/dbEdgePairs.h +++ b/src/db/db/dbEdgePairs.h @@ -204,6 +204,11 @@ public: */ explicit EdgePairs (DeepShapeStore &dss); + /** + * @brief Converts the shape collection to a deep one using the specified layer + */ + virtual void convert_to_deep (const db::DeepLayer &layer); + /** * @brief Writes the edge pair collection to a file * diff --git a/src/db/db/dbEdges.cc b/src/db/db/dbEdges.cc index 1cad75949..f64d23747 100644 --- a/src/db/db/dbEdges.cc +++ b/src/db/db/dbEdges.cc @@ -114,6 +114,13 @@ Edges::Edges (DeepShapeStore &dss) mp_delegate = new DeepEdges (DeepLayer (&dss, layout_index, dss.layout (layout_index).insert_layer ())); } +void +Edges::convert_to_deep (const db::DeepLayer &layer) +{ + tl_assert (mp_delegate->deep () == 0); + set_delegate (copy_data_id (new db::DeepEdges (layer))); +} + const db::RecursiveShapeIterator & Edges::iter () const { diff --git a/src/db/db/dbEdges.h b/src/db/db/dbEdges.h index ff8007d19..a12d09c58 100644 --- a/src/db/db/dbEdges.h +++ b/src/db/db/dbEdges.h @@ -264,6 +264,11 @@ public: */ explicit Edges (DeepShapeStore &dss); + /** + * @brief Converts the shape collection to a deep one using the specified layer + */ + virtual void convert_to_deep (const db::DeepLayer &layer); + /** * @brief Implementation of the ShapeCollection interface */ diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc index 1eb73b68f..9424007b8 100644 --- a/src/db/db/dbNetlistDeviceExtractor.cc +++ b/src/db/db/dbNetlistDeviceExtractor.cc @@ -130,8 +130,10 @@ void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, unsigned int layo std::pair alias = dss.layer_for_flat (tl::id_of (l->second->get_delegate ())); if (alias.first) { - // use deep layer alias for a given flat one (if found) - layers.push_back (alias.second.layer ()); + // use deep layer alias for a given flat one (if found) and convert layer to a deep one + db::DeepLayer dl = alias.second; + l->second->convert_to_deep (dl); + layers.push_back (dl.layer ()); } else { throw tl::Exception (tl::sprintf (tl::to_string (tr ("Invalid region passed to input layer '%s' for device extraction (device %s): must be of deep region kind")), ld->name, name ())); } diff --git a/src/db/db/dbRegion.cc b/src/db/db/dbRegion.cc index f290b87d3..8e40874fd 100644 --- a/src/db/db/dbRegion.cc +++ b/src/db/db/dbRegion.cc @@ -132,6 +132,13 @@ Region::Region (DeepShapeStore &dss) mp_delegate = new db::DeepRegion (db::DeepLayer (&dss, layout_index, dss.layout (layout_index).insert_layer ())); } +void +Region::convert_to_deep (const db::DeepLayer &layer) +{ + tl_assert (mp_delegate->deep () == 0); + set_delegate (copy_data_id (new db::DeepRegion (layer))); +} + void Region::write (const std::string &fn) const { diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index 655462a01..3a230fdf1 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -256,6 +256,11 @@ public: */ void write (const std::string &fn) const; + /** + * @brief Converts the shape collection to a deep one using the specified layer + */ + virtual void convert_to_deep (const db::DeepLayer &layer); + /** * @brief Implementation of the ShapeCollection interface */ diff --git a/src/db/db/dbShapeCollection.h b/src/db/db/dbShapeCollection.h index a03c008b2..0f48ffef9 100644 --- a/src/db/db/dbShapeCollection.h +++ b/src/db/db/dbShapeCollection.h @@ -75,7 +75,12 @@ class DB_PUBLIC ShapeCollectionDelegateBase : public tl::UniqueId { public: - ShapeCollectionDelegateBase () { } + ShapeCollectionDelegateBase () + : m_data_id (tl::id_of (this)) + { + // .. nothing yet .. + } + virtual ~ShapeCollectionDelegateBase () { } virtual DeepShapeCollectionDelegateBase *deep () { return 0; } @@ -88,6 +93,22 @@ public: apply_property_translator (db::PropertiesTranslator::make_remove_all ()); } } + + tl::id_type data_id () const + { + return m_data_id; + } + +private: + friend class ShapeCollection; + + tl::id_type m_data_id; + + // used for conversion to deep + void set_data_id (tl::id_type data_id) + { + m_data_id = data_id; + } }; /** @@ -102,6 +123,11 @@ public: virtual ShapeCollectionDelegateBase *get_delegate () const = 0; + /** + * @brief Converts the shape collection to a deep one using the specified layer + */ + virtual void convert_to_deep (const db::DeepLayer &layer) = 0; + /** * @brief Applies a PropertyTranslator * @@ -111,6 +137,14 @@ public: * delivered by "properties_repository". */ void apply_property_translator (const db::PropertiesTranslator &pt); + +protected: + template + Delegate *copy_data_id (Delegate *dlg) + { + dlg->set_data_id (get_delegate ()->data_id ()); + return dlg; + } }; } diff --git a/src/db/db/dbTexts.cc b/src/db/db/dbTexts.cc index 902a5cf2e..1e15801ed 100644 --- a/src/db/db/dbTexts.cc +++ b/src/db/db/dbTexts.cc @@ -99,6 +99,13 @@ Texts::Texts (DeepShapeStore &dss) mp_delegate = new DeepTexts (DeepLayer (&dss, layout_index, dss.layout (layout_index).insert_layer ())); } +void +Texts::convert_to_deep (const db::DeepLayer &layer) +{ + tl_assert (mp_delegate->deep () == 0); + set_delegate (copy_data_id (new db::DeepTexts (layer))); +} + void Texts::write (const std::string &fn) const { diff --git a/src/db/db/dbTexts.h b/src/db/db/dbTexts.h index 74441be07..276f9b415 100644 --- a/src/db/db/dbTexts.h +++ b/src/db/db/dbTexts.h @@ -208,6 +208,11 @@ public: */ void write (const std::string &fn) const; + /** + * @brief Converts the shape collection to a deep one using the specified layer + */ + virtual void convert_to_deep (const db::DeepLayer &layer); + /** * @brief Implementation of the ShapeCollection interface */ diff --git a/src/db/db/gsiDeclDbEdgePairs.cc b/src/db/db/gsiDeclDbEdgePairs.cc index 0ea5564f0..5a865399a 100644 --- a/src/db/db/gsiDeclDbEdgePairs.cc +++ b/src/db/db/gsiDeclDbEdgePairs.cc @@ -630,9 +630,9 @@ static bool is_deep (const db::EdgePairs *ep) return dynamic_cast (ep->delegate ()) != 0; } -static size_t id (const db::EdgePairs *ep) +static size_t data_id (const db::EdgePairs *ep) { - return tl::id_of (ep->delegate ()); + return ep->delegate ()->data_id (); } static db::EdgePairs filtered (const db::EdgePairs *r, const gsi::EdgePairFilterBase *f) @@ -1114,7 +1114,7 @@ Class decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs", "\n" "This method has been added in version 0.26." ) + - method_ext ("data_id", &id, + method_ext ("data_id", &data_id, "@brief Returns the data ID (a unique identifier for the underlying data storage)\n" "\n" "This method has been added in version 0.26." diff --git a/src/db/db/gsiDeclDbEdges.cc b/src/db/db/gsiDeclDbEdges.cc index a434a7d60..667878d62 100644 --- a/src/db/db/gsiDeclDbEdges.cc +++ b/src/db/db/gsiDeclDbEdges.cc @@ -892,9 +892,9 @@ static db::Edges *new_texts_as_dots2 (const db::RecursiveShapeIterator &si, db:: return new db::Edges (db::Region (si).texts_as_dots (pat, pattern, dss)); } -static size_t id (const db::Edges *e) +static size_t data_id (const db::Edges *e) { - return tl::id_of (e->delegate ()); + return e->delegate ()->data_id (); } static std::vector andnot_with_edges (const db::Edges *r, const db::Edges &other) @@ -2572,7 +2572,7 @@ Class decl_Edges (decl_dbShapeCollection, "db", "Edges", "\n" "This method has been added in version 0.26." ) + - method_ext ("data_id", &id, + method_ext ("data_id", &data_id, "@brief Returns the data ID (a unique identifier for the underlying data storage)\n" "\n" "This method has been added in version 0.26." diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 528342e4a..de29f6ba7 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -1288,9 +1288,9 @@ static bool is_deep (const db::Region *region) return dynamic_cast (region->delegate ()) != 0; } -static size_t id (const db::Region *r) +static size_t data_id (const db::Region *r) { - return tl::id_of (r->delegate ()); + return r->delegate ()->data_id (); } @@ -4214,7 +4214,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "This method has been added in version 0.26." ) + - method_ext ("data_id", &id, + method_ext ("data_id", &data_id, "@brief Returns the data ID (a unique identifier for the underlying data storage)\n" "\n" "This method has been added in version 0.26." diff --git a/src/db/db/gsiDeclDbTexts.cc b/src/db/db/gsiDeclDbTexts.cc index 22209b412..21f04d888 100644 --- a/src/db/db/gsiDeclDbTexts.cc +++ b/src/db/db/gsiDeclDbTexts.cc @@ -477,9 +477,9 @@ static bool is_deep (const db::Texts *t) return dynamic_cast (t->delegate ()) != 0; } -static size_t id (const db::Texts *t) +static size_t data_id (const db::Texts *t) { - return tl::id_of (t->delegate ()); + return t->delegate ()->data_id (); } static db::Texts filtered (const db::Texts *r, const gsi::TextFilterBase *f) @@ -686,7 +686,7 @@ Class decl_Texts (decl_dbShapeCollection, "db", "Texts", method_ext ("is_deep?", &is_deep, "@brief Returns true if the edge pair collection is a deep (hierarchical) one\n" ) + - method_ext ("data_id", &id, + method_ext ("data_id", &data_id, "@brief Returns the data ID (a unique identifier for the underlying data storage)\n" ) + method ("+|join", &db::Texts::operator+, gsi::arg ("other"), diff --git a/src/drc/drc/built-in-macros/_drc_netter.rb b/src/drc/drc/built-in-macros/_drc_netter.rb index e5ec8f0a2..75506aae2 100644 --- a/src/drc/drc/built-in-macros/_drc_netter.rb +++ b/src/drc/drc/built-in-macros/_drc_netter.rb @@ -323,7 +323,9 @@ module DRC # # If layers are not named, they will be given a name made from the # \name_prefix and an incremental number when the layer is used for the - # first time. + # first time. As the default name prefix is "l", you may can name conflicts + # with auto-named layers, if you register explicit layer names like "l5". + # Consider changing the name prefix in that case to some prefix you are not using. # # \name can only be used once on a layer and the layer names must be # unique (not taken by another layer). diff --git a/src/lvs/unit_tests/lvsSimpleTests.cc b/src/lvs/unit_tests/lvsSimpleTests.cc index 53222d344..e248cee48 100644 --- a/src/lvs/unit_tests/lvsSimpleTests.cc +++ b/src/lvs/unit_tests/lvsSimpleTests.cc @@ -362,3 +362,9 @@ TEST(63_FlagMissingPorts) run_test (_this, "flag_missing_ports", "flag_missing_ports.gds", false, true, "TOP"); } +// Split substrate - marker and global connection (issue #2345) +TEST(64_SplitSubstrate) +{ + run_test (_this, "split_substrate", "split_substrate.gds", true, false /*no LVS*/); +} + diff --git a/testdata/drc/drcSimpleTests_au121.gds b/testdata/drc/drcSimpleTests_au121.gds index 5476d6713..e873870f5 100644 Binary files a/testdata/drc/drcSimpleTests_au121.gds and b/testdata/drc/drcSimpleTests_au121.gds differ diff --git a/testdata/lvs/split_substrate.cir b/testdata/lvs/split_substrate.cir new file mode 100644 index 000000000..c6971c69e --- /dev/null +++ b/testdata/lvs/split_substrate.cir @@ -0,0 +1,13 @@ +* Extracted by KLayout + +.SUBCKT TOP A Q IOSUB SUBSTRATE +X$1 \$7 \$1 Q IOSUB IOSUB INV +X$2 \$7 A \$1 SUBSTRATE SUBSTRATE INV +.ENDS TOP + +.SUBCKT INV \$2 \$4 \$5 \$1 \$I11 +M$1 \$2 \$4 \$5 \$2 PMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U ++ PD=3.45U +M$2 \$1 \$4 \$5 \$I11 NMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U ++ PD=3.45U +.ENDS INV diff --git a/testdata/lvs/split_substrate.gds b/testdata/lvs/split_substrate.gds new file mode 100644 index 000000000..e33ad4d0b Binary files /dev/null and b/testdata/lvs/split_substrate.gds differ diff --git a/testdata/lvs/split_substrate.l2n b/testdata/lvs/split_substrate.l2n new file mode 100644 index 000000000..95cb99951 --- /dev/null +++ b/testdata/lvs/split_substrate.l2n @@ -0,0 +1,215 @@ +#%l2n-klayout +W(TOP) +U(0.001) +L(l3 '1/0') +L(l4 '3/0') +L(l15 '3/1') +L(l8 '4/0') +L(l11 '5/0') +L(l12 '6/0') +L(l16 '6/1') +L(l13 '7/0') +L(l14 '8/0') +L(l17) +L(l22 '10/0') +L(l7) +L(l10) +L(l2) +L(l9) +L(l6) +L(l21) +L(l18) +L(l20) +L(l19) +C(l3 l3 l10) +C(l4 l4 l15 l11) +C(l15 l4 l15) +C(l8 l8 l12 l10 l2 l9 l6) +CS(l8 l10 l2 l9 l6) +C(l11 l4 l11 l12) +CS(l11 l4) +C(l12 l8 l11 l12 l16 l13) +C(l16 l12 l16) +C(l13 l12 l13 l14) +C(l14 l13 l14 l17) +C(l17 l14 l17) +C(l22 l22 l21 l20) +C(l7 l7 l18 l20) +C(l10 l3 l8 l10) +CS(l10 l3) +C(l2 l8 l2) +C(l9 l8 l9 l21 l19) +C(l6 l8 l6) +C(l21 l22 l9 l21) +CS(l21 l22) +C(l18 l7 l18) +C(l20 l22 l7 l20) +C(l19 l9 l19) +G(l22 IOSUB) +G(l18 SUBSTRATE) +G(l19 SUBSTRATE) +GS(l19 SUBSTRATE) +H(W B('Net with incomplete wiring (soft-connected partial nets)') C(TOP) X('soft-connection-check')) +H(B('\tPartial net #1: TOP/INV[r0 3,1.6]:$1 - $2') C(TOP) Q('(1.5,3.95;1.5,4.85;5.3,4.85;5.3,3.95)')) +H(B('\tPartial net #2: TOP/INV[r0 7.7,1.6]:$2 - $2') C(TOP) Q('(6.2,3.95;6.2,4.85;10,4.85;10,3.95)')) +K(PMOS MOS4) +K(NMOS MOS4) +D(D$PMOS PMOS + T(S + R(l2 (-900 -475) (775 950)) + ) + T(G + R(l4 (-125 -475) (250 950)) + ) + T(D + R(l2 (125 -475) (775 950)) + ) + T(B + R(l3 (-125 -475) (250 950)) + ) +) +D(D$NMOS NMOS + T(S + R(l6 (-900 -475) (775 950)) + ) + T(G + R(l4 (-125 -475) (250 950)) + ) + T(D + R(l6 (125 -475) (775 950)) + ) + T(B + R(l7 (-125 -475) (250 950)) + ) +) +X(INV + R((-1500 -800) (3800 4600)) + N(1 I($1) + R(l8 (1700 100) (200 200)) + R(l8 (-200 -600) (200 200)) + R(l8 (-1610 -210) (220 220)) + R(l8 (-220 180) (220 220)) + R(l12 (890 -760) (800 900)) + R(l12 (-1980 -830) (360 760)) + R(l13 (-305 -705) (250 250)) + R(l13 (-250 150) (250 250)) + R(l13 (1175 -225) (200 200)) + R(l13 (-200 -600) (200 200)) + R(l14 (-3400 -350) (3000 900)) + R(l14 (-200 -900) (1000 900)) + R(l9 (-700 -950) (400 1000)) + R(l6 (-1875 -975) (775 950)) + ) + N(2 I($2) + R(l3 (-1500 1800) (3000 2000)) + R(l3 (-200 -2000) (1000 2000)) + R(l8 (-2010 -1310) (220 220)) + R(l8 (-220 180) (220 220)) + R(l8 (1190 -210) (200 200)) + R(l8 (-200 -600) (200 200)) + R(l12 (-1680 -280) (360 760)) + R(l12 (820 -830) (800 900)) + R(l13 (-1925 -775) (250 250)) + R(l13 (-250 150) (250 250)) + R(l13 (1175 -225) (200 200)) + R(l13 (-200 -600) (200 200)) + R(l14 (-3400 -350) (3000 900)) + R(l14 (-200 -900) (1000 900)) + R(l10 (-700 -950) (400 1000)) + R(l2 (-1875 -975) (775 950)) + ) + N(3 I($4) + R(l4 (-125 -250) (250 2500)) + R(l4 (-250 -3050) (250 1600)) + R(l4 (-250 1200) (250 1600)) + ) + N(4 I($5) + R(l8 (-510 -310) (220 220)) + R(l8 (-220 180) (220 220)) + R(l8 (-220 2180) (220 220)) + R(l8 (-220 180) (220 220)) + R(l12 (-290 -3530) (360 2840)) + R(l12 (-360 -2800) (360 760)) + R(l12 (-360 2040) (360 760)) + R(l2 (-680 -855) (775 950)) + R(l6 (-775 -3750) (775 950)) + ) + N(5 I($I11)) + P(2) + P(3) + P(4) + P(1) + P(5) + D(1 D$PMOS + Y(0 2800) + E(L 0.25) + E(W 0.95) + E(AS 0.73625) + E(AD 0.73625) + E(PS 3.45) + E(PD 3.45) + T(S 4) + T(G 3) + T(D 2) + T(B 2) + ) + D(2 D$NMOS + Y(0 0) + E(L 0.25) + E(W 0.95) + E(AS 0.73625) + E(AD 0.73625) + E(PS 3.45) + E(PD 3.45) + T(S 4) + T(G 3) + T(D 1) + T(B 5) + ) +) +X(TOP + R((1334 621) (9246 5073)) + N(1 I($1) + R(l4 (2920 2600) (3980 400)) + R(l11 (-300 -300) (200 200)) + R(l12 (-300 -300) (690 400)) + ) + N(2 I(A) + R(l4 (7700 2600) (2880 400)) + R(l15 (-2380 -200) (0 0)) + ) + N(3 I(Q) + R(l12 (1810 2600) (690 400)) + R(l16 (-400 -200) (0 0)) + ) + N(4 I(IOSUB) + R(l22 (1334 621) (4230 5073)) + R(l21 (-964 -4594) (400 1000)) + R(l20 (-2125 -975) (250 950)) + ) + N(5 I($7) + R(l3 (4000 3400) (2700 2000)) + ) + N(6 I(SUBSTRATE) + R(l18 (7575 1125) (250 950)) + R(l19 (1475 -975) (400 1000)) + ) + P(2 I(A)) + P(3 I(Q)) + P(4 I(IOSUB)) + P(6 I(SUBSTRATE)) + X(1 INV Y(3000 1600) + P(0 5) + P(1 1) + P(2 3) + P(3 4) + P(4 4) + ) + X(2 INV Y(7700 1600) + P(0 5) + P(1 2) + P(2 1) + P(3 6) + P(4 6) + ) +) diff --git a/testdata/lvs/split_substrate.lvs b/testdata/lvs/split_substrate.lvs new file mode 100644 index 000000000..43204067d --- /dev/null +++ b/testdata/lvs/split_substrate.lvs @@ -0,0 +1,107 @@ + +$lvs_test_source && source($lvs_test_source) + +if $lvs_test_target_l2n + report_netlist($lvs_test_target_l2n) +else + report_netlist +end + +writer = write_spice(true, false) +$lvs_test_target_cir && target_netlist($lvs_test_target_cir, writer, "Extracted by KLayout") + +deep + +# Drawing layers + +nwell = input(1, 0) +active = input(2, 0) +nplus = input(2, 1) +pplus = input(2, 2) +poly = input(3, 0) +poly_lbl = input(3, 1) +diff_cont = input(4, 0) +poly_cont = input(5, 0) +metal1 = input(6, 0) +metal1_lbl = input(6, 1) +via1 = input(7, 0) +metal2 = input(8, 0) +metal2_lbl = input(8, 1) +iosub = input(10, 0) + +# Bulk layer for terminal provisioning + +bulk = polygon_layer + +psd = nil +nsd = nil + +# Computed layers + +active_in_nwell = active & nwell +pactive = active_in_nwell & pplus +ntie = active_in_nwell & nplus +pgate = pactive & poly +psd = pactive - pgate + +active_outside_nwell = active - nwell +nactive = active_outside_nwell & nplus +ptie = active_outside_nwell & pplus +ngate = nactive & poly +nsd = nactive - ngate + +# Device extraction + +# PMOS transistor device extraction +extract_devices(mos4("PMOS"), { "SD" => psd, "G" => pgate, "W" => nwell, + "tS" => psd, "tD" => psd, "tG" => poly }) + +# NMOS transistor device extraction +extract_devices(mos4("NMOS"), { "SD" => nsd, "G" => ngate, "W" => bulk, + "tS" => nsd, "tD" => nsd, "tG" => poly }) + +# Define connectivity for netlist extraction + +# Inter-layer + +soft_connect(diff_cont, psd) +soft_connect(diff_cont, nsd) +soft_connect(diff_cont, ptie) +soft_connect(diff_cont, ntie) +soft_connect(ntie, nwell) +soft_connect(poly_cont, poly) + +connect(diff_cont, metal1) +connect(poly_cont, metal1) +connect(metal1, via1) +connect(via1, metal2) + +# attach labels +connect(poly, poly_lbl) +connect(metal1, metal1_lbl) +connect(metal2, metal2_lbl) + +# Split bulk and ptie into inside and outside iosub +(bulk_io, bulk_reg) = bulk.andnot(iosub) +(ptie_io, ptie_reg) = ptie.andnot(iosub) + +# connect outside to "SUBSTRATE" globally +connect(bulk, bulk_reg) +connect(ptie, ptie_reg) +connect_global(bulk_reg, "SUBSTRATE") +soft_connect_global(ptie_reg, "SUBSTRATE") + +# connect inside to "IOSUB" via polygons +connect(bulk, bulk_io) +connect(ptie, ptie_io) +connect(bulk_io, iosub) +soft_connect(ptie_io, iosub) +connect_global(iosub, "IOSUB") + +# Netlist section (NOTE: we only check log here) +# for debugging: _make_soft_connection_diodes(true) +netlist + +netlist.simplify + +