From 3dff7549f2389a89c59bb689660e65a866ad88e7 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 16 Jul 2020 01:49:18 +0200 Subject: [PATCH] Implemented #588: Netlist browser enhancements 1. The netlist browser now got events for selection and probe events 2. The netlist browser was overhauled to support "infinite depth" views 3. Ambiguities are not shown as errors now 4. New classes for support netlist object selections and the netlist browser. Multiple selections for netlist browser. --- .../gsiDeclLayNetlistBrowserDialog.cc | 51 +++++-- .../laybasic/layNetlistBrowserDialog.cc | 41 +---- .../laybasic/layNetlistBrowserDialog.h | 17 +-- .../laybasic/layNetlistBrowserPage.cc | 144 ++++++++++-------- src/laybasic/laybasic/layNetlistBrowserPage.h | 37 +---- 5 files changed, 126 insertions(+), 164 deletions(-) diff --git a/src/laybasic/laybasic/gsiDeclLayNetlistBrowserDialog.cc b/src/laybasic/laybasic/gsiDeclLayNetlistBrowserDialog.cc index fc1ce6ba3..f662339e2 100644 --- a/src/laybasic/laybasic/gsiDeclLayNetlistBrowserDialog.cc +++ b/src/laybasic/laybasic/gsiDeclLayNetlistBrowserDialog.cc @@ -126,7 +126,7 @@ Class decl_NetlistObjectPath ("lay", "NetlistObjectPath" gsi::method ("is_null?", &lay::NetlistObjectPath::is_null, "@brief Returns a value indicating whether the path is an empty one.\n" ), - "@brief An object describing the instantiation of an object.\n" + "@brief An object describing the instantiation of a netlist object.\n" "This class describes the instantiation of a net or a device or a circuit in terms of " "a root circuit and a subcircuit chain leading to the indicated object.\n" "\n" @@ -135,6 +135,39 @@ Class decl_NetlistObjectPath ("lay", "NetlistObjectPath" "This class has been introduced in version 0.27.\n" ); +static lay::NetlistObjectPath first (const lay::NetlistObjectsPath *pp) +{ + return pp->first (); +} + +static lay::NetlistObjectPath second (const lay::NetlistObjectsPath *pp) +{ + return pp->second (); +} + +Class decl_NetlistObjectsPath ("lay", "NetlistObjectsPath", + gsi::method_ext ("first", &first, + "@brief Gets the first object's path.\n" + "In cases of paired netlists (LVS database), the first path points to the layout netlist object.\n" + "For the single netlist, the first path is the only path supplied." + ) + + gsi::method_ext ("second", &second, + "@brief Gets the second object's path.\n" + "In cases of paired netlists (LVS database), the first path points to the schematic netlist object.\n" + "For the single netlist, the scecond path is always a null path." + ), + "@brief An object describing the instantiation of a single netlist object or a pair of those.\n" + "This class is basically a pair of netlist object paths (see \\NetlistObjectPath). When derived from a single netlist view, " + "only the first path is valid and will point to the selected object (a net, a device or a circuit). The second path is null.\n" + "\n" + "If the path is derived from a paired netlist view (a LVS report view), the first path corresponds to the object in the layout netlist, " + "the second one to the object in the schematic netlist.\n" + "If the selected object isn't a matched one, either the first or second path may be a null or a partial path without a final net or device object " + "or a partial path.\n" + "\n" + "This class has been introduced in version 0.27.\n" +); + static lay::NetlistObjectPath current_path_first (lay::NetlistBrowserDialog *dialog) { return dialog->current_path ().first (); @@ -169,18 +202,12 @@ Class decl_NetlistBrowserDialog ("lay", "NetlistBrows gsi::method_ext ("current_path_second", ¤t_path_second, "@brief Gets the path of the current object on the second (schematic in case of LVS database) side.\n" ) + - // @@@ - gsi::method ("selected_nets", &lay::NetlistBrowserDialog::selected_nets, - "@brief Gets the nets currently selected in the netlist database browser.\n" + gsi::method ("current_path", &lay::NetlistBrowserDialog::current_path, + "@brief Gets the path of the current object as a path pair (combines layout and schematic object paths in case of a LVS database view).\n" ) + - gsi::method ("selected_devices", &lay::NetlistBrowserDialog::selected_devices, - "@brief Gets the devices currently selected in the netlist database browser.\n" - ) + - gsi::method ("selected_subcircuits", &lay::NetlistBrowserDialog::selected_subcircuits, - "@brief Gets the subcircuits currently selected in the netlist database browser.\n" - ) + - gsi::method ("selected_circuits", &lay::NetlistBrowserDialog::selected_circuits, - "@brief Gets the circuits currently selected in the netlist database browser.\n" + gsi::method ("selected_paths", &lay::NetlistBrowserDialog::selected_paths, + "@brief Gets the nets currently selected objects (paths) in the netlist database browser.\n" + "The result is an array of path pairs. See \\NetlistObjectsPath for details about these pairs." ), "@brief Represents the netlist browser dialog.\n" "This dialog is a part of the \\LayoutView class and can be obtained through \\LayoutView#netlist_browser.\n" diff --git a/src/laybasic/laybasic/layNetlistBrowserDialog.cc b/src/laybasic/laybasic/layNetlistBrowserDialog.cc index 85cc4b4c3..b44db19bc 100644 --- a/src/laybasic/laybasic/layNetlistBrowserDialog.cc +++ b/src/laybasic/laybasic/layNetlistBrowserDialog.cc @@ -146,46 +146,13 @@ NetlistBrowserDialog::current_path () const } } -const std::vector & -NetlistBrowserDialog::selected_nets () const +const std::vector & +NetlistBrowserDialog::selected_paths () const { if (browser_page) { - return browser_page->current_nets (); + return browser_page->selected_paths (); } else { - static std::vector empty; - return empty; - } -} - -const std::vector & -NetlistBrowserDialog::selected_devices () const -{ - if (browser_page) { - return browser_page->current_devices (); - } else { - static std::vector empty; - return empty; - } -} - -const std::vector & -NetlistBrowserDialog::selected_subcircuits () const -{ - if (browser_page) { - return browser_page->current_subcircuits (); - } else { - static std::vector empty; - return empty; - } -} - -const std::vector & -NetlistBrowserDialog::selected_circuits () const -{ - if (browser_page) { - return browser_page->current_circuits (); - } else { - static std::vector empty; + static std::vector empty; return empty; } } diff --git a/src/laybasic/laybasic/layNetlistBrowserDialog.h b/src/laybasic/laybasic/layNetlistBrowserDialog.h index 2c3d84bcb..1c350fc78 100644 --- a/src/laybasic/laybasic/layNetlistBrowserDialog.h +++ b/src/laybasic/laybasic/layNetlistBrowserDialog.h @@ -72,22 +72,7 @@ public: /** * @brief Gets the selected nets */ - const std::vector &selected_nets () const; - - /** - * @brief Gets the selected devices - */ - const std::vector &selected_devices () const; - - /** - * @brief Gets the selected subcircuits - */ - const std::vector &selected_subcircuits () const; - - /** - * @brief Gets the selected circuits - */ - const std::vector &selected_circuits () const; + const std::vector &selected_paths () const; /** * @brief An event indicating that the selection has changed diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index 15fabc830..cf055fe0c 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -471,8 +471,18 @@ NetlistBrowserPage::selection_changed () NetlistBrowserModel *model = dynamic_cast (directory_tree->model ()); tl_assert (model != 0); + QModelIndexList selected = directory_tree->selectionModel ()->selectedIndexes (); + + std::vector selected_paths; + selected_paths.reserve (selected.size ()); + for (QModelIndexList::const_iterator i = selected.begin (); i != selected.end (); ++i) { + if (i->column () == 0) { + selected_paths.push_back (model->path_from_index (*i)); + } + } + QModelIndex current = directory_tree->selectionModel ()->currentIndex (); - highlight (model->path_from_index (current)); + highlight (model->path_from_index (current), selected_paths); selection_changed_event (); } @@ -792,11 +802,6 @@ NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb) clear_markers (); - m_current_nets.clear (); - m_current_devices.clear (); - m_current_subcircuits.clear (); - m_current_circuits.clear (); - m_cell_context_cache = db::ContextCache (mp_database.get () ? mp_database->internal_layout () : 0); setup_trees (); @@ -888,11 +893,12 @@ NetlistBrowserPage::setup_trees () } void -NetlistBrowserPage::highlight (const NetlistObjectsPath &path) +NetlistBrowserPage::highlight (const NetlistObjectsPath ¤t_path, const std::vector &selected_paths) { - if (path != m_current_path) { + if (current_path != m_current_path && selected_paths != m_selected_paths) { - m_current_path = path; + m_current_path = current_path; + m_selected_paths = selected_paths; clear_markers (); adjust_view (); @@ -961,24 +967,26 @@ NetlistBrowserPage::adjust_view () const db::Layout &original_layout = mp_view->cellview (m_cv_index)->layout (); const db::Circuit *top_circuit = mp_database->netlist ()->circuit_by_name (original_layout.cell_name (mp_view->cellview (m_cv_index).cell_index ())); - const db::Circuit *circuit = m_current_path.root.first; - if (! circuit) { - return; - } - const db::Layout *layout = mp_database->internal_layout (); const db::Cell *cell = (top_circuit && layout->is_valid_cell_index (top_circuit->cell_index ()) ? &layout->cell (top_circuit->cell_index ()) : mp_database->internal_top_cell ()); if (! layout || ! cell) { return; } - db::DCplxTrans trans; + db::DBox bbox; - if (circuit) { + for (std::vector::const_iterator path = m_selected_paths.begin (); path != m_selected_paths.end (); ++path) { + + const db::Circuit *circuit = path->root.first; + if (! circuit) { + continue; + } + + db::DCplxTrans trans; trans = trans_for (circuit, *layout, *cell, m_cell_context_cache, db::DCplxTrans ()); - for (std::list >::const_iterator p = m_current_path.path.begin (); p != m_current_path.path.end () && circuit; ++p) { + for (std::list >::const_iterator p = path->path.begin (); p != path->path.end () && circuit; ++p) { if (p->first) { circuit = p->first->circuit_ref (); trans = trans * p->first->trans (); @@ -987,16 +995,14 @@ NetlistBrowserPage::adjust_view () } } - } - - db::DBox bbox; - - if (circuit) { + if (! circuit) { + continue; + } db::Box ebox; - const db::Device *device = m_current_path.device.first; - const db::Net *net = m_current_path.net.first; + const db::Device *device = path->device.first; + const db::Net *net = path->net.first; if (device) { @@ -1018,7 +1024,7 @@ NetlistBrowserPage::adjust_view () db::Box layer_bbox; db::recursive_cluster_shape_iterator shapes (mp_database->net_clusters (), *layer, cell_index, cluster_id); while (! shapes.at_end ()) { - layer_bbox += shapes->bbox (); + layer_bbox += shapes->bbox ().transformed (shapes.trans ()); ++shapes; } @@ -1030,7 +1036,7 @@ NetlistBrowserPage::adjust_view () ebox += bbox_for_circuit (layout, circuit); } - bbox = trans * db::CplxTrans (layout->dbu ()) * ebox; + bbox += trans * db::CplxTrans (layout->dbu ()) * ebox; } @@ -1253,38 +1259,12 @@ NetlistBrowserPage::update_highlights () const db::Layout &original_layout = mp_view->cellview (m_cv_index)->layout (); const db::Circuit *top_circuit = mp_database->netlist ()->circuit_by_name (original_layout.cell_name (mp_view->cellview (m_cv_index).cell_index ())); - const db::Circuit *circuit = m_current_path.root.first; - if (! circuit) { - return; - } - const db::Layout *layout = mp_database->internal_layout (); const db::Cell *cell = (top_circuit && layout->is_valid_cell_index (top_circuit->cell_index ()) ? &layout->cell (top_circuit->cell_index ()) : mp_database->internal_top_cell ()); if (! layout || ! cell) { return; } - // computes the transformation supplied by the path - - db::DCplxTrans trans; - - if (circuit) { - - trans = trans_for (circuit, *layout, *cell, m_cell_context_cache, db::DCplxTrans ()); - - for (std::list >::const_iterator p = m_current_path.path.begin (); p != m_current_path.path.end () && circuit; ++p) { - if (p->first) { - circuit = p->first->circuit_ref (); - trans = trans * p->first->trans (); - } else { - circuit = 0; - } - } - - } - - // a map of display properties vs. layer properties - std::map display_by_lp; for (lay::LayerPropertiesConstIterator lp = mp_view->begin_layers (); ! lp.at_end (); ++lp) { if (! lp->has_children () && lp->cellview_index () == int (m_cv_index) && lp->layer_index () >= 0 && (unsigned int) lp->layer_index () < original_layout.layers ()) { @@ -1292,22 +1272,55 @@ NetlistBrowserPage::update_highlights () } } - std::vector tv = mp_view->cv_transform_variants (m_cv_index); - - // correct DBU differences between the storage layout and the original layout - for (std::vector::iterator t = tv.begin (); t != tv.end (); ++t) { - *t = *t * trans * db::DCplxTrans (layout->dbu () / original_layout.dbu ()); - } - size_t n_markers = 0; bool not_all_shapes_are_shown = false; - if (m_current_path.net.first) { - not_all_shapes_are_shown = produce_highlights_for_net (m_current_path.net.first, n_markers, display_by_lp, tv); - } else if (m_current_path.device.first) { - not_all_shapes_are_shown = produce_highlights_for_device (m_current_path.device.first, n_markers, tv); - } else if (circuit) { - not_all_shapes_are_shown = produce_highlights_for_circuit (circuit, n_markers, tv); + for (std::vector::const_iterator path = m_selected_paths.begin (); path != m_selected_paths.end (); ++path) { + + const db::Circuit *circuit = path->root.first; + if (! circuit) { + continue; + } + + // computes the transformation supplied by the path + + db::DCplxTrans trans = trans_for (circuit, *layout, *cell, m_cell_context_cache, db::DCplxTrans ()); + + for (std::list >::const_iterator p = path->path.begin (); p != path->path.end () && circuit; ++p) { + if (p->first) { + circuit = p->first->circuit_ref (); + trans = trans * p->first->trans (); + } else { + circuit = 0; + } + } + + if (! circuit) { + continue; + } + + // a map of display properties vs. layer properties + + // correct DBU differences between the storage layout and the original layout + std::vector tv = mp_view->cv_transform_variants (m_cv_index); + for (std::vector::iterator t = tv.begin (); t != tv.end (); ++t) { + *t = *t * trans * db::DCplxTrans (layout->dbu () / original_layout.dbu ()); + } + + if (path->net.first) { + if (produce_highlights_for_net (path->net.first, n_markers, display_by_lp, tv)) { + not_all_shapes_are_shown = true; + } + } else if (path->device.first) { + if (produce_highlights_for_device (path->device.first, n_markers, tv)) { + not_all_shapes_are_shown = true; + } + } else if (circuit) { + if (produce_highlights_for_circuit (circuit, n_markers, tv)) { + not_all_shapes_are_shown = true; + } + } + } if (not_all_shapes_are_shown) { @@ -1318,7 +1331,6 @@ NetlistBrowserPage::update_highlights () } else { info_label->hide (); } - } void diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.h b/src/laybasic/laybasic/layNetlistBrowserPage.h index 88a48acca..11fb8418d 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.h +++ b/src/laybasic/laybasic/layNetlistBrowserPage.h @@ -179,33 +179,9 @@ public: /** * @brief Gets the selected nets */ - const std::vector ¤t_nets () const + const std::vector &selected_paths () const { - return m_current_nets; - } - - /** - * @brief Gets the selected devices - */ - const std::vector ¤t_devices () const - { - return m_current_devices; - } - - /** - * @brief Gets the selected subcircuits - */ - const std::vector ¤t_subcircuits () const - { - return m_current_subcircuits; - } - - /** - * @brief Gets the selected circuits - */ - const std::vector ¤t_circuits () const - { - return m_current_circuits; + return m_selected_paths; } /** @@ -258,13 +234,8 @@ private: std::vector mp_markers; bool m_enable_updates; bool m_update_needed; - // @@@ TODO: make multiple ... lay::NetlistObjectsPath m_current_path; - // @@@ TODO: remove - std::vector m_current_nets; - std::vector m_current_devices; - std::vector m_current_subcircuits; - std::vector m_current_circuits; + std::vector m_selected_paths; lay::NetInfoDialog *mp_info_dialog; tl::DeferredMethod dm_update_highlights; tl::DeferredMethod dm_rerun_macro; @@ -275,7 +246,7 @@ private: void navigate_to (const QModelIndex &index, bool forward = true); void adjust_view (); void clear_markers (); - void highlight (const lay::NetlistObjectsPath &path); + void highlight (const NetlistObjectsPath ¤t_path, const std::vector &selected_paths); std::vector selected_nets (); std::vector selected_devices (); std::vector selected_subcircuits ();