From 36a3540e1652dd4c417522b24c475e3ae265a5f7 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 25 Feb 2019 23:51:21 +0100 Subject: [PATCH] Allow empty regions for device extractor. --- src/db/db/dbDeepShapeStore.cc | 27 +++- src/db/db/dbDeepShapeStore.h | 13 ++ src/db/db/dbNetlistDeviceExtractor.cc | 21 ++- src/db/unit_tests/dbLayoutToNetlistTests.cc | 155 ++++++++++++++++++++ 4 files changed, 208 insertions(+), 8 deletions(-) diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index 0d464e5f6..19f3a7255 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -222,14 +222,23 @@ DeepLayer::check_dss () const struct DeepShapeStore::LayoutHolder { LayoutHolder (const db::ICplxTrans &trans) - : refs (0), layout (false), builder (&layout, trans) + : refs (0), layout (false), builder (&layout, trans), m_empty_layer (std::numeric_limits::max ()) { // .. nothing yet .. } + unsigned int make_empty_layer () + { + if (m_empty_layer == std::numeric_limits::max ()) { + m_empty_layer = layout.insert_layer (); + layer_refs [m_empty_layer] += 1; // the empty layer is not deleted + } + return m_empty_layer; + } + void add_layer_ref (unsigned int layer) { - layer_refs[layer] += 1; + layer_refs [layer] += 1; } void remove_layer_ref (unsigned int layer) @@ -244,6 +253,9 @@ struct DeepShapeStore::LayoutHolder db::Layout layout; db::HierarchyBuilder builder; std::map layer_refs; + +private: + unsigned int m_empty_layer; }; // ---------------------------------------------------------------------------------- @@ -426,6 +438,17 @@ DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator return DeepLayer (this, layout_index, layer_index); } +DeepLayer DeepShapeStore::empty_layer (unsigned int layout_index) +{ + return DeepLayer (this, layout_index, m_layouts[layout_index]->make_empty_layer ()); +} + +DeepLayer DeepShapeStore::empty_layer () +{ + require_singular (); + return empty_layer (0); +} + DeepLayer DeepShapeStore::create_custom_layer (const db::RecursiveShapeIterator &si, HierarchyBuilderShapeReceiver *pipe, const db::ICplxTrans &trans) { unsigned int layout_index = layout_for_iter (si, trans); diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index b0958be42..1f197d424 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -294,6 +294,19 @@ public: */ DeepLayer create_custom_layer (const db::RecursiveShapeIterator &si, HierarchyBuilderShapeReceiver *pipe, const ICplxTrans &trans = db::ICplxTrans ()); + /** + * @brief Gets the empty working layer + * + * This method will deliver an empty layer for the given layout index. CAUTION: don't modify this layer as it may + * be reused. + */ + DeepLayer empty_layer (unsigned int layout_index); + + /** + * @brief Gets the empty working layer for the singular layout + */ + DeepLayer empty_layer (); + /** * @brief Inserts the deep layer's shapes into some target layout */ diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc index 7f6394ec0..74d7ed6b3 100644 --- a/src/db/db/dbNetlistDeviceExtractor.cc +++ b/src/db/db/dbNetlistDeviceExtractor.cc @@ -140,14 +140,23 @@ void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, const NetlistDevi tl_assert (l->second != 0); db::DeepRegion *dr = dynamic_cast (l->second->delegate ()); if (dr == 0) { - throw tl::Exception (tl::sprintf (tl::to_string (tr ("Invalid region passed to input layer '%s' for device extraction: must be of deep region kind")), ld->name)); - } - if (&dr->deep_layer ().layout () != &dss.layout () || &dr->deep_layer ().initial_cell () != &dss.initial_cell ()) { - throw tl::Exception (tl::sprintf (tl::to_string (tr ("Invalid region passed to input layer '%s' for device extraction: not originating from the same source")), ld->name)); - } + if (l->second->empty ()) { + // provide a substitute empty layer + layers.push_back (dss.empty_layer ().layer ()); + } else { + throw tl::Exception (tl::sprintf (tl::to_string (tr ("Invalid region passed to input layer '%s' for device extraction: must be of deep region kind")), ld->name)); + } - layers.push_back (dr->deep_layer ().layer ()); + } else { + + if (&dr->deep_layer ().layout () != &dss.layout () || &dr->deep_layer ().initial_cell () != &dss.initial_cell ()) { + throw tl::Exception (tl::sprintf (tl::to_string (tr ("Invalid region passed to input layer '%s' for device extraction: not originating from the same source")), ld->name)); + } + + layers.push_back (dr->deep_layer ().layer ()); + + } } diff --git a/src/db/unit_tests/dbLayoutToNetlistTests.cc b/src/db/unit_tests/dbLayoutToNetlistTests.cc index b16d1673e..15d7a4d82 100644 --- a/src/db/unit_tests/dbLayoutToNetlistTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistTests.cc @@ -1742,3 +1742,158 @@ TEST(6_MoreDeviceTypes) " DLVNMOS $6 (S=VSS,G=A,D=$6,B=BULK) [L=1.2,W=1.7,AS=2.346,AD=2.1165,PS=6.16,PD=5.89]\n" ); } + +TEST(7_MoreByEmptyDeviceTypes) +{ + db::Layout ly; + db::LayerMap lmap; + + unsigned int nwell = define_layer (ly, lmap, 1); + unsigned int active = define_layer (ly, lmap, 2); + unsigned int thickgox = define_layer (ly, lmap, 1003); // does not exist + unsigned int pplus = define_layer (ly, lmap, 4); + unsigned int nplus = define_layer (ly, lmap, 5); + unsigned int poly = define_layer (ly, lmap, 6); + unsigned int poly_lbl = define_layer (ly, lmap, 7); + unsigned int cont = define_layer (ly, lmap, 8); + unsigned int metal1 = define_layer (ly, lmap, 9); + unsigned int metal1_lbl = define_layer (ly, lmap, 10); + unsigned int via1 = define_layer (ly, lmap, 11); + unsigned int metal2 = define_layer (ly, lmap, 12); + unsigned int metal2_lbl = define_layer (ly, lmap, 13); + + { + 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_l6.gds"); + + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly, options); + } + + db::Cell &tc = ly.cell (*ly.begin_top_down ()); + db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set ())); + + std::auto_ptr rbulk (l2n.make_layer ("bulk")); + std::auto_ptr rnwell (l2n.make_layer (nwell, "nwell")); + std::auto_ptr rthickgox (l2n.make_layer (thickgox, "thickgox")); + std::auto_ptr ractive (l2n.make_layer (active, "active")); + std::auto_ptr rpplus (l2n.make_layer (pplus, "pplus")); + std::auto_ptr rnplus (l2n.make_layer (nplus, "nplus")); + std::auto_ptr rpoly (l2n.make_polygon_layer (poly, "poly")); + std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); + std::auto_ptr rcont (l2n.make_polygon_layer (cont, "cont")); + std::auto_ptr rmetal1 (l2n.make_polygon_layer (metal1, "metal1")); + std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); + std::auto_ptr rvia1 (l2n.make_polygon_layer (via1, "via1")); + std::auto_ptr rmetal2 (l2n.make_polygon_layer (metal2, "metal2")); + std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); + + // derived regions + + db::Region ractive_in_nwell = *ractive & *rnwell; + db::Region rpactive = ractive_in_nwell - *rnplus; + db::Region rntie = ractive_in_nwell & *rnplus; + db::Region rpgate = rpactive & *rpoly; + db::Region rpsd = rpactive - rpgate; + db::Region rhv_pgate = rpgate & *rthickgox; + db::Region rlv_pgate = rpgate - rhv_pgate; + db::Region rhv_psd = rpsd & *rthickgox; + db::Region rlv_psd = rpsd - *rthickgox; + + l2n.register_layer(rntie, "ntie"); + l2n.register_layer(rpsd, "psd"); + + db::Region ractive_outside_nwell = *ractive - *rnwell; + db::Region rnactive = ractive_outside_nwell - *rpplus; + db::Region rptie = ractive_outside_nwell & *rpplus; + db::Region rngate = rnactive & *rpoly; + db::Region rnsd = rnactive - rngate; + db::Region rhv_ngate = rngate & *rthickgox; + db::Region rlv_ngate = rngate - rhv_ngate; + db::Region rhv_nsd = rnsd & *rthickgox; + db::Region rlv_nsd = rnsd - *rthickgox; + + l2n.register_layer(rptie, "ptie"); + l2n.register_layer(rnsd, "nsd"); + + db::NetlistDeviceExtractorMOS4Transistor hvpmos_ex ("HVPMOS"); + db::NetlistDeviceExtractorMOS4Transistor hvnmos_ex ("HVNMOS"); + db::NetlistDeviceExtractorMOS4Transistor lvpmos_ex ("LVPMOS"); + db::NetlistDeviceExtractorMOS4Transistor lvnmos_ex ("LVNMOS"); + + // device extraction + + db::NetlistDeviceExtractor::input_layers dl; + + dl["SD"] = &rpsd; + dl["G"] = &rhv_pgate; + dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes + dl["W"] = rnwell.get (); + l2n.extract_devices (hvpmos_ex, dl); + + dl["SD"] = &rpsd; + dl["G"] = &rlv_pgate; + dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes + dl["W"] = rnwell.get (); + l2n.extract_devices (lvpmos_ex, dl); + + dl["SD"] = &rnsd; + dl["G"] = &rhv_ngate; + dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes + dl["W"] = rbulk.get (); + l2n.extract_devices (hvnmos_ex, dl); + + dl["SD"] = &rnsd; + dl["G"] = &rlv_ngate; + dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes + dl["W"] = rbulk.get (); + l2n.extract_devices (lvnmos_ex, dl); + + // Intra-layer + l2n.connect (rpsd); + l2n.connect (rnsd); + l2n.connect (*rnwell); + l2n.connect (*rpoly); + l2n.connect (*rcont); + l2n.connect (*rmetal1); + l2n.connect (*rvia1); + l2n.connect (*rmetal2); + l2n.connect (rptie); + l2n.connect (rntie); + // Inter-layer + l2n.connect (*rcont, rntie); + l2n.connect (*rcont, rptie); + l2n.connect (*rnwell, rntie); + l2n.connect (rpsd, *rcont); + l2n.connect (rnsd, *rcont); + l2n.connect (*rpoly, *rcont); + l2n.connect (*rcont, *rmetal1); + l2n.connect (*rmetal1, *rvia1); + l2n.connect (*rvia1, *rmetal2); + l2n.connect (*rpoly, *rpoly_lbl); // attaches labels + l2n.connect (*rmetal1, *rmetal1_lbl); // attaches labels + l2n.connect (*rmetal2, *rmetal2_lbl); // attaches labels + // Global + l2n.connect_global (rptie, "BULK"); + l2n.connect_global (*rbulk, "BULK"); + + l2n.extract_netlist (); + + // compare netlist as string + EXPECT_EQ (l2n.netlist ()->to_string (), + "Circuit TOP ():\n" + " DLVPMOS $1 (S=Z,G=$5,D=VDD2,B=$8) [L=1.5,W=4.05,AS=5.4675,AD=2.73375,PS=10.8,PD=5.4]\n" + " DLVPMOS $2 (S=VDD2,G=Z,D=$5,B=$8) [L=1.5,W=4.05,AS=2.73375,AD=5.4675,PS=5.4,PD=10.8]\n" + " DLVPMOS $3 (S=$10,G=A,D=$6,B=$9) [L=1.5,W=2.475,AS=1.11375,AD=3.155625,PS=5.85,PD=7.5]\n" + " DLVNMOS $4 (S=VSS,G=A,D=$6,B=BULK) [L=1.2,W=1.7,AS=2.346,AD=2.1165,PS=6.16,PD=5.89]\n" + " DLVNMOS $5 (S=Z,G=$6,D=VSS,B=BULK) [L=1.5,W=5.25,AS=7.0875,AD=3.54375,PS=13.2,PD=6.6]\n" + " DLVNMOS $6 (S=VSS,G=A,D=$5,B=BULK) [L=1.5,W=5.25,AS=3.54375,AD=7.0875,PS=6.6,PD=13.2]\n" + ); +}