diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index 4c32c396b..e56814f69 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -227,11 +227,10 @@ struct DeepShapeStore::LayoutHolder // .. nothing yet .. } - unsigned int make_empty_layer () + unsigned int empty_layer () const { 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 + const_cast (this)->make_empty_layer (); } return m_empty_layer; } @@ -256,6 +255,12 @@ struct DeepShapeStore::LayoutHolder private: unsigned int m_empty_layer; + + void make_empty_layer () + { + m_empty_layer = layout.insert_layer (); + layer_refs [m_empty_layer] += 1; // the empty layer is not deleted + } }; // ---------------------------------------------------------------------------------- @@ -282,6 +287,9 @@ DeepShapeStore::~DeepShapeStore () { --s_instance_count; + // because of unregistration we must not do this in the destructor: + m_layers_for_flat.clear (); + for (std::vector::iterator h = m_layouts.begin (); h != m_layouts.end (); ++h) { delete *h; } @@ -290,6 +298,12 @@ DeepShapeStore::~DeepShapeStore () DeepLayer DeepShapeStore::create_from_flat (const db::Region ®ion, double max_area_ratio, size_t max_vertex_count, const db::ICplxTrans &trans) { + // reuse existing layer + std::pair lff = layer_for_flat (region); + if (lff.first) { + return lff.second; + } + require_singular (); unsigned int layer = layout ().insert_layer (); @@ -308,11 +322,32 @@ DeepLayer DeepShapeStore::create_from_flat (const db::Region ®ion, double max db::PolygonReferenceHierarchyBuilderShapeReceiver refs (&layout (), m_text_enlargement, m_text_property_name); db::ReducingHierarchyBuilderShapeReceiver red (&refs, max_area_ratio, max_vertex_count); - for (db::Region::const_iterator p = region.begin (); ! p.at_end (); ++p) { - red.push (*p, trans, world, 0, shapes); + // try to maintain the texts - go through shape iterator + std::pair ii = region.begin_iter (); + db::ICplxTrans ttop = trans * ii.second; + while (! ii.first.at_end ()) { + red.push (*ii.first, ttop * ii.first.trans (), world, 0, shapes); + ++ii.first; } - return DeepLayer (this, 0 /*singular layout index*/, layer); + DeepLayer dl (this, 0 /*singular layout index*/, layer); + m_layers_for_flat [tl::id_of (region.delegate ())] = dl; + return dl; +} + +std::pair DeepShapeStore::layer_for_flat (const db::Region ®ion) const +{ + return layer_for_flat (tl::id_of (region.delegate ())); +} + +std::pair DeepShapeStore::layer_for_flat (size_t region_id) const +{ + std::map::const_iterator lff = m_layers_for_flat.find (region_id); + if (lff == m_layers_for_flat.end ()) { + return std::make_pair (false, DeepLayer ()); + } else { + return std::make_pair (true, lff->second); + } } bool DeepShapeStore::is_singular () const @@ -475,12 +510,12 @@ DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator return DeepLayer (this, layout_index, layer_index); } -DeepLayer DeepShapeStore::empty_layer (unsigned int layout_index) +DeepLayer DeepShapeStore::empty_layer (unsigned int layout_index) const { - return DeepLayer (this, layout_index, m_layouts[layout_index]->make_empty_layer ()); + return DeepLayer (const_cast (this), layout_index, m_layouts[layout_index]->empty_layer ()); } -DeepLayer DeepShapeStore::empty_layer () +DeepLayer DeepShapeStore::empty_layer () const { require_singular (); return empty_layer (0); diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index d08e47c3f..cdcbee1d0 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -264,9 +264,25 @@ public: * * This method is intended for use with singular-created DSS objects (see * singular constructor). + * + * After a flat layer has been created for a region, it can be retrieved + * from the region later with layer_for_flat (region). */ DeepLayer create_from_flat (const db::Region ®ion, double max_area_ratio = 0.0, size_t max_vertex_count = 0, const db::ICplxTrans &trans = db::ICplxTrans ()); + /** + * @brief Gets the layer for a given flat region. + * + * If a layer has been created for a flat region with create_from_flat, it can be retrieved with this method. + * The first return value is true in this case. + */ + std::pair layer_for_flat (const db::Region ®ion) const; + + /** + * @brief Same as layer_for_flat, but takes a region Id + */ + std::pair layer_for_flat (size_t region_id) const; + /** * @brief Inserts a polygon layer into the deep shape store * @@ -316,12 +332,12 @@ public: * 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); + DeepLayer empty_layer (unsigned int layout_index) const; /** * @brief Gets the empty working layer for the singular layout */ - DeepLayer empty_layer (); + DeepLayer empty_layer () const; /** * @brief Inserts the deep layer's shapes into some target layout @@ -577,6 +593,7 @@ private: DeepShapeStore &operator= (const DeepShapeStore &); std::vector m_layouts; + std::map m_layers_for_flat; layout_map_type m_layout_map; int m_threads; double m_max_area_ratio; diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 04dfa6af7..cc89b9326 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -56,6 +56,12 @@ LayoutToNetlist::LayoutToNetlist (db::DeepShapeStore *dss, unsigned int layout_i init (); } +LayoutToNetlist::LayoutToNetlist (db::DeepShapeStore *dss) + : mp_dss (dss), m_netlist_extracted (false), m_is_flat (false) +{ + init (); +} + LayoutToNetlist::LayoutToNetlist (const std::string &topcell_name, double dbu) : m_iter (), m_netlist_extracted (false), m_is_flat (true) { @@ -66,11 +72,21 @@ LayoutToNetlist::LayoutToNetlist (const std::string &topcell_name, double dbu) } LayoutToNetlist::LayoutToNetlist () - : m_iter (), mp_internal_dss (new db::DeepShapeStore ()), mp_dss (mp_internal_dss.get ()), m_netlist_extracted (false), m_is_flat (true) + : m_iter (), mp_internal_dss (new db::DeepShapeStore ()), mp_dss (mp_internal_dss.get ()), m_netlist_extracted (false), m_is_flat (false) { init (); } +LayoutToNetlist::~LayoutToNetlist () +{ + // NOTE: do this in this order because of unregistration of the layers + m_named_regions.clear (); + m_dlrefs.clear (); + mp_internal_dss.reset (0); + mp_netlist.reset (0); + m_net_clusters.clear (); +} + void LayoutToNetlist::init () { if (! mp_dss.get ()) { @@ -179,15 +195,13 @@ void LayoutToNetlist::connect (const db::Region &l) if (m_netlist_extracted) { throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted"))); } - if (! is_deep (l)) { - throw (tl::Exception (tl::to_string (tr ("Non-hierarchical layers cannot be used in intra-layer connectivity for netlist extraction")))); - } + if (! is_persisted (l)) { throw (tl::Exception (tl::to_string (tr ("Only named layers can be used in intra-layer connectivity for netlist extraction")))); } // we need to keep a reference, so we can safely delete the region - db::DeepLayer dl (l); + db::DeepLayer dl = deep_layer_of (l); m_dlrefs.insert (dl); m_conn.connect (dl.layer ()); @@ -198,12 +212,6 @@ void LayoutToNetlist::connect (const db::Region &a, const db::Region &b) if (m_netlist_extracted) { throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted"))); } - if (! is_deep (a)) { - throw (tl::Exception (tl::to_string (tr ("Non-hierarchical layers cannot be used in inter-layer connectivity (first layer) for netlist extraction")))); - } - if (! is_deep (b)) { - throw (tl::Exception (tl::to_string (tr ("Non-hierarchical layers cannot be used in inter-layer connectivity (second layer) for netlist extraction")))); - } if (! is_persisted (a)) { throw (tl::Exception (tl::to_string (tr ("Only named layers can be used in inter-layer connectivity (first layer) for netlist extraction")))); } @@ -212,7 +220,8 @@ void LayoutToNetlist::connect (const db::Region &a, const db::Region &b) } // we need to keep a reference, so we can safely delete the region - db::DeepLayer dla (a), dlb (b); + db::DeepLayer dla = deep_layer_of (a); + db::DeepLayer dlb = deep_layer_of (b); m_dlrefs.insert (dla); m_dlrefs.insert (dlb); @@ -224,15 +233,12 @@ size_t LayoutToNetlist::connect_global (const db::Region &l, const std::string & if (m_netlist_extracted) { throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted"))); } - if (! is_deep (l)) { - throw (tl::Exception (tl::to_string (tr ("Non-hierarchical layers cannot be used in global connectivity for netlist extraction")))); - } if (! is_persisted (l)) { throw (tl::Exception (tl::to_string (tr ("Only named layers can be used in global connectivity for netlist extraction")))); } // we need to keep a reference, so we can safely delete the region - db::DeepLayer dl (l); + db::DeepLayer dl = deep_layer_of (l); m_dlrefs.insert (dl); return m_conn.connect_global (dl.layer (), gn); @@ -316,7 +322,7 @@ void LayoutToNetlist::register_layer (const db::Region ®ion, const std::strin if (region.empty ()) { dl = dss ().empty_layer (); } else { - throw tl::Exception (tl::to_string (tr ("Layer is not a deep region"))); + throw tl::Exception (tl::to_string (tr ("Layer is not a deep region and cannot be registered with name: ")) + n); } } else { @@ -381,13 +387,29 @@ db::Region *LayoutToNetlist::layer_by_index (unsigned int index) } } -unsigned int LayoutToNetlist::layer_of (const db::Region ®ion) const +db::DeepLayer LayoutToNetlist::deep_layer_of (const db::Region ®ion) const { const db::DeepRegion *dr = dynamic_cast (region.delegate ()); if (! dr) { - throw (tl::Exception (tl::to_string (tr ("Non-hierarchical layers cannot be used in netlist extraction")))); + + std::pair lff = dss ().layer_for_flat (region); + if (lff.first) { + return lff.second; + } else if (region.empty ()) { + // provide a substitute empty layer for empty + return dss ().empty_layer (); + } else { + throw (tl::Exception (tl::to_string (tr ("Non-hierarchical layers cannot be used in netlist extraction")))); + } + + } else { + return dr->deep_layer (); } - return dr->deep_layer ().layer (); +} + +unsigned int LayoutToNetlist::layer_of (const db::Region ®ion) const +{ + return deep_layer_of (region).layer (); } db::CellMapping LayoutToNetlist::cell_mapping_into (db::Layout &layout, db::Cell &cell, bool with_device_cells) diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 3c57b9c7a..367cf9340 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -95,6 +95,19 @@ public: */ LayoutToNetlist (db::DeepShapeStore *dss, unsigned int layout_index); + /** + * @brief Alternative constructor using an external deep shape storage + * + * This constructor allows using an external DSS. It's intended to be used + * with existing DSS instances. Existing layers can be registered with + * "register_layer". The LayoutToNetlist object will hold a weak reference + * to the DSS but not own the DSS. + * + * NOTE: this version cannot create layers but just register layers + * which are present inside the DSS given as the argument. + */ + LayoutToNetlist (db::DeepShapeStore *dss); + /** * @brief Alternative constructor for flat mode * @@ -109,6 +122,11 @@ public: */ LayoutToNetlist (); + /** + * @brief The destructor + */ + ~LayoutToNetlist (); + /** * @brief Sets the number of threads to use for operations which support multiple threads */ @@ -517,6 +535,7 @@ private: size_t search_net (const db::ICplxTrans &trans, const db::Cell *cell, const db::local_cluster &test_cluster, std::vector &rev_inst_path); void build_net_rec (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const char *net_cell_name_prefix, const char *cell_name_prefix, const char *device_cell_name_prefix, std::map, db::cell_index_type> &cmap, const ICplxTrans &tr) const; void build_net_rec (db::cell_index_type ci, size_t cid, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const Net *net, const char *net_cell_name_prefix, const char *cell_name_prefix, const char *device_cell_name_prefix, std::map, db::cell_index_type> &cmap, const ICplxTrans &tr) const; + db::DeepLayer deep_layer_of (const db::Region ®ion) const; }; } diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc index 74d7ed6b3..b219fe1a3 100644 --- a/src/db/db/dbNetlistDeviceExtractor.cc +++ b/src/db/db/dbNetlistDeviceExtractor.cc @@ -141,7 +141,11 @@ void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, const NetlistDevi db::DeepRegion *dr = dynamic_cast (l->second->delegate ()); if (dr == 0) { - if (l->second->empty ()) { + std::pair alias = dss.layer_for_flat (tl::id_of (l->second->delegate ())); + if (alias.first) { + // use deep layer alias for a given flat one (if found) + layers.push_back (alias.second.layer ()); + } else if (l->second->empty ()) { // provide a substitute empty layer layers.push_back (dss.empty_layer ().layer ()); } else { diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index 37dc8650f..92884f92e 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -39,11 +39,16 @@ static db::LayoutToNetlist *make_l2n_default () return new db::LayoutToNetlist (); } -static db::LayoutToNetlist *make_l2n_from_existing_dss (db::DeepShapeStore *dss, unsigned int layout_index) +static db::LayoutToNetlist *make_l2n_from_existing_dss_with_layout (db::DeepShapeStore *dss, unsigned int layout_index) { return new db::LayoutToNetlist (dss, layout_index); } +static db::LayoutToNetlist *make_l2n_from_existing_dss (db::DeepShapeStore *dss) +{ + return new db::LayoutToNetlist (dss); +} + static db::LayoutToNetlist *make_l2n_flat (const std::string &topcell_name, double dbu) { return new db::LayoutToNetlist (topcell_name, dbu); @@ -109,9 +114,18 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "@brief Creates a new and empty extractor object\n" "The main objective for this constructor is to create an object suitable for reading an annotated netlist.\n" ) + - gsi::constructor ("new", &make_l2n_from_existing_dss, gsi::arg ("dss"), gsi::arg ("layout_index", 0), + gsi::constructor ("new", &make_l2n_from_existing_dss, gsi::arg ("dss"), "@brief Creates a new extractor object reusing an existing \\DeepShapeStore object\n" - "This constrcutor can be used if there is a DSS object already from which the " + "This constructor can be used if there is a DSS object already from which the " + "shapes can be taken. This version can only be used with \\register to " + "add layers (regions) inside the 'dss' object.\n" + "\n" + "The make_... methods will not create new layers as there is no particular place " + "defined where to create the layers." + ) + + gsi::constructor ("new", &make_l2n_from_existing_dss_with_layout, gsi::arg ("dss"), gsi::arg ("layout_index"), + "@brief Creates a new extractor object reusing an existing \\DeepShapeStore object\n" + "This constructor can be used if there is a DSS object already from which the " "shapes can be taken. NOTE: in this case, the make_... functions will create " "new layers inside this DSS. To register existing layers (regions) use \\register.\n" ) + diff --git a/src/db/unit_tests/dbDeepShapeStoreTests.cc b/src/db/unit_tests/dbDeepShapeStoreTests.cc index 982548adb..70d625495 100644 --- a/src/db/unit_tests/dbDeepShapeStoreTests.cc +++ b/src/db/unit_tests/dbDeepShapeStoreTests.cc @@ -22,6 +22,8 @@ #include "dbDeepShapeStore.h" +#include "dbRegion.h" +#include "dbDeepRegion.h" #include "tlUnitTest.h" #include "tlStream.h" @@ -184,3 +186,25 @@ TEST(3_TextTreatment) EXPECT_EQ (dss_layout->properties_repository ().prop_name (ps.begin ()->first).to_string (), "text"); EXPECT_EQ (ps.begin ()->second.to_string (), "TEXT"); } + +TEST(4_FlatAndEmptyInput) +{ + db::DeepShapeStore dss ("TOP", 0.01); + EXPECT_EQ (dss.layout ().dbu (), 0.01); + + db::Region r1; + r1.insert (db::Box (0, 0, 1000, 1000)); + + db::Region r2; + r2.insert (db::Box (100, 100, 900, 900)); + + db::Region r3; + + db::Region dr1 (new db::DeepRegion (dss.create_from_flat (r1))); + db::Region dr2 (new db::DeepRegion (dss.create_from_flat (r2))); + db::Region dr3 (new db::DeepRegion (dss.create_from_flat (r3))); + + EXPECT_EQ ((dr1 - dr2).to_string (), "(0,0;0,900;100,900;100,100;900,100;900,900;0,900;0,1000;1000,1000;1000,0)"); + EXPECT_EQ ((dr1 - dr3).to_string (), "(0,0;0,1000;1000,1000;1000,0)"); +} + diff --git a/src/db/unit_tests/dbLayoutToNetlistTests.cc b/src/db/unit_tests/dbLayoutToNetlistTests.cc index 15d7a4d82..98a13b305 100644 --- a/src/db/unit_tests/dbLayoutToNetlistTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistTests.cc @@ -1897,3 +1897,359 @@ TEST(7_MoreByEmptyDeviceTypes) " 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" ); } + +TEST(8_FlatExtraction) +{ + 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, 3); + 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 (ly.cell_name (tc.cell_index ()), ly.dbu ()); + + std::auto_ptr rbulk (new db::Region ()); + std::auto_ptr rnwell (new db::Region (db::RecursiveShapeIterator (ly, tc, nwell))); + std::auto_ptr rthickgox (new db::Region (db::RecursiveShapeIterator (ly, tc, thickgox))); + std::auto_ptr ractive (new db::Region (db::RecursiveShapeIterator (ly, tc, active))); + std::auto_ptr rpplus (new db::Region (db::RecursiveShapeIterator (ly, tc, pplus))); + std::auto_ptr rnplus (new db::Region (db::RecursiveShapeIterator (ly, tc, nplus))); + std::auto_ptr rpoly (new db::Region (db::RecursiveShapeIterator (ly, tc, poly))); + std::auto_ptr rpoly_lbl (new db::Region (db::RecursiveShapeIterator (ly, tc, poly_lbl))); + std::auto_ptr rcont (new db::Region (db::RecursiveShapeIterator (ly, tc, cont))); + std::auto_ptr rmetal1 (new db::Region (db::RecursiveShapeIterator (ly, tc, metal1))); + std::auto_ptr rmetal1_lbl (new db::Region (db::RecursiveShapeIterator (ly, tc, metal1_lbl))); + std::auto_ptr rvia1 (new db::Region (db::RecursiveShapeIterator (ly, tc, via1))); + std::auto_ptr rmetal2 (new db::Region (db::RecursiveShapeIterator (ly, tc, metal2))); + std::auto_ptr rmetal2_lbl (new db::Region (db::RecursiveShapeIterator (ly, tc, metal2_lbl))); + + l2n.register_layer (*rbulk, "bulk"); + l2n.register_layer (*rnwell, "nwell"); + l2n.register_layer (*rthickgox, "thickgox"); + l2n.register_layer (*ractive, "active"); + l2n.register_layer (*rpplus, "pplus"); + l2n.register_layer (*rnplus, "nplus"); + l2n.register_layer (*rpoly, "poly"); + l2n.register_layer (*rpoly_lbl, "poly_lbl"); + l2n.register_layer (*rcont, "cont"); + l2n.register_layer (*rmetal1, "metal1"); + l2n.register_layer (*rmetal1_lbl, "metal1_lbl"); + l2n.register_layer (*rvia1, "via1"); + l2n.register_layer (*rmetal2, "metal2"); + l2n.register_layer (*rmetal2_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"); + // required to provide deep layers for flat ones for the extractor: + l2n.register_layer (rhv_pgate, "hv_pgate"); + l2n.register_layer (rlv_pgate, "lv_pgate"); + + 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"); + // required to provide deep layers for flat ones for the extractor: + l2n.register_layer (rhv_ngate, "hv_ngate"); + l2n.register_layer (rlv_ngate, "lv_ngate"); + + 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" + " DHVPMOS $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" + " DHVPMOS $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" + " DHVNMOS $4 (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" + " DHVNMOS $5 (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" + " 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(9_FlatExtractionWithExternalDSS) +{ + 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, 103); // 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::DeepShapeStore dss; + db::LayoutToNetlist l2n (&dss); + + std::auto_ptr rbulk (new db::Region ()); + std::auto_ptr rnwell (new db::Region (db::RecursiveShapeIterator (ly, tc, nwell), dss)); + std::auto_ptr rthickgox (new db::Region (db::RecursiveShapeIterator (ly, tc, thickgox), dss)); + std::auto_ptr ractive (new db::Region (db::RecursiveShapeIterator (ly, tc, active), dss)); + std::auto_ptr rpplus (new db::Region (db::RecursiveShapeIterator (ly, tc, pplus), dss)); + std::auto_ptr rnplus (new db::Region (db::RecursiveShapeIterator (ly, tc, nplus), dss)); + std::auto_ptr rpoly (new db::Region (db::RecursiveShapeIterator (ly, tc, poly), dss)); + std::auto_ptr rpoly_lbl (new db::Region (db::RecursiveShapeIterator (ly, tc, poly_lbl), dss)); + std::auto_ptr rcont (new db::Region (db::RecursiveShapeIterator (ly, tc, cont), dss)); + std::auto_ptr rmetal1 (new db::Region (db::RecursiveShapeIterator (ly, tc, metal1), dss)); + std::auto_ptr rmetal1_lbl (new db::Region (db::RecursiveShapeIterator (ly, tc, metal1_lbl), dss)); + std::auto_ptr rvia1 (new db::Region (db::RecursiveShapeIterator (ly, tc, via1), dss)); + std::auto_ptr rmetal2 (new db::Region (db::RecursiveShapeIterator (ly, tc, metal2), dss)); + std::auto_ptr rmetal2_lbl (new db::Region (db::RecursiveShapeIterator (ly, tc, metal2_lbl), dss)); + + l2n.register_layer (*rbulk, "bulk"); + l2n.register_layer (*rnwell, "nwell"); + l2n.register_layer (*rthickgox, "thickgox"); + l2n.register_layer (*ractive, "active"); + l2n.register_layer (*rpplus, "pplus"); + l2n.register_layer (*rnplus, "nplus"); + l2n.register_layer (*rpoly, "poly"); + l2n.register_layer (*rpoly_lbl, "poly_lbl"); + l2n.register_layer (*rcont, "cont"); + l2n.register_layer (*rmetal1, "metal1"); + l2n.register_layer (*rmetal1_lbl, "metal1_lbl"); + l2n.register_layer (*rvia1, "via1"); + l2n.register_layer (*rmetal2, "metal2"); + l2n.register_layer (*rmetal2_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"); + // required to provide deep layers for flat ones for the extractor: + l2n.register_layer (rhv_pgate, "hv_pgate"); + l2n.register_layer (rlv_pgate, "lv_pgate"); + + 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"); + // required to provide deep layers for flat ones for the extractor: + l2n.register_layer (rhv_ngate, "hv_ngate"); + l2n.register_layer (rlv_ngate, "lv_ngate"); + + 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" + ); +} +