From a10d56e6b60f04dffeff9a63962e7fd60e8e8853 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 13 Jul 2020 22:11:10 +0200 Subject: [PATCH] WIP: netlist browser - net object paths, single + pairs, tests --- .../laybasic/layNetlistBrowserModel.cc | 69 +++++++++- .../laybasic/layNetlistBrowserModel.h | 68 +++++++++- .../laybasic/layNetlistBrowserPage.cc | 8 +- src/laybasic/laybasic/layNetlistBrowserPage.h | 4 +- .../laybasic/layNetlistBrowserTreeModel.cc | 4 +- .../laybasic/layNetlistBrowserTreeModel.h | 4 +- .../unit_tests/layNetlistBrowserModelTests.cc | 126 +++++++++++++++++- 7 files changed, 259 insertions(+), 24 deletions(-) diff --git a/src/laybasic/laybasic/layNetlistBrowserModel.cc b/src/laybasic/laybasic/layNetlistBrowserModel.cc index 689ad41cb..5e4934951 100644 --- a/src/laybasic/laybasic/layNetlistBrowserModel.cc +++ b/src/laybasic/laybasic/layNetlistBrowserModel.cc @@ -36,6 +36,67 @@ namespace lay { +// ---------------------------------------------------------------------------------- +// NetlistObjectPath implementation + +NetlistObjectsPath +NetlistObjectsPath::from_first (const NetlistObjectPath &p) +{ + NetlistObjectsPath pp; + pp.root.first = p.root; + for (NetlistObjectPath::path_iterator i = p.path.begin (); i != p.path.end (); ++i) { + pp.path.push_back (std::make_pair (*i, (const db::SubCircuit *) 0)); + } + pp.device.first = p.device; + pp.net.first = p.net; + return pp; +} + +NetlistObjectsPath +NetlistObjectsPath::from_second (const NetlistObjectPath &p) +{ + NetlistObjectsPath pp; + pp.root.second = p.root; + for (NetlistObjectPath::path_iterator i = p.path.begin (); i != p.path.end (); ++i) { + pp.path.push_back (std::make_pair ((const db::SubCircuit *) 0, *i)); + } + pp.device.second = p.device; + pp.net.second = p.net; + return pp; +} + +NetlistObjectPath +NetlistObjectsPath::first () const +{ + NetlistObjectPath p; + p.root = root.first; + for (NetlistObjectsPath::path_iterator i = path.begin (); i != path.end (); ++i) { + if (! i->first) { + return NetlistObjectPath (); + } + p.path.push_back (i->first); + } + p.device = device.first; + p.net = net.first; + return p; +} + +NetlistObjectPath +NetlistObjectsPath::second () const +{ + NetlistObjectPath p; + p.root = root.second; + for (NetlistObjectsPath::path_iterator i = path.begin (); i != path.end (); ++i) { + if (! i->second) { + return NetlistObjectPath (); + } + p.path.push_back (i->second); + } + p.device = device.second; + p.net = net.second; + return p; +} + // ---------------------------------------------------------------------------------- // NetColorizer implementation @@ -2435,10 +2496,10 @@ NetlistBrowserModel::data (const QModelIndex &index, int role) const return QVariant (); } -NetlistObjectPath -NetlistBrowserModel::netpath_from_index (const QModelIndex &index) const +NetlistObjectsPath +NetlistBrowserModel::path_from_index (const QModelIndex &index) const { - NetlistObjectPath np; + NetlistObjectsPath np; np.net = net_from_index (index, false); np.device = device_from_index (index, false); @@ -2463,7 +2524,7 @@ NetlistBrowserModel::netpath_from_index (const QModelIndex &index) const } QModelIndex -NetlistBrowserModel::index_from_netpath (const NetlistObjectPath &path) +NetlistBrowserModel::index_from_path (const NetlistObjectsPath &path) { QModelIndex index = index_from_circuit (path.root); diff --git a/src/laybasic/laybasic/layNetlistBrowserModel.h b/src/laybasic/laybasic/layNetlistBrowserModel.h index 1fd624ce8..3d80362e7 100644 --- a/src/laybasic/laybasic/layNetlistBrowserModel.h +++ b/src/laybasic/laybasic/layNetlistBrowserModel.h @@ -179,14 +179,22 @@ private: }; /** - * @brief An object describing the instantiation path of a net + * @brief An object describing the instantiation path of a net, a device or a (sub)circuit pair + * + * This object applies to pairs of these objects. A class providing a path for a single + * object is NetlistObjectPath */ struct LAYBASIC_PUBLIC NetlistObjectPath { - typedef std::list > path_type; + typedef std::list path_type; typedef path_type::const_iterator path_iterator; - NetlistObjectPath () { } + NetlistObjectPath () : root (0), net (0), device (0) { } + + bool is_null () const + { + return ! root; + } bool operator== (const NetlistObjectPath &other) const { @@ -198,6 +206,46 @@ struct LAYBASIC_PUBLIC NetlistObjectPath return ! operator== (other); } + const db::Circuit *root; + std::list path; + const db::Net *net; + const db::Device *device; +}; + +/** + * @brief An object describing the instantiation path of a net, a device or a (sub)circuit pair + * + * This object applies to pairs of these objects. A class providing a path for a single + * object is NetlistObjectPath + */ +struct LAYBASIC_PUBLIC NetlistObjectsPath +{ + typedef std::list > path_type; + typedef path_type::const_iterator path_iterator; + + NetlistObjectsPath () { } + + bool is_null () const + { + return ! root.first && ! root.second; + } + + static NetlistObjectsPath from_first(const NetlistObjectPath &p); + static NetlistObjectsPath from_second (const NetlistObjectPath &p); + + NetlistObjectPath first () const; + NetlistObjectPath second () const; + + bool operator== (const NetlistObjectsPath &other) const + { + return root == other.root && path == other.path && net == other.net && device == other.device; + } + + bool operator!= (const NetlistObjectsPath &other) const + { + return ! operator== (other); + } + std::pair root; std::list > path; std::pair net; @@ -292,8 +340,18 @@ public: QIcon icon_for_connection (const std::pair &net) const; QModelIndex index_from_url (const QString &url) const; - NetlistObjectPath netpath_from_index (const QModelIndex &index) const; - QModelIndex index_from_netpath (const NetlistObjectPath &path); + + NetlistObjectsPath path_from_index (const QModelIndex &index) const; + NetlistObjectPath spath_from_index (const QModelIndex &index) const + { + return path_from_index (index).first (); + } + + QModelIndex index_from_path (const NetlistObjectsPath &path); + QModelIndex index_from_path (const NetlistObjectPath &path) + { + return index_from_path (NetlistObjectsPath::from_first (path)); + } private slots: void colors_changed (); diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index 9f9de9fcb..32a2c8bd0 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -347,7 +347,7 @@ NetlistBrowserPage::current_index_changed (const QModelIndex &index) add_to_history (index, true); - NetlistObjectPath path = netlist_model->netpath_from_index (index); + NetlistObjectsPath path = netlist_model->path_from_index (index); QModelIndex circuit_index = tree_model->index_from_netpath (path); m_signals_enabled = false; @@ -460,7 +460,7 @@ NetlistBrowserPage::selection_changed () tl_assert (model != 0); QModelIndex current = directory_tree->selectionModel ()->currentIndex (); - highlight (model->netpath_from_index (current)); + highlight (model->path_from_index (current)); } void @@ -517,7 +517,7 @@ NetlistBrowserPage::navigate_to (const QModelIndex &index, bool fwd) return; } - lay::NetlistObjectPath path = netlist_model->netpath_from_index (index); + lay::NetlistObjectsPath path = netlist_model->path_from_index (index); QModelIndex circuit_index = tree_model->index_from_netpath (path); hierarchy_tree->setCurrentIndex (circuit_index); @@ -874,7 +874,7 @@ NetlistBrowserPage::setup_trees () } void -NetlistBrowserPage::highlight (const NetlistObjectPath &path) +NetlistBrowserPage::highlight (const NetlistObjectsPath &path) { if (path != m_current_path) { diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.h b/src/laybasic/laybasic/layNetlistBrowserPage.h index 37aff1312..5c0b61f60 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.h +++ b/src/laybasic/laybasic/layNetlistBrowserPage.h @@ -235,7 +235,7 @@ private: bool m_enable_updates; bool m_update_needed; // @@@ TODO: make multiple ... - lay::NetlistObjectPath m_current_path; + lay::NetlistObjectsPath m_current_path; // @@@ TODO: remove std::vector m_current_nets; std::vector m_current_devices; @@ -251,7 +251,7 @@ private: void navigate_to (const QModelIndex &index, bool forward = true); void adjust_view (); void clear_markers (); - void highlight (const lay::NetlistObjectPath &path); + void highlight (const lay::NetlistObjectsPath &path); std::vector selected_nets (); std::vector selected_devices (); std::vector selected_subcircuits (); diff --git a/src/laybasic/laybasic/layNetlistBrowserTreeModel.cc b/src/laybasic/laybasic/layNetlistBrowserTreeModel.cc index db47fad4b..f77138f8f 100644 --- a/src/laybasic/laybasic/layNetlistBrowserTreeModel.cc +++ b/src/laybasic/laybasic/layNetlistBrowserTreeModel.cc @@ -270,13 +270,13 @@ static bool is_compatible (const std::pair sc (p->first ? p->first->circuit_ref () : 0, p->second ? p->second->circuit_ref (): 0); std::pair circuit = circuits_from_index (idx); diff --git a/src/laybasic/laybasic/layNetlistBrowserTreeModel.h b/src/laybasic/laybasic/layNetlistBrowserTreeModel.h index c4fe0696d..d0f182bfc 100644 --- a/src/laybasic/laybasic/layNetlistBrowserTreeModel.h +++ b/src/laybasic/laybasic/layNetlistBrowserTreeModel.h @@ -42,7 +42,7 @@ namespace lay { class IndexedNetlistModel; -struct NetlistObjectPath; +struct NetlistObjectsPath; // ---------------------------------------------------------------------------------- // NetlistBrowserTreeModel definition @@ -78,7 +78,7 @@ public: std::pair circuits_from_index (const QModelIndex &index) const; QModelIndex index_from_circuits (const std::pair &circuits) const; - QModelIndex index_from_netpath (const NetlistObjectPath &path) const; + QModelIndex index_from_netpath (const NetlistObjectsPath &path) const; private: NetlistBrowserTreeModel (const NetlistBrowserTreeModel &); diff --git a/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc b/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc index 19d53cee8..3b951e718 100644 --- a/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc +++ b/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc @@ -417,8 +417,8 @@ TEST (3) db::Circuit *root = l2n.netlist ()->circuit_by_name ("RINGO"); EXPECT_EQ (root != 0, true); - lay::NetlistObjectPath path; - EXPECT_EQ (model->index_from_netpath (path).isValid (), false); + lay::NetlistObjectsPath path; + EXPECT_EQ (model->index_from_path (path).isValid (), false); path.root.first = root; @@ -427,7 +427,7 @@ TEST (3) path.net.first = net; - QModelIndex index = model->index_from_netpath (path); + QModelIndex index = model->index_from_path (path); EXPECT_EQ (index.isValid (), true); EXPECT_EQ (tl::to_string (model->data (index, Qt::UserRole).toString ()), "FB"); @@ -444,7 +444,7 @@ TEST (4) db::Circuit *root = l2n.netlist ()->circuit_by_name ("RINGO"); EXPECT_EQ (root != 0, true); - lay::NetlistObjectPath path; + lay::NetlistObjectsPath path; path.root.first = root; db::SubCircuit *sc1 = root->begin_subcircuits ().operator-> (); @@ -456,8 +456,124 @@ TEST (4) path.net.first = net; - QModelIndex index = model->index_from_netpath (path); + QModelIndex index = model->index_from_path (path); EXPECT_EQ (index.isValid (), true); EXPECT_EQ (tl::to_string (model->data (index, Qt::UserRole).toString ()), "NOUT"); } + +// Netlist object path: single vs. pairs - first +TEST (5) +{ + db::LayoutVsSchematic lvs; + lvs.load (tl::testsrc () + "/testdata/lay/lvsdb_browser.lvsdb"); + + lay::NetColorizer colorizer; + std::auto_ptr model (new lay::NetlistBrowserModel (0, &lvs, &colorizer)); + QModelIndex idx; + + db::Circuit *root = lvs.netlist ()->circuit_by_name ("INV2PAIR"); + EXPECT_EQ (root != 0, true); + db::Circuit *sc = lvs.netlist ()->circuit_by_name ("INV2"); + EXPECT_EQ (sc != 0, true); + + lay::NetlistObjectPath path; + EXPECT_EQ (path.is_null (), true); + path.root = root; + EXPECT_EQ (path.is_null (), false); + + idx = model->index_from_path (path); + EXPECT_EQ (idx.isValid (), true); + EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "INV2PAIR|INV2PAIR"); + EXPECT_EQ (path == model->path_from_index (idx).first (), true); + + path.net = root->net_by_cluster_id (5); + idx = model->index_from_path (lay::NetlistObjectsPath::from_first (path)); + EXPECT_EQ (idx.isValid (), true); + EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "$5|4"); + EXPECT_EQ (path == model->path_from_index (idx).first (), true); + + path.path.push_back (root->subcircuit_by_id (1)); + EXPECT_EQ (path.path.back () != 0, true); + EXPECT_EQ (path.path.back ()->expanded_name (), "$1"); + EXPECT_EQ (path.path.back ()->circuit_ref ()->name (), "INV2"); + + path.net = 0; + idx = model->index_from_path (lay::NetlistObjectsPath::from_first (path)); + EXPECT_EQ (idx.isValid (), true); + // A pure subcircuit path addresses the "Circuit" representative node of the subcircuit + EXPECT_EQ (tl::to_string (model->data (idx, Qt::DisplayRole).toString ()), "Circuit"); + EXPECT_EQ (tl::to_string (model->data (model->parent (idx), Qt::UserRole).toString ()), "INV2|$1"); + EXPECT_EQ (path == model->path_from_index (idx).first (), true); + + path.net = sc->net_by_cluster_id (2); + idx = model->index_from_path (lay::NetlistObjectsPath::from_first (path)); + EXPECT_EQ (idx.isValid (), true); + EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "IN|2"); + EXPECT_EQ (path == model->path_from_index (idx).first (), true); + + path.net = 0; + path.device = sc->device_by_id (1); + idx = model->index_from_path (lay::NetlistObjectsPath::from_first (path)); + EXPECT_EQ (idx.isValid (), true); + EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "$1|$1|PMOS|PMOS"); + EXPECT_EQ (path == model->path_from_index (idx).first (), true); +} + +// Netlist object path: single vs. pairs - second +TEST (6) +{ + db::LayoutVsSchematic lvs; + lvs.load (tl::testsrc () + "/testdata/lay/lvsdb_browser.lvsdb"); + + lay::NetColorizer colorizer; + std::auto_ptr model (new lay::NetlistBrowserModel (0, &lvs, &colorizer)); + QModelIndex idx; + + db::Circuit *root = lvs.reference_netlist ()->circuit_by_name ("INV2PAIR"); + EXPECT_EQ (root != 0, true); + db::Circuit *sc = lvs.reference_netlist ()->circuit_by_name ("INV2"); + EXPECT_EQ (sc != 0, true); + + lay::NetlistObjectPath path; + EXPECT_EQ (path.is_null (), true); + path.root = root; + EXPECT_EQ (path.is_null (), false); + + idx = model->index_from_path (lay::NetlistObjectsPath::from_second (path)); + EXPECT_EQ (idx.isValid (), true); + EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "INV2PAIR|INV2PAIR"); + EXPECT_EQ (path == model->path_from_index (idx).second (), true); + + path.net = root->net_by_name ("4"); + idx = model->index_from_path (lay::NetlistObjectsPath::from_second (path)); + EXPECT_EQ (idx.isValid (), true); + EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "$5|4"); + EXPECT_EQ (path == model->path_from_index (idx).second (), true); + + path.path.push_back (root->subcircuit_by_name ("$2")); + EXPECT_EQ (path.path.back () != 0, true); + EXPECT_EQ (path.path.back ()->expanded_name (), "$2"); + EXPECT_EQ (path.path.back ()->circuit_ref ()->name (), "INV2"); + + path.net = 0; + idx = model->index_from_path (lay::NetlistObjectsPath::from_second (path)); + EXPECT_EQ (idx.isValid (), true); + // A pure subcircuit path addresses the "Circuit" representative node of the subcircuit + EXPECT_EQ (tl::to_string (model->data (idx, Qt::DisplayRole).toString ()), "Circuit"); + EXPECT_EQ (tl::to_string (model->data (model->parent (idx), Qt::UserRole).toString ()), "INV2|$2"); + EXPECT_EQ (path == model->path_from_index (idx).second (), true); + + path.net = sc->net_by_name ("2"); + idx = model->index_from_path (lay::NetlistObjectsPath::from_second (path)); + EXPECT_EQ (idx.isValid (), true); + EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "IN|2"); + EXPECT_EQ (path == model->path_from_index (idx).second (), true); + + path.net = 0; + path.device = sc->device_by_id (1); + idx = model->index_from_path (lay::NetlistObjectsPath::from_second (path)); + EXPECT_EQ (idx.isValid (), true); + EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "$1|$1|PMOS|PMOS"); + EXPECT_EQ (path == model->path_from_index (idx).second (), true); +}