diff --git a/src/db/db/dbCellMapping.cc b/src/db/db/dbCellMapping.cc index 7d29d5d13..0b10257b4 100644 --- a/src/db/db/dbCellMapping.cc +++ b/src/db/db/dbCellMapping.cc @@ -295,7 +295,7 @@ CellMapping::create_from_names (const db::Layout &layout_a, db::cell_index_type } std::vector -CellMapping::create_missing_mapping (db::Layout &layout_a, db::cell_index_type /*cell_index_a*/, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells) +CellMapping::create_missing_mapping (db::Layout &layout_a, db::cell_index_type /*cell_index_a*/, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells, const std::set *include_cells) { std::vector new_cells; std::vector new_cells_b; @@ -305,7 +305,9 @@ CellMapping::create_missing_mapping (db::Layout &layout_a, db::cell_index_type / called_b.insert (cell_index_b); for (std::set::const_iterator b = called_b.begin (); b != called_b.end (); ++b) { - if (m_b2a_mapping.find (*b) == m_b2a_mapping.end () && (! exclude_cells || exclude_cells->find (*b) == exclude_cells->end ())) { + if (m_b2a_mapping.find (*b) == m_b2a_mapping.end () + && (! exclude_cells || exclude_cells->find (*b) == exclude_cells->end ()) + && (! include_cells || include_cells->find (*b) != include_cells->end ())) { db::cell_index_type new_cell = layout_a.add_cell (layout_b.cell_name (*b)); new_cells.push_back (new_cell); new_cells_b.push_back (*b); diff --git a/src/db/db/dbCellMapping.h b/src/db/db/dbCellMapping.h index 63740b1ca..858028659 100644 --- a/src/db/db/dbCellMapping.h +++ b/src/db/db/dbCellMapping.h @@ -190,9 +190,12 @@ public: * * If given, "exclude_cells" can specify a list of cells not to map. * + * If given, "include_cells" can specify a list of cells which are included in the + * cell tree to create. Cells not in the "include_cells" list are ignored. + * * The returned vector lists the new cells. */ - std::vector create_missing_mapping (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells = 0); + std::vector create_missing_mapping (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells = 0, const std::set *include_cells = 0); private: void extract_unique (std::map >::const_iterator cand, diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index 47c37a347..e7fc66bcb 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -713,7 +713,7 @@ DeepShapeStore::issue_variants (unsigned int layout_index, const std::map *excluded_cells) +DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout *into_layout, db::cell_index_type into_cell, const std::set *excluded_cells, const std::set *included_cells) { const db::Layout *source_layout = &m_layouts [layout_index]->layout; if (source_layout->begin_top_down () == source_layout->end_top_cells ()) { @@ -774,7 +774,7 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout // Add new cells for the variants and (possible) devices which are cells added during the device // extraction process - cm->second.create_missing_mapping (*into_layout, into_cell, *source_layout, source_top, excluded_cells); + cm->second.create_missing_mapping (*into_layout, into_cell, *source_layout, source_top, excluded_cells, included_cells); } diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index 2246e8a18..2c92f39f7 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -375,9 +375,11 @@ public: * "layout_index" is the layout to return to it's original. "into_layout" is the original layout, "into_cell" * the original cell. * - * "excluded_cells" - if not 0 - will exclude the given cells (and flatten them). + * "excluded_cells" - if not 0 - will exclude the given cells + * + * "included_cells" - if not 0 - will only include the given cells in the cell mapping */ - const db::CellMapping &cell_mapping_to_original (unsigned int layout_index, db::Layout *into_layout, db::cell_index_type into_cell, const std::set *excluded_cells = 0); + const db::CellMapping &cell_mapping_to_original (unsigned int layout_index, db::Layout *into_layout, db::cell_index_type into_cell, const std::set *excluded_cells = 0, const std::set *included_cells = 0); /** * @brief Create cell variants from the given variant collector diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 131d464d0..05c273c79 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -445,7 +445,7 @@ 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) +db::CellMapping LayoutToNetlist::make_cell_mapping_into (db::Layout &layout, db::Cell &cell, const std::vector *nets, bool with_device_cells) { std::set device_cells; if (! with_device_cells && mp_netlist.get ()) { @@ -454,7 +454,31 @@ db::CellMapping LayoutToNetlist::cell_mapping_into (db::Layout &layout, db::Cell } } - return dss ().cell_mapping_to_original (m_layout_index, &layout, cell.cell_index (), &device_cells); + std::set net_cells; + if (nets) { + // Compute the "included cell" list for cell_mapping_to_original: these are all cells which + // are required to represent the net hierarchically. + for (std::vector::const_iterator n = nets->begin (); n != nets->end (); ++n) { + const db::Net *net = *n; + db::cell_index_type net_cell = net->circuit ()->cell_index (); + if (net_cells.find (net_cell) == net_cells.end ()) { + net_cells.insert (net_cell); + internal_layout()->cell (net_cell).collect_caller_cells (net_cells); + } + } + } + + return dss ().cell_mapping_to_original (m_layout_index, &layout, cell.cell_index (), &device_cells, nets ? &net_cells : 0); +} + +db::CellMapping LayoutToNetlist::cell_mapping_into (db::Layout &layout, db::Cell &cell, const std::vector &nets, bool with_device_cells) +{ + return make_cell_mapping_into (layout, cell, &nets, with_device_cells); +} + +db::CellMapping LayoutToNetlist::cell_mapping_into (db::Layout &layout, db::Cell &cell, bool with_device_cells) +{ + return make_cell_mapping_into (layout, cell, 0, with_device_cells); } db::CellMapping LayoutToNetlist::const_cell_mapping_into (const db::Layout &layout, const db::Cell &cell) @@ -563,11 +587,11 @@ static bool deliver_shape (const db::PolygonRef &pr, db::Shapes &shapes, const T return true; } -template -static bool deliver_shapes_of_net_recursive (const db::Netlist * /*nl*/, const db::hier_clusters &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, const db::ICplxTrans &tr, To &to, db::properties_id_type propid) +template +static bool deliver_shapes_of_net_recursive (const db::Netlist * /*nl*/, const db::hier_clusters &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, const db::ICplxTrans &tr, To &to, db::properties_id_type propid) { // deliver the net shapes - for (db::recursive_cluster_shape_iterator rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { + for (db::recursive_cluster_shape_iterator rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { if (! deliver_shape (*rci, to, tr * rci.trans (), propid)) { return false; } @@ -575,56 +599,61 @@ static bool deliver_shapes_of_net_recursive (const db::Netlist * /*nl*/, const d return true; } -template -static bool deliver_shapes_of_net_nonrecursive (const db::Netlist *nl, const db::hier_clusters &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, const db::ICplxTrans &tr, To &to, db::properties_id_type propid) +template +static bool deliver_shapes_of_net (bool recursive, const db::Netlist *nl, const db::hier_clusters &clusters, db::cell_index_type ci, size_t cid, const std::map &lmap, const db::ICplxTrans &tr, db::properties_id_type propid) { - // NOTE: this scheme will deliver the shapes from the cell, including (!) - // subcells that are purged + // shortcut + if (lmap.empty ()) { + return true; + } - db::cell_index_type prev_ci = ci; + const db::connected_clusters &cc = clusters.clusters_per_cell (ci); + const db::local_cluster &lc = cc.cluster_by_id (cid); - // deliver the net shapes - for (db::recursive_cluster_shape_iterator rci (clusters, layer_id, ci, cid); !rci.at_end (); ) { - - db::cell_index_type cci = rci.cell_index (); - if (cci != prev_ci && cci != ci && (! nl || nl->circuit_by_cell_index (cci) || nl->device_abstract_by_cell_index (cci))) { - - rci.skip_cell (); - - } else { - - if (! deliver_shape (*rci, to, tr * rci.trans (), propid)) { + for (typename std::map::const_iterator l = lmap.begin (); l != lmap.end (); ++l) { + for (typename db::local_cluster::shape_iterator s = lc.begin (l->first); ! s.at_end (); ++s) { + if (! deliver_shape (*s, *l->second, tr, propid)) { return false; } - prev_ci = cci; - - ++rci; - } + } + + const typename db::connected_clusters::connections_type &conn = cc.connections_for_cluster (cid); + for (typename db::connected_clusters::connections_type::const_iterator c = conn.begin (); c != conn.end (); ) { + + db::cell_index_type cci = c->inst_cell_index (); + if (! recursive && (! nl || nl->circuit_by_cell_index (cci) || nl->device_abstract_by_cell_index (cci))) { + // skip this cell in non-recursive mode (and all following instances of the same cell too) + typename db::connected_clusters::connections_type::const_iterator cc = c; + while (++cc != conn.end ()) { + if (cc->inst_cell_index () != cci) { + break; + } + } + c = cc; + continue; + } + + if (! deliver_shapes_of_net (recursive, nl, clusters, cci, c->id (), lmap, tr * c->inst_trans (), propid)) { + return false; + } + ++c; } return true; } -template -static bool deliver_shapes_of_net (bool recursive, const db::Netlist *nl, const db::hier_clusters &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, const db::ICplxTrans &tr, To &to, db::properties_id_type propid) -{ - if (recursive) { - return deliver_shapes_of_net_recursive (nl, clusters, ci, cid, layer_id, tr, to, propid); - } else { - return deliver_shapes_of_net_nonrecursive (nl, clusters, ci, cid, layer_id, tr, to, propid); - } -} - - void LayoutToNetlist::shapes_of_net (const db::Net &net, const db::Region &of_layer, bool recursive, db::Shapes &to, db::properties_id_type propid) const { unsigned int lid = layer_of (of_layer); const db::Circuit *circuit = net.circuit (); tl_assert (circuit != 0); - deliver_shapes_of_net (recursive, mp_netlist.get (), m_net_clusters, circuit->cell_index (), net.cluster_id (), lid, db::ICplxTrans (), to, propid); + std::map lmap; + lmap [lid] = &to; + + deliver_shapes_of_net (recursive, mp_netlist.get (), m_net_clusters, circuit->cell_index (), net.cluster_id (), lmap, db::ICplxTrans (), propid); } db::Region *LayoutToNetlist::shapes_of_net (const db::Net &net, const db::Region &of_layer, bool recursive) const @@ -634,8 +663,10 @@ db::Region *LayoutToNetlist::shapes_of_net (const db::Net &net, const db::Region tl_assert (circuit != 0); std::auto_ptr res (new db::Region ()); + std::map lmap; + lmap [lid] = res.get (); - deliver_shapes_of_net (recursive, mp_netlist.get (), m_net_clusters, circuit->cell_index (), net.cluster_id (), lid, db::ICplxTrans (), *res, 0); + deliver_shapes_of_net (recursive, mp_netlist.get (), m_net_clusters, circuit->cell_index (), net.cluster_id (), lmap, db::ICplxTrans (), 0); return res.release (); } @@ -661,14 +692,15 @@ LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout & bool any_connections = circuit_cell_name_prefix && ! ccl.connections_for_cluster (cid).empty (); if (! any_connections) { - bool consider_cell = any_connections; - for (std::map::const_iterator l = lmap.begin (); l != lmap.end () && !consider_cell; ++l) { + StopOnFirst sof; + std::map sof_lmap; + for (std::map::const_iterator l = lmap.begin (); l != lmap.end (); ++l) { if (l->second) { - StopOnFirst sof; - consider_cell = !deliver_shapes_of_net (hier_mode == BNH_Flatten, mp_netlist.get (), m_net_clusters, ci, cid, layer_of (*l->second), tr, sof, 0); + sof_lmap.insert (std::make_pair (layer_of (*l->second), &sof)); } } + bool consider_cell = !deliver_shapes_of_net (hier_mode == BNH_Flatten, mp_netlist.get (), m_net_clusters, ci, cid, sof_lmap, tr, 0); if (! consider_cell) { // shortcut if cell is empty -> no net cell will be produced return; @@ -683,12 +715,15 @@ LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout & } + std::map target_lmap; for (std::map::const_iterator l = lmap.begin (); l != lmap.end (); ++l) { if (l->second) { - deliver_shapes_of_net (hier_mode == BNH_Flatten, mp_netlist.get (), m_net_clusters, ci, cid, layer_of (*l->second), tr, target_cell->shapes (l->first), netname_propid); + target_lmap.insert (std::make_pair (layer_of (*l->second), &target_cell->shapes (l->first))); } } + deliver_shapes_of_net (hier_mode == BNH_Flatten, mp_netlist.get (), m_net_clusters, ci, cid, target_lmap, tr, netname_propid); + if (hier_mode != BNH_SubcircuitCells && ! device_cell_name_prefix) { return; } @@ -780,26 +815,53 @@ LayoutToNetlist::build_all_nets (const db::CellMapping &cmap, db::Layout &target } void -LayoutToNetlist::build_nets (const std::set *nets, const db::CellMapping &cmap, db::Layout &target, const std::map &lmap, const char *net_cell_name_prefix, const tl::Variant &netname_prop, BuildNetHierarchyMode hier_mode, const char *circuit_cell_name_prefix, const char *device_cell_name_prefix) const +LayoutToNetlist::build_net_rec (const db::Net &net, db::Layout &target, db::cell_index_type circuit_cell, const db::CellMapping &cmap, const std::map &lmap, const char *net_cell_name_prefix, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const ICplxTrans &tr) const +{ + if (! cmap.has_mapping (circuit_cell)) { + + const db::Cell &cc = internal_layout ()->cell (circuit_cell); + + for (db::Cell::parent_inst_iterator p = cc.begin_parent_insts (); ! p.at_end (); ++p) { + + db::CellInstArray ci = p->child_inst ().cell_inst (); + for (db::CellInstArray::iterator ia = ci.begin (); ! ia.at_end(); ++ia) { + + db::ICplxTrans tr_parent = ci.complex_trans (*ia) * tr; + build_net_rec (net, target, p->parent_cell_index (), cmap, lmap, net_cell_name_prefix, netname_propid, hier_mode, cell_name_prefix, device_cell_name_prefix, reuse_table, tr_parent); + + } + + } + + } else { + + double mag = internal_layout ()->dbu () / target.dbu (); + + db::cell_index_type target_ci = cmap.cell_mapping (circuit_cell); + build_net_rec (net, target, target.cell (target_ci), lmap, net_cell_name_prefix, netname_propid, hier_mode, cell_name_prefix, device_cell_name_prefix, reuse_table, db::ICplxTrans (mag) * tr); + + } +} + +void +LayoutToNetlist::build_nets (const std::vector *nets, const db::CellMapping &cmap, db::Layout &target, const std::map &lmap, const char *net_cell_name_prefix, const tl::Variant &netname_prop, BuildNetHierarchyMode hier_mode, const char *circuit_cell_name_prefix, const char *device_cell_name_prefix) const { if (! m_netlist_extracted) { throw tl::Exception (tl::to_string (tr ("The netlist has not been extracted yet"))); } + std::set net_set; + if (nets) { + net_set.insert (nets->begin (), nets->end ()); + } + cell_reuse_table_type cell_reuse_table; - double mag = internal_layout ()->dbu () / target.dbu (); const db::Netlist *netlist = mp_netlist.get (); for (db::Netlist::const_circuit_iterator c = netlist->begin_circuits (); c != netlist->end_circuits (); ++c) { - if (! cmap.has_mapping (c->cell_index ())) { - continue; - } - bool is_top_circuit = c->begin_parents () == c->end_parents (); - db::cell_index_type target_ci = cmap.cell_mapping (c->cell_index ()); - for (db::Circuit::const_net_iterator n = c->begin_nets (); n != c->end_nets (); ++n) { // exlude local nets in recursive mode except if they are explicitly selected @@ -807,9 +869,9 @@ LayoutToNetlist::build_nets (const std::set *nets, const db::Ce continue; } - if (! nets || nets->find (n.operator-> ()) != nets->end ()) { + if (! nets || net_set.find (n.operator-> ()) != net_set.end ()) { db::properties_id_type netname_propid = make_netname_propid (target, netname_prop, *n); - build_net_rec (*n, target, target.cell (target_ci), lmap, net_cell_name_prefix, netname_propid, hier_mode, circuit_cell_name_prefix, device_cell_name_prefix, cell_reuse_table, db::ICplxTrans (mag)); + build_net_rec (*n, target, c->cell_index (), cmap, lmap, net_cell_name_prefix, netname_propid, hier_mode, circuit_cell_name_prefix, device_cell_name_prefix, cell_reuse_table, db::ICplxTrans ()); } } @@ -835,15 +897,15 @@ LayoutToNetlist::build_nets (const std::set *nets, const db::Ce if (n) { double dbu = target.dbu (); - db::ICplxTrans tr = db::ICplxTrans (mag) * (db::CplxTrans (dbu).inverted () * subcircuit.trans () * db::CplxTrans (dbu)); + db::ICplxTrans tr = db::CplxTrans (dbu).inverted () * subcircuit.trans () * db::CplxTrans (dbu); db::properties_id_type netname_propid = make_netname_propid (target, netname_prop, *n); if (net_cell_name_prefix) { std::string ncn = std::string (net_cell_name_prefix) + subcircuit.expanded_name () + ":"; - build_net_rec (*n, target, target.cell (target_ci), lmap, ncn.c_str (), netname_propid, hier_mode, circuit_cell_name_prefix, device_cell_name_prefix, cell_reuse_table, tr); + build_net_rec (*n, target, c->cell_index (), cmap, lmap, ncn.c_str (), netname_propid, hier_mode, circuit_cell_name_prefix, device_cell_name_prefix, cell_reuse_table, tr); } else { - build_net_rec (*n, target, target.cell (target_ci), lmap, net_cell_name_prefix, netname_propid, hier_mode, circuit_cell_name_prefix, device_cell_name_prefix, cell_reuse_table, tr); + build_net_rec (*n, target, c->cell_index (), cmap, lmap, net_cell_name_prefix, netname_propid, hier_mode, circuit_cell_name_prefix, device_cell_name_prefix, cell_reuse_table, tr); } } diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 198ad7b50..5e61137c7 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -435,10 +435,19 @@ public: */ db::CellMapping cell_mapping_into (db::Layout &layout, db::Cell &cell, bool with_device_cells = false); + /** + * @brief Creates a cell mapping for copying shapes from the internal layout to the given target layout for a given list of nets + * This version will only create cells which are required to represent the given nets. + * If 'with_device_cells' is true, cells will be produced for devices. These are cells not corresponding to circuits, so they are disabled normally. + * Use this option, if you want to access device terminal shapes per device. + * CAUTION: This function may create new cells in "layout". + */ + db::CellMapping cell_mapping_into (db::Layout &layout, db::Cell &cell, const std::vector &nets, bool with_device_cells = false); + /** * @brief Creates a cell mapping for copying shapes from the internal layout to the given target layout. * This version will not create new cells in the target layout. - * If the required cells do not exist there yet, flatting will happen. + * If the required cells do not exist there yet, flattening will happen. */ db::CellMapping const_cell_mapping_into (const db::Layout &layout, const db::Cell &cell); @@ -601,7 +610,7 @@ public: /** * @brief Like build_all_nets, but with the ability to select some nets */ - void build_nets (const std::set *nets, const db::CellMapping &cmap, db::Layout &target, const std::map &lmap, const char *net_cell_name_prefix, const tl::Variant &netname_prop, BuildNetHierarchyMode hier_mode, const char *circuit_cell_name_prefix, const char *device_cell_name_prefix) const; + void build_nets (const std::vector *nets, const db::CellMapping &cmap, db::Layout &target, const std::map &lmap, const char *net_cell_name_prefix, const tl::Variant &netname_prop, BuildNetHierarchyMode hier_mode, const char *circuit_cell_name_prefix, const char *device_cell_name_prefix) const; /** * @brief Finds the net by probing a specific location on the given layer @@ -730,12 +739,14 @@ private: 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, cell_index_type circuit_cell, const db::CellMapping &cmap, const std::map &lmap, const char *net_cell_name_prefix, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const ICplxTrans &tr) const; 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, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, 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, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const ICplxTrans &tr) const; db::DeepLayer deep_layer_of (const db::Region ®ion) const; void ensure_layout () const; std::string make_new_name (const std::string &stem = std::string ()); db::properties_id_type make_netname_propid (db::Layout &ly, const tl::Variant &netname_prop, const db::Net &net) const; + db::CellMapping make_cell_mapping_into (db::Layout &layout, db::Cell &cell, const std::vector *nets, bool with_device_cells); }; } diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index 962ef786f..c7db7b5fe 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -81,6 +81,14 @@ static void build_all_nets (const db::LayoutToNetlist *l2n, const db::CellMappin l2n->build_all_nets (cmap, target, lmap, net_cell_name_prefix.is_nil () ? 0 : np.c_str (), netname_prop, hier_mode, circuit_cell_name_prefix.is_nil () ? 0 : cp.c_str (), device_cell_name_prefix.is_nil () ? 0 : dp.c_str ()); } +static void build_nets (const db::LayoutToNetlist *l2n, const std::vector &nets, const db::CellMapping &cmap, db::Layout &target, const std::map &lmap, const tl::Variant &net_cell_name_prefix, const tl::Variant &netname_prop, db::LayoutToNetlist::BuildNetHierarchyMode hier_mode, const tl::Variant &circuit_cell_name_prefix, const tl::Variant &device_cell_name_prefix) +{ + std::string cp = circuit_cell_name_prefix.to_string (); + std::string np = net_cell_name_prefix.to_string (); + std::string dp = device_cell_name_prefix.to_string (); + l2n->build_nets (&nets, cmap, target, lmap, net_cell_name_prefix.is_nil () ? 0 : np.c_str (), netname_prop, hier_mode, circuit_cell_name_prefix.is_nil () ? 0 : cp.c_str (), device_cell_name_prefix.is_nil () ? 0 : dp.c_str ()); +} + static std::vector l2n_layer_names (const db::LayoutToNetlist *l2n) { std::vector ln; @@ -331,11 +339,21 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "This method is required to derive the internal layer index - for example for\n" "investigating the cluster tree.\n" ) + - gsi::method ("cell_mapping_into", &db::LayoutToNetlist::cell_mapping_into, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("with_device_cells", false), + gsi::method ("cell_mapping_into", (db::CellMapping (db::LayoutToNetlist::*) (db::Layout &, db::Cell &, bool)) &db::LayoutToNetlist::cell_mapping_into, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("with_device_cells", false), "@brief Creates a cell mapping for copying shapes from the internal layout to the given target layout.\n" "If 'with_device_cells' is true, cells will be produced for devices. These are cells not corresponding to circuits, so they are disabled normally.\n" "Use this option, if you want to access device terminal shapes per device.\n" - "CAUTION: this function may create new cells in 'layout'.\n" + "\n" + "CAUTION: this function may create new cells in 'layout'. Use \\const_cell_mapping_into if you want to use the target layout's hierarchy and not modify it.\n" + ) + + gsi::method ("cell_mapping_into", (db::CellMapping (db::LayoutToNetlist::*) (db::Layout &, db::Cell &, const std::vector &, bool)) &db::LayoutToNetlist::cell_mapping_into, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("nets"), gsi::arg ("with_device_cells", false), + "@brief Creates a cell mapping for copying shapes from the internal layout to the given target layout.\n" + "This version will only create cells which are required to represent the nets from the 'nets' argument.\n" + "\n" + "If 'with_device_cells' is true, cells will be produced for devices. These are cells not corresponding to circuits, so they are disabled normally.\n" + "Use this option, if you want to access device terminal shapes per device.\n" + "\n" + "CAUTION: this function may create new cells in 'layout'. Use \\const_cell_mapping_into if you want to use the target layout's hierarchy and not modify it.\n" ) + gsi::method ("const_cell_mapping_into", &db::LayoutToNetlist::const_cell_mapping_into, gsi::arg ("layout"), gsi::arg ("cell"), "@brief Creates a cell mapping for copying shapes from the internal layout to the given target layout.\n" @@ -389,9 +407,10 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", gsi::method_ext ("build_all_nets", &build_all_nets, gsi::arg ("cmap"), gsi::arg ("target"), gsi::arg ("lmap"), gsi::arg ("net_cell_name_prefix", tl::Variant (), "nil"), gsi::arg ("netname_prop", tl::Variant (), "nil"), gsi::arg ("hier_mode", db::LayoutToNetlist::BNH_Flatten, "BNH_Flatten"), gsi::arg ("circuit_cell_name_prefix", tl::Variant (), "nil"), gsi::arg ("device_cell_name_prefix", tl::Variant (), "nil"), "@brief Builds a full hierarchical representation of the nets\n" "\n" - "This method copies all nets into cells corresponding to the circuits. It uses the cmap\n" - "object to determine the target cell (create them with \"cell_mapping_into\" or \"const_cell_mapping_into\").\n" - "If no mapping is requested, the specific circuit it skipped.\n" + "This method copies all nets into cells corresponding to the circuits. It uses the 'cmap'\n" + "object to determine the target cell (create it with \"cell_mapping_into\" or \"const_cell_mapping_into\").\n" + "If no mapping is provided for a specific circuit cell, the nets are copied into the next mapped parent as " + "many times as the circuit cell appears there (circuit flattening).\n" "\n" "The method has three net annotation modes:\n" "@ul\n" @@ -427,6 +446,9 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "@param net_cell_name_prefix See method description\n" "@param device_cell_name_prefix See above\n" ) + + gsi::method_ext ("build_nets", &build_nets, gsi::arg ("nets"), gsi::arg ("cmap"), gsi::arg ("target"), gsi::arg ("lmap"), gsi::arg ("net_cell_name_prefix", tl::Variant (), "nil"), gsi::arg ("netname_prop", tl::Variant (), "nil"), gsi::arg ("hier_mode", db::LayoutToNetlist::BNH_Flatten, "BNH_Flatten"), gsi::arg ("circuit_cell_name_prefix", tl::Variant (), "nil"), gsi::arg ("device_cell_name_prefix", tl::Variant (), "nil"), + "@brief Like \\build_all_nets, but with the ability to select some nets." + ) + gsi::method ("probe_net", (db::Net *(db::LayoutToNetlist::*) (const db::Region &, const db::DPoint &)) &db::LayoutToNetlist::probe_net, gsi::arg ("of_layer"), gsi::arg ("point"), "@brief Finds the net by probing a specific location on the given layer\n" "\n" diff --git a/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc b/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc index 0178c3f6a..3b8abc93c 100644 --- a/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc @@ -86,7 +86,164 @@ TEST(1_ReaderBasic) std::string au = tl::testsrc (); au = tl::combine_path (au, "testdata"); au = tl::combine_path (au, "algo"); - au = tl::combine_path (au, "l2n_reader_au.gds"); + au = tl::combine_path (au, "l2n_reader_au_1.gds"); + + db::compare_layouts (_this, ly2, au); + } + + { + db::Layout ly2; + ly2.dbu (l2n.internal_layout ()->dbu ()); + db::Cell &top2 = ly2.cell (ly2.add_cell ("TOP")); + + std::map lmap; + 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"); + + std::vector nets; + nets.push_back (l2n.netlist ()->circuit_by_name ("RINGO")->net_by_name ("VSS")); + nets.push_back (l2n.netlist ()->circuit_by_name ("RINGO")->net_by_name ("VDD")); + + db::CellMapping cm = l2n.cell_mapping_into (ly2, top2, nets); + + l2n.build_nets (&nets, cm, ly2, lmap, "NET_", tl::Variant (), db::LayoutToNetlist::BNH_Disconnected, 0, "DEVICE_"); + + std::string au = tl::testsrc (); + au = tl::combine_path (au, "testdata"); + au = tl::combine_path (au, "algo"); + au = tl::combine_path (au, "l2n_reader_au_1b.gds"); + + db::compare_layouts (_this, ly2, au); + } + + { + db::Layout ly2; + ly2.dbu (l2n.internal_layout ()->dbu ()); + db::Cell &top2 = ly2.cell (ly2.add_cell ("TOP")); + + std::map lmap; + 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"); + + std::vector nets; + nets.push_back (l2n.netlist ()->circuit_by_name ("RINGO")->net_by_name ("VSS")); + nets.push_back (l2n.netlist ()->circuit_by_name ("RINGO")->net_by_name ("VDD")); + + db::CellMapping cm = l2n.cell_mapping_into (ly2, top2, nets); + + l2n.build_nets (&nets, cm, ly2, lmap, "NET_", tl::Variant (), db::LayoutToNetlist::BNH_Flatten, 0, "DEVICE_"); + + std::string au = tl::testsrc (); + au = tl::combine_path (au, "testdata"); + au = tl::combine_path (au, "algo"); + au = tl::combine_path (au, "l2n_reader_au_1c.gds"); + + db::compare_layouts (_this, ly2, au); + } + + { + db::Layout ly2; + ly2.dbu (l2n.internal_layout ()->dbu ()); + db::Cell &top2 = ly2.cell (ly2.add_cell ("TOP")); + + std::map lmap; + 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"); + + std::vector nets; + nets.push_back (l2n.netlist ()->circuit_by_name ("RINGO")->net_by_name ("VSS")); + nets.push_back (l2n.netlist ()->circuit_by_name ("RINGO")->net_by_name ("VDD")); + + db::CellMapping cm = l2n.cell_mapping_into (ly2, top2, nets); + + l2n.build_nets (&nets, cm, ly2, lmap, "NET_", tl::Variant (), db::LayoutToNetlist::BNH_SubcircuitCells, "CIRCUIT_", "DEVICE_"); + + std::string au = tl::testsrc (); + au = tl::combine_path (au, "testdata"); + au = tl::combine_path (au, "algo"); + au = tl::combine_path (au, "l2n_reader_au_1d.gds"); + + db::compare_layouts (_this, ly2, au); + } + + { + db::Layout ly2; + ly2.dbu (l2n.internal_layout ()->dbu ()); + db::Cell &top2 = ly2.cell (ly2.add_cell ("TOP")); + + std::map lmap; + 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"); + + std::vector nets; + nets.push_back (l2n.netlist ()->circuit_by_name ("RINGO")->net_by_name ("VSS")); + nets.push_back (l2n.netlist ()->circuit_by_name ("RINGO")->net_by_name ("VDD")); + nets.push_back (l2n.netlist ()->circuit_by_name ("INV2")->net_by_name ("IN")); + + db::CellMapping cm = l2n.cell_mapping_into (ly2, top2, nets); + + l2n.build_nets (&nets, cm, ly2, lmap, "NET_", tl::Variant (), db::LayoutToNetlist::BNH_SubcircuitCells, "CIRCUIT_", 0); + + std::string au = tl::testsrc (); + au = tl::combine_path (au, "testdata"); + au = tl::combine_path (au, "algo"); + au = tl::combine_path (au, "l2n_reader_au_1e.gds"); + + db::compare_layouts (_this, ly2, au); + } + + { + db::Layout ly2; + ly2.dbu (l2n.internal_layout ()->dbu ()); + db::Cell &top2 = ly2.cell (ly2.add_cell ("TOP")); + + std::map lmap; + 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"); + + std::vector nets; + nets.push_back (l2n.netlist ()->circuit_by_name ("RINGO")->net_by_name ("VSS")); + nets.push_back (l2n.netlist ()->circuit_by_name ("RINGO")->net_by_name ("VDD")); + nets.push_back (l2n.netlist ()->circuit_by_name ("INV2")->net_by_name ("IN")); + + db::CellMapping cm = l2n.const_cell_mapping_into (ly2, top2); + + l2n.build_nets (&nets, cm, ly2, lmap, "NET_", tl::Variant (), db::LayoutToNetlist::BNH_SubcircuitCells, "CIRCUIT_", "DEVICE_"); + + std::string au = tl::testsrc (); + au = tl::combine_path (au, "testdata"); + au = tl::combine_path (au, "algo"); + au = tl::combine_path (au, "l2n_reader_au_1f.gds"); db::compare_layouts (_this, ly2, au); } diff --git a/src/laybasic/laybasic/NetlistBrowserDialog.ui b/src/laybasic/laybasic/NetlistBrowserDialog.ui index e74ef4cd7..58babbab9 100644 --- a/src/laybasic/laybasic/NetlistBrowserDialog.ui +++ b/src/laybasic/laybasic/NetlistBrowserDialog.ui @@ -172,7 +172,7 @@ - 1 + 0 @@ -192,7 +192,7 @@ 0 - + 0 diff --git a/src/laybasic/laybasic/layNetlistBrowserDialog.cc b/src/laybasic/laybasic/layNetlistBrowserDialog.cc index 333850491..159f9ddba 100644 --- a/src/laybasic/laybasic/layNetlistBrowserDialog.cc +++ b/src/laybasic/laybasic/layNetlistBrowserDialog.cc @@ -76,7 +76,7 @@ NetlistBrowserDialog::NetlistBrowserDialog (lay::PluginRoot *root, lay::LayoutVi { Ui::NetlistBrowserDialog::setupUi (this); - browser_frame->set_plugin_root (root); + browser_page->set_plugin_root (root); if (view ()) { view ()->cellviews_changed_event.add (this, &NetlistBrowserDialog::cellviews_changed); @@ -282,7 +282,7 @@ NetlistBrowserDialog::probe_net (const db::DPoint &p, bool trace_path) } // select the net if one was found - browser_frame->select_net (net); + browser_page->select_net (net); } void @@ -353,40 +353,9 @@ END_PROTECTED void NetlistBrowserDialog::export_clicked () { -BEGIN_PROTECTED - -#if 0 // @@@ - if (m_l2n_index >= int (view ()->num_rdbs ()) || m_l2n_index < 0) { - return; + if (m_l2n_index < int (view ()->num_l2ndbs ()) && m_l2n_index >= 0) { + browser_page->export_all (); } - - const rdb::Database *rdb = view ()->get_rdb (m_l2n_index); - if (! rdb) { - return; - } - - const lay::CellView &cv = view ()->cellview (m_cv_index); - if (! cv.is_valid ()) { - return; - } - - try { - - view ()->manager ()->transaction (tl::to_string (QObject::tr ("Export Net"))); - - // .... - - view ()->manager ()->commit (); - view ()->update_content (); - - } catch (...) { - view ()->manager ()->commit (); - view ()->update_content (); - throw; - } -#endif - -END_PROTECTED } void @@ -431,9 +400,9 @@ BEGIN_PROTECTED tl::log << tl::to_string (QObject::tr ("Loading file: ")) << l2ndb->filename (); tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Loading"))); - browser_frame->set_l2ndb (0); + browser_page->set_l2ndb (0); l2ndb->load (l2ndb->filename ()); - browser_frame->set_l2ndb (l2ndb); + browser_page->set_l2ndb (l2ndb); } @@ -450,7 +419,7 @@ BEGIN_PROTECTED std::string fmts = tl::to_string (QObject::tr ("All files (*)")); #if 0 // TODO: would be good to have this: // collect the formats available ... - for (tl::Registrar::iterator rdr = tl::Registrar::begin (); rdr != tl::Registrar::end (); ++rdr) { + for (tl::Registrar::iterator rdr = tl::Registrar::begin (); rdr != tl::Registrar::end (); ++rdr) { fmts += ";;" + rdr->file_format (); } #else @@ -480,7 +449,7 @@ NetlistBrowserDialog::configure (const std::string &name, const std::string &val { bool need_update = false; bool taken = true; - bool show_all = browser_frame->show_all (); + bool show_all = browser_page->show_all (); if (name == cfg_l2ndb_show_all) { @@ -577,12 +546,12 @@ NetlistBrowserDialog::configure (const std::string &name, const std::string &val } if (active () && need_update) { - browser_frame->set_max_shape_count (m_max_shape_count); - browser_frame->set_window (m_window, m_window_dim); - browser_frame->set_highlight_style (m_marker_color, m_marker_line_width, m_marker_vertex_size, m_marker_halo, m_marker_dither_pattern, m_marker_intensity, m_use_original_colors, m_auto_color_enabled ? &m_auto_colors : 0); + browser_page->set_max_shape_count (m_max_shape_count); + browser_page->set_window (m_window, m_window_dim); + browser_page->set_highlight_style (m_marker_color, m_marker_line_width, m_marker_vertex_size, m_marker_halo, m_marker_dither_pattern, m_marker_intensity, m_use_original_colors, m_auto_color_enabled ? &m_auto_colors : 0); } - browser_frame->show_all (show_all); + browser_page->show_all (show_all); return taken; } @@ -636,7 +605,7 @@ NetlistBrowserDialog::l2ndbs_changed () void NetlistBrowserDialog::cellview_changed (int) { - browser_frame->update_highlights (); + browser_page->update_highlights (); } void @@ -725,13 +694,13 @@ NetlistBrowserDialog::update_content () m_unload_all_action->setEnabled (l2ndb != 0); m_reload_action->setEnabled (l2ndb != 0); - browser_frame->enable_updates (false); // Avoid building the internal lists several times ... - browser_frame->set_l2ndb (l2ndb); - browser_frame->set_max_shape_count (m_max_shape_count); - browser_frame->set_highlight_style (m_marker_color, m_marker_line_width, m_marker_vertex_size, m_marker_halo, m_marker_dither_pattern, m_marker_intensity, m_use_original_colors, m_auto_color_enabled ? &m_auto_colors : 0); - browser_frame->set_window (m_window, m_window_dim); - browser_frame->set_view (view (), m_cv_index); - browser_frame->enable_updates (true); + browser_page->enable_updates (false); // Avoid building the internal lists several times ... + browser_page->set_l2ndb (l2ndb); + browser_page->set_max_shape_count (m_max_shape_count); + browser_page->set_highlight_style (m_marker_color, m_marker_line_width, m_marker_vertex_size, m_marker_halo, m_marker_dither_pattern, m_marker_intensity, m_use_original_colors, m_auto_color_enabled ? &m_auto_colors : 0); + browser_page->set_window (m_window, m_window_dim); + browser_page->set_view (view (), m_cv_index); + browser_page->enable_updates (true); if (l2ndb) { // Note: it appears to be required to show the browser page after it has been configured. @@ -769,8 +738,8 @@ NetlistBrowserDialog::deactivated () lay::PluginRoot::instance ()->config_set (cfg_l2ndb_window_state, lay::save_dialog_state (this, false /*don't store the section sizes*/).c_str ()); } - browser_frame->set_l2ndb (0); - browser_frame->set_view (0, 0); + browser_page->set_l2ndb (0); + browser_page->set_view (0, 0); } void diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index 655ee9171..86ae197ca 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -31,6 +31,7 @@ #include "layNetInfoDialog.h" #include "layNetExportDialog.h" #include "tlProgress.h" +#include "tlExceptions.h" #include "dbLayoutToNetlist.h" #include "dbNetlistDeviceClasses.h" #include "dbCellMapping.h" @@ -1157,18 +1158,24 @@ NetlistBrowserPage::clear_markers () void NetlistBrowserPage::export_selected () { +BEGIN_PROTECTED + std::vector nets = selected_nets (); if (nets.empty ()) { return; } export_nets (&nets); + +END_PROTECTED } void NetlistBrowserPage::export_all () { +BEGIN_PROTECTED export_nets (0); +END_PROTECTED } void @@ -1198,15 +1205,16 @@ NetlistBrowserPage::export_nets (const std::vector *nets) db::cell_index_type target_top_index = target_layout.add_cell (source_layout.cell_name (source_top.cell_index ())); - db::CellMapping cm = database->cell_mapping_into (target_layout, target_layout.cell (target_top_index)); - std::map lm = database->create_layermap (target_layout, dialog->start_layer_number ()); - - std::set net_set; - if (nets) { - net_set.insert (nets->begin (), nets->end ()); + db::CellMapping cm; + if (! nets) { + cm = database->cell_mapping_into (target_layout, target_layout.cell (target_top_index)); + } else { + cm = database->cell_mapping_into (target_layout, target_layout.cell (target_top_index), *nets); } - database->build_nets (nets ? &net_set : 0, cm, target_layout, lm, + std::map lm = database->create_layermap (target_layout, dialog->start_layer_number ()); + + database->build_nets (nets, cm, target_layout, lm, dialog->net_prefix ().empty () ? 0 : dialog->net_prefix ().c_str (), dialog->net_propname (), dialog->produce_circuit_cells () ? db::LayoutToNetlist::BNH_SubcircuitCells : db::LayoutToNetlist::BNH_Flatten, diff --git a/testdata/algo/l2n_reader_au.gds b/testdata/algo/l2n_reader_au_1.gds similarity index 100% rename from testdata/algo/l2n_reader_au.gds rename to testdata/algo/l2n_reader_au_1.gds diff --git a/testdata/algo/l2n_reader_au_1b.gds b/testdata/algo/l2n_reader_au_1b.gds new file mode 100644 index 000000000..103fdb19a Binary files /dev/null and b/testdata/algo/l2n_reader_au_1b.gds differ diff --git a/testdata/algo/l2n_reader_au_1c.gds b/testdata/algo/l2n_reader_au_1c.gds new file mode 100644 index 000000000..4ade45111 Binary files /dev/null and b/testdata/algo/l2n_reader_au_1c.gds differ diff --git a/testdata/algo/l2n_reader_au_1d.gds b/testdata/algo/l2n_reader_au_1d.gds new file mode 100644 index 000000000..8946b1e3d Binary files /dev/null and b/testdata/algo/l2n_reader_au_1d.gds differ diff --git a/testdata/algo/l2n_reader_au_1e.gds b/testdata/algo/l2n_reader_au_1e.gds new file mode 100644 index 000000000..e917635e7 Binary files /dev/null and b/testdata/algo/l2n_reader_au_1e.gds differ diff --git a/testdata/algo/l2n_reader_au_1f.gds b/testdata/algo/l2n_reader_au_1f.gds new file mode 100644 index 000000000..937a9bda3 Binary files /dev/null and b/testdata/algo/l2n_reader_au_1f.gds differ