From ebd00c186b66fed9e592d57868f2a31e6629f9e3 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 12 Jun 2019 22:55:24 +0200 Subject: [PATCH] Enhancements for net export feature - some refactoring - better performance (was slow because layer iteration was done outside of loop and recursive cluster iterator) - with selected nets, only the required hierarchy is produced. For this a new argument is added to LayoutToNetlist::create_cell_mapping (nets) which allows selecting the nets for which a cell mapping is requested --- src/db/db/dbCellMapping.cc | 6 +- src/db/db/dbCellMapping.h | 5 +- src/db/db/dbDeepShapeStore.cc | 4 +- src/db/db/dbDeepShapeStore.h | 6 +- src/db/db/dbLayoutToNetlist.cc | 174 ++++++++++++------ src/db/db/dbLayoutToNetlist.h | 15 +- src/db/db/gsiDeclDbLayoutToNetlist.cc | 32 +++- .../dbLayoutToNetlistReaderTests.cc | 159 +++++++++++++++- src/laybasic/laybasic/NetlistBrowserDialog.ui | 4 +- .../laybasic/layNetlistBrowserDialog.cc | 75 +++----- .../laybasic/layNetlistBrowserPage.cc | 22 ++- ...{l2n_reader_au.gds => l2n_reader_au_1.gds} | Bin testdata/algo/l2n_reader_au_1b.gds | Bin 0 -> 7938 bytes testdata/algo/l2n_reader_au_1c.gds | Bin 0 -> 23298 bytes testdata/algo/l2n_reader_au_1d.gds | Bin 0 -> 10672 bytes testdata/algo/l2n_reader_au_1e.gds | Bin 0 -> 10768 bytes testdata/algo/l2n_reader_au_1f.gds | Bin 0 -> 15632 bytes 17 files changed, 369 insertions(+), 133 deletions(-) rename testdata/algo/{l2n_reader_au.gds => l2n_reader_au_1.gds} (100%) create mode 100644 testdata/algo/l2n_reader_au_1b.gds create mode 100644 testdata/algo/l2n_reader_au_1c.gds create mode 100644 testdata/algo/l2n_reader_au_1d.gds create mode 100644 testdata/algo/l2n_reader_au_1e.gds create mode 100644 testdata/algo/l2n_reader_au_1f.gds 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 0000000000000000000000000000000000000000..103fdb19a3bba43775c2810eb98315220ae17286 GIT binary patch literal 7938 zcmcJUF=(At7>2*x-u{j0HE1+WA%PBh0|6l^iqKq8B8fFbn*@=Nw9r{P6vs}*Md(z- zMJW!VTc-}<(4m8abn4uxI!bYHPCQS(^K!11bJBay-$HoG_vQWH@68R#eTg;J>3nW; z6P+`ESYthV!``y~@c(VH(`5iE#y>iOzr6=LzSLf8XW>fdWN2KO~-B%0xvlm_8d(-uz z=7BF%uRC?OsCoYWqobqSLga+t_-<35|8 zJvkw{(Tkdw^0%Sao#WiUdfoFw^n)(Cg0UyubO+`@io){x8EvVDF2NrJJaE;BfvH z_2K=`CjL(R?VkHX&GY`Xdb8L5^8670+1*6)$9*<`t$zN3`$PN}eoVwa?z8^2`u;8V zhxjl4lZb!ZXZ>sS%a7e3;(tCA6%qfq&-&NuSC`x$;yd^z5&yW)`q%2$Z@53if8)_py_5WQ&GSRe^ZC&Q&7PC| zbY)TVeEv4{>CVybr>pwc52Bx)PUQ8E`|RsSN9J{gA-UN|SFgJsl7Fz3NdCCb=BMkD6Ox;* zENWiLU$3vbfBk{$A^A7%B$7Ywv-#<|p=D~pi_osB_ ziST}%uI$wOn8W#7)Q7M2CeMfNOGn1v?rC1~uhr9qkDq_siSeZ?J2fx)*X!pmxDTBd zU%IkW^Rj=fzJJSo=)CySm7SWG{cH8hkKKpPi!WW-sd?GIR=>LBK6GAu>B>&c%l@_c z^&9R(=f#(_3YBgswc2~d3{fKa> literal 0 HcmV?d00001 diff --git a/testdata/algo/l2n_reader_au_1c.gds b/testdata/algo/l2n_reader_au_1c.gds new file mode 100644 index 0000000000000000000000000000000000000000..4ade45111ffb08d0430b72bc5eea3e7e1a489a79 GIT binary patch literal 23298 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 blbasn-;|F3weG{VKK};wRekdr8Vdgf4)_J~ literal 0 HcmV?d00001 diff --git a/testdata/algo/l2n_reader_au_1d.gds b/testdata/algo/l2n_reader_au_1d.gds new file mode 100644 index 0000000000000000000000000000000000000000..8946b1e3db57db2ad1dee7a87ba1db63f1ae068a GIT binary patch literal 10672 zcmd^_PiRzE6vl7Ham-AnVq?-(h#pLy50zIE%z-}&s#eZT(j=&gxg zUb+1B!n_+;pU>+nl_n;S%z3PYjzRW86K-S3> z|J<)@))&ivJ6Gd}FZo+^uYA52 zr4t@4zI-dh7tR8F(R~BHM~l0KC&^!P{h96+{&}fiy1(nR)GytyXmK!Ae=I-Ky|Vvx z(LX1jpG9AuIffQrzMj(0@P)GvzSKPl-=oFdz7#*x{h~jv-QRUnyI;}bpz>Gg{%WZ- zJ2`*s$i#&7wchtLPlI|#Fa9o7`p%c9L$g)&HLI?w9BgH;zRRtw8hq5ss^Pa=Sv4xp zEcs{O?i`O}_gYys{c0<#=Fa$4E1z<5hr2JIYl=K2DmU~g2U*k=7ho^u8{cld@D51oG} z_*Q2-^$(s^{~-J=M?JD{lF#)|9-kn-;Tu{!2{-N8d52Al~r$_XY ze6D^he{n$dLG+i-dqh9U=jyM8-{PF&Fca~LbDPo=2%S1-rW8%r)Ze)MTYl3unF&SH zHJSND(>0mtMAJ2y*+kPdnaM=cHDmYuEFtguWTp~L_nAB6_i6S{S-vl`rCZV$g3KN( zH#}NAfA$DZ_FqtB_Q*`a(Bk>C$4>BL>SrbaU-224y=G<-dj0xF^xXS5dgT0xht8jw z0_O~J?#v_%Egm}mcz#^{gJ+cwa{gP6dc=Q{Z@ed_t{*c6e1iC9CShptkpFmoT>V3L zln>&6_^LGgH7Ph;L>Rh87R`kLSnLKXp_2ApWN>dBlH`&-Kqt z0iPhgnMoL0Jmf!~A6Nfeuku0s&pq^r|0JL5pP2$aL3}flFtm8ce>^{~{>9_U2l2l& z?h*em`(6IS7s857O!KY{|@ryTJL9n zP<5Ze?|xJDZ+@UYnLXf}nS`Rn!~SFWgS%CS*#f%EBor+k){o^6T~Hln3+OVFP_%eh zKbAjoS9O>zpvz1`(c)qKSpL{{)nT@PE;9*5i-+}N`BSG=huH$U%p?>o9@dZLAG)nN z%ofmPCZTBYuzoCmaX@vLEuhOxLeb)3{k8B{nMrh)O7jQgj~SRpRD1RBD40*w|6)S! U^8Bmc2OIMIoyCg0=oE|Yf0tF>hX4Qo literal 0 HcmV?d00001 diff --git a/testdata/algo/l2n_reader_au_1e.gds b/testdata/algo/l2n_reader_au_1e.gds new file mode 100644 index 0000000000000000000000000000000000000000..e917635e7cc90bf2567d2ccd444185d5cb7ec9da GIT binary patch literal 10768 zcmd^_PiRzE6vl7zGOj(Sqwzib&}~i>Qkh zT$EC}up&}gyAWKI7K#=ZF1oNT#BE&!+og(NHR^G6B)yTtz?nP0H@q0IlYN2_-qO3WY1?@Z_)7ya|1FIf0N^pAM7diVK+{v-UJ z&B`yns(eGM_iRq^yK43S{ao}nR4QQcC+9jo^=S3(4a)CyxhJ+Sd19B&TTiXt;vG4w zFY0-1`BTrUqSe8~ys7gl{i~ced7b0Dd9?cC)jYm%=HQF=Yw$f<-OW8t{)*>Moj2j1 zkoo1jwj7rE<-96d9Zbw0%1@m)+5eL0AD7oJqJPAr)fX=%^izD{?1V3KZ-?*E>TYL( zpE|FiKcVNf<%*tHMXQ6#U*^0PqG)D2PuHcB+E#l~AKsTKqe|uBedoI5#POt6v^toW zG{Ju`FOTclN(JovP52*sw0bm~%}4*g1=VkRUiB5N4(9Pi@4E7P`;>2J_0H=Fen+kU z2j9v3r(}M?&QIiuf9BEZ(JAFGbES)VrT1>zChtN8=lc88?`_4tHs|KA%XyF$yjNwf zs;*gfRpH%6_8K_b$g1IcjjS4dvyoNfUpBI;w9v?^sh1mBRX*xh#h)N*o~ZKlza_7W zioAmsF6$=%(CXQr0F)>1@YQ{I=Z9x#_3Tdo&EeaeE1zHf4L^OKfD-qAU`+2b$n_iS z^~iON`x&1gwa-weLZxtjS)2h~3ae`3ZX`^NoD|Mc+*;v2r9)${x}gKu-L zX8y@5>K}wZb;cw6#{EqH^zjMe8@{2{^ZYl1Z*#6@{&K(i2jQ3RdSu_YpXr}IK0$oL zH?(@5|7P%Q&ehC6e?a|%@b^u4WZ$@->7PD6L43nEw0fTZX7Fv!2IsH&MkwA-%j=LL z2}n=7%parGvlEa|zI^_YZ?cxOJfQ?8;eX9-^$(&yIO`GraliKdHMRCi#+Rh<@D9)DPvC)~h~SLWKlQgq^y7Y}ekgzUHPr{v-?Pah`f)!~Ka@W|r1~KG`%ZX7KkjGhuY})V zPO)c?CJ=qeoWj*hDeA7Ne&hBTMcp;2gre@6R6bF6O)8zJyC#)Q)LoNGChD#!E%+>< z;9T7`sZ^rwn(|SAVS z?-BoTzxJ7!xPD{`_yqAyCShpxJpbYRu=z)BC?CZC=mn4XkNcVa$rSJj;+ssu(CT^q z!}($JkFQfci2w0LkNA)Knf}QX@Co9ZOv2FWdH%!sVe^*`Dj&rE#EeJ$$NfzIWD58M z@l7USX!Sh*;ry`qC$A_U#Q)S8kNA)Knf}QX@Co9ZOv2FWdH%!sVe^;!l@H>-eAgrX z<9?=pG6j5s_$HGuw0fTZaDLeQ^9Pg<;(y;d0o5{g#O_aDk1 z-l95W3+R$bC|W&VKa@XmQgz4{&?S>lw0gdND1Ypx>X0ppVx^iy$TOZl)u-U{yUe~LKZ)RX6}!2~ N#qvmBu77*G`yU_P@EHIA literal 0 HcmV?d00001 diff --git a/testdata/algo/l2n_reader_au_1f.gds b/testdata/algo/l2n_reader_au_1f.gds new file mode 100644 index 0000000000000000000000000000000000000000..937a9bda3f6e2e0778dc2cf25367472132764eb0 GIT binary patch literal 15632 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 literal 0 HcmV?d00001