diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index 00db14b56..2d9a1e509 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -46,6 +46,7 @@ public: DeepRegion (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool merged_semantics = true, double area_ratio = 3.0, size_t max_vertex_count = 16); DeepRegion (const DeepRegion &other); + DeepRegion (const DeepLayer &dl); virtual ~DeepRegion (); @@ -94,10 +95,9 @@ protected: private: DeepRegion &operator= (const DeepRegion &other); - DeepRegion (const DeepLayer &dl); DeepLayer m_deep_layer; - // @@@ have hierarchical merged polygons later + // TODO: have hierarchical merged polygons later mutable db::Shapes m_merged_polygons; mutable bool m_merged_polygons_valid; diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index 438456bc4..b7bf576d3 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -195,7 +195,7 @@ struct DeepShapeStore::LayoutHolder void remove_layer_ref (unsigned int layer) { if ((layer_refs[layer] -= 1) <= 0) { - layout.clear_layer (layer); + layout.delete_layer (layer); layer_refs.erase (layer); } } @@ -343,7 +343,9 @@ DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator db::Layout &layout = m_layouts.back ()->layout; layout.hier_changed_event.add (this, &DeepShapeStore::invalidate_hier); - layout.dbu (si.layout ()->dbu ()); + if (si.layout ()) { + layout.dbu (si.layout ()->dbu ()); + } m_layout_map[si] = layout_index; diff --git a/src/db/db/dbHierarchyBuilder.cc b/src/db/db/dbHierarchyBuilder.cc index 8c4e409ea..5331f1cad 100644 --- a/src/db/db/dbHierarchyBuilder.cc +++ b/src/db/db/dbHierarchyBuilder.cc @@ -36,13 +36,22 @@ static HierarchyBuilderShapeInserter def_inserter; int compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIterator &iter1, const db::RecursiveShapeIterator &iter2) { + if ((iter1.layout () == 0) != (iter2.layout () == 0)) { + return (iter1.layout () == 0) < (iter2.layout () == 0); + } + if ((iter1.top_cell () == 0) != (iter2.top_cell () == 0)) { + return (iter1.top_cell () == 0) < (iter2.top_cell () == 0); + } + // basic source (layout, top_cell) needs to be the same of course if (iter1.layout () != iter2.layout ()) { // NOTE: pointer compare :-( return iter1.layout () < iter2.layout () ? -1 : 1; } - if (iter1.top_cell ()->cell_index () != iter2.top_cell ()->cell_index ()) { - return iter1.top_cell ()->cell_index () < iter2.top_cell ()->cell_index () ? -1 : 1; + if (iter1.top_cell ()) { + if (iter1.top_cell ()->cell_index () != iter2.top_cell ()->cell_index ()) { + return iter1.top_cell ()->cell_index () < iter2.top_cell ()->cell_index () ? -1 : 1; + } } // max depth controls the main hierarchical appearance @@ -51,10 +60,11 @@ compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIter } // if a region is set, the hierarchical appearance is the same only if the layers and - // complex region are indentical + // complex region are identical if ((iter1.region () == db::Box::world ()) != (iter2.region () == db::Box::world ())) { return (iter1.region () == db::Box::world ()) < (iter2.region () == db::Box::world ()) ? -1 : 1; } + if (iter1.region () != db::Box::world ()) { if (iter1.has_complex_region () != iter2.has_complex_region ()) { return iter1.has_complex_region () < iter2.has_complex_region () ? -1 : 1; @@ -174,30 +184,36 @@ HierarchyBuilder::begin (const RecursiveShapeIterator *iter) m_cell_stack.clear (); m_cells_seen.clear (); + if (! iter->layout () || ! iter->top_cell ()) { + return; + } + std::pair > key (iter->top_cell ()->cell_index (), std::set ()); m_cm_entry = m_cell_map.find (key); - m_cm_new_entry = false; if (m_cm_entry == m_cell_map.end ()) { db::cell_index_type new_top_index = mp_target->add_cell (iter->layout ()->cell_name (key.first)); m_cm_entry = m_cell_map.insert (std::make_pair (key, new_top_index)).first; - m_cm_new_entry = true; } db::Cell &new_top = mp_target->cell (m_cm_entry->second); m_cells_seen.insert (key); + // NOTE: we consider the top cell "new" if it does not have instances. + // We can do so as the recursive shape iterator will always deliver all instances + // and not a partial set of instances. + m_cm_new_entry = new_top.begin ().at_end (); m_cell_stack.push_back (std::make_pair (m_cm_new_entry, &new_top)); } void -HierarchyBuilder::end (const RecursiveShapeIterator * /*iter*/) +HierarchyBuilder::end (const RecursiveShapeIterator *iter) { - tl_assert (m_cell_stack.size () == 1); + tl_assert (! iter->layout () || ! iter->top_cell () || m_cell_stack.size () == 1); m_initial_pass = false; m_cells_seen.clear (); - mp_initial_cell = m_cell_stack.front ().second; + mp_initial_cell = m_cell_stack.empty () ? 0 : m_cell_stack.front ().second; m_cell_stack.clear (); m_cm_entry = cell_map_type::const_iterator (); m_cm_new_entry = false; diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 73a9608e9..db9bed42b 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -36,6 +36,7 @@ static bool is_deep (const db::Region &r) } // the iterator provides the hierarchical selection (enabling/disabling cells etc.) + LayoutToNetlist::LayoutToNetlist (const db::RecursiveShapeIterator &iter) : m_iter (iter), m_netlist_extracted (false) { @@ -44,6 +45,17 @@ LayoutToNetlist::LayoutToNetlist (const db::RecursiveShapeIterator &iter) throw tl::Exception (tl::to_string (tr ("The netlist extractor cannot work on clipped layouts"))); } + init (); +} + +LayoutToNetlist::LayoutToNetlist () + : m_iter (), m_netlist_extracted (false) +{ + init (); +} + +void LayoutToNetlist::init () +{ m_dss.set_text_enlargement (1); m_dss.set_text_property_name (tl::Variant ("LABEL")); } @@ -83,11 +95,11 @@ db::Region *LayoutToNetlist::make_layer (const std::string &n) db::RecursiveShapeIterator si (m_iter); si.shape_flags (db::ShapeIterator::Nothing); - db::Region *region = new db::Region (si, m_dss); + std::auto_ptr region (new db::Region (si, m_dss)); if (! n.empty ()) { - name (*region, n); + register_layer (*region, n); } - return region; + return region.release (); } db::Region *LayoutToNetlist::make_layer (unsigned int layer_index, const std::string &n) @@ -96,11 +108,11 @@ db::Region *LayoutToNetlist::make_layer (unsigned int layer_index, const std::st si.set_layer (layer_index); si.shape_flags (db::ShapeIterator::All); - db::Region *region = new db::Region (si, m_dss); + std::auto_ptr region (new db::Region (si, m_dss)); if (! n.empty ()) { - name (*region, n); + register_layer (*region, n); } - return region; + return region.release (); } db::Region *LayoutToNetlist::make_text_layer (unsigned int layer_index, const std::string &n) @@ -109,11 +121,11 @@ db::Region *LayoutToNetlist::make_text_layer (unsigned int layer_index, const st si.set_layer (layer_index); si.shape_flags (db::ShapeIterator::Texts); - db::Region *region = new db::Region (si, m_dss); + std::auto_ptr region (new db::Region (si, m_dss)); if (! n.empty ()) { - name (*region, n); + register_layer (*region, n); } - return region; + return region.release (); } db::Region *LayoutToNetlist::make_polygon_layer (unsigned int layer_index, const std::string &n) @@ -122,11 +134,11 @@ db::Region *LayoutToNetlist::make_polygon_layer (unsigned int layer_index, const si.set_layer (layer_index); si.shape_flags (db::ShapeIterator::Paths | db::ShapeIterator::Polygons | db::ShapeIterator::Boxes); - db::Region *region = new db::Region (si, m_dss); + std::auto_ptr region (new db::Region (si, m_dss)); if (! n.empty ()) { - name (*region, n); + register_layer (*region, n); } - return region; + return region.release (); } void LayoutToNetlist::extract_devices (db::NetlistDeviceExtractor &extractor, const std::map &layers) @@ -148,6 +160,9 @@ void LayoutToNetlist::connect (const db::Region &l) 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); @@ -167,6 +182,12 @@ void LayoutToNetlist::connect (const db::Region &a, const db::Region &b) 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")))); + } + if (! is_persisted (b)) { + throw (tl::Exception (tl::to_string (tr ("Only named layers can be used in inter-layer connectivity (second layer) for netlist extraction")))); + } // we need to keep a reference, so we can safely delete the region db::DeepLayer dla (a), dlb (b); @@ -182,7 +203,10 @@ size_t LayoutToNetlist::connect_global (const db::Region &l, const std::string & 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")))); + 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 @@ -232,6 +256,14 @@ const db::Cell *LayoutToNetlist::internal_top_cell () const return &m_dss.const_initial_cell (); } +void LayoutToNetlist::ensure_internal_layout () +{ + if (m_dss.layouts () == 0) { + // the dummy layer acts as a reference holder for the layout + m_dummy_layer = m_dss.create_polygon_layer (db::RecursiveShapeIterator ()); + } +} + db::Layout *LayoutToNetlist::internal_layout () { return &m_dss.layout (); @@ -242,13 +274,69 @@ db::Cell *LayoutToNetlist::internal_top_cell () return &m_dss.initial_cell (); } -void LayoutToNetlist::name (const db::Region ®ion, const std::string &name) +void LayoutToNetlist::register_layer (const db::Region ®ion, const std::string &n) { - unsigned int li = layer_of (region); - db::Layout &ly = m_dss.layout (); - db::LayerProperties lp = ly.get_properties (li); - lp.name = name; - ly.set_properties (li, lp); + if (m_named_regions.find (n) != m_named_regions.end ()) { + throw tl::Exception (tl::to_string (tr ("Layer name is already used: ")) + n); + } + + db::DeepRegion *delegate = dynamic_cast (region.delegate()); + if (! delegate) { + throw tl::Exception (tl::to_string (tr ("Layer is not a deep region"))); + } + + if (is_persisted (region)) { + std::string prev_name = name (region); + m_named_regions.erase (prev_name); + } + + m_named_regions [n] = delegate->deep_layer (); + m_name_of_layer [layer_of (region)] = n; +} + +std::string LayoutToNetlist::name (const db::Region ®ion) const +{ + std::map::const_iterator n = m_name_of_layer.find (layer_of (region)); + if (n != m_name_of_layer.end ()) { + return n->second; + } else { + return std::string (); + } +} + +std::string LayoutToNetlist::name (unsigned int l) const +{ + std::map::const_iterator n = m_name_of_layer.find (l); + if (n != m_name_of_layer.end ()) { + return n->second; + } else { + return std::string (); + } +} + +bool LayoutToNetlist::is_persisted (const db::Region ®ion) const +{ + return m_name_of_layer.find (layer_of (region)) != m_name_of_layer.end (); +} + +db::Region *LayoutToNetlist::layer_by_name (const std::string &name) +{ + std::map::const_iterator l = m_named_regions.find (name); + if (l == m_named_regions.end ()) { + return 0; + } else { + return new db::Region (new db::DeepRegion (l->second)); + } +} + +db::Region *LayoutToNetlist::layer_by_index (unsigned int index) +{ + std::map::const_iterator n = m_name_of_layer.find (index); + if (n == m_name_of_layer.end ()) { + return 0; + } else { + return layer_by_name (n->second); + } } unsigned int LayoutToNetlist::layer_of (const db::Region ®ion) const @@ -433,8 +521,10 @@ LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout & bool consider_cell = any_connections; for (std::map::const_iterator l = lmap.begin (); l != lmap.end () && !consider_cell; ++l) { - StopOnFirst sof; - consider_cell = deliver_shapes_of_net_nonrecursive (mp_netlist.get (), m_net_clusters, ci, cid, layer_of (*l->second), tr, sof); + if (l->second) { + StopOnFirst sof; + consider_cell = !deliver_shapes_of_net_nonrecursive (mp_netlist.get (), m_net_clusters, ci, cid, layer_of (*l->second), tr, sof); + } } if (! consider_cell) { @@ -452,7 +542,9 @@ LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout & } for (std::map::const_iterator l = lmap.begin (); l != lmap.end (); ++l) { - deliver_shapes_of_net_nonrecursive (mp_netlist.get (), m_net_clusters, ci, cid, layer_of (*l->second), tr, target_cell->shapes (l->first)); + if (l->second) { + deliver_shapes_of_net_nonrecursive (mp_netlist.get (), m_net_clusters, ci, cid, layer_of (*l->second), tr, target_cell->shapes (l->first)); + } } if (! circuit_cell_name_prefix && ! device_cell_name_prefix) { diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index c332d48a0..4030a5a00 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -73,6 +73,8 @@ class DB_PUBLIC LayoutToNetlist : public gsi::ObjectBase, public tl::Object { public: + typedef std::map::const_iterator layer_iterator; + /** * @brief The constructor * @@ -80,6 +82,11 @@ public: */ LayoutToNetlist (const db::RecursiveShapeIterator &iter); + /** + * @brief The default constructor + */ + LayoutToNetlist (); + /** * @brief Sets the number of threads to use for operations which support multiple threads */ @@ -115,28 +122,74 @@ public: size_t max_vertex_count () const; /** - * @brief Names a layer + * @brief Register a layer under the given name * This is a formal name for the layer. Using a name or layer properties * (see below) enhances readability of backannotated information - * if layers are involved. Use this method or the other variants to - * attach a name or standard layer properties to a region delivered - * by "make_layer" or derived from other regions through boolean - * operations. + * if layers are involved. Use this method to attach a name to a region + * derived by boolean operations for example. + * Named regions are persisted inside the LayoutToNetlist object. Only + * named regions can be put into "connect". */ - void name (const db::Region ®ion, const std::string &name); + void register_layer (const db::Region ®ion, const std::string &name); /** - * @brief Gets the name of the given layer + * @brief Gets the name of the given region + * Returns an empty string if the region does not have a name. */ - std::string name (const db::Region ®ion) const + std::string name (const db::Region ®ion) const; + + /** + * @brief Gets the name of the given layer by index + * Returns an empty string if the layer does not have a name. + */ + std::string name (unsigned int) const; + + /** + * @brief Returns true, if the region is a persisted region + * Persisted regions have a name and are kept inside the LayoutToNetlist + * object. + */ + bool is_persisted (const db::Region ®ion) const; + + /** + * @brief Gets the region (layer) with the given name + * If the name is not valid, this method returns 0. Otherwise it + * will return a new'd Region object referencing the layer with + * the given name. It must be deleted by the caller. + */ + db::Region *layer_by_name (const std::string &name); + + /** + * @brief Gets the region (layer) by index + * If the index is not valid, this method returns 0. Otherwise it + * will return a new'd Region object referencing the layer with + * the given name. It must be deleted by the caller. + * Only named layers are managed by LayoutToNetlist and can + * be retrieved with this method. + */ + db::Region *layer_by_index (unsigned int index); + + /** + * @brief Iterates over the layer indexes and names managed by this object (begin) + */ + layer_iterator begin_layers () const { - return internal_layout ()->get_properties (layer_of (region)).name; + return m_name_of_layer.begin (); + } + + /** + * @brief Iterates over the layer indexes and names managed by this object (end) + */ + layer_iterator end_layers () const + { + return m_name_of_layer.end (); } /** * @brief Creates a new empty region + * This method returns a new'd object which must be deleted by the caller. */ - db::Region *make_layer (const std::string &n); + db::Region *make_layer (const std::string &name = std::string ()); /** * @brief Creates a new region representing an original layer @@ -144,6 +197,11 @@ public: * This variant produces polygons and takes texts for net name annotation. * A variant not taking texts is "make_polygon_layer". A Variant only taking * texts is "make_text_layer". + * All variants return a new'd object which must be deleted by the caller. + * Named regions are considered "precious". The LayoutToNetlist object will + * keep a reference on all named layers, so they persist during the lifetime + * of the LayoutToNetlist object. + * Only named layers can be used for connect (see below). */ db::Region *make_layer (unsigned int layer_index, const std::string &name = std::string ()); @@ -179,18 +237,21 @@ public: * a derived layer. Certain limitations apply. It's safe to use * boolean operations for deriving layers. Other operations are applicable as long as they are * capable of delivering hierarchical layers. + * Regions put into "connect" need to be named. */ void connect (const db::Region &l); /** * @brief Defines an inter-layer connection for the given layers. * The conditions mentioned with intra-layer "connect" apply for this method too. + * Regions put into "connect" need to be named. */ void connect (const db::Region &a, const db::Region &b); /** * @brief Connects the given layer with a global net with the given name * Returns the global net ID + * Regions put into "connect" need to be named. */ size_t connect_global (const db::Region &l, const std::string &gn); @@ -237,6 +298,11 @@ public: */ db::Cell *internal_top_cell (); + /** + * @brief Ensures the internal layout is made + */ + void ensure_internal_layout (); + /** * @brief Gets the connectivity object */ @@ -406,8 +472,12 @@ private: db::hier_clusters m_net_clusters; std::auto_ptr mp_netlist; std::set m_dlrefs; + std::map m_named_regions; + std::map m_name_of_layer; bool m_netlist_extracted; + db::DeepLayer m_dummy_layer; + void init (); 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; diff --git a/src/db/db/dbLayoutToNetlistReader.cc b/src/db/db/dbLayoutToNetlistReader.cc index cc051af0b..efa35d487 100644 --- a/src/db/db/dbLayoutToNetlistReader.cc +++ b/src/db/db/dbLayoutToNetlistReader.cc @@ -29,46 +29,6 @@ namespace db namespace l2n_std_reader { -class Layers -{ -public: - Layers () { } - - ~Layers () - { - for (std::map::const_iterator i = m_layers.begin (); i != m_layers.end (); ++i) { - delete i->second; - } - m_layers.clear (); - } - - void add (const std::string &name, db::Region *region) - { - if (m_layers.find (name) != m_layers.end ()) { - delete region; - throw tl::Exception (tl::to_string (tr ("Duplicate layer name: ")) + name); - } - m_layers.insert (std::make_pair (name, region)); - } - - bool has_layer (const std::string &name) const - { - return m_layers.find (name) != m_layers.end (); - } - - db::Region &layer (const std::string &name) - { - std::map::const_iterator l = m_layers.find (name); - if (l == m_layers.end ()) { - throw tl::Exception (tl::to_string (tr ("Not a valid layer name: ")) + name); - } - return *l->second; - } - -private: - std::map m_layers; -}; - class Brace { public: @@ -185,9 +145,13 @@ void LayoutToNetlistStandardReader::read (db::LayoutToNetlist *l2n) } } -const db::Region *LayoutToNetlistStandardReader::layer_by_name (const std::string &name) +static db::Region &layer_by_name (db::LayoutToNetlist *l2n, const std::string &name) { - return mp_layers->has_layer (name) ? &mp_layers->layer (name) : 0; + db::Region *l = l2n->layer_by_name (name); + if (! l) { + throw tl::Exception (tl::to_string (tr ("Not a valid layer name: ")) + name); + } + return *l; } void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n) @@ -196,13 +160,17 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n) std::string description; // TODO: there probably is a more efficient way to force the layout inside l2n to be made - l2n->make_layer (std::string ()); + l2n->ensure_internal_layout (); tl_assert (l2n->internal_layout ()); + l2n->internal_layout ()->dbu (1.0); // mainly for testing + + if (l2n->internal_layout ()->cells () == 0) { + l2n->internal_layout ()->add_cell ("TOP"); + } + tl_assert (l2n->internal_top_cell () != 0); l2n->make_netlist (); - mp_layers.reset (new Layers ()); - while (! at_end ()) { if (test (skeys::version_key) || test (lkeys::version_key)) { @@ -237,7 +205,7 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n) Brace br (this); std::string layer; read_word_or_quoted (layer); - mp_layers->add (layer, l2n->make_layer (layer)); + delete l2n->make_layer (layer); br.done (); } else if (test (skeys::connect_key) || test (lkeys::connect_key)) { @@ -248,7 +216,7 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n) while (br) { std::string l2; read_word_or_quoted (l2); - l2n->connect (mp_layers->layer (l1), mp_layers->layer (l2)); + l2n->connect (layer_by_name (l2n, l1), layer_by_name (l2n, l2)); } br.done (); @@ -260,7 +228,7 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n) while (br) { std::string g; read_word_or_quoted (g); - l2n->connect_global (mp_layers->layer (l1), g); + l2n->connect_global (layer_by_name (l2n, l1), g); } br.done (); @@ -377,7 +345,7 @@ LayoutToNetlistStandardReader::read_geometry (db::LayoutToNetlist *l2n) Brace br (this); read_word_or_quoted (lname); - unsigned int lid = l2n->layer_of (mp_layers->layer (lname)); + unsigned int lid = l2n->layer_of (layer_by_name (l2n, lname)); db::Coord l = read_coord (); db::Coord b = read_coord (); @@ -394,7 +362,7 @@ LayoutToNetlistStandardReader::read_geometry (db::LayoutToNetlist *l2n) Brace br (this); read_word_or_quoted (lname); - unsigned int lid = l2n->layer_of (mp_layers->layer (lname)); + unsigned int lid = l2n->layer_of (layer_by_name (l2n, lname)); std::vector pt; diff --git a/src/db/db/dbLayoutToNetlistReader.h b/src/db/db/dbLayoutToNetlistReader.h index 276614197..2c0d7e996 100644 --- a/src/db/db/dbLayoutToNetlistReader.h +++ b/src/db/db/dbLayoutToNetlistReader.h @@ -65,8 +65,6 @@ public: void read (db::LayoutToNetlist *l2n); - const db::Region *layer_by_name (const std::string &name); - private: friend class l2n_std_reader::Brace; typedef l2n_std_reader::Brace Brace; @@ -85,7 +83,6 @@ private: std::string m_path; std::string m_line; tl::Extractor m_ex; - std::auto_ptr mp_layers; void do_read (db::LayoutToNetlist *l2n); diff --git a/src/db/db/dbLayoutToNetlistWriter.cc b/src/db/db/dbLayoutToNetlistWriter.cc index 437ca16d8..7d04696ff 100644 --- a/src/db/db/dbLayoutToNetlistWriter.cc +++ b/src/db/db/dbLayoutToNetlistWriter.cc @@ -63,14 +63,13 @@ std_writer_impl::std_writer_impl (tl::OutputStream &stream) // .. nothing yet .. } -static std::string name_for_layer (const db::Layout *layout, unsigned int l) +static std::string name_for_layer (const db::LayoutToNetlist *l2n, unsigned int l) { - const db::LayerProperties &lp = layout->get_properties (l); - if (lp.is_named ()) { - return tl::to_word_or_quoted_string (lp.name); - } else { - return "L" + tl::to_string (l); + std::string n = l2n->name (l); + if (n.empty ()) { + n = "L" + tl::to_string (l); } + return n; } template @@ -104,7 +103,7 @@ void std_writer_impl::write (const db::LayoutToNetlist *l2n) *mp_stream << endl << "# Mask layers" << endl; } for (db::Connectivity::layer_iterator l = l2n->connectivity ().begin_layers (); l != l2n->connectivity ().end_layers (); ++l) { - *mp_stream << Keys::layer_key << "(" << name_for_layer (ly, *l) << ")" << endl; + *mp_stream << Keys::layer_key << "(" << name_for_layer (l2n, *l) << ")" << endl; } if (! Keys::is_short ()) { @@ -115,9 +114,9 @@ void std_writer_impl::write (const db::LayoutToNetlist *l2n) db::Connectivity::layer_iterator ce = l2n->connectivity ().end_connected (*l); db::Connectivity::layer_iterator cb = l2n->connectivity ().begin_connected (*l); if (cb != ce) { - *mp_stream << Keys::connect_key << "(" << name_for_layer (ly, *l); + *mp_stream << Keys::connect_key << "(" << name_for_layer (l2n, *l); for (db::Connectivity::layer_iterator c = l2n->connectivity ().begin_connected (*l); c != ce; ++c) { - *mp_stream << " " << name_for_layer (ly, *c); + *mp_stream << " " << name_for_layer (l2n, *c); } *mp_stream << ")" << endl; } @@ -136,7 +135,7 @@ void std_writer_impl::write (const db::LayoutToNetlist *l2n) } any = true; } - *mp_stream << Keys::global_key << "(" << name_for_layer (ly, *l); + *mp_stream << Keys::global_key << "(" << name_for_layer (l2n, *l); for (db::Connectivity::global_nets_iterator g = gb; g != ge; ++g) { *mp_stream << " " << tl::to_word_or_quoted_string (l2n->connectivity ().global_net_name (*g)); } @@ -260,7 +259,6 @@ void std_writer_impl::write (const db::LayoutToNetlist *l2n, const db::Net throw tl::Exception (tl::to_string (tr ("Can't write annotated netlist before extraction has been done"))); } - const db::Layout *ly = l2n->internal_layout (); const db::hier_clusters &clusters = l2n->net_clusters (); const db::Circuit *circuit = net.circuit (); const db::Connectivity &conn = l2n->connectivity (); @@ -290,7 +288,7 @@ void std_writer_impl::write (const db::LayoutToNetlist *l2n, const db::Net } *mp_stream << indent2; - write (si.operator-> (), si.trans (), name_for_layer (ly, *l)); + write (si.operator-> (), si.trans (), name_for_layer (l2n, *l)); *mp_stream << endl; prev_ci = ci; @@ -365,7 +363,6 @@ void std_writer_impl::write (const db::LayoutToNetlist *l2n, const db::Dev { const std::vector &td = device_model.device_class ()->terminal_definitions (); - const db::Layout *ly = l2n->internal_layout (); const db::hier_clusters &clusters = l2n->net_clusters (); const db::Connectivity &conn = l2n->connectivity (); @@ -379,7 +376,7 @@ void std_writer_impl::write (const db::LayoutToNetlist *l2n, const db::Dev for (db::local_cluster::shape_iterator s = lc.begin (*l); ! s.at_end (); ++s) { *mp_stream << indent2; - write (s.operator-> (), db::ICplxTrans (), name_for_layer (ly, *l)); + write (s.operator-> (), db::ICplxTrans (), name_for_layer (l2n, *l)); *mp_stream << endl; } diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index 1165bae84..ec3c0ba08 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -502,12 +502,36 @@ public: Region &operator= (const Region &other); /** - * @brief Constructor from an object - * - * Creates a region representing a single instance of that object + * @brief Constructor from a box */ - template - Region (const Sh &s) + explicit Region (const db::Box &s) + : mp_delegate (0) + { + insert (s); + } + + /** + * @brief Constructor from a polygon + */ + explicit Region (const db::Polygon &s) + : mp_delegate (0) + { + insert (s); + } + + /** + * @brief Constructor from a simple polygon + */ + explicit Region (const db::SimplePolygon &s) + : mp_delegate (0) + { + insert (s); + } + + /** + * @brief Constructor from a path + */ + explicit Region (const db::Path &s) : mp_delegate (0) { insert (s); @@ -521,7 +545,7 @@ public: * style. */ template - Region (const Iter &b, const Iter &e) + explicit Region (const Iter &b, const Iter &e) : mp_delegate (0) { reserve (e - b); @@ -536,7 +560,7 @@ public: * Creates a region from a recursive shape iterator. This allows feeding a region * from a hierarchy of cells. */ - Region (const RecursiveShapeIterator &si); + explicit Region (const RecursiveShapeIterator &si); /** * @brief Constructor from a RecursiveShapeIterator with a transformation @@ -545,7 +569,7 @@ public: * from a hierarchy of cells. The transformation is useful to scale to a specific * DBU for example. */ - Region (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics = true); + explicit Region (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics = true); /** * @brief Constructor from a RecursiveShapeIterator providing a deep representation @@ -556,12 +580,12 @@ public: * "area_ratio" and "max_vertex_count" are optimization parameters for the * shape splitting algorithm. */ - Region (const RecursiveShapeIterator &si, DeepShapeStore &dss, double area_ratio = 3.0, size_t max_vertex_count = 16); + explicit Region (const RecursiveShapeIterator &si, DeepShapeStore &dss, double area_ratio = 3.0, size_t max_vertex_count = 16); /** * @brief Constructor from a RecursiveShapeIterator providing a deep representation with transformation */ - Region (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool merged_semantics = true, double area_ratio = 3.0, size_t max_vertex_count = 16); + explicit Region (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool merged_semantics = true, double area_ratio = 3.0, size_t max_vertex_count = 16); /** * @brief Gets the underlying delegate object diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index c8c0eb80d..7fc2e642b 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -23,6 +23,7 @@ #include "gsiDecl.h" #include "dbLayoutToNetlist.h" #include "dbLayoutToNetlistWriter.h" +#include "dbLayoutToNetlistReader.h" #include "tlStream.h" namespace gsi @@ -33,6 +34,11 @@ static db::LayoutToNetlist *make_l2n (const db::RecursiveShapeIterator &iter) return new db::LayoutToNetlist (iter); } +static db::LayoutToNetlist *make_l2n_default () +{ + return new db::LayoutToNetlist (); +} + static db::Layout *l2n_internal_layout (db::LayoutToNetlist *l2n) { // although this isn't very clean, we dare to do so as const references are pretty useless in script languages. @@ -67,10 +73,31 @@ static void write_l2n (const db::LayoutToNetlist *l2n, const std::string &path, writer.write (l2n); } +static void read_l2n (db::LayoutToNetlist *l2n, const std::string &path) +{ + tl::InputStream stream (path); + db::LayoutToNetlistStandardReader reader (stream); + reader.read (l2n); +} + +static std::vector l2n_layer_names (const db::LayoutToNetlist *l2n) +{ + std::vector ln; + for (db::LayoutToNetlist::layer_iterator l = l2n->begin_layers (); l != l2n->end_layers (); ++l) { + ln.push_back (l->second); + } + return ln; +} + Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", gsi::constructor ("new", &make_l2n, gsi::arg ("iter"), - "@brief The constructor\n" - "See the class description for details.\n" + "@brief Creates a new extractor connected to an original layout\n" + "This constructor will attach the extractor to an original layout through the " + "shape iterator.\n" + ) + + gsi::constructor ("new", &make_l2n_default, + "@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::method ("threads=", &db::LayoutToNetlist::set_threads, gsi::arg ("n"), "@brief Sets the number of threads to use for operations which support multiple threads\n" @@ -95,34 +122,65 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", gsi::method ("max_vertex_count", &db::LayoutToNetlist::max_vertex_count, "See \\max_vertex_count= for details about this attribute." ) + - gsi::method ("name", &db::LayoutToNetlist::name, gsi::arg ("l"), + gsi::method ("name", (std::string (db::LayoutToNetlist::*) (const db::Region ®ion) const) &db::LayoutToNetlist::name, gsi::arg ("l"), + "@brief Get the name of the given layer\n" + ) + + gsi::method ("name", (std::string (db::LayoutToNetlist::*) (unsigned int) const) &db::LayoutToNetlist::name, gsi::arg ("l"), + "@brief Get the name of the given layer (by index)\n" + ) + + gsi::method ("register", (void (db::LayoutToNetlist::*) (const db::Region ®ion, const std::string &)) &db::LayoutToNetlist::register_layer, gsi::arg ("l"), gsi::arg ("n"), "@brief Names the given layer\n" "'l' must be a hierarchical region derived with \\make_layer, \\make_text_layer or \\make_polygon_layer or " "a region derived from those by boolean operations or other hierarchical operations.\n" "\n" "Naming a layer allows the system to indicate the layer in various contexts, i.e. " - "when writing the data to a file.\n" + "when writing the data to a file. Named layers are also persisted inside the LayoutToNetlist object. " + "They are not discarded when the Region object is destroyed. Only named layers can be put into " + "\\connect.\n" ) + - gsi::method ("make_layer", &db::LayoutToNetlist::make_layer, gsi::arg ("layer_index"), gsi::arg ("name", std::string ()), + gsi::method_ext ("layer_names", &l2n_layer_names, + "@brief Returns a list of names of the layer kept inside the LayoutToNetlist object." + ) + + gsi::factory ("layer_by_name", &db::LayoutToNetlist::layer_by_name, gsi::arg ("name"), + "@brief Gets a layer object for the given name.\n" + "The returned object is a copy which represents the named layer." + ) + + gsi::factory ("layer_by_index", &db::LayoutToNetlist::layer_by_index, gsi::arg ("index"), + "@brief Gets a layer object for the given index.\n" + "Only named layers can be retrieved with this method. " + "The returned object is a copy which represents the named layer." + ) + + gsi::method ("is_persisted?", &db::LayoutToNetlist::is_persisted, gsi::arg ("layer"), + "@brief Returns true, if the given layer is a persisted region.\n" + "Persisted layers are kept inside the LayoutToNetlist object and are not released " + "if their object is destroyed. Named layers are persisted, unnamed layers are not. " + "Only persisted, named layers can be put into \\connect." + ) + + gsi::factory ("make_layer", (db::Region *(db::LayoutToNetlist::*) (const std::string &)) &db::LayoutToNetlist::make_layer, gsi::arg ("name", std::string ()), + "@brief Creates a new, empty hierarchical region\n" + "\n" + "The name is optional. If given, the layer will already be named accordingly (see \\register).\n" + ) + + gsi::factory ("make_layer", (db::Region *(db::LayoutToNetlist::*) (unsigned int, const std::string &)) &db::LayoutToNetlist::make_layer, gsi::arg ("layer_index"), gsi::arg ("name", std::string ()), "@brief Creates a new hierarchical region representing an original layer\n" "'layer_index' is the layer index of the desired layer in the original layout.\n" "This variant produces polygons and takes texts for net name annotation.\n" "A variant not taking texts is \\make_polygon_layer. A Variant only taking\n" "texts is \\make_text_layer.\n" "\n" - "The name is optional. If given, the layer will already be named accordingly (see \\name).\n" + "The name is optional. If given, the layer will already be named accordingly (see \\register).\n" ) + - gsi::method ("make_text_layer", &db::LayoutToNetlist::make_text_layer, gsi::arg ("layer_index"), gsi::arg ("name", std::string ()), + gsi::factory ("make_text_layer", &db::LayoutToNetlist::make_text_layer, gsi::arg ("layer_index"), gsi::arg ("name", std::string ()), "@brief Creates a new region representing an original layer taking texts only\n" "See \\make_layer for details.\n" "\n" - "The name is optional. If given, the layer will already be named accordingly (see \\name).\n" + "The name is optional. If given, the layer will already be named accordingly (see \\register).\n" ) + - gsi::method ("make_polygon_layer", &db::LayoutToNetlist::make_polygon_layer, gsi::arg ("layer_index"), gsi::arg ("name", std::string ()), + gsi::factory ("make_polygon_layer", &db::LayoutToNetlist::make_polygon_layer, gsi::arg ("layer_index"), gsi::arg ("name", std::string ()), "@brief Creates a new region representing an original layer taking polygons and texts\n" "See \\make_layer for details.\n" "\n" - "The name is optional. If given, the layer will already be named accordingly (see \\name).\n" + "The name is optional. If given, the layer will already be named accordingly (see \\register).\n" ) + gsi::method ("extract_devices", &db::LayoutToNetlist::extract_devices, gsi::arg ("extractor"), gsi::arg ("layers"), "@brief Extracts devices\n" @@ -280,6 +338,10 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", gsi::method_ext ("write", &write_l2n, gsi::arg ("path"), gsi::arg ("short_format", false), "@brief Writes the extracted netlist to a file.\n" "This method employs the native format of KLayout.\n" + ) + + gsi::method_ext ("read", &read_l2n, gsi::arg ("path"), + "@brief Reads the extracted netlist from the file.\n" + "This method employs the native format of KLayout.\n" ), "@brief A generic framework for extracting netlists from layouts\n" "\n" diff --git a/src/db/unit_tests/dbHierarchyBuilderTests.cc b/src/db/unit_tests/dbHierarchyBuilderTests.cc index 3892eecf4..c5eb117ca 100644 --- a/src/db/unit_tests/dbHierarchyBuilderTests.cc +++ b/src/db/unit_tests/dbHierarchyBuilderTests.cc @@ -59,6 +59,41 @@ TEST(1) db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au1.gds"); } +TEST(1_WithEmptyLayer) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/hierarchy_builder_l1.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + + db::Layout target; + db::HierarchyBuilder builder (&target); + + db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), std::set ()); + iter.push (&builder); + + for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) { + + unsigned int li1 = (*li).first; + unsigned int target_layer = target.insert_layer (*(*li).second); + builder.set_target_layer (target_layer); + + db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), li1); + + iter.push (&builder); + + } + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au1.gds"); +} + TEST(2_WithoutClip) { db::Layout ly; @@ -251,6 +286,56 @@ TEST(2_WithEmptyResult) db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au2e.gds"); } +TEST(2_WithClipAndSimplificationAndEmptyLayer) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/hierarchy_builder_l1.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::Layout target; + db::ReducingHierarchyBuilderShapeReceiver red(0, 1.2, 4); + db::ClippingHierarchyBuilderShapeReceiver clip(&red); + db::HierarchyBuilder builder (&target, &clip); + + db::cell_index_type target_top = target.add_cell ("CLIP_TOP"); + + db::Box clip_box (5000, -2000, 18500, 6000); + + builder.set_target_layer (target.insert_layer (db::LayerProperties (100, 0))); + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), std::set (), clip_box); + + iter.push (&builder); + + target.cell (target_top).insert (db::CellInstArray (db::CellInst (builder.initial_cell ()->cell_index ()), db::Trans ())); + + for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) { + + builder.reset (); + + unsigned int li1 = (*li).first; + unsigned int target_layer = target.insert_layer (*(*li).second); + builder.set_target_layer (target_layer); + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), li1, clip_box); + + iter.push (&builder); + + target.cell (target_top).insert (db::CellInstArray (db::CellInst (builder.initial_cell ()->cell_index ()), db::Trans ())); + + } + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au2f.gds"); +} + TEST(3_ComplexRegionWithClip) { db::Layout ly; diff --git a/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc b/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc index 83aaeab10..c7dc80031 100644 --- a/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc @@ -34,10 +34,7 @@ TEST(1_ReaderBasic) { - db::Layout ly; - - db::Cell &tc = ly.cell (ly.add_cell ("TOP")); - db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set ())); + db::LayoutToNetlist l2n; std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au.txt"); tl::InputStream is_in (in_path); @@ -69,20 +66,20 @@ TEST(1_ReaderBasic) { db::Layout ly2; - ly2.dbu (ly.dbu ()); + ly2.dbu (l2n.internal_layout ()->dbu ()); db::Cell &top2 = ly2.cell (ly2.add_cell ("TOP")); db::CellMapping cm = l2n.cell_mapping_into (ly2, top2, true /*with device cells*/); std::map lmap; - lmap [ly2.insert_layer (db::LayerProperties (10, 0))] = reader.layer_by_name ("psd"); - lmap [ly2.insert_layer (db::LayerProperties (11, 0))] = reader.layer_by_name ("nsd"); - lmap [ly2.insert_layer (db::LayerProperties (3, 0)) ] = reader.layer_by_name ("poly"); - lmap [ly2.insert_layer (db::LayerProperties (4, 0)) ] = reader.layer_by_name ("diff_cont"); - lmap [ly2.insert_layer (db::LayerProperties (5, 0)) ] = reader.layer_by_name ("poly_cont"); - lmap [ly2.insert_layer (db::LayerProperties (6, 0)) ] = reader.layer_by_name ("metal1"); - lmap [ly2.insert_layer (db::LayerProperties (7, 0)) ] = reader.layer_by_name ("via1"); - lmap [ly2.insert_layer (db::LayerProperties (8, 0)) ] = reader.layer_by_name ("metal2"); + lmap [ly2.insert_layer (db::LayerProperties (10, 0))] = l2n.layer_by_name ("psd"); + lmap [ly2.insert_layer (db::LayerProperties (11, 0))] = l2n.layer_by_name ("nsd"); + lmap [ly2.insert_layer (db::LayerProperties (3, 0)) ] = l2n.layer_by_name ("poly"); + lmap [ly2.insert_layer (db::LayerProperties (4, 0)) ] = l2n.layer_by_name ("diff_cont"); + lmap [ly2.insert_layer (db::LayerProperties (5, 0)) ] = l2n.layer_by_name ("poly_cont"); + lmap [ly2.insert_layer (db::LayerProperties (6, 0)) ] = l2n.layer_by_name ("metal1"); + lmap [ly2.insert_layer (db::LayerProperties (7, 0)) ] = l2n.layer_by_name ("via1"); + lmap [ly2.insert_layer (db::LayerProperties (8, 0)) ] = l2n.layer_by_name ("metal2"); l2n.build_all_nets (cm, ly2, lmap, "NET_", 0, "DEVICE_"); @@ -97,10 +94,7 @@ TEST(1_ReaderBasic) TEST(1b_ReaderBasicShort) { - db::Layout ly; - - db::Cell &tc = ly.cell (ly.add_cell ("TOP")); - db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set ())); + db::LayoutToNetlist l2n; std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_s.txt"); tl::InputStream is_in (in_path); @@ -132,10 +126,7 @@ TEST(1b_ReaderBasicShort) TEST(2_ReaderWithGlobalNets) { - db::Layout ly; - - db::Cell &tc = ly.cell (ly.add_cell ("TOP")); - db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set ())); + 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"); tl::InputStream is_in (in_path); @@ -167,24 +158,24 @@ TEST(2_ReaderWithGlobalNets) { db::Layout ly2; - ly2.dbu (ly.dbu ()); + ly2.dbu (l2n.internal_layout ()->dbu ()); db::Cell &top2 = ly2.cell (ly2.add_cell ("TOP")); db::CellMapping cm = l2n.cell_mapping_into (ly2, top2, true /*with device cells*/); std::map lmap; - lmap [ly2.insert_layer (db::LayerProperties (10, 0))] = reader.layer_by_name ("psd"); - lmap [ly2.insert_layer (db::LayerProperties (11, 0))] = reader.layer_by_name ("nsd"); - lmap [ly2.insert_layer (db::LayerProperties (12, 0))] = reader.layer_by_name ("rbulk"); - lmap [ly2.insert_layer (db::LayerProperties (13, 0))] = reader.layer_by_name ("ptie"); - lmap [ly2.insert_layer (db::LayerProperties (14, 0))] = reader.layer_by_name ("ntie"); - lmap [ly2.insert_layer (db::LayerProperties (1, 0)) ] = reader.layer_by_name ("nwell"); - lmap [ly2.insert_layer (db::LayerProperties (3, 0)) ] = reader.layer_by_name ("poly"); - lmap [ly2.insert_layer (db::LayerProperties (4, 0)) ] = reader.layer_by_name ("diff_cont"); - lmap [ly2.insert_layer (db::LayerProperties (5, 0)) ] = reader.layer_by_name ("poly_cont"); - lmap [ly2.insert_layer (db::LayerProperties (6, 0)) ] = reader.layer_by_name ("metal1"); - lmap [ly2.insert_layer (db::LayerProperties (7, 0)) ] = reader.layer_by_name ("via1"); - lmap [ly2.insert_layer (db::LayerProperties (8, 0)) ] = reader.layer_by_name ("metal2"); + lmap [ly2.insert_layer (db::LayerProperties (10, 0))] = l2n.layer_by_name ("psd"); + lmap [ly2.insert_layer (db::LayerProperties (11, 0))] = l2n.layer_by_name ("nsd"); + lmap [ly2.insert_layer (db::LayerProperties (12, 0))] = l2n.layer_by_name ("rbulk"); + lmap [ly2.insert_layer (db::LayerProperties (13, 0))] = l2n.layer_by_name ("ptie"); + lmap [ly2.insert_layer (db::LayerProperties (14, 0))] = l2n.layer_by_name ("ntie"); + lmap [ly2.insert_layer (db::LayerProperties (1, 0)) ] = l2n.layer_by_name ("nwell"); + lmap [ly2.insert_layer (db::LayerProperties (3, 0)) ] = l2n.layer_by_name ("poly"); + lmap [ly2.insert_layer (db::LayerProperties (4, 0)) ] = l2n.layer_by_name ("diff_cont"); + lmap [ly2.insert_layer (db::LayerProperties (5, 0)) ] = l2n.layer_by_name ("poly_cont"); + lmap [ly2.insert_layer (db::LayerProperties (6, 0)) ] = l2n.layer_by_name ("metal1"); + lmap [ly2.insert_layer (db::LayerProperties (7, 0)) ] = l2n.layer_by_name ("via1"); + lmap [ly2.insert_layer (db::LayerProperties (8, 0)) ] = l2n.layer_by_name ("metal2"); l2n.build_all_nets (cm, ly2, lmap, "NET_", "CIRCUIT_", "DEVICE_"); diff --git a/src/db/unit_tests/dbLayoutToNetlistTests.cc b/src/db/unit_tests/dbLayoutToNetlistTests.cc index cc358fee1..e063dab20 100644 --- a/src/db/unit_tests/dbLayoutToNetlistTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistTests.cc @@ -122,7 +122,52 @@ static unsigned int define_layer (db::Layout &ly, db::LayerMap &lmap, int gds_la return lid; } -TEST(1_Basic) +TEST(0_Basic) +{ + db::LayoutToNetlist l2n; + + std::auto_ptr reg (l2n.make_layer ("l1")); + EXPECT_EQ (l2n.is_persisted (*reg), true); + EXPECT_EQ (l2n.name (*reg), "l1"); + EXPECT_EQ (l2n.layer_of (*reg), 0u); + EXPECT_EQ (l2n.internal_layout ()->is_valid_layer (0), true); + reg.reset (0); + EXPECT_EQ (l2n.internal_layout ()->is_valid_layer (0), true); + EXPECT_EQ (l2n.name (0u), "l1"); + + EXPECT_EQ (l2n.layer_by_index (1) == 0, true); + EXPECT_EQ (l2n.layer_by_name ("l2") == 0, true); + + std::auto_ptr reg_copy (l2n.layer_by_name ("l1")); + EXPECT_EQ (reg_copy.get () != 0, true); + EXPECT_EQ (l2n.name (*reg_copy), "l1"); + EXPECT_EQ (l2n.layer_of (*reg_copy), 0u); + reg_copy.reset (l2n.layer_by_index (0)); + EXPECT_EQ (reg_copy.get () != 0, true); + EXPECT_EQ (l2n.name (*reg_copy), "l1"); + EXPECT_EQ (l2n.layer_of (*reg_copy), 0u); + reg_copy.reset (0); + + std::auto_ptr reg2 (l2n.make_layer ()); + EXPECT_EQ (l2n.name (1u), ""); + EXPECT_EQ (l2n.name (*reg2), ""); + EXPECT_EQ (l2n.layer_of (*reg2), 1u); + EXPECT_EQ (l2n.internal_layout ()->is_valid_layer (1), true); + reg2.reset (0); + EXPECT_EQ (l2n.internal_layout ()->is_valid_layer (1), false); + + std::auto_ptr reg3 (l2n.make_layer ("l3")); + EXPECT_EQ (l2n.name (*reg3), "l3"); + EXPECT_EQ (l2n.layer_of (*reg3), 1u); + + std::string s; + for (db::LayoutToNetlist::layer_iterator l = l2n.begin_layers (); l != l2n.end_layers (); ++l) { + s += tl::to_string (l->first) + ":" + l->second + ";"; + } + EXPECT_EQ (s, "0:l1;1:l3;"); +} + +TEST(1_BasicExtraction) { db::Layout ly; db::LayerMap lmap; @@ -157,17 +202,17 @@ TEST(1_Basic) db::Cell &tc = ly.cell (*ly.begin_top_down ()); db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set ())); - std::auto_ptr rnwell (l2n.make_layer (nwell)); - std::auto_ptr ractive (l2n.make_layer (active)); - std::auto_ptr rpoly (l2n.make_polygon_layer (poly)); - std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl)); - std::auto_ptr rdiff_cont (l2n.make_polygon_layer (diff_cont)); - std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont)); - std::auto_ptr rmetal1 (l2n.make_polygon_layer (metal1)); - std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl)); - std::auto_ptr rvia1 (l2n.make_polygon_layer (via1)); - std::auto_ptr rmetal2 (l2n.make_polygon_layer (metal2)); - std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl)); + std::auto_ptr rnwell (l2n.make_layer (nwell, "nwell")); + std::auto_ptr ractive (l2n.make_layer (active, "active")); + 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 rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont")); + std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_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 @@ -215,6 +260,9 @@ TEST(1_Basic) // net extraction + l2n.register_layer (rpsd, "psd"); + l2n.register_layer (rnsd, "nsd"); + // Intra-layer l2n.connect (rpsd); l2n.connect (rnsd); @@ -513,17 +561,17 @@ TEST(2_Probing) db::Cell &tc = ly.cell (*ly.begin_top_down ()); db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set ())); - std::auto_ptr rnwell (l2n.make_layer (nwell)); - std::auto_ptr ractive (l2n.make_layer (active)); - std::auto_ptr rpoly (l2n.make_polygon_layer (poly)); - std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl)); - std::auto_ptr rdiff_cont (l2n.make_polygon_layer (diff_cont)); - std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont)); - std::auto_ptr rmetal1 (l2n.make_polygon_layer (metal1)); - std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl)); - std::auto_ptr rvia1 (l2n.make_polygon_layer (via1)); - std::auto_ptr rmetal2 (l2n.make_polygon_layer (metal2)); - std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl)); + std::auto_ptr rnwell (l2n.make_layer (nwell, "nwell")); + std::auto_ptr ractive (l2n.make_layer (active, "active")); + 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 rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont")); + std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_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 @@ -568,6 +616,9 @@ TEST(2_Probing) // net extraction + l2n.register_layer (rpsd, "psd"); + l2n.register_layer (rnsd, "nsd"); + // Intra-layer l2n.connect (rpsd); l2n.connect (rnsd); @@ -754,19 +805,19 @@ TEST(3_GlobalNetConnections) db::Cell &tc = ly.cell (*ly.begin_top_down ()); db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set ())); - std::auto_ptr rnwell (l2n.make_layer (nwell)); - std::auto_ptr ractive (l2n.make_layer (active)); - std::auto_ptr rpplus (l2n.make_layer (pplus)); - std::auto_ptr rnplus (l2n.make_layer (nplus)); - std::auto_ptr rpoly (l2n.make_polygon_layer (poly)); - std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl)); - std::auto_ptr rdiff_cont (l2n.make_polygon_layer (diff_cont)); - std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont)); - std::auto_ptr rmetal1 (l2n.make_polygon_layer (metal1)); - std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl)); - std::auto_ptr rvia1 (l2n.make_polygon_layer (via1)); - std::auto_ptr rmetal2 (l2n.make_polygon_layer (metal2)); - std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl)); + std::auto_ptr rnwell (l2n.make_layer (nwell, "nwell")); + 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 rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont")); + std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_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 @@ -819,6 +870,11 @@ TEST(3_GlobalNetConnections) // net extraction + l2n.register_layer (rpsd, "psd"); + l2n.register_layer (rnsd, "nsd"); + l2n.register_layer (rptie, "ptie"); + l2n.register_layer (rntie, "ntie"); + // Intra-layer l2n.connect (rpsd); l2n.connect (rnsd); @@ -1021,20 +1077,20 @@ TEST(4_GlobalNetDeviceExtraction) 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 (ly.insert_layer ())); - std::auto_ptr rnwell (l2n.make_layer (nwell)); - std::auto_ptr ractive (l2n.make_layer (active)); - std::auto_ptr rpplus (l2n.make_layer (pplus)); - std::auto_ptr rnplus (l2n.make_layer (nplus)); - std::auto_ptr rpoly (l2n.make_polygon_layer (poly)); - std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl)); - std::auto_ptr rdiff_cont (l2n.make_polygon_layer (diff_cont)); - std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont)); - std::auto_ptr rmetal1 (l2n.make_polygon_layer (metal1)); - std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl)); - std::auto_ptr rvia1 (l2n.make_polygon_layer (via1)); - std::auto_ptr rmetal2 (l2n.make_polygon_layer (metal2)); - std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl)); + std::auto_ptr rbulk (l2n.make_layer (ly.insert_layer (), "bulk")); + std::auto_ptr rnwell (l2n.make_layer (nwell, "nwell")); + 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 rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont")); + std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_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 @@ -1089,6 +1145,11 @@ TEST(4_GlobalNetDeviceExtraction) // net extraction + l2n.register_layer (rpsd, "psd"); + l2n.register_layer (rnsd, "nsd"); + l2n.register_layer (rptie, "ptie"); + l2n.register_layer (rntie, "ntie"); + // Intra-layer l2n.connect (rpsd); l2n.connect (rnsd); @@ -1294,20 +1355,20 @@ TEST(5_DeviceExtractionWithDeviceCombination) 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 (ly.insert_layer ())); - std::auto_ptr rnwell (l2n.make_layer (nwell)); - std::auto_ptr ractive (l2n.make_layer (active)); - std::auto_ptr rpplus (l2n.make_layer (pplus)); - std::auto_ptr rnplus (l2n.make_layer (nplus)); - std::auto_ptr rpoly (l2n.make_polygon_layer (poly)); - std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl)); - std::auto_ptr rdiff_cont (l2n.make_polygon_layer (diff_cont)); - std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont)); - std::auto_ptr rmetal1 (l2n.make_polygon_layer (metal1)); - std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl)); - std::auto_ptr rvia1 (l2n.make_polygon_layer (via1)); - std::auto_ptr rmetal2 (l2n.make_polygon_layer (metal2)); - std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl)); + std::auto_ptr rbulk (l2n.make_layer ("bulk")); + std::auto_ptr rnwell (l2n.make_layer (nwell, "nwell")); + 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 rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont")); + std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_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 @@ -1362,6 +1423,11 @@ TEST(5_DeviceExtractionWithDeviceCombination) // net extraction + l2n.register_layer (rpsd, "psd"); + l2n.register_layer (rnsd, "nsd"); + l2n.register_layer (rptie, "ptie"); + l2n.register_layer (rntie, "ntie"); + // Intra-layer l2n.connect (rpsd); l2n.connect (rnsd); diff --git a/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc b/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc index 02d81d3e3..426e69980 100644 --- a/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc @@ -90,16 +90,16 @@ TEST(1_WriterBasic) db::Region rpactive = *ractive & *rnwell; db::Region rpgate = rpactive & *rpoly; db::Region rpsd = rpactive - rpgate; - l2n.name (rpactive, "pactive"); - l2n.name (rpgate, "pgate"); - l2n.name (rpsd, "psd"); + l2n.register_layer (rpactive, "pactive"); + l2n.register_layer (rpgate, "pgate"); + l2n.register_layer (rpsd, "psd"); db::Region rnactive = *ractive - *rnwell; db::Region rngate = rnactive & *rpoly; db::Region rnsd = rnactive - rngate; - l2n.name (rnactive, "nactive"); - l2n.name (rngate, "ngate"); - l2n.name (rnsd, "nsd"); + l2n.register_layer (rnactive, "nactive"); + l2n.register_layer (rngate, "ngate"); + l2n.register_layer (rnsd, "nsd"); db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS"); db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS"); @@ -296,20 +296,20 @@ TEST(2_WriterWithGlobalNets) db::Region rntie = ractive_in_nwell & *rnplus; db::Region rpgate = rpactive & *rpoly; db::Region rpsd = rpactive - rpgate; - l2n.name (rpactive, "pactive"); - l2n.name (rntie, "ntie"); - l2n.name (rpgate, "pgate"); - l2n.name (rpsd, "psd"); + l2n.register_layer (rpactive, "pactive"); + l2n.register_layer (rntie, "ntie"); + l2n.register_layer (rpgate, "pgate"); + l2n.register_layer (rpsd, "psd"); db::Region ractive_outside_nwell = *ractive - *rnwell; db::Region rnactive = ractive_outside_nwell & *rnplus; db::Region rptie = ractive_outside_nwell & *rpplus; db::Region rngate = rnactive & *rpoly; db::Region rnsd = rnactive - rngate; - l2n.name (rnactive, "nactive"); - l2n.name (rptie, "ptie"); - l2n.name (rngate, "ngate"); - l2n.name (rnsd, "nsd"); + l2n.register_layer (rnactive, "nactive"); + l2n.register_layer (rptie, "ptie"); + l2n.register_layer (rngate, "ngate"); + l2n.register_layer (rnsd, "nsd"); // return the computed layers into the original layout and write it for debugging purposes diff --git a/testdata/algo/hierarchy_builder_au2f.gds b/testdata/algo/hierarchy_builder_au2f.gds new file mode 100644 index 000000000..7d244fcf7 Binary files /dev/null and b/testdata/algo/hierarchy_builder_au2f.gds differ diff --git a/testdata/ruby/dbLayoutToNetlist.rb b/testdata/ruby/dbLayoutToNetlist.rb index 9ee4ab918..89e920d2b 100644 --- a/testdata/ruby/dbLayoutToNetlist.rb +++ b/testdata/ruby/dbLayoutToNetlist.rb @@ -61,7 +61,7 @@ class DBLayoutToNetlist_TestClass < TestBase assert_equal(l2n.internal_layout.cell(ci).name, ly2.cell(cm.cell_mapping(ci)).name) end - rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0) ) + rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0), "metal1" ) bulk_id = l2n.connect_global(rmetal1, "BULK") assert_equal(l2n.global_net_name(bulk_id), "BULK") @@ -76,11 +76,11 @@ class DBLayoutToNetlist_TestClass < TestBase # only plain backend connectivity - rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0) ) - rmetal1_lbl = l2n.make_text_layer( ly.layer(6, 1) ) - rvia1 = l2n.make_polygon_layer( ly.layer(7, 0) ) - rmetal2 = l2n.make_polygon_layer( ly.layer(8, 0) ) - rmetal2_lbl = l2n.make_text_layer( ly.layer(8, 1) ) + rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0), "metal1" ) + rmetal1_lbl = l2n.make_text_layer( ly.layer(6, 1), "metal1_lbl" ) + rvia1 = l2n.make_polygon_layer( ly.layer(7, 0), "via1" ) + rmetal2 = l2n.make_polygon_layer( ly.layer(8, 0), "metal2" ) + rmetal2_lbl = l2n.make_text_layer( ly.layer(8, 1), "metal2_lbl" ) # Intra-layer l2n.connect(rmetal1) @@ -141,19 +141,21 @@ END # only plain connectivity - ractive = l2n.make_layer( ly.layer(2, 0) ) - rpoly = l2n.make_polygon_layer( ly.layer(3, 0) ) - rpoly_lbl = l2n.make_text_layer( ly.layer(3, 1) ) - rdiff_cont = l2n.make_polygon_layer( ly.layer(4, 0) ) - rpoly_cont = l2n.make_polygon_layer( ly.layer(5, 0) ) - rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0) ) - rmetal1_lbl = l2n.make_text_layer( ly.layer(6, 1) ) - rvia1 = l2n.make_polygon_layer( ly.layer(7, 0) ) - rmetal2 = l2n.make_polygon_layer( ly.layer(8, 0) ) - rmetal2_lbl = l2n.make_text_layer( ly.layer(8, 1) ) + ractive = l2n.make_layer( ly.layer(2, 0), "active" ) + rpoly = l2n.make_polygon_layer( ly.layer(3, 0), "poly" ) + rpoly_lbl = l2n.make_text_layer( ly.layer(3, 1), "poly_lbl" ) + rdiff_cont = l2n.make_polygon_layer( ly.layer(4, 0), "diff_cont" ) + rpoly_cont = l2n.make_polygon_layer( ly.layer(5, 0), "poly_cont" ) + rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0), "metal1" ) + rmetal1_lbl = l2n.make_text_layer( ly.layer(6, 1), "metal1_lbl" ) + rvia1 = l2n.make_polygon_layer( ly.layer(7, 0), "via1" ) + rmetal2 = l2n.make_polygon_layer( ly.layer(8, 0), "metal2" ) + rmetal2_lbl = l2n.make_text_layer( ly.layer(8, 1), "metal2_lbl" ) rsd = ractive - rpoly + l2n.register(rsd, "sd") + # Intra-layer l2n.connect(rsd) l2n.connect(rpoly) @@ -206,17 +208,17 @@ END l2n = RBA::LayoutToNetlist::new(RBA::RecursiveShapeIterator::new(ly, ly.top_cell, [])) - rnwell = l2n.make_layer( ly.layer(1, 0) ) - ractive = l2n.make_layer( ly.layer(2, 0) ) - rpoly = l2n.make_polygon_layer( ly.layer(3, 0) ) - rpoly_lbl = l2n.make_text_layer( ly.layer(3, 1) ) - rdiff_cont = l2n.make_polygon_layer( ly.layer(4, 0) ) - rpoly_cont = l2n.make_polygon_layer( ly.layer(5, 0) ) - rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0) ) - rmetal1_lbl = l2n.make_text_layer( ly.layer(6, 1) ) - rvia1 = l2n.make_polygon_layer( ly.layer(7, 0) ) - rmetal2 = l2n.make_polygon_layer( ly.layer(8, 0) ) - rmetal2_lbl = l2n.make_text_layer( ly.layer(8, 1) ) + rnwell = l2n.make_layer( ly.layer(1, 0), "nwell" ) + ractive = l2n.make_layer( ly.layer(2, 0), "active" ) + rpoly = l2n.make_polygon_layer( ly.layer(3, 0), "poly" ) + rpoly_lbl = l2n.make_text_layer( ly.layer(3, 1), "poly_lbl" ) + rdiff_cont = l2n.make_polygon_layer( ly.layer(4, 0), "diff_cont" ) + rpoly_cont = l2n.make_polygon_layer( ly.layer(5, 0), "poly_cont" ) + rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0), "metal1" ) + rmetal1_lbl = l2n.make_text_layer( ly.layer(6, 1), "metal1_lbl" ) + rvia1 = l2n.make_polygon_layer( ly.layer(7, 0), "via1" ) + rmetal2 = l2n.make_polygon_layer( ly.layer(8, 0), "metal2" ) + rmetal2_lbl = l2n.make_text_layer( ly.layer(8, 1), "metal2_lbl" ) rpactive = ractive & rnwell rpgate = rpactive & rpoly @@ -236,6 +238,9 @@ END # Define connectivity for netlist extraction + l2n.register(rpsd, "psd") + l2n.register(rnsd, "nsd") + # Intra-layer l2n.connect(rpsd) l2n.connect(rnsd) @@ -297,20 +302,20 @@ END l2n = RBA::LayoutToNetlist::new(RBA::RecursiveShapeIterator::new(ly, ly.top_cell, [])) - rbulk = l2n.make_polygon_layer( ly.layer ) - rnwell = l2n.make_polygon_layer( ly.layer(1, 0) ) - ractive = l2n.make_polygon_layer( ly.layer(2, 0) ) - rpoly = l2n.make_polygon_layer( ly.layer(3, 0) ) - rpoly_lbl = l2n.make_text_layer( ly.layer(3, 1) ) - rdiff_cont = l2n.make_polygon_layer( ly.layer(4, 0) ) - rpoly_cont = l2n.make_polygon_layer( ly.layer(5, 0) ) - rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0) ) - rmetal1_lbl = l2n.make_text_layer( ly.layer(6, 1) ) - rvia1 = l2n.make_polygon_layer( ly.layer(7, 0) ) - rmetal2 = l2n.make_polygon_layer( ly.layer(8, 0) ) - rmetal2_lbl = l2n.make_text_layer( ly.layer(8, 1) ) - rpplus = l2n.make_polygon_layer( ly.layer(10, 0) ) - rnplus = l2n.make_polygon_layer( ly.layer(11, 0) ) + rbulk = l2n.make_layer( "bulk" ) + rnwell = l2n.make_polygon_layer( ly.layer(1, 0) , "nwell" ) + ractive = l2n.make_polygon_layer( ly.layer(2, 0) , "active" ) + rpoly = l2n.make_polygon_layer( ly.layer(3, 0) , "poly" ) + rpoly_lbl = l2n.make_text_layer( ly.layer(3, 1) , "poly_lbl" ) + rdiff_cont = l2n.make_polygon_layer( ly.layer(4, 0) , "diff_cont" ) + rpoly_cont = l2n.make_polygon_layer( ly.layer(5, 0) , "poly_cont" ) + rmetal1 = l2n.make_polygon_layer( ly.layer(6, 0) , "metal1" ) + rmetal1_lbl = l2n.make_text_layer( ly.layer(6, 1) , "metal1_lbl" ) + rvia1 = l2n.make_polygon_layer( ly.layer(7, 0) , "via1" ) + rmetal2 = l2n.make_polygon_layer( ly.layer(8, 0) , "metal2" ) + rmetal2_lbl = l2n.make_text_layer( ly.layer(8, 1) , "metal2_lbl" ) + rpplus = l2n.make_polygon_layer( ly.layer(10, 0) , "pplus" ) + rnplus = l2n.make_polygon_layer( ly.layer(11, 0) , "nplus" ) ractive_in_nwell = ractive & rnwell rpactive = ractive_in_nwell & rpplus @@ -334,6 +339,11 @@ END # Define connectivity for netlist extraction + l2n.register(rpsd, "psd") + l2n.register(rnsd, "nsd") + l2n.register(rptie, "ptie") + l2n.register(rntie, "ntie") + # Intra-layer l2n.connect(rpsd) l2n.connect(rnsd) @@ -417,6 +427,24 @@ END end + def test_13_ReadAndWrite + + l2n = RBA::LayoutToNetlist::new + + input = File.join($ut_testsrc, "testdata", "algo", "l2n_writer_au.txt") + l2n.read(input) + + tmp = File::join($ut_testtmp, "tmp.txt") + l2n.write(tmp) + + assert_equal(File.open(tmp, "r").read, File.open(input, "r").read) + + assert_equal(l2n.layer_names.join(","), "poly,poly_lbl,diff_cont,poly_cont,metal1,metal1_lbl,via1,metal2,metal2_lbl,psd,nsd") + assert_equal(l2n.name(l2n.layer_by_name("metal1")), "metal1") + assert_equal(l2n.name(l2n.layer_by_index(l2n.layer_of(l2n.layer_by_name("metal1")))), "metal1") + + end + end load("test_epilogue.rb")