From ae9064021ccd21cc90a361fc3b8b2dad57b62a61 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 21 Apr 2019 10:41:20 +0200 Subject: [PATCH] WIP: netlist browser. --- src/db/db/dbCircuit.h | 24 + src/db/db/dbNetlist.h | 8 + src/laybasic/laybasic/NetlistBrowserDialog.ui | 3 +- src/laybasic/laybasic/gsiDeclLayLayoutView.cc | 20 + src/laybasic/laybasic/layLayoutView.cc | 8 +- .../laybasic/layNetlistBrowserDialog.cc | 2 +- .../laybasic/layNetlistBrowserPage.cc | 913 ++++++++++++++++++ 7 files changed, 974 insertions(+), 4 deletions(-) diff --git a/src/db/db/dbCircuit.h b/src/db/db/dbCircuit.h index 042a3e144..021b0e97a 100644 --- a/src/db/db/dbCircuit.h +++ b/src/db/db/dbCircuit.h @@ -309,6 +309,14 @@ public: */ void remove_net (Net *net); + /** + * @brief Gets the number of nets + */ + size_t net_count () const + { + return m_nets.size (); + } + /** * @brief Begin iterator for the nets of the circuit (non-const version) */ @@ -393,6 +401,14 @@ public: */ void remove_device (Device *device); + /** + * @brief Gets the number of devices + */ + size_t device_count () const + { + return m_nets.size (); + } + /** * @brief Gets the device from a given ID (const version) * @@ -477,6 +493,14 @@ public: */ void remove_subcircuit (SubCircuit *subcircuit); + /** + * @brief Gets the number of subcircuits + */ + size_t subcircuit_count () const + { + return m_subcircuits.size (); + } + /** * @brief Gets the subcircuit from a given ID (const version) * diff --git a/src/db/db/dbNetlist.h b/src/db/db/dbNetlist.h index 95555d29c..3dd848b86 100644 --- a/src/db/db/dbNetlist.h +++ b/src/db/db/dbNetlist.h @@ -138,6 +138,14 @@ public: */ void remove_circuit (Circuit *circuit); + /** + * @brief Gets the number of circuits + */ + size_t circuit_count () const + { + return m_circuits.size (); + } + /** * @brief Flattens the given circuit * All subcircuit references are replaced by the content of this circuit. diff --git a/src/laybasic/laybasic/NetlistBrowserDialog.ui b/src/laybasic/laybasic/NetlistBrowserDialog.ui index c8be982eb..7cde819e6 100644 --- a/src/laybasic/laybasic/NetlistBrowserDialog.ui +++ b/src/laybasic/laybasic/NetlistBrowserDialog.ui @@ -230,8 +230,7 @@ Choose "Open" from the "File ..." menu -to load a netlist, a net database -or a LVS cross-reference +to load a netlist or a netlist/LVS database Qt::AlignCenter diff --git a/src/laybasic/laybasic/gsiDeclLayLayoutView.cc b/src/laybasic/laybasic/gsiDeclLayLayoutView.cc index f4093f94c..f60483dbb 100644 --- a/src/laybasic/laybasic/gsiDeclLayLayoutView.cc +++ b/src/laybasic/laybasic/gsiDeclLayLayoutView.cc @@ -1422,6 +1422,16 @@ Class decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou "@brief Gets the report database with the given index\n" "@return The \\ReportDatabase object or nil if the index is not valid" ) + + gsi::method ("add_rdb", &lay::LayoutView::add_rdb, gsi::arg ("db"), + "@brief Adds the given database to the view\n" + "\n" + "This method will add an existing database to the view. It will then appear in the marker database browser.\n" + "A similar method is \\create_rdb which will create a new database within the view.\n" + "\n" + "@return The index of the database within the view (see \\rdb)\n" + "\n" + "This method has been added in version 0.26." + ) + gsi::method_ext ("create_rdb", &create_rdb, gsi::arg ("name"), "@brief Creates a new report database and returns the index of the new database\n" "@param name The name of the new report database\n" @@ -1460,6 +1470,16 @@ Class decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou "\n" "This method has been added in version 0.26." ) + + gsi::method ("add_l2ndb", &lay::LayoutView::add_l2ndb, gsi::arg ("db"), + "@brief Adds the given database to the view\n" + "\n" + "This method will add an existing database to the view. It will then appear in the netlist database browser.\n" + "A similar method is \\create_l2ndb which will create a new database within the view.\n" + "\n" + "@return The index of the database within the view (see \\l2ndb)\n" + "\n" + "This method has been added in version 0.26." + ) + gsi::method_ext ("create_l2ndb", &create_l2ndb, gsi::arg ("name"), "@brief Creates a new netlist database and returns the index of the new database\n" "@param name The name of the new netlist database\n" diff --git a/src/laybasic/laybasic/layLayoutView.cc b/src/laybasic/laybasic/layLayoutView.cc index 92b128231..a59d02907 100644 --- a/src/laybasic/laybasic/layLayoutView.cc +++ b/src/laybasic/laybasic/layLayoutView.cc @@ -7090,7 +7090,7 @@ static void make_unique_name (T *object, Iter from, Iter to) do { - bool found = false; + bool found = n.empty (); for (Iter i = from; i != to && !found; ++i) { if ((*i)->name () == n) { found = true; @@ -7114,6 +7114,9 @@ LayoutView::add_l2ndb (db::LayoutToNetlist *l2ndb) make_unique_name (l2ndb, m_l2ndbs.begin (), m_l2ndbs.end ()); m_l2ndbs.push_back (l2ndb); + // Mark this object as owned by us (for GSI) + l2ndb->keep (); + l2ndb_list_changed_event (); return (unsigned int)(m_l2ndbs.size () - 1); @@ -7164,6 +7167,9 @@ LayoutView::add_rdb (rdb::Database *rdb) make_unique_name (rdb, m_l2ndbs.begin (), m_l2ndbs.end ()); m_rdbs.push_back (rdb); + // Mark this object as owned by us (for GSI) + rdb->keep (); + rdb_list_changed_event (); return (unsigned int)(m_rdbs.size () - 1); diff --git a/src/laybasic/laybasic/layNetlistBrowserDialog.cc b/src/laybasic/laybasic/layNetlistBrowserDialog.cc index 65949b6fc..072b3c6b6 100644 --- a/src/laybasic/laybasic/layNetlistBrowserDialog.cc +++ b/src/laybasic/laybasic/layNetlistBrowserDialog.cc @@ -562,7 +562,7 @@ NetlistBrowserDialog::deactivated () void NetlistBrowserDialog::menu_activated (const std::string &symbol) { - if (symbol == "marker_browser::show") { + if (symbol == "netlist_browser::show") { view ()->deactivate_all_browsers (); activate (); } else { diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index 9de2c56f4..a24d779cb 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -22,12 +22,925 @@ #include "layNetlistBrowserPage.h" +#include "dbLayoutToNetlist.h" namespace lay { extern std::string cfg_l2ndb_show_all; +// ---------------------------------------------------------------------------------- +// NetlistBrowserModel definition and implementation + +/** + * @brief The NetlistBrowserModel + * + * The model hierarchy is the following + * - circuits + * - 0..#pins: pins + * - net (1x) + * - #pins..#pins+#nets: nets + * - 0..#devices: terminals + * - other terminals and nets + * - #devices..#devices+#pins: pins + * - #devices+#pins..: subcircuit pins + * - other pins and nets + * - #pins+#nets..#pins+#nets+#subcircuits: subcircuits + * - pins and nets + * - #pins+#nets+#subcircuits..: devices + * - terminals and nets + */ +class NetlistBrowserModel + : public QAbstractItemModel +{ +public: + NetlistBrowserModel (db::LayoutToNetlist *l2ndb); + + virtual int columnCount (const QModelIndex &parent) const; + virtual QVariant data (const QModelIndex &index, int role) const; + virtual Qt::ItemFlags flags (const QModelIndex &index) const; + virtual bool hasChildren (const QModelIndex &parent) const; + virtual QVariant headerData (int section, Qt::Orientation orientation, int role) const; + virtual QModelIndex index (int row, int column, const QModelIndex &parent) const; + virtual QModelIndex parent (const QModelIndex &index) const; + virtual int rowCount (const QModelIndex &parent) const; + +private: + + static inline void *make_id (size_t i1) + { + return reinterpret_cast (i1); + } + + static inline void *make_id (size_t i1, size_t n1, size_t i2) + { + return reinterpret_cast (i1 + n1 * i2); + } + + static inline void *make_id (size_t i1, size_t n1, size_t i2, size_t n2, size_t i3) + { + return reinterpret_cast (i1 + n1 * (i2 + n2 * i3)); + } + + static inline void *make_id (size_t i1, size_t n1, size_t i2, size_t n2, size_t i3, size_t n3, size_t i4) + { + return reinterpret_cast (i1 + n1 * (i2 + n2 * (i3 + n3 * i4))); + } + + static inline void *make_id (size_t i1, size_t n1, size_t i2, size_t n2, size_t i3, size_t n3, size_t i4, size_t n4, size_t i5) + { + return reinterpret_cast (i1 + n1 * (i2 + n2 * (i3 + n3 * (i4 + n4 * i5)))); + } + + static inline void *make_id (size_t i1, size_t n1, size_t i2, size_t n2, size_t i3, size_t n3, size_t i4, size_t n4, size_t i5, size_t n5, size_t i6) + { + return reinterpret_cast (i1 + n1 * (i2 + n2 * (i3 + n3 * (i4 + n4 * (i5 + n5 * i6))))); + } + + static inline size_t pop (void *&idp, size_t n) + { + size_t id = reinterpret_cast (idp); + size_t i = id % n; + id /= n; + idp = reinterpret_cast (id); + return i; + } + + static inline bool always (bool) + { + return true; + } + + virtual void *make_id_circuit (size_t circuit_index) const + { + return make_id (circuit_index); + } + + virtual void *make_id_circuit_pin (size_t circuit_index, size_t pin_index) const + { + return make_id (circuit_index, netlist ()->circuit_count (), 1, 8, pin_index); + } + + void *make_id_circuit_pin_net (size_t circuit_index, size_t pin_index, size_t net_index) const + { + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 1, 8, pin_index, circuit->pin_count (), net_index); + } + + void *make_id_circuit_net (size_t circuit_index, size_t net_index) const + { + return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index); + } + + void *make_id_circuit_net_device_terminal (size_t circuit_index, size_t net_index, size_t terminal_ref_index) const + { + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index, circuit->net_count (), 1, 4, terminal_ref_index); + } + + void *make_id_circuit_net_device_terminal_others (size_t circuit_index, size_t net_index, size_t terminal_ref_index, size_t other_index) const + { + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + db::Net *net = net_from_id (make_id_circuit_net (circuit_index, net_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index, circuit->net_count (), 1, 4, terminal_ref_index, net->terminal_count (), other_index + 1); + } + + void *make_id_circuit_net_pin (size_t circuit_index, size_t net_index, size_t pin_index) const + { + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index, circuit->net_count (), 2, 4, pin_index); + } + + void *make_id_circuit_net_subcircuit_pin (size_t circuit_index, size_t net_index, size_t pin_ref_index) const + { + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index, circuit->net_count (), 3, 4, pin_ref_index); + } + + void *make_id_circuit_net_subcircuit_pin_others (size_t circuit_index, size_t net_index, size_t pin_ref_index, size_t other_index) const + { + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + db::Net *net = net_from_id (make_id_circuit_net (circuit_index, net_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index, circuit->net_count (), 3, 4, pin_ref_index, net->subcircuit_pin_count (), other_index + 1); + } + + void *make_id_circuit_subcircuit (size_t circuit_index, size_t subcircuit_index) const + { + return make_id (circuit_index, netlist ()->circuit_count (), 3, 8, subcircuit_index); + } + + void *make_id_circuit_subcircuit_pin (size_t circuit_index, size_t subcircuit_index, size_t pin_index) const + { + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 3, 8, subcircuit_index, circuit->subcircuit_count (), pin_index + 1); + } + + void *make_id_circuit_device (size_t circuit_index, size_t device_index) const + { + return make_id (circuit_index, netlist ()->circuit_count (), 4, 8, device_index); + } + + void *make_id_circuit_device_terminal (size_t circuit_index, size_t device_index, size_t terminal_index) const + { + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 4, 8, device_index, circuit->device_count (), terminal_index + 1); + } + + bool is_id_circuit (void *id) const + { + pop (id, netlist ()->circuit_count ()); + return id == 0; + } + + bool is_id_circuit_pin (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 1 && always (pop (id, circuit->pin_count ())) && id == 0); + } + + bool is_id_circuit_pin_net (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 1 && always (pop (id, circuit->pin_count ())) && id != 0); + } + + bool is_id_circuit_net (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && id == 0); + } + + bool is_id_circuit_net_device_terminal (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && pop (id, 4) == 1 && always (pop (id, net->terminal_count ())) && id == 0); + } + + bool is_id_circuit_net_device_terminal_others (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && pop (id, 4) == 1 && always (pop (id, net->terminal_count ())) && id != 0); + } + + bool is_id_circuit_net_pin (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && pop (id, 4) == 2); + } + + bool is_id_circuit_net_subcircuit_pin (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && pop (id, 4) == 3 && always (pop (id, net->subcircuit_pin_count ())) && id == 0); + } + + bool is_id_circuit_net_subcircuit_pin_others (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && pop (id, 4) == 3 && always (pop (id, net->subcircuit_pin_count ())) && id != 0); + } + + bool is_id_circuit_subcircuit (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 3 && always (pop (id, circuit->subcircuit_count ())) && id == 0); + } + + bool is_id_circuit_subcircuit_pin (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 3 && always (pop (id, circuit->subcircuit_count ())) && id != 0); + } + + bool is_id_circuit_device (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 4 && always (pop (id, circuit->device_count ())) && id == 0); + } + + bool is_id_circuit_device_terminal (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 4 && always (pop (id, circuit->device_count ())) && id != 0); + } + + size_t circuit_index_from_id (void *id) const + { + return pop (id, netlist ()->circuit_count ()); + } + + size_t circuit_pin_index_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + return pop (id, circuit->pin_count ()); + } + + size_t circuit_device_index_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + return pop (id, circuit->device_count ()); + } + + size_t circuit_device_terminal_index_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + pop (id, circuit->device_count ()); + return reinterpret_cast (id) - 1; + } + + size_t circuit_subcircuit_index_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + return pop (id, circuit->subcircuit_count ()); + } + + size_t circuit_subcircuit_pin_index_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + pop (id, circuit->subcircuit_count ()); + return reinterpret_cast (id) - 1; + } + + size_t circuit_net_index_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + return pop (id, circuit->net_count ()); + } + + size_t circuit_net_subcircuit_pin_index_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + pop (id, circuit->net_count ()); + pop (id, 4); + return pop (id, net->subcircuit_pin_count ()); + } + + size_t circuit_net_subcircuit_pin_other_index_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + pop (id, circuit->net_count ()); + pop (id, 4); + pop (id, net->subcircuit_pin_count ()); + return reinterpret_cast (id) - 1; + } + + size_t circuit_net_device_terminal_index_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + pop (id, circuit->net_count ()); + pop (id, 4); + return pop (id, net->terminal_count ()); + } + + size_t circuit_net_device_terminal_other_index_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + pop (id, circuit->net_count ()); + pop (id, 4); + pop (id, net->terminal_count ()); + return reinterpret_cast (id) - 1; + } + + db::Circuit *circuit_from_id (void *id) const + { + size_t index = circuit_index_from_id (id); + + std::map::iterator c = m_circuit_by_index.find (index); + if (c == m_circuit_by_index.end ()) { + + c = m_circuit_by_index.insert (std::make_pair (index, (db::Circuit *) 0)).first; + for (db::Netlist::circuit_iterator i = netlist ()->begin_circuits (); i != netlist ()->end_circuits (); ++i) { + if (index-- == 0) { + c->second = i.operator-> (); + break; + } + } + + } + + return c->second; + } + + db::Net *net_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + size_t index = circuit_net_index_from_id (id); + + std::map >::iterator cc = m_net_by_circuit_and_index.find (circuit); + if (cc != m_net_by_circuit_and_index.end ()) { + cc = m_net_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; + } + + std::map::iterator c = cc->second.find (index); + if (c == cc->second.end ()) { + + c = cc->second.insert (std::make_pair (index, (db::Net *) 0)).first; + for (db::Circuit::net_iterator i = circuit->begin_nets (); i != circuit->end_nets (); ++i) { + if (index-- == 0) { + c->second = i.operator-> (); + break; + } + } + + } + + return c->second; + } + + const db::NetSubcircuitPinRef *net_pinref_from_id (void *id) const + { + db::Net *net = net_from_id (id); + size_t index = circuit_net_subcircuit_pin_index_from_id (id); + + std::map >::iterator cc = m_pinref_by_net_and_index.find (net); + if (cc != m_pinref_by_net_and_index.end ()) { + cc = m_pinref_by_net_and_index.insert (std::make_pair (net, std::map ())).first; + } + + std::map::iterator c = cc->second.find (index); + if (c == cc->second.end ()) { + + c = cc->second.insert (std::make_pair (index, (db::NetSubcircuitPinRef *) 0)).first; + for (db::Net::subcircuit_pin_iterator i = net->begin_subcircuit_pins (); i != net->end_subcircuit_pins (); ++i) { + if (index-- == 0) { + c->second = i.operator-> (); + break; + } + } + + } + + return c->second; + } + + const db::NetTerminalRef *net_terminalref_from_id (void *id) const + { + db::Net *net = net_from_id (id); + size_t index = circuit_net_device_terminal_index_from_id (id); + + std::map >::iterator cc = m_terminalref_by_net_and_index.find (net); + if (cc != m_terminalref_by_net_and_index.end ()) { + cc = m_terminalref_by_net_and_index.insert (std::make_pair (net, std::map ())).first; + } + + std::map::iterator c = cc->second.find (index); + if (c == cc->second.end ()) { + + c = cc->second.insert (std::make_pair (index, (db::NetTerminalRef *) 0)).first; + for (db::Net::terminal_iterator i = net->begin_terminals (); i != net->end_terminals (); ++i) { + if (index-- == 0) { + c->second = i.operator-> (); + break; + } + } + + } + + return c->second; + } + + db::Device *device_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + size_t index = circuit_device_index_from_id (id); + + std::map >::iterator cc = m_device_by_circuit_and_index.find (circuit); + if (cc != m_device_by_circuit_and_index.end ()) { + cc = m_device_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; + } + + std::map::iterator c = cc->second.find (index); + if (c == cc->second.end ()) { + + c = cc->second.insert (std::make_pair (index, (db::Device *) 0)).first; + for (db::Circuit::device_iterator i = circuit->begin_devices (); i != circuit->end_devices (); ++i) { + if (index-- == 0) { + c->second = i.operator-> (); + break; + } + } + + } + + return c->second; + } + + db::Pin *pin_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + size_t index = circuit_pin_index_from_id (id); + + std::map >::iterator cc = m_pin_by_circuit_and_index.find (circuit); + if (cc != m_pin_by_circuit_and_index.end ()) { + cc = m_pin_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; + } + + std::map::iterator c = cc->second.find (index); + if (c == cc->second.end ()) { + + c = cc->second.insert (std::make_pair (index, (db::Pin *) 0)).first; + for (db::Circuit::pin_iterator i = circuit->begin_pins (); i != circuit->end_pins (); ++i) { + if (index-- == 0) { + c->second = i.operator-> (); + break; + } + } + + } + + return c->second; + } + + db::SubCircuit *subcircuit_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + size_t index = circuit_subcircuit_index_from_id (id); + + std::map >::iterator cc = m_subcircuit_by_circuit_and_index.find (circuit); + if (cc != m_subcircuit_by_circuit_and_index.end ()) { + cc = m_subcircuit_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; + } + + std::map::iterator c = cc->second.find (index); + if (c == cc->second.end ()) { + + c = cc->second.insert (std::make_pair (index, (db::SubCircuit *) 0)).first; + for (db::Circuit::subcircuit_iterator i = circuit->begin_subcircuits (); i != circuit->end_subcircuits (); ++i) { + if (index-- == 0) { + c->second = i.operator-> (); + break; + } + } + + } + + return c->second; + } + + db::Netlist *netlist () const + { + return const_cast (mp_l2ndb->netlist ()); + } + + db::LayoutToNetlist *mp_l2ndb; + mutable std::map m_circuit_by_index; + mutable std::map > m_net_by_circuit_and_index; + mutable std::map > m_pinref_by_net_and_index; + mutable std::map > m_terminalref_by_net_and_index; + mutable std::map > m_device_by_circuit_and_index; + mutable std::map > m_pin_by_circuit_and_index; + mutable std::map > m_subcircuit_by_circuit_and_index; +}; + +NetlistBrowserModel::NetlistBrowserModel (db::LayoutToNetlist *l2ndb) + : mp_l2ndb (l2ndb) +{ + // .. nothing yet .. +} + +int +NetlistBrowserModel::columnCount (const QModelIndex & /*parent*/) const +{ + // Item type & icon, link or description + return 2; +} + +QVariant +NetlistBrowserModel::data (const QModelIndex &index, int role) const +{ + if (role != Qt::DisplayRole || ! index.isValid ()) { + return QVariant (); + } + + void *id = index.internalPointer (); + + /* + * - circuits + * - 0..#pins: pins + * - net (1x) + * - #pins..#pins+#nets: nets + * - 0..#devices: terminals + * - other terminals and nets + * - #devices..#devices+#pins: pins + * - #devices+#pins..: subcircuit pins + * - other pins and nets + * - #pins+#nets..#pins+#nets+#subcircuits: subcircuits + * - pins and nets + * - #pins+#nets+#subcircuits..: devices + * - terminals and nets + */ + + if (is_id_circuit (id)) { + + db::Circuit *circuit = circuit_from_id (id); + if (circuit) { + return tl::to_qstring (circuit->name ()); + } + + } else if (is_id_circuit_pin (id) || is_id_circuit_net_subcircuit_pin_others (id)) { + + db::Pin *pin = pin_from_id (id); + if (pin) { + return tl::to_qstring (pin->expanded_name ()); + } + + } else if (is_id_circuit_device (id)) { + + db::Device *device = device_from_id (id); + if (device) { + return tl::to_qstring (device->expanded_name ()); + } + + } else if (is_id_circuit_subcircuit (id)) { + + db::SubCircuit *subcircuit = subcircuit_from_id (id); + if (subcircuit) { + return tl::to_qstring (subcircuit->expanded_name ()); + } + + } else if (is_id_circuit_net (id)) { + + db::Net *net = net_from_id (id); + if (net) { + return tl::to_qstring (net->expanded_name ()); + } + + } else if (is_id_circuit_net_subcircuit_pin (id)) { + + const db::NetSubcircuitPinRef *ref = net_pinref_from_id (id); + if (ref && ref->pin ()) { + return tl::to_qstring (ref->pin ()->expanded_name ()); + } + + } else if (is_id_circuit_net_device_terminal (id)) { + + const db::NetTerminalRef *ref = net_terminalref_from_id (id); + if (ref && ref->terminal_def ()) { + return tl::to_qstring (ref->terminal_def ()->name ()); + } + + } else if (is_id_circuit_net_device_terminal_others (id)) { + + const db::NetTerminalRef *ref = net_terminalref_from_id (id); + size_t other_index = circuit_net_device_terminal_other_index_from_id (id); + + if (ref && ref->device_class () && ref->device_class ()->terminal_definitions ().size () > other_index) { + const db::DeviceTerminalDefinition &def = ref->device_class ()->terminal_definitions ()[other_index]; + return tl::to_qstring (def.name ()); + } + + } + + return QVariant (); +} + +Qt::ItemFlags +NetlistBrowserModel::flags (const QModelIndex & /*index*/) const +{ + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; +} + +bool +NetlistBrowserModel::hasChildren (const QModelIndex &parent) const +{ + if (! parent.isValid ()) { + + return mp_l2ndb->netlist () && mp_l2ndb->netlist ()->circuit_count () > 0; + + } else { + + void *id = parent.internalPointer (); + + if (is_id_circuit (id)) { + db::Circuit *circuit = circuit_from_id (id); + return circuit->device_count () + circuit->pin_count () + circuit->net_count () + circuit->subcircuit_count () > 0; + } else if (is_id_circuit_pin (id)) { + return true; + } else if (is_id_circuit_device (id)) { + db::Device *device = device_from_id (id); + return device->device_class () && ! device->device_class ()->terminal_definitions ().empty (); + } else if (is_id_circuit_subcircuit (id)) { + db::SubCircuit *subcircuit = subcircuit_from_id (id); + return subcircuit->circuit_ref () && subcircuit->circuit_ref ()->pin_count () > 0; + } else if (is_id_circuit_net (id)) { + db::Net *net = net_from_id (id); + return net->pin_count () + net->subcircuit_pin_count () + net->terminal_count () > 0; + } else if (is_id_circuit_net_subcircuit_pin (id)) { + const db::NetSubcircuitPinRef *ref = net_pinref_from_id (id); + return ref->subcircuit ()->circuit_ref () && ref->subcircuit ()->circuit_ref ()->pin_count () > 0; + } else if (is_id_circuit_net_device_terminal (id)) { + const db::NetTerminalRef *ref = net_terminalref_from_id (id); + return ref->device_class () && ! ref->device_class ()->terminal_definitions ().empty (); + } else { + return false; + } + + } +} + +QVariant +NetlistBrowserModel::headerData (int /*section*/, Qt::Orientation /*orientation*/, int /*role*/) const +{ + return QVariant (); +} + +QModelIndex +NetlistBrowserModel::index (int row, int column, const QModelIndex &parent) const +{ + if (! parent.isValid ()) { + + return createIndex (row, column, make_id_circuit (row)); + + } else { + + void *id = parent.internalPointer (); + + /* + * - circuits + * - 0..#pins: pins + * - net (1x) + * - #pins..#pins+#nets: nets + * - 0..#devices: terminals + * - other terminals and nets + * - #devices..#devices+#pins: pins + * - #devices+#pins..: subcircuit pins + * - other pins and nets + * - #pins+#nets..#pins+#nets+#subcircuits: subcircuits + * - pins and nets + * - #pins+#nets+#subcircuits..: devices + * - terminals and nets + */ + + if (is_id_circuit (id)) { + + db::Circuit *circuit = circuit_from_id (id); + if (size_t (row) < circuit->pin_count ()) { + return createIndex (row, column, make_id_circuit_pin (circuit_index_from_id (id), row)); + } + row -= int (circuit->pin_count ()); + if (size_t (row) < circuit->net_count ()) { + return createIndex (row, column, make_id_circuit_net (circuit_index_from_id (id), row)); + } + row -= int (circuit->net_count ()); + if (size_t (row) < circuit->subcircuit_count ()) { + return createIndex (row, column, make_id_circuit_subcircuit (circuit_index_from_id (id), row)); + } + row -= int (circuit->subcircuit_count ()); + if (size_t (row) < circuit->device_count ()) { + return createIndex (row, column, make_id_circuit_device (circuit_index_from_id (id), row)); + } + + } else if (is_id_circuit_pin (id)) { + + return createIndex (row, column, make_id_circuit_pin_net (circuit_index_from_id (id), circuit_pin_index_from_id (id), row)); + + } else if (is_id_circuit_device (id)) { + + return createIndex (row, column, make_id_circuit_device_terminal (circuit_index_from_id (id), circuit_device_index_from_id (id), row)); + + } else if (is_id_circuit_subcircuit (id)) { + + return createIndex (row, column, make_id_circuit_subcircuit_pin (circuit_index_from_id (id), circuit_subcircuit_index_from_id (id), row)); + + } else if (is_id_circuit_net (id)) { + + db::Net *net = net_from_id (id); + if (size_t (row) < net->terminal_count ()) { + return createIndex (row, column, make_id_circuit_net_device_terminal (circuit_index_from_id (id), circuit_net_index_from_id (id), row)); + } + row -= int (net->terminal_count ()); + if (size_t (row) < net->pin_count ()) { + return createIndex (row, column, make_id_circuit_net_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), row)); + } + row -= int (net->pin_count ()); + if (size_t (row) < net->subcircuit_pin_count ()) { + return createIndex (row, column, make_id_circuit_net_subcircuit_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), row)); + } + + } else if (is_id_circuit_net_subcircuit_pin (id)) { + + return createIndex (row, column, make_id_circuit_net_subcircuit_pin_others (circuit_index_from_id (id), circuit_net_index_from_id (id), circuit_net_subcircuit_pin_index_from_id (id), row)); + + } else if (is_id_circuit_net_device_terminal (id)) { + + return createIndex (row, column, make_id_circuit_net_device_terminal_others (circuit_index_from_id (id), circuit_net_index_from_id (id), circuit_net_device_terminal_index_from_id (id), row)); + + } + + } + + return QModelIndex (); +} + +QModelIndex +NetlistBrowserModel::parent (const QModelIndex &index) const +{ + if (! index.isValid ()) { + + return QModelIndex (); + + } else { + + void *id = index.internalPointer (); + int column = index.column (); + + /* + * - circuits + * - 0..#pins: pins + * - net (1x) + * - #pins..#pins+#nets: nets + * - 0..#devices: terminals + * - other terminals and nets + * - #devices..#devices+#pins: pins + * - #devices+#pins..: subcircuit pins + * - other pins and nets + * - #pins+#nets..#pins+#nets+#subcircuits: subcircuits + * - pins and nets + * - #pins+#nets+#subcircuits..: devices + * - terminals and nets + */ + + if (is_id_circuit (id)) { + + return QModelIndex (); + + } else if (is_id_circuit_pin (id) || is_id_circuit_net (id) || is_id_circuit_device (id) || is_id_circuit_subcircuit (id)) { + + return createIndex (int (circuit_index_from_id (id)), column, make_id_circuit (circuit_index_from_id (id))); + + } else if (is_id_circuit_pin_net (id)) { + + return createIndex (int (circuit_pin_index_from_id (id)), column, make_id_circuit_pin (circuit_index_from_id (id), circuit_pin_index_from_id (id))); + + } else if (is_id_circuit_net_device_terminal (id) || is_id_circuit_net_pin (id) || is_id_circuit_net_subcircuit_pin (id)) { + + db::Circuit *circuit = circuit_from_id (id); + return createIndex (int (circuit->pin_count () + circuit_net_index_from_id (id)), column, make_id_circuit_net (circuit_index_from_id (id), circuit_net_index_from_id (id))); + + } else if (is_id_circuit_subcircuit_pin (id)) { + + db::Circuit *circuit = circuit_from_id (id); + return createIndex (int (circuit->pin_count () + circuit->net_count () + circuit_subcircuit_index_from_id (id)), column, make_id_circuit_subcircuit (circuit_index_from_id (id), circuit_subcircuit_index_from_id (id))); + + } else if (is_id_circuit_device_terminal (id)) { + + db::Circuit *circuit = circuit_from_id (id); + return createIndex (int (circuit->pin_count () + circuit->net_count () + circuit->subcircuit_count () + circuit_device_terminal_index_from_id (id)), column, make_id_circuit_device (circuit_index_from_id (id), circuit_device_index_from_id (id))); + + } else if (is_id_circuit_net_device_terminal_others (id)) { + + return createIndex (circuit_net_device_terminal_index_from_id (id), column, make_id_circuit_net_device_terminal (circuit_index_from_id (id), circuit_net_index_from_id (id), circuit_net_device_terminal_index_from_id (id))); + + } else if (is_id_circuit_net_subcircuit_pin_others (id)) { + + db::Net *net = net_from_id (id); + return createIndex (size_t (net->terminal_count () + net->pin_count () + circuit_net_subcircuit_pin_index_from_id (id)), column, make_id_circuit_net_subcircuit_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), circuit_net_subcircuit_pin_index_from_id (id))); + + } + + } + + return QModelIndex (); +} + +int +NetlistBrowserModel::rowCount (const QModelIndex &parent) const +{ + if (! parent.isValid ()) { + + return int (mp_l2ndb->netlist ()->circuit_count ()); + + } else { + + void *id = parent.internalPointer (); + + /* + * - circuits + * - 0..#pins: pins + * - net (1x) + * - #pins..#pins+#nets: nets + * - 0..#devices: terminals + * - other terminals and nets + * - #devices..#devices+#pins: pins + * - #devices+#pins..: subcircuit pins + * - other pins and nets + * - #pins+#nets..#pins+#nets+#subcircuits: subcircuits + * - pins and nets + * - #pins+#nets+#subcircuits..: devices + * - terminals and nets + */ + + if (is_id_circuit (id)) { + + db::Circuit *circuit = circuit_from_id (id); + return int (circuit->pin_count () + circuit->net_count () + circuit->subcircuit_count () + circuit->device_count ()); + + } else if (is_id_circuit_pin (id)) { + + return 1; + + } else if (is_id_circuit_device (id) || is_id_circuit_net_device_terminal (id)) { + + db::Device *device = device_from_id (id); + return int (device->device_class () ? device->device_class ()->terminal_definitions ().size () : 0); + + } else if (is_id_circuit_subcircuit (id) || is_id_circuit_net_subcircuit_pin (id)) { + + db::SubCircuit *subcircuit = subcircuit_from_id (id); + return int (subcircuit->circuit_ref () ? subcircuit->circuit_ref ()->pin_count () : 0); + + } else if (is_id_circuit_net (id)) { + + db::Net *net = net_from_id (id); + return int (net->terminal_count () + net->pin_count () + net->subcircuit_pin_count ()); + + } + + } + + return 0; +} + // ---------------------------------------------------------------------------------- // NetlistBrowserPage implementation