diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 9e2d164d5..9232b78ea 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -1041,9 +1041,9 @@ LayoutToNetlist::build_nets (const std::vector *nets, const db: } } -db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::DPoint &point) +db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::DPoint &point, std::vector *sc_path_out, db::Circuit *initial_circuit) { - return probe_net (of_region, db::CplxTrans (internal_layout ()->dbu ()).inverted () * point); + return probe_net (of_region, db::CplxTrans (internal_layout ()->dbu ()).inverted () * point, sc_path_out, initial_circuit); } size_t LayoutToNetlist::search_net (const db::ICplxTrans &trans, const db::Cell *cell, const db::local_cluster &test_cluster, std::vector &rev_inst_path) @@ -1077,7 +1077,7 @@ size_t LayoutToNetlist::search_net (const db::ICplxTrans &trans, const db::Cell return 0; } -db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Point &point) +db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Point &point, std::vector *sc_path_out, db::Circuit *initial_circuit) { if (! m_netlist_extracted) { throw tl::Exception (tl::to_string (tr ("The netlist has not been extracted yet"))); @@ -1089,6 +1089,14 @@ db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Poin unsigned int layer = layer_of (of_region); + const db::Cell *top_cell = internal_top_cell (); + if (initial_circuit && internal_layout ()->is_valid_cell_index (initial_circuit->cell_index ())) { + top_cell = &internal_layout ()->cell (initial_circuit->cell_index ()); + } + if (! top_cell) { + return 0; + } + // Prepare a test cluster db::Box box (point - db::Vector (1, 1), point + db::Vector (1, 1)); db::GenericRepository sr; @@ -1097,7 +1105,7 @@ db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Poin std::vector inst_path; - size_t cluster_id = search_net (db::ICplxTrans (), internal_top_cell (), test_cluster, inst_path); + size_t cluster_id = search_net (db::ICplxTrans (), top_cell, test_cluster, inst_path); if (cluster_id > 0) { // search_net delivers the path in reverse order @@ -1105,7 +1113,7 @@ db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Poin std::vector cell_indexes; cell_indexes.reserve (inst_path.size () + 1); - cell_indexes.push_back (internal_top_cell ()->cell_index ()); + cell_indexes.push_back (top_cell->cell_index ()); for (std::vector::const_iterator i = inst_path.begin (); i != inst_path.end (); ++i) { cell_indexes.push_back (i->inst_ptr.cell_index ()); } @@ -1142,38 +1150,57 @@ db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Poin } + std::vector sc_path; + + db::Net *topmost_net = net; + // follow the path up in the net hierarchy using the transformation and the upper cell index as the // guide line - while (! inst_path.empty () && net->pin_count () > 0) { + while (circuit && ! inst_path.empty ()) { cell_indexes.pop_back (); - const db::Pin *pin = circuit->pin_by_id (net->begin_pins ()->pin_id ()); - tl_assert (pin != 0); + const db::Pin *pin = 0; + if (net && net->pin_count () > 0) { + pin = circuit->pin_by_id (net->begin_pins ()->pin_id ()); + tl_assert (pin != 0); + } db::DCplxTrans dtrans = dbu_trans * inst_path.back ().complex_trans () * dbu_trans_inv; // try to find a parent circuit which connects to this net db::Circuit *upper_circuit = 0; + db::SubCircuit *subcircuit = 0; db::Net *upper_net = 0; - for (db::Circuit::refs_iterator r = circuit->begin_refs (); r != circuit->end_refs () && ! upper_net; ++r) { + for (db::Circuit::refs_iterator r = circuit->begin_refs (); r != circuit->end_refs () && ! upper_circuit; ++r) { if (r->trans ().equal (dtrans) && r->circuit () && r->circuit ()->cell_index () == cell_indexes.back ()) { - upper_net = r->net_for_pin (pin->id ()); - upper_circuit = r->circuit (); + subcircuit = r.operator-> (); + if (pin) { + upper_net = subcircuit->net_for_pin (pin->id ()); + } + upper_circuit = subcircuit->circuit (); } } + net = upper_net; + if (upper_net) { - circuit = upper_circuit; - net = upper_net; - inst_path.pop_back (); + topmost_net = upper_net; } else { - break; + sc_path.push_back (subcircuit); } + circuit = upper_circuit; + inst_path.pop_back (); + } - return net; + if (sc_path_out) { + std::reverse (sc_path.begin (), sc_path.end ()); + *sc_path_out = sc_path; + } + + return topmost_net; } else { return 0; diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 63bf835aa..4d103e66e 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -709,8 +709,11 @@ public: * * This variant accepts a micrometer-unit location. The location is given in the * coordinate space of the initial cell. + * + * The subcircuit path leading to the topmost net is stored in *sc_path_out if this + * pointer is non-null. */ - db::Net *probe_net (const db::Region &of_region, const db::DPoint &point); + db::Net *probe_net (const db::Region &of_region, const db::DPoint &point, std::vector *sc_path_out = 0, Circuit *initial_circuit = 0); /** * @brief Finds the net by probing a specific location on the given layer @@ -718,7 +721,7 @@ public: * This variant accepts a database-unit location. The location is given in the * coordinate space of the initial cell. */ - db::Net *probe_net (const db::Region &of_region, const db::Point &point); + db::Net *probe_net (const db::Region &of_region, const db::Point &point, std::vector *sc_path_out = 0, Circuit *initial_circuit = 0); /** * @brief Runs an antenna check on the extracted clusters diff --git a/src/db/db/dbNetlistCrossReference.cc b/src/db/db/dbNetlistCrossReference.cc index a0a0464a6..9982fdc40 100644 --- a/src/db/db/dbNetlistCrossReference.cc +++ b/src/db/db/dbNetlistCrossReference.cc @@ -55,6 +55,39 @@ NetlistCrossReference::per_circuit_data_for (const std::pair::const_iterator i = m_other_pin.find (pin); + if (i != m_other_pin.end ()) { + return i->second; + } else { + return 0; + } +} + +const db::Device * +NetlistCrossReference::other_device_for (const db::Device *device) const +{ + std::map::const_iterator i = m_other_device.find (device); + if (i != m_other_device.end ()) { + return i->second; + } else { + return 0; + } +} + +const db::SubCircuit * +NetlistCrossReference::other_subcircuit_for (const db::SubCircuit *subcircuit) const +{ + std::map::const_iterator i = m_other_subcircuit.find (subcircuit); + if (i != m_other_subcircuit.end ()) { + return i->second; + } else { + return 0; + } +} + const db::Circuit * NetlistCrossReference::other_circuit_for (const db::Circuit *circuit) const { @@ -568,6 +601,16 @@ NetlistCrossReference::build_subcircuit_pin_refs (const std::pair, const db::NetSubcircuitPinRef *>::iterator b = s2t_b.lower_bound (std::make_pair (sb, 0)); + if (b != s2t_b.end () && b->first.first == sb) { + pb = b->second; + // remove the entry so we won't find it again + s2t_b.erase (b); + } + } + } data.subcircuit_pins.push_back (std::make_pair (a->second, pb)); diff --git a/src/db/db/dbNetlistCrossReference.h b/src/db/db/dbNetlistCrossReference.h index d61868445..c0e9be7eb 100644 --- a/src/db/db/dbNetlistCrossReference.h +++ b/src/db/db/dbNetlistCrossReference.h @@ -256,6 +256,9 @@ public: return m_circuits.end (); } + const db::Pin *other_pin_for (const db::Pin *pin) const; + const db::Device *other_device_for (const db::Device *device) const; + const db::SubCircuit *other_subcircuit_for (const db::SubCircuit *subcircuit) const; const db::Circuit *other_circuit_for (const db::Circuit *circuit) const; const db::Net *other_net_for (const db::Net *net) const; const PerNetData *per_net_data_for (const std::pair &nets) const; diff --git a/src/db/db/dbSubCircuit.cc b/src/db/db/dbSubCircuit.cc index 3d7dd7a7d..bf736f80d 100644 --- a/src/db/db/dbSubCircuit.cc +++ b/src/db/db/dbSubCircuit.cc @@ -119,6 +119,17 @@ const Net *SubCircuit::net_for_pin (size_t pin_id) const return 0; } +const NetSubcircuitPinRef *SubCircuit::netref_for_pin (size_t pin_id) const +{ + if (pin_id < m_pin_refs.size ()) { + Net::subcircuit_pin_iterator p = m_pin_refs [pin_id]; + if (p != Net::subcircuit_pin_iterator ()) { + return p.operator-> (); + } + } + return 0; +} + void SubCircuit::connect_pin (size_t pin_id, Net *net) { if (net_for_pin (pin_id) == net) { diff --git a/src/db/db/dbSubCircuit.h b/src/db/db/dbSubCircuit.h index fa16d971e..c69a8e1e0 100644 --- a/src/db/db/dbSubCircuit.h +++ b/src/db/db/dbSubCircuit.h @@ -171,6 +171,21 @@ public: return const_cast (((const SubCircuit *) this)->net_for_pin (pin_id)); } + /** + * @brief Gets the net attached to a specific pin as a subcircuit pin ref object + * Returns 0 if no net is attached. + */ + const NetSubcircuitPinRef *netref_for_pin (size_t pin_id) const; + + /** + * @brief Gets the net attached to a specific pin as a subcircuit pin ref object (non-const version) + * Returns 0 if no net is attached. + */ + NetSubcircuitPinRef *netref_for_pin (size_t pin_id) + { + return const_cast (((const SubCircuit *) this)->netref_for_pin (pin_id)); + } + /** * @brief Connects the given pin to the given net * If the net is 0 the pin is disconnected. diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index 1e5cce32d..cedc464ab 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -543,7 +543,7 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", 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"), + gsi::method ("probe_net", (db::Net *(db::LayoutToNetlist::*) (const db::Region &, const db::DPoint &, std::vector *, db::Circuit *)) &db::LayoutToNetlist::probe_net, gsi::arg ("of_layer"), gsi::arg ("point"), gsi::arg ("sc_path_out", (std::vector *) 0, "nil"), gsi::arg ("initial_circuit", (db::Circuit *) 0, "nil"), "@brief Finds the net by probing a specific location on the given layer\n" "\n" "This method will find a net looking at the given layer at the specific position.\n" @@ -551,20 +551,30 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "in the specified location. The function will report the topmost net from far above the\n" "hierarchy of circuits as possible.\n" "\n" + "If \\initial_circuit is given, the probing will start from this circuit and from the " + "cell this circuit represents. By default, the probing will start from the top circuit.\n" + "\n" "If no net is found at all, 0 is returned.\n" "\n" - "It is recommended to use \\probe on the netlist right after extraction.\n" + "It is recommended to use \\probe_net on the netlist right after extraction.\n" "Optimization functions such as \\Netlist#purge will remove parts of the net which means\n" "shape to net probing may no longer work for these nets.\n" "\n" + "If non-null and an array, 'sc_path_out' will receive a list of \\SubCircuits objects which lead to the " + "net from the top circuit of the database.\n" + "\n" "This variant accepts a micrometer-unit location. The location is given in the\n" "coordinate space of the initial cell.\n" + "\n" + "The \\sc_path_out and \\initial_circuit parameters have been added in version 0.27.\n" ) + - gsi::method ("probe_net", (db::Net *(db::LayoutToNetlist::*) (const db::Region &, const db::Point &)) &db::LayoutToNetlist::probe_net, gsi::arg ("of_layer"), gsi::arg ("point"), + gsi::method ("probe_net", (db::Net *(db::LayoutToNetlist::*) (const db::Region &, const db::Point &, std::vector *, db::Circuit *)) &db::LayoutToNetlist::probe_net, gsi::arg ("of_layer"), gsi::arg ("point"), gsi::arg ("sc_path_out", (std::vector *) 0, "nil"), gsi::arg ("initial_circuit", (db::Circuit *) 0, "nil"), "@brief Finds the net by probing a specific location on the given layer\n" "See the description of the other \\probe_net variant.\n" "This variant accepts a database-unit location. The location is given in the\n" "coordinate space of the initial cell.\n" + "\n" + "The \\sc_path_out and \\initial_circuit parameters have been added in version 0.27.\n" ) + gsi::method ("write|write_l2n", &db::LayoutToNetlist::save, gsi::arg ("path"), gsi::arg ("short_format", false), "@brief Writes the extracted netlist to a file.\n" diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index b8b7636c9..77cd998a6 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -466,6 +466,21 @@ Class decl_dbSubCircuit (decl_dbNetlistObject, "db", "SubCircuit gsi::method_ext ("disconnect_pin", &gsi::subcircuit_disconnect_pin1, gsi::arg ("pin"), "@brief Disconnects the given pin from any net.\n" "This version takes a \\Pin reference instead of a pin ID." + ) + + gsi::method ("trans", &db::SubCircuit::trans, + "@brief Gets the physical transformation for the subcircuit.\n" + "\n" + "This property applies to subcircuits derived from a layout. It specifies the " + "placement of the respective cell.\n" + "\n" + "This property has been introduced in version 0.27." + ) + + gsi::method ("trans=", &db::SubCircuit::set_trans, gsi::arg ("trans"), + "@brief Sets the physical transformation for the subcircuit.\n" + "\n" + "See \\trans for details about this property.\n" + "\n" + "This property has been introduced in version 0.27." ), "@brief A subcircuit inside a circuit.\n" "Circuits may instantiate other circuits as subcircuits similar to cells " diff --git a/src/db/db/gsiDeclDbNetlistCrossReference.cc b/src/db/db/gsiDeclDbNetlistCrossReference.cc index 13078d5e1..de230a506 100644 --- a/src/db/db/gsiDeclDbNetlistCrossReference.cc +++ b/src/db/db/gsiDeclDbNetlistCrossReference.cc @@ -403,6 +403,34 @@ Class decl_dbNetlistCrossReference (decl_dbNetlistCom "The return value will be nil if no match is found. " "Otherwise it is the 'b' net for nets from the 'a' netlist and vice versa." ) + + gsi::method ("other_circuit_for", &db::NetlistCrossReference::other_circuit_for, gsi::arg ("circuit"), + "@brief Gets the matching other circuit for a given primary circuit.\n" + "The return value will be nil if no match is found. " + "Otherwise it is the 'b' circuit for circuits from the 'a' netlist and vice versa." + "\n\n" + "This method has been introduced in version 0.27.\n" + ) + + gsi::method ("other_device_for", &db::NetlistCrossReference::other_device_for, gsi::arg ("device"), + "@brief Gets the matching other device for a given primary device.\n" + "The return value will be nil if no match is found. " + "Otherwise it is the 'b' device for devices from the 'a' netlist and vice versa." + "\n\n" + "This method has been introduced in version 0.27.\n" + ) + + gsi::method ("other_pin_for", &db::NetlistCrossReference::other_pin_for, gsi::arg ("pin"), + "@brief Gets the matching other pin for a given primary pin.\n" + "The return value will be nil if no match is found. " + "Otherwise it is the 'b' pin for pins from the 'a' netlist and vice versa." + "\n\n" + "This method has been introduced in version 0.27.\n" + ) + + gsi::method ("other_subcircuit_for", &db::NetlistCrossReference::other_subcircuit_for, gsi::arg ("subcircuit"), + "@brief Gets the matching other subcircuit for a given primary subcircuit.\n" + "The return value will be nil if no match is found. " + "Otherwise it is the 'b' subcircuit for subcircuits from the 'a' netlist and vice versa." + "\n\n" + "This method has been introduced in version 0.27.\n" + ) + gsi::method ("clear", &db::NetlistCrossReference::clear, "@hide\n" ) + diff --git a/src/db/unit_tests/dbNetlistCompareTests.cc b/src/db/unit_tests/dbNetlistCompareTests.cc index b98d25af7..60eec5eb9 100644 --- a/src/db/unit_tests/dbNetlistCompareTests.cc +++ b/src/db/unit_tests/dbNetlistCompareTests.cc @@ -2167,17 +2167,14 @@ TEST(14_Subcircuit2NandMismatchNoSwap) " pin $4:$4 [Match]\n" " net IN1:INT [Mismatch]\n" " pin $0:(null)\n" - " subcircuit_pin (null):$2[$2]\n" - " subcircuit_pin $1[$0]:(null)\n" + " subcircuit_pin $1[$0]:$2[$2]\n" " subcircuit_pin $2[$0]:$1[$0]\n" " net IN2:IN2 [Mismatch]\n" " pin $1:$1\n" - " subcircuit_pin (null):$2[$0]\n" - " subcircuit_pin $1[$1]:(null)\n" + " subcircuit_pin $1[$1]:$2[$0]\n" " net INT:IN1 [Mismatch]\n" " pin (null):$0\n" - " subcircuit_pin (null):$2[$1]\n" - " subcircuit_pin $1[$2]:(null)\n" + " subcircuit_pin $1[$2]:$2[$1]\n" " subcircuit_pin $2[$1]:$1[$1]\n" " net OUT:OUT [Match]\n" " pin $2:$2\n" diff --git a/src/lay/lay/layGSIHelpProvider.cc b/src/lay/lay/layGSIHelpProvider.cc index 2307e7f3c..171b3fc6a 100644 --- a/src/lay/lay/layGSIHelpProvider.cc +++ b/src/lay/lay/layGSIHelpProvider.cc @@ -285,16 +285,6 @@ static DocumentationParser &cls_documentation (const gsi::ClassBase *cls) } } -static const std::string &aliased_name (const gsi::ClassBase *cls) -{ - const std::string &alias = cls_documentation (cls).alias; - if (alias.empty ()) { - return cls->name (); - } else { - return alias; - } -} - static std::string make_qualified_name (const gsi::ClassBase *cls) { std::string qname; @@ -703,9 +693,9 @@ type_to_s (const gsi::ArgType &a, bool linked, bool for_return) s += "new "; } if (linked) { - s += "" + escape_xml (aliased_name (a.cls ())) + ""; + s += "" + escape_xml (make_qualified_name (a.cls ())) + ""; } else { - s += aliased_name (a.cls ()); + s += make_qualified_name (a.cls ()); } break; case gsi::T_vector: diff --git a/src/lay/lay/layMacroEditorTree.cc b/src/lay/lay/layMacroEditorTree.cc index 703cf7aaa..da5b3bcea 100644 --- a/src/lay/lay/layMacroEditorTree.cc +++ b/src/lay/lay/layMacroEditorTree.cc @@ -161,7 +161,10 @@ void MacroTreeModel::macro_changed () void MacroTreeModel::update_data () { - emit dataChanged (index (0, 0, QModelIndex ()), index (rowCount (QModelIndex()) - 1, 0, QModelIndex ())); + int rc = rowCount (QModelIndex()); + if (rc > 0) { + emit dataChanged (index (0, 0, QModelIndex ()), index (rc - 1, 0, QModelIndex ())); + } } void MacroTreeModel::about_to_change () diff --git a/src/laybasic/laybasic/gsiDeclLayNetlistBrowserDialog.cc b/src/laybasic/laybasic/gsiDeclLayNetlistBrowserDialog.cc new file mode 100644 index 000000000..f662339e2 --- /dev/null +++ b/src/laybasic/laybasic/gsiDeclLayNetlistBrowserDialog.cc @@ -0,0 +1,237 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "gsiDecl.h" +#include "gsiDeclBasic.h" +#include "gsiSignals.h" +#include "layNetlistBrowserDialog.h" +#include "layLayoutView.h" + +namespace tl +{ + +// disable copy and default constructor for NetlistBrowserDialog +template <> struct type_traits : public type_traits +{ + typedef tl::false_tag has_copy_constructor; + typedef tl::false_tag has_default_constructor; +}; + +} + +namespace gsi +{ + +static void set_root (lay::NetlistObjectPath *path, db::Circuit *r) +{ + path->root = r; +} + +static db::Circuit *root (const lay::NetlistObjectPath *path) +{ + return const_cast (path->root); +} + +static void set_device (lay::NetlistObjectPath *path, db::Device *r) +{ + path->device = r; +} + +static db::Device *device (const lay::NetlistObjectPath *path) +{ + return const_cast (path->device); +} + +static void set_net (lay::NetlistObjectPath *path, db::Net *r) +{ + path->net = r; +} + +static db::Net *net (const lay::NetlistObjectPath *path) +{ + return const_cast (path->net); +} + +static std::vector path (const lay::NetlistObjectPath *p) +{ + std::vector pp; + pp.reserve (p->path.size ()); + for (lay::NetlistObjectPath::path_iterator i = p->path.begin (); i != p->path.end (); ++i) { + pp.push_back (const_cast (*i)); + } + return pp; +} + +static void set_path (lay::NetlistObjectPath *p, const std::vector &path) +{ + p->path = lay::NetlistObjectPath::path_type (path.begin (), path.end ()); +} + +Class decl_NetlistObjectPath ("lay", "NetlistObjectPath", + gsi::method_ext ("root=", &set_root, gsi::arg ("root"), + "@brief Sets the root circuit of the path.\n" + "The root circuit is the circuit from which the path starts.\n" + ) + + gsi::method_ext ("root", &root, + "@brief Gets the root circuit of the path.\n" + ) + + gsi::method_ext ("path=", &set_path, gsi::arg ("path"), + "@brief Sets the path.\n" + "The path is a list of subcircuits leading from the root to the final object. " + "The final (net, device) object is located in the circuit called by the last subcircuit " + "of the subcircuit chain. If the subcircuit list is empty, the final object is located inside " + "the root object." + ) + + gsi::method_ext ("path", &path, + "@brief Gets the path.\n" + ) + + gsi::method_ext ("net=", &set_net, gsi::arg ("net"), + "@brief Sets the net the path points to.\n" + "If the path describes the location of a net, this member will indicate it.\n" + "The other way to describe a final object is \\device=. If neither a device nor " + "net is given, the path describes a circuit and how it is referenced from the root." + ) + + gsi::method_ext ("net", &net, + "@brief Gets the net the path points to.\n" + ) + + gsi::method_ext ("device=", &set_device, gsi::arg ("device"), + "@brief Sets the device the path points to.\n" + "If the path describes the location of a device, this member will indicate it.\n" + "The other way to describe a final object is \\net=. If neither a device nor " + "net is given, the path describes a circuit and how it is referenced from the root." + ) + + gsi::method_ext ("device", &device, + "@brief Gets the device the path points to.\n" + ) + + 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 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" + "See \\net= or \\device= for the indicated object, \\path= for the subcircuit chain.\n" + "\n" + "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 (); +} + +static lay::NetlistObjectPath current_path_second (lay::NetlistBrowserDialog *dialog) +{ + return dialog->current_path ().second (); +} + +Class decl_NetlistBrowserDialog ("lay", "NetlistBrowserDialog", + gsi::event ("on_current_db_changed", &lay::NetlistBrowserDialog::current_db_changed_event, + "@brief This event is triggered when the current database is changed.\n" + "The current database can be obtained with \\db." + ) + + gsi::event ("on_selection_changed", &lay::NetlistBrowserDialog::selection_changed_event, + "@brief This event is triggered when the selection changed.\n" + "The selection can be obtained with \\current_path_first, \\current_path_second, \\selected_nets, \\selected_devices, \\selected_subcircuits and \\selected_circuits." + ) + + gsi::event ("on_probe", &lay::NetlistBrowserDialog::probe_event, gsi::arg ("first_path"), gsi::arg ("second_path"), + "@brief This event is triggered when a net is probed.\n" + "The first path will indicate the location of the probed net in terms of two paths: one describing the instantiation of the " + "net in layout space and one in schematic space. Both objects are \\NetlistObjectPath objects which hold the root circuit, the " + "chain of subcircuits leading to the circuit containing the net and the net itself." + ) + + gsi::method ("db", &lay::NetlistBrowserDialog::db, + "@brief Gets the database the browser is connected to.\n" + ) + + gsi::method_ext ("current_path_first", ¤t_path_first, + "@brief Gets the path of the current object on the first (layout in case of LVS database) side.\n" + ) + + 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 ("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_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" + "This interface allows to interact with the browser - mainly to get information about state changes.\n" + "\n" + "This class has been introduced in version 0.27.\n" +); + +static lay::NetlistBrowserDialog *netlist_browser (lay::LayoutView *lv) +{ + return lv->get_plugin (); +} + +// extend lay::LayoutView with the getter for the netlist browser +static +gsi::ClassExt decl_ext_layout_view ( + gsi::method_ext ("netlist_browser", &netlist_browser, + "@brief Gets the netlist browser object for the given layout view\n" + "\n" + "\nThis method has been added in version 0.27.\n" + ) +); + + + +} + diff --git a/src/laybasic/laybasic/layIndexedNetlistModel.cc b/src/laybasic/laybasic/layIndexedNetlistModel.cc index 9fbd69fd0..4dd2ea7c3 100644 --- a/src/laybasic/laybasic/layIndexedNetlistModel.cc +++ b/src/laybasic/laybasic/layIndexedNetlistModel.cc @@ -236,67 +236,73 @@ SingleIndexedNetlistModel::top_circuit_count () const size_t SingleIndexedNetlistModel::net_count (const circuit_pair &circuits) const { - return circuits.first->net_count (); + return circuits.first ? circuits.first->net_count () : 0; } size_t SingleIndexedNetlistModel::net_terminal_count (const net_pair &nets) const { - return nets.first->terminal_count (); + return nets.first ? nets.first->terminal_count () : 0; } size_t SingleIndexedNetlistModel::net_subcircuit_pin_count (const net_pair &nets) const { - return nets.first->subcircuit_pin_count (); + return nets.first ? nets.first->subcircuit_pin_count () : 0; } size_t SingleIndexedNetlistModel::net_pin_count (const net_pair &nets) const { - return nets.first->pin_count (); + return nets.first ? nets.first->pin_count () : 0; } size_t SingleIndexedNetlistModel::device_count (const circuit_pair &circuits) const { - return circuits.first->device_count (); + return circuits.first ? circuits.first->device_count () : 0; +} + +size_t +SingleIndexedNetlistModel::subcircuit_pin_count (const subcircuit_pair &subcircuits) const +{ + return subcircuits.first ? subcircuits.first->circuit_ref ()->pin_count () : 0; } size_t SingleIndexedNetlistModel::pin_count (const circuit_pair &circuits) const { - return circuits.first->pin_count (); + return circuits.first ? circuits.first->pin_count () : 0; } size_t SingleIndexedNetlistModel::subcircuit_count (const circuit_pair &circuits) const { - return circuits.first->subcircuit_count (); + return circuits.first ? circuits.first->subcircuit_count () : 0; } size_t SingleIndexedNetlistModel::child_circuit_count (const circuit_pair &circuits) const { - return circuits.first->end_children () - circuits.first->begin_children (); + return circuits.first ? (circuits.first->end_children () - circuits.first->begin_children ()) : 0; } IndexedNetlistModel::circuit_pair SingleIndexedNetlistModel::parent_of (const net_pair &nets) const { - return std::make_pair (nets.first->circuit (), (const db::Circuit *) 0); + return std::make_pair (nets.first ? nets.first->circuit () : 0, (const db::Circuit *) 0); } IndexedNetlistModel::circuit_pair SingleIndexedNetlistModel::parent_of (const device_pair &devices) const { - return std::make_pair (devices.first->circuit (), (const db::Circuit *) 0); + return std::make_pair (devices.first ? devices.first->circuit () : 0, (const db::Circuit *) 0); } IndexedNetlistModel::circuit_pair SingleIndexedNetlistModel::parent_of (const subcircuit_pair &subcircuits) const { - return std::make_pair (subcircuits.first->circuit (), (const db::Circuit *) 0); + return std::make_pair (subcircuits.first ? subcircuits.first->circuit () : 0, (const db::Circuit *) 0); } std::pair @@ -346,6 +352,34 @@ SingleIndexedNetlistModel::net_subcircuit_pinref_from_index (const net_pair &net return attr_by_object_and_index (nets, index, nets.first->begin_subcircuit_pins (), nets.first->end_subcircuit_pins (), none, none, m_subcircuit_pinref_by_net_and_index, sort_by_pin_name ()); } +IndexedNetlistModel::net_subcircuit_pin_pair +SingleIndexedNetlistModel::subcircuit_pinref_from_index (const subcircuit_pair &subcircuits, size_t index) const +{ + if (! subcircuits.first) { + return IndexedNetlistModel::net_subcircuit_pin_pair (0, 0); + } + + std::map >::iterator i = m_subcircuit_pins_by_index.find (subcircuits); + if (i == m_subcircuit_pins_by_index.end ()) { + + i = m_subcircuit_pins_by_index.insert (std::make_pair (subcircuits, std::vector ())).first; + + std::vector &refs = i->second; + const db::Circuit *circuit = subcircuits.first->circuit_ref (); + for (db::Circuit::const_pin_iterator p = circuit->begin_pins (); p != circuit->end_pins (); ++p) { + const db::NetSubcircuitPinRef *ref = subcircuits.first->netref_for_pin (p->id ()); + if (! ref) { + m_synthetic_pinrefs.push_back (db::NetSubcircuitPinRef (const_cast (subcircuits.first), p->id ())); + ref = & m_synthetic_pinrefs.back (); + } + refs.push_back (net_subcircuit_pin_pair (ref, 0)); + } + + } + + return index < i->second.size () ? i->second [index] : IndexedNetlistModel::net_subcircuit_pin_pair (0, 0); +} + IndexedNetlistModel::net_terminal_pair SingleIndexedNetlistModel::net_terminalref_from_index (const net_pair &nets, size_t index) const { diff --git a/src/laybasic/laybasic/layIndexedNetlistModel.h b/src/laybasic/laybasic/layIndexedNetlistModel.h index 1ccfcc901..e874c3ca7 100644 --- a/src/laybasic/laybasic/layIndexedNetlistModel.h +++ b/src/laybasic/laybasic/layIndexedNetlistModel.h @@ -80,6 +80,7 @@ public: virtual size_t net_subcircuit_pin_count (const net_pair &nets) const = 0; virtual size_t net_pin_count (const net_pair &nets) const = 0; virtual size_t device_count (const circuit_pair &circuits) const = 0; + virtual size_t subcircuit_pin_count (const subcircuit_pair &subcircuits) const = 0; virtual size_t pin_count (const circuit_pair &circuits) const = 0; virtual size_t subcircuit_count (const circuit_pair &circuits) const = 0; virtual size_t child_circuit_count (const circuit_pair &circuits) const = 0; @@ -95,6 +96,7 @@ public: virtual const db::Net *second_net_for (const db::Net *first) const = 0; virtual const db::Circuit *second_circuit_for (const db::Circuit *first) const = 0; virtual net_subcircuit_pin_pair net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const = 0; + virtual net_subcircuit_pin_pair subcircuit_pinref_from_index (const subcircuit_pair &subcircuits, size_t index) const = 0; virtual net_terminal_pair net_terminalref_from_index (const net_pair &nets, size_t index) const = 0; virtual net_pin_pair net_pinref_from_index (const net_pair &nets, size_t index) const = 0; virtual std::pair device_from_index (const circuit_pair &circuits, size_t index) const = 0; @@ -149,6 +151,7 @@ public: virtual size_t net_pin_count (const net_pair &nets) const; virtual size_t device_count (const circuit_pair &circuits) const; virtual size_t pin_count (const circuit_pair &circuits) const; + virtual size_t subcircuit_pin_count (const subcircuit_pair &subcircuits) const; virtual size_t subcircuit_count (const circuit_pair &circuits) const; virtual size_t child_circuit_count (const circuit_pair &circuits) const; @@ -163,6 +166,7 @@ public: virtual const db::Net *second_net_for (const db::Net *first) const; virtual const db::Circuit *second_circuit_for (const db::Circuit *first) const; virtual net_subcircuit_pin_pair net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const; + virtual net_subcircuit_pin_pair subcircuit_pinref_from_index (const subcircuit_pair &subcircuits, size_t index) const; virtual net_terminal_pair net_terminalref_from_index (const net_pair &nets, size_t index) const; virtual net_pin_pair net_pinref_from_index (const net_pair &nets, size_t index) const; virtual std::pair device_from_index (const circuit_pair &circuits, size_t index) const; @@ -194,6 +198,8 @@ private: mutable std::map m_pin_index_by_object; mutable std::map m_subcircuit_index_by_object; mutable std::map m_device_index_by_object; + mutable std::map > m_subcircuit_pins_by_index; + mutable std::list m_synthetic_pinrefs; }; } diff --git a/src/laybasic/laybasic/layNetlistBrowserDialog.cc b/src/laybasic/laybasic/layNetlistBrowserDialog.cc index 50866fa8d..b44db19bc 100644 --- a/src/laybasic/laybasic/layNetlistBrowserDialog.cc +++ b/src/laybasic/laybasic/layNetlistBrowserDialog.cc @@ -120,6 +120,8 @@ NetlistBrowserDialog::NetlistBrowserDialog (lay::Dispatcher *root, lay::LayoutVi connect (sticky_cbx, SIGNAL (clicked ()), this, SLOT (sticky_mode_clicked ())); cellviews_changed (); + + browser_page->selection_changed_event.add (this, &NetlistBrowserDialog::selection_changed); } NetlistBrowserDialog::~NetlistBrowserDialog () @@ -127,6 +129,34 @@ NetlistBrowserDialog::~NetlistBrowserDialog () tl::Object::detach_from_all_events (); } +db::LayoutToNetlist * +NetlistBrowserDialog::db () +{ + return browser_page->db (); +} + +const lay::NetlistObjectsPath & +NetlistBrowserDialog::current_path () const +{ + if (browser_page) { + return browser_page->current_path (); + } else { + static lay::NetlistObjectsPath empty; + return empty; + } +} + +const std::vector & +NetlistBrowserDialog::selected_paths () const +{ + if (browser_page) { + return browser_page->selected_paths (); + } else { + static std::vector empty; + return empty; + } +} + void NetlistBrowserDialog::configure_clicked () { @@ -254,40 +284,60 @@ NetlistBrowserDialog::probe_net (const db::DPoint &p, bool trace_path) } - const db::Net *net = 0; + db::Net *net = 0; + db::Circuit *root = 0; + std::vector sc_path; db::LayoutToNetlist *l2ndb = view ()->get_l2ndb (m_l2n_index); if (l2ndb) { - // determines the corresponding layer inside the database and probe the net from this region and the - // start point. + root = l2ndb->netlist ()->circuit_by_name (cv->layout ().cell_name (cv.cell_index ())); + if (root) { - std::vector regions; + // determines the corresponding layer inside the database and probe the net from this region and the + // start point. - const db::Connectivity &conn = l2ndb->connectivity (); - for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) { - db::LayerProperties lp = l2ndb->internal_layout ()->get_properties (*layer); - if (! lp.is_null ()) { - db::Region *region = l2ndb->layer_by_index (*layer); - if (lp == cv->layout ().get_properties (start_layer)) { - // a matching original layer is looked up with higher prio - regions.insert (regions.begin (), region); - } else { - regions.push_back (region); + std::vector regions; + + const db::Connectivity &conn = l2ndb->connectivity (); + for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) { + db::LayerProperties lp = l2ndb->internal_layout ()->get_properties (*layer); + if (! lp.is_null ()) { + db::Region *region = l2ndb->layer_by_index (*layer); + if (lp == cv->layout ().get_properties (start_layer)) { + // a matching original layer is looked up with higher prio + regions.insert (regions.begin (), region); + } else { + regions.push_back (region); + } } } - } - // probe the net + // probe the net + + for (std::vector::const_iterator r = regions.begin (); r != regions.end () && !net; ++r) { + sc_path.clear (); + net = l2ndb->probe_net (**r, start_point, &sc_path, root); + } - for (std::vector::const_iterator r = regions.begin (); r != regions.end () && !net; ++r) { - net = l2ndb->probe_net (**r, start_point); } } // select the net if one was found - browser_page->select_net (net); + lay::NetlistObjectPath path; + if (net) { + path.root = root; + path.net = net; + path.path = lay::NetlistObjectPath::path_type (sc_path.begin (), sc_path.end ()); + } + + browser_page->select_path (path); + + // emits the probe event + // NOTE: browser_page->current_path () will hold the paired path with the schematic side being + // expanded. + probe_event (browser_page->current_path ().first (), browser_page->current_path ().second ()); } void @@ -421,9 +471,15 @@ 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_page->set_l2ndb (0); - l2ndb->load (l2ndb->filename ()); - browser_page->set_l2ndb (l2ndb); + browser_page->set_db (0); + try { + l2ndb->load (l2ndb->filename ()); + browser_page->set_db (l2ndb); + current_db_changed_event (); + } catch (...) { + current_db_changed_event (); + throw; + } } @@ -707,6 +763,8 @@ NetlistBrowserDialog::update_content () central_stack->setCurrentIndex (1); } + bool db_changed = false; + m_saveas_action->setEnabled (l2ndb != 0); m_export_action->setEnabled (l2ndb != 0); m_unload_action->setEnabled (l2ndb != 0); @@ -714,7 +772,10 @@ NetlistBrowserDialog::update_content () m_reload_action->setEnabled (l2ndb != 0); browser_page->enable_updates (false); // Avoid building the internal lists several times ... - browser_page->set_l2ndb (l2ndb); + if (browser_page->db () != l2ndb) { + db_changed = true; + browser_page->set_db (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); @@ -740,6 +801,10 @@ NetlistBrowserDialog::update_content () if (l2ndb_cb->currentIndex () != m_l2n_index) { l2ndb_cb->setCurrentIndex (m_l2n_index); } + + if (db_changed) { + current_db_changed_event (); + } } void @@ -751,8 +816,16 @@ NetlistBrowserDialog::deactivated () lay::Dispatcher::instance ()->config_set (cfg_l2ndb_window_state, lay::save_dialog_state (this, false /*don't store the section sizes*/).c_str ()); } - browser_page->set_l2ndb (0); + bool db_changed = false; + if (browser_page->db () != 0) { + db_changed = true; + browser_page->set_db (0); + } browser_page->set_view (0, 0); + + if (db_changed) { + current_db_changed_event (); + } } void diff --git a/src/laybasic/laybasic/layNetlistBrowserDialog.h b/src/laybasic/laybasic/layNetlistBrowserDialog.h index 73b0b5fe6..1c350fc78 100644 --- a/src/laybasic/laybasic/layNetlistBrowserDialog.h +++ b/src/laybasic/laybasic/layNetlistBrowserDialog.h @@ -29,6 +29,7 @@ #include "layNetlistBrowser.h" #include "layViewObject.h" #include "layColorPalette.h" +#include "tlEvents.h" namespace lay { @@ -46,6 +47,38 @@ public: void load (int lay_index, int cv_index); + /** + * @brief This event is emitted after the current database changed + */ + tl::Event current_db_changed_event; + + /** + * @brief This event is emitted when a shape is probed + * The first path is that of the layout, the second that of the schematic in case of a + * LVS database. + */ + tl::event probe_event; + + /** + * @brief Gets the current database + */ + db::LayoutToNetlist *db (); + + /** + * @brief Gets the current object's path + */ + const lay::NetlistObjectsPath ¤t_path () const; + + /** + * @brief Gets the selected nets + */ + const std::vector &selected_paths () const; + + /** + * @brief An event indicating that the selection has changed + */ + tl::Event selection_changed_event; + private: // implementation of the lay::Browser interface virtual void activated (); @@ -64,6 +97,11 @@ private: void cellview_changed (int index); void l2ndbs_changed (); + void selection_changed () + { + selection_changed_event (); + } + public slots: void cv_index_changed (int); void l2ndb_index_changed (int); diff --git a/src/laybasic/laybasic/layNetlistBrowserModel.cc b/src/laybasic/laybasic/layNetlistBrowserModel.cc index 6d2ca9d88..5e4934951 100644 --- a/src/laybasic/laybasic/layNetlistBrowserModel.cc +++ b/src/laybasic/laybasic/layNetlistBrowserModel.cc @@ -30,10 +30,73 @@ #include #include #include +#include +#include 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 @@ -158,585 +221,13 @@ NetColorizer::color_of_net (const db::Net *net) const } // ---------------------------------------------------------------------------------- -// NetlistBrowserModel implementation +// Implementation of the item classes -static inline void *make_id (size_t i1) +const std::string field_sep (" / "); + +static QString escaped (const std::string &s) { - return reinterpret_cast (i1); -} - -/* not used yet: -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; -} - -static void *no_id = reinterpret_cast (-1); - -NetlistBrowserModel::NetlistBrowserModel (QWidget *parent, db::LayoutToNetlist *l2ndb, NetColorizer *colorizer) - : QAbstractItemModel (parent), mp_l2ndb (l2ndb), mp_lvsdb (0), mp_colorizer (colorizer) -{ - mp_indexer.reset (new SingleIndexedNetlistModel (l2ndb->netlist ())); - connect (mp_colorizer, SIGNAL (colors_changed ()), this, SLOT (colors_changed ())); - - m_object_column = 0; - m_status_column = -1; - m_first_column = 2; - m_second_column = -1; -} - -NetlistBrowserModel::NetlistBrowserModel (QWidget *parent, db::LayoutVsSchematic *lvsdb, NetColorizer *colorizer) - : QAbstractItemModel (parent), mp_l2ndb (0), mp_lvsdb (lvsdb), mp_colorizer (colorizer) -{ - mp_indexer.reset (new NetlistCrossReferenceModel (lvsdb->cross_ref ())); - connect (mp_colorizer, SIGNAL (colors_changed ()), this, SLOT (colors_changed ())); - - m_object_column = 0; - m_status_column = 1; - m_first_column = 2; - m_second_column = 3; -} - -NetlistBrowserModel::~NetlistBrowserModel () -{ - // .. nothing yet .. -} - -void * -NetlistBrowserModel::make_id_circuit (size_t circuit_index) const -{ - if (circuit_index == lay::no_netlist_index) { - return no_id; - } else { - return make_id (circuit_index); - } -} - -void * -NetlistBrowserModel::make_id_circuit_pin (size_t circuit_index, size_t pin_index) const -{ - if (circuit_index == lay::no_netlist_index || pin_index == lay::no_netlist_index) { - return no_id; - } else { - return make_id (circuit_index, mp_indexer->circuit_count (), 1, 8, pin_index); - } -} - -void * -NetlistBrowserModel::make_id_circuit_pin_net (size_t circuit_index, size_t pin_index, size_t net_index) const -{ - if (circuit_index == lay::no_netlist_index || pin_index == lay::no_netlist_index || net_index == lay::no_netlist_index) { - return no_id; - } else { - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (make_id_circuit (circuit_index)); - return make_id (circuit_index, mp_indexer->circuit_count (), 1, 8, pin_index, mp_indexer->pin_count (circuits), net_index + 1); - } -} - -void * -NetlistBrowserModel::make_id_circuit_net (size_t circuit_index, size_t net_index) const -{ - if (circuit_index == lay::no_netlist_index || net_index == lay::no_netlist_index) { - return no_id; - } else { - return make_id (circuit_index, mp_indexer->circuit_count (), 2, 8, net_index); - } -} - -void * -NetlistBrowserModel::make_id_circuit_net_device_terminal (size_t circuit_index, size_t net_index, size_t terminal_ref_index) const -{ - if (circuit_index == lay::no_netlist_index || net_index == lay::no_netlist_index || terminal_ref_index == lay::no_netlist_index) { - return no_id; - } else { - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (make_id_circuit (circuit_index)); - return make_id (circuit_index, mp_indexer->circuit_count (), 2, 8, net_index, mp_indexer->net_count (circuits), 1, 4, terminal_ref_index); - } -} - -void * -NetlistBrowserModel::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 -{ - if (circuit_index == lay::no_netlist_index || net_index == lay::no_netlist_index || terminal_ref_index == lay::no_netlist_index || other_index == lay::no_netlist_index) { - return no_id; - } else { - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (make_id_circuit (circuit_index)); - IndexedNetlistModel::net_pair nets = nets_from_id (make_id_circuit_net (circuit_index, net_index)); - return make_id (circuit_index, mp_indexer->circuit_count (), 2, 8, net_index, mp_indexer->net_count (circuits), 1, 4, terminal_ref_index, mp_indexer->net_terminal_count (nets), other_index + 1); - } -} - -void * -NetlistBrowserModel::make_id_circuit_net_pin (size_t circuit_index, size_t net_index, size_t pin_index) const -{ - if (circuit_index == lay::no_netlist_index || net_index == lay::no_netlist_index || pin_index == lay::no_netlist_index) { - return no_id; - } else { - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (make_id_circuit (circuit_index)); - return make_id (circuit_index, mp_indexer->circuit_count (), 2, 8, net_index, mp_indexer->net_count (circuits), 2, 4, pin_index); - } -} - -void * -NetlistBrowserModel::make_id_circuit_net_subcircuit_pin (size_t circuit_index, size_t net_index, size_t pin_ref_index) const -{ - if (circuit_index == lay::no_netlist_index || net_index == lay::no_netlist_index || pin_ref_index == lay::no_netlist_index) { - return no_id; - } else { - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (make_id_circuit (circuit_index)); - return make_id (circuit_index, mp_indexer->circuit_count (), 2, 8, net_index, mp_indexer->net_count (circuits), 3, 4, pin_ref_index); - } -} - -void * -NetlistBrowserModel::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 -{ - if (circuit_index == lay::no_netlist_index || net_index == lay::no_netlist_index || pin_ref_index == lay::no_netlist_index || other_index == lay::no_netlist_index) { - return no_id; - } else { - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (make_id_circuit (circuit_index)); - IndexedNetlistModel::net_pair nets = nets_from_id (make_id_circuit_net (circuit_index, net_index)); - return make_id (circuit_index, mp_indexer->circuit_count (), 2, 8, net_index, mp_indexer->net_count (circuits), 3, 4, pin_ref_index, mp_indexer->net_subcircuit_pin_count (nets), other_index + 1); - } -} - -void * -NetlistBrowserModel::make_id_circuit_subcircuit (size_t circuit_index, size_t subcircuit_index) const -{ - if (circuit_index == lay::no_netlist_index || subcircuit_index == lay::no_netlist_index) { - return no_id; - } else { - return make_id (circuit_index, mp_indexer->circuit_count (), 3, 8, subcircuit_index); - } -} - -void * -NetlistBrowserModel::make_id_circuit_subcircuit_pin (size_t circuit_index, size_t subcircuit_index, size_t pin_index) const -{ - if (circuit_index == lay::no_netlist_index || subcircuit_index == lay::no_netlist_index || pin_index == lay::no_netlist_index) { - return no_id; - } else { - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (make_id_circuit (circuit_index)); - return make_id (circuit_index, mp_indexer->circuit_count (), 3, 8, subcircuit_index, mp_indexer->subcircuit_count (circuits), pin_index + 1); - } -} - -void * -NetlistBrowserModel::make_id_circuit_device (size_t circuit_index, size_t device_index) const -{ - if (circuit_index == lay::no_netlist_index || device_index == lay::no_netlist_index) { - return no_id; - } else { - return make_id (circuit_index, mp_indexer->circuit_count (), 4, 8, device_index); - } -} - -void * -NetlistBrowserModel::make_id_circuit_device_terminal (size_t circuit_index, size_t device_index, size_t terminal_index) const -{ - if (circuit_index == lay::no_netlist_index || device_index == lay::no_netlist_index || terminal_index == lay::no_netlist_index) { - return no_id; - } else { - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (make_id_circuit (circuit_index)); - return make_id (circuit_index, mp_indexer->circuit_count (), 4, 8, device_index, mp_indexer->device_count (circuits), terminal_index + 1); - } -} - -bool -NetlistBrowserModel::is_id_circuit (void *id) const -{ - if (mp_indexer->circuit_count () == 0) { - return false; - } - - pop (id, mp_indexer->circuit_count ()); - return id == 0; -} - -bool -NetlistBrowserModel::is_id_circuit_pin (void *id) const -{ - if (mp_indexer->circuit_count () == 0) { - return false; - } - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - pop (id, mp_indexer->circuit_count ()); - return (pop (id, 8) == 1 && always (pop (id, mp_indexer->pin_count (circuits))) && id == 0); -} - -bool -NetlistBrowserModel::is_id_circuit_pin_net (void *id) const -{ - if (mp_indexer->circuit_count () == 0) { - return false; - } - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - pop (id, mp_indexer->circuit_count ()); - return (pop (id, 8) == 1 && always (pop (id, mp_indexer->pin_count (circuits))) && id != 0); -} - -bool -NetlistBrowserModel::is_id_circuit_net (void *id) const -{ - if (mp_indexer->circuit_count () == 0) { - return false; - } - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - pop (id, mp_indexer->circuit_count ()); - return (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && id == 0); -} - -bool -NetlistBrowserModel::is_id_circuit_net_device_terminal (void *id) const -{ - if (mp_indexer->circuit_count () == 0) { - return false; - } - - void *org_id = id; - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - pop (id, mp_indexer->circuit_count ()); - if (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 1) { - IndexedNetlistModel::net_pair nets = nets_from_id (org_id); - pop (id, mp_indexer->net_terminal_count (nets)); - return id == 0; - } - - return false; -} - -bool -NetlistBrowserModel::is_id_circuit_net_device_terminal_others (void *id) const -{ - if (mp_indexer->circuit_count () == 0) { - return false; - } - - void *org_id = id; - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - pop (id, mp_indexer->circuit_count ()); - if (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 1) { - IndexedNetlistModel::net_pair nets = nets_from_id (org_id); - pop (id, mp_indexer->net_terminal_count (nets)); - return id != 0; - } - - return false; -} - -bool -NetlistBrowserModel::is_id_circuit_net_pin (void *id) const -{ - if (mp_indexer->circuit_count () == 0) { - return false; - } - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - pop (id, mp_indexer->circuit_count ()); - return (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 2); -} - -bool -NetlistBrowserModel::is_id_circuit_net_subcircuit_pin (void *id) const -{ - if (mp_indexer->circuit_count () == 0) { - return false; - } - - void *org_id = id; - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - pop (id, mp_indexer->circuit_count ()); - if (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 3) { - IndexedNetlistModel::net_pair nets = nets_from_id (org_id); - pop (id, mp_indexer->net_subcircuit_pin_count (nets)); - return id == 0; - } - - return false; -} - -bool -NetlistBrowserModel::is_id_circuit_net_subcircuit_pin_others (void *id) const -{ - if (mp_indexer->circuit_count () == 0) { - return false; - } - - void *org_id = id; - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - pop (id, mp_indexer->circuit_count ()); - if (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 3) { - IndexedNetlistModel::net_pair nets = nets_from_id (org_id); - pop (id, mp_indexer->net_subcircuit_pin_count (nets)); - return id != 0; - } - - return false; -} - -bool -NetlistBrowserModel::is_id_circuit_subcircuit (void *id) const -{ - if (mp_indexer->circuit_count () == 0) { - return false; - } - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - pop (id, mp_indexer->circuit_count ()); - return (pop (id, 8) == 3 && always (pop (id, mp_indexer->subcircuit_count (circuits))) && id == 0); -} - -bool -NetlistBrowserModel::is_id_circuit_subcircuit_pin (void *id) const -{ - if (mp_indexer->circuit_count () == 0) { - return false; - } - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - pop (id, mp_indexer->circuit_count ()); - return (pop (id, 8) == 3 && always (pop (id, mp_indexer->subcircuit_count (circuits))) && id != 0); -} - -bool -NetlistBrowserModel::is_id_circuit_device (void *id) const -{ - if (mp_indexer->circuit_count () == 0) { - return false; - } - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - pop (id, mp_indexer->circuit_count ()); - return (pop (id, 8) == 4 && always (pop (id, mp_indexer->device_count (circuits))) && id == 0); -} - -bool -NetlistBrowserModel::is_id_circuit_device_terminal (void *id) const -{ - if (mp_indexer->circuit_count () == 0) { - return false; - } - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - pop (id, mp_indexer->circuit_count ()); - return (pop (id, 8) == 4 && always (pop (id, mp_indexer->device_count (circuits))) && id != 0); -} - -size_t -NetlistBrowserModel::circuit_index_from_id (void *id) const -{ - return pop (id, mp_indexer->circuit_count ()); -} - -size_t -NetlistBrowserModel::circuit_pin_index_from_id (void *id) const -{ - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - pop (id, mp_indexer->circuit_count ()); - pop (id, 8); - return pop (id, mp_indexer->pin_count (circuits)); -} - -size_t -NetlistBrowserModel::circuit_device_index_from_id (void *id) const -{ - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - pop (id, mp_indexer->circuit_count ()); - pop (id, 8); - return pop (id, mp_indexer->device_count (circuits)); -} - -size_t -NetlistBrowserModel::circuit_device_terminal_index_from_id (void *id) const -{ - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - pop (id, mp_indexer->circuit_count ()); - pop (id, 8); - pop (id, mp_indexer->device_count (circuits)); - return reinterpret_cast (id) - 1; -} - -size_t -NetlistBrowserModel::circuit_subcircuit_index_from_id (void *id) const -{ - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - pop (id, mp_indexer->circuit_count ()); - pop (id, 8); - return pop (id, mp_indexer->subcircuit_count (circuits)); -} - -size_t -NetlistBrowserModel::circuit_subcircuit_pin_index_from_id (void *id) const -{ - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - pop (id, mp_indexer->circuit_count ()); - pop (id, 8); - pop (id, mp_indexer->subcircuit_count (circuits)); - return reinterpret_cast (id) - 1; -} - -size_t -NetlistBrowserModel::circuit_net_index_from_id (void *id) const -{ - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - pop (id, mp_indexer->circuit_count ()); - pop (id, 8); - return pop (id, mp_indexer->net_count (circuits)); -} - -size_t -NetlistBrowserModel::circuit_net_pin_index_from_id (void *id) const -{ - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - pop (id, mp_indexer->circuit_count ()); - pop (id, 8); - pop (id, mp_indexer->net_count (circuits)); - pop (id, 4); - return reinterpret_cast (id); -} - -size_t -NetlistBrowserModel::circuit_net_subcircuit_pin_index_from_id (void *id) const -{ - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - IndexedNetlistModel::net_pair nets = nets_from_id (id); - pop (id, mp_indexer->circuit_count ()); - pop (id, 8); - pop (id, mp_indexer->net_count (circuits)); - pop (id, 4); - return pop (id, mp_indexer->net_subcircuit_pin_count (nets)); -} - -size_t -NetlistBrowserModel::circuit_net_subcircuit_pin_other_index_from_id (void *id) const -{ - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - IndexedNetlistModel::net_pair nets = nets_from_id (id); - pop (id, mp_indexer->circuit_count ()); - pop (id, 8); - pop (id, mp_indexer->net_count (circuits)); - pop (id, 4); - pop (id, mp_indexer->net_subcircuit_pin_count (nets)); - return reinterpret_cast (id) - 1; -} - -size_t -NetlistBrowserModel::circuit_net_device_terminal_index_from_id (void *id) const -{ - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - IndexedNetlistModel::net_pair nets = nets_from_id (id); - pop (id, mp_indexer->circuit_count ()); - pop (id, 8); - pop (id, mp_indexer->net_count (circuits)); - pop (id, 4); - return pop (id, mp_indexer->net_terminal_count (nets)); -} - -size_t -NetlistBrowserModel::circuit_net_device_terminal_other_index_from_id (void *id) const -{ - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - IndexedNetlistModel::net_pair nets = nets_from_id (id); - pop (id, mp_indexer->circuit_count ()); - pop (id, 8); - pop (id, mp_indexer->net_count (circuits)); - pop (id, 4); - pop (id, mp_indexer->net_terminal_count (nets)); - return reinterpret_cast (id) - 1; -} - -int -NetlistBrowserModel::columnCount (const QModelIndex & /*parent*/) const -{ - // Item type & icon, link or description - return mp_indexer->is_single () ? 3 : 4; -} - -QIcon icon_for_status (db::NetlistCrossReference::Status status) -{ - if (status == db::NetlistCrossReference::NoMatch || status == db::NetlistCrossReference::Mismatch) { - return QIcon (":/error2_16.png"); - } else if (status == db::NetlistCrossReference::MatchWithWarning || status == db::NetlistCrossReference::Skipped) { - return QIcon (":/warn_16.png"); - } else { - return QIcon (); - } -} - -QVariant -NetlistBrowserModel::data (const QModelIndex &index, int role) const -{ - if (! index.isValid ()) { - return QVariant (); - } - - if (role == Qt::DecorationRole && index.column () == m_object_column) { - return QVariant (icon (index)); - } else if (role == Qt::DecorationRole && index.column () == m_status_column) { - return QVariant (icon_for_status (status (index))); - } else if (role == Qt::DisplayRole) { - return QVariant (text (index)); - } else if (role == Qt::ToolTipRole && index.column () == m_status_column) { - return tooltip (index); - } else if (role == Qt::UserRole) { - return QVariant (search_text (index)); - } else if (role == Qt::FontRole) { - db::NetlistCrossReference::Status st = status (index); - if (st == db::NetlistCrossReference::NoMatch || st == db::NetlistCrossReference::Mismatch || st == db::NetlistCrossReference::Skipped) { - QFont font; - font.setWeight (QFont::Bold); - return QVariant (font); - } - } else if (role == Qt::ForegroundRole) { - db::NetlistCrossReference::Status st = status (index); - if (st == db::NetlistCrossReference::Match || st == db::NetlistCrossReference::MatchWithWarning) { - // taken from marker browser: - return QVariant (QColor (0, 192, 0)); - } - } - return QVariant (); + return tl::to_qstring (tl::escaped_to_html (s)); } template @@ -899,138 +390,6 @@ std::string devices_string (const std::pair"; - - s += tl::escaped_to_html (title); - - s += ""; - - return tl::to_qstring (s); -} - -QString -NetlistBrowserModel::make_link_to (const std::pair &nets, int column) const -{ - if ((! nets.first || column == m_second_column) && (! nets.second || column == m_first_column)) { - return QString (); - } else { - - IndexedNetlistModel::circuit_pair circuits = mp_indexer->parent_of (nets); - void *id = no_id; - // NOTE: the nets may not be a valid net pair. In this case, circuits is (0, 0) and - // no link is generated - if (circuits.first || circuits.second) { - id = make_id_circuit_net (mp_indexer->circuit_index (circuits), mp_indexer->net_index (nets)); - } - - if (mp_indexer->is_single () || column == m_first_column) { - return build_url (id, "net", str_from_expanded_name (nets.first)); - } else if (column == m_second_column) { - return build_url (id, "net", str_from_expanded_name (nets.second)); - } else { - return build_url (id, "net", str_from_expanded_names (nets, mp_indexer->is_single ())); - } - - } -} - -QString -NetlistBrowserModel::make_link_to (const std::pair &devices, int column) const -{ - if ((! devices.first || column == m_second_column) && (! devices.second || column == m_first_column)) { - return QString (); - } else { - - IndexedNetlistModel::circuit_pair circuits = mp_indexer->parent_of (devices); - void *id = no_id; - // NOTE: the devices may not be a valid device pair. In this case, circuits is (0, 0) and - // no link is generated - if (circuits.first || circuits.second) { - id = make_id_circuit_device (mp_indexer->circuit_index (circuits), mp_indexer->device_index (devices)); - } - - if (mp_indexer->is_single () || column == m_first_column) { - return build_url (id, "device", str_from_expanded_name (devices.first)); - } else if (column == m_second_column) { - return build_url (id, "device", str_from_expanded_name (devices.second)); - } else { - return build_url (id, "device", str_from_expanded_names (devices, mp_indexer->is_single ())); - } - - } -} - -QString -NetlistBrowserModel::make_link_to (const std::pair &pins, const std::pair &circuits, int column) const -{ - if ((! pins.first || column == m_second_column) && (! pins.second || column == m_first_column)) { - return QString (); - } else { - void *id = make_id_circuit_pin (mp_indexer->circuit_index (circuits), mp_indexer->pin_index (pins, circuits)); - if (mp_indexer->is_single () || column == m_first_column) { - return build_url (id, "pin", str_from_expanded_name (pins.first)); - } else if (column == m_second_column) { - return build_url (id, "pin", str_from_expanded_name (pins.second)); - } else { - return build_url (id, "pin", str_from_expanded_names (pins, mp_indexer->is_single ())); - } - } -} - -QString -NetlistBrowserModel::make_link_to (const std::pair &circuits, int column) const -{ - if ((! circuits.first || column == m_second_column) && (! circuits.second || column == m_first_column)) { - return QString (); - } else { - void *id = make_id_circuit (mp_indexer->circuit_index (circuits)); - if (mp_indexer->is_single () || column == m_first_column) { - return build_url (id, "circuit", str_from_name (circuits.first)); - } else if (column == m_second_column) { - return build_url (id, "circuit", str_from_name (circuits.second)); - } else { - return build_url (id, "circuit", str_from_names (circuits, mp_indexer->is_single ())); - } - } -} - -QString -NetlistBrowserModel::make_link_to (const std::pair &subcircuits, int column) const -{ - if ((! subcircuits.first || column == m_second_column) && (! subcircuits.second || column == m_first_column)) { - return QString (); - } else { - - IndexedNetlistModel::circuit_pair circuits = mp_indexer->parent_of (subcircuits); - void *id = no_id; - // NOTE: the subcircuits may not be a valid subcircuit pair. In this case, circuits is (0, 0) and - // no link is generated - if (circuits.first || circuits.second) { - id = make_id_circuit_subcircuit (mp_indexer->circuit_index (circuits), mp_indexer->subcircuit_index (subcircuits)); - } - - if (mp_indexer->is_single () || column == m_first_column) { - return build_url (id, "subcircuit", str_from_expanded_name (subcircuits.first)); - } else if (column == m_second_column) { - return build_url (id, "subcircuit", str_from_expanded_name (subcircuits.second)); - } else { - return build_url (id, "subcircuit", str_from_expanded_names (subcircuits, mp_indexer->is_single ())); - } - - } -} - static IndexedNetlistModel::circuit_pair circuit_refs_from_subcircuits (const IndexedNetlistModel::subcircuit_pair &subcircuits) { @@ -1058,6 +417,20 @@ IndexedNetlistModel::subcircuit_pair subcircuits_from_pinrefs (const IndexedNetl return std::make_pair (subcircuit1, subcircuit2); } +static +IndexedNetlistModel::net_pair nets_from_pinrefs (const IndexedNetlistModel::net_subcircuit_pin_pair &pinrefs) +{ + const db::Net *net1 = 0, *net2 = 0; + if (pinrefs.first) { + net1 = pinrefs.first->net (); + } + if (pinrefs.second) { + net2 = pinrefs.second->net (); + } + + return std::make_pair (net1, net2); +} + static IndexedNetlistModel::device_pair devices_from_termrefs (const IndexedNetlistModel::net_terminal_pair &termrefs) { @@ -1101,17 +474,17 @@ IndexedNetlistModel::pin_pair pins_from_pinrefs (const IndexedNetlistModel::net_ } static -IndexedNetlistModel::net_pair nets_from_subcircuit_pins (const IndexedNetlistModel::subcircuit_pair &subcircuits, const IndexedNetlistModel::pin_pair &pins) +IndexedNetlistModel::pin_pair pins_from_netrefs (const IndexedNetlistModel::net_subcircuit_pin_pair &netrefs) { - const db::Net *net1 = 0, *net2 = 0; - if (pins.first && subcircuits.first) { - net1 = subcircuits.first->net_for_pin (pins.first->id ()); + const db::Pin *pin1 = 0, *pin2 = 0; + if (netrefs.first) { + pin1 = netrefs.first->pin (); } - if (pins.second && subcircuits.second) { - net2 = subcircuits.second->net_for_pin (pins.second->id ()); + if (netrefs.second) { + pin2 = netrefs.second->pin (); } - return std::make_pair (net1, net2); + return std::make_pair (pin1, pin2); } static @@ -1138,15 +511,39 @@ static std::pairterminal_def () : 0, termrefs.second ? termrefs.second->terminal_def () : 0); } -static std::pair terminal_defs_from_device_classes (const std::pair &device_classes, size_t terminal_id) +static std::pair terminal_defs_from_device_classes (IndexedNetlistModel *model, const std::pair &device_classes, const std::pair &devices, size_t terminal_id) { const db::DeviceTerminalDefinition *td1 = 0, *td2 = 0; if (device_classes.first && device_classes.first->terminal_definitions ().size () > terminal_id) { td1 = &device_classes.first->terminal_definitions () [terminal_id]; } - if (device_classes.second && device_classes.second->terminal_definitions ().size () > terminal_id) { - td2 = &device_classes.second->terminal_definitions () [terminal_id]; + + if (device_classes.second) { + + size_t second_terminal_id = terminal_id; + + // Because of terminal swapping we need to look up the second terminal by looking for equivalent terminals which carry the corresponding net + if (td1 && devices.first && devices.second) { + + size_t td1_id_norm = device_classes.first->normalize_terminal_id (td1->id ()); + const db::Net *n2 = model->second_net_for (devices.first->net_for_terminal (terminal_id)); + + for (size_t i = 0; i < device_classes.second->terminal_definitions ().size (); ++i) { + const db::DeviceTerminalDefinition &td = device_classes.second->terminal_definitions () [i]; + if (device_classes.second->normalize_terminal_id (td.id ()) == td1_id_norm) { + if (devices.second->net_for_terminal (i) == n2) { + second_terminal_id = i; + break; + } + } + } + + } + + td2 = &device_classes.second->terminal_definitions () [second_terminal_id]; + } + return std::make_pair (td1, td2); } @@ -1164,222 +561,15 @@ IndexedNetlistModel::net_pair nets_from_device_terminals (const IndexedNetlistMo return std::make_pair (net1, net2); } -const std::string field_sep (" / "); - -static QString escaped (const std::string &s) -{ - return tl::to_qstring (tl::escaped_to_html (s)); -} - QString NetlistBrowserModel::text (const QModelIndex &index) const { - void *id = index.internalPointer (); - - if (is_id_circuit (id)) { - - // circuit: - // + single mode: name | | - // + dual mode: name(a)/name(b) | name(a) | name(b) - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - if (index.column () == m_object_column) { - return escaped (str_from_names (circuits, mp_indexer->is_single ())); - } else if (!mp_indexer->is_single () && (index.column () == m_first_column || index.column () == m_second_column)) { - return escaped (str_from_name (index.column () == m_first_column ? circuits.first : circuits.second)); - } - - } else if (is_id_circuit_pin (id)) { - - // pin: - // + single mode: xname | | - // + dual mode: xname(a)/xname(b) | xname(a) | xname(b) - IndexedNetlistModel::pin_pair pins = pins_from_id (id); - if (index.column () == m_object_column) { - return escaped (str_from_expanded_names (pins, mp_indexer->is_single ())); - } else if (!mp_indexer->is_single () && (index.column () == m_first_column || index.column () == m_second_column)) { - return escaped (str_from_expanded_name (index.column () == m_first_column ? pins.first : pins.second)); - } - - } else if (is_id_circuit_pin_net (id)) { - - // circuit/pin/net: header column = name, second column link to net - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - IndexedNetlistModel::pin_pair pins = pins_from_id (id); - IndexedNetlistModel::net_pair nets = nets_from_circuit_pins (circuits, pins); - - if (index.column () == m_object_column) { - return escaped (str_from_expanded_names (nets, mp_indexer->is_single ())); - } else if (index.column () == m_first_column || index.column () == m_second_column) { - return make_link_to (nets, index.column ()); - } - - } else if (is_id_circuit_device (id)) { - - // circuit/device: header column = class + parameters, second column device name - IndexedNetlistModel::device_pair devices = devices_from_id (id); - - if (mp_indexer->is_single ()) { - - if (index.column () == m_object_column) { - return escaped (device_string (devices.first)); - } else if (index.column () == m_first_column) { - return escaped (str_from_expanded_name (devices.first)); - } - - } else { - - if (index.column () == m_object_column) { - return escaped (devices_string (devices, mp_indexer->is_single (), false /*without parameters*/)); - } else if (index.column () == m_first_column) { - return escaped (str_from_expanded_name (devices.first) + field_sep + device_string (devices.first)); - } else if (index.column () == m_second_column) { - return escaped (str_from_expanded_name (devices.second) + field_sep + device_string (devices.second)); - } - - } - - } else if (is_id_circuit_device_terminal (id)) { - - // circuit/device/terminal: header column = terminal name, second column link to net - IndexedNetlistModel::device_pair devices = devices_from_id (id); - size_t terminal = circuit_device_terminal_index_from_id (id); - - std::pair device_classes = device_classes_from_devices (devices); - std::pair termdefs = terminal_defs_from_device_classes (device_classes, terminal); - - if (index.column () == m_object_column) { - - return escaped (str_from_names (termdefs, mp_indexer->is_single ())); - - } else if (index.column () == m_first_column || index.column () == m_second_column) { - - IndexedNetlistModel::net_pair nets = nets_from_device_terminals (devices, termdefs); - return make_link_to (nets, index.column ()); - - } - - } else if (is_id_circuit_subcircuit (id)) { - - // circuit/subcircuit: header column = circuit name, second column subcircuit name - IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_id (id); - IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits); - if (index.column () == m_object_column) { - return make_link_to (circuit_refs); - } else if (index.column () == m_first_column) { - return escaped (str_from_expanded_name (subcircuits.first)); - } else if (index.column () == m_second_column) { - return escaped (str_from_expanded_name (subcircuits.second)); - } - - } else if (is_id_circuit_subcircuit_pin (id)) { - - // circuit/pin: header column = pin name, other columns net name - IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_id (id); - IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits); - IndexedNetlistModel::pin_pair pins = pins_from_id (id); - - if (index.column () == m_object_column) { - return make_link_to (pins, circuit_refs); - } else if (index.column () == m_first_column || index.column () == m_second_column) { - return make_link_to (nets_from_subcircuit_pins (subcircuits, pins), index.column ()); - } - - } else if (is_id_circuit_net (id)) { - - // circuit/net: header column = node count, second column net name - IndexedNetlistModel::net_pair nets = nets_from_id (id); - if (index.column () == m_object_column) { - return escaped (str_from_expanded_names (nets, mp_indexer->is_single ())); - } else if (index.column () == m_first_column && nets.first) { - return escaped (nets.first->expanded_name () + " (" + tl::to_string (nets.first->pin_count () + nets.first->terminal_count () + nets.first->subcircuit_pin_count ()) + ")"); - } else if (index.column () == m_second_column && nets.second) { - return escaped (nets.second->expanded_name () + " (" + tl::to_string (nets.second->pin_count () + nets.second->terminal_count () + nets.second->subcircuit_pin_count ()) + ")"); - } - - } else if (is_id_circuit_net_pin (id)) { - - // circuit/net/pin: header column = pin name, second column empty (for now) - IndexedNetlistModel::net_pin_pair pinrefs = net_pinrefs_from_id (id); - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - if (mp_indexer->is_single () && index.column () == m_object_column) { - return make_link_to (pins_from_pinrefs (pinrefs), circuits); - } else if (! mp_indexer->is_single () && (index.column () == m_first_column || index.column () == m_second_column)) { - return make_link_to (pins_from_pinrefs (pinrefs), circuits, index.column ()); - } - - } else if (is_id_circuit_net_subcircuit_pin (id)) { - - // circuit/net/pin: header column = pin name, second column empty (for now) - IndexedNetlistModel::net_subcircuit_pin_pair pinrefs = net_subcircuit_pinrefs_from_id (id); - IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_pinrefs (pinrefs); - IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits); - - if (index.column () == m_object_column) { - return make_link_to (pins_from_pinrefs (pinrefs), circuit_refs) + tl::to_qstring (field_sep) + make_link_to (circuit_refs); - } else if (index.column () == m_first_column || index.column () == m_second_column) { - return make_link_to (subcircuits_from_pinrefs (pinrefs), index.column ()); - } - - } else if (is_id_circuit_net_subcircuit_pin_others (id)) { - - // circuit/net/device terminal/more: header column = pin name, second column = net link - IndexedNetlistModel::net_subcircuit_pin_pair pinrefs = net_subcircuit_pinrefs_from_id (id); - IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_pinrefs (pinrefs); - size_t other_index = circuit_net_subcircuit_pin_other_index_from_id (id); - - IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits); - IndexedNetlistModel::pin_pair pins = mp_indexer->pin_from_index (circuit_refs, other_index).first; - - if (index.column () == m_object_column) { - return make_link_to (pins, circuit_refs); - } else if (index.column () == m_first_column || index.column () == m_second_column) { - return make_link_to (nets_from_subcircuit_pins (subcircuits, pins), index.column ()); - } - - } else if (is_id_circuit_net_device_terminal (id)) { - - // circuit/net/device terminal: header column = terminal and device string, second column = device name - IndexedNetlistModel::net_terminal_pair refs = net_terminalrefs_from_id (id); - IndexedNetlistModel::device_pair devices = devices_from_termrefs (refs); - - if (index.column () == m_object_column) { - - std::pair termdefs = terminal_defs_from_terminal_refs (refs); - - if (mp_indexer->is_single ()) { - return escaped (str_from_name (termdefs.first) + field_sep + device_string (devices.first)); - } else { - return escaped (str_from_names (termdefs, mp_indexer->is_single ()) + field_sep + devices_string (devices, mp_indexer->is_single (), true /*with parameters*/)); - } - - } else if (index.column () == m_first_column || index.column () == m_second_column) { - return make_link_to (devices, index.column ()); - } - - } else if (is_id_circuit_net_device_terminal_others (id)) { - - // circuit/net/device terminal/more: header column = terminal name, second column = net link - IndexedNetlistModel::net_terminal_pair refs = net_terminalrefs_from_id (id); - size_t other_index = circuit_net_device_terminal_other_index_from_id (id); - - IndexedNetlistModel::device_pair devices = devices_from_termrefs (refs); - std::pair device_classes = device_classes_from_devices (devices); - std::pair termdefs = terminal_defs_from_device_classes (device_classes, other_index); - - if (index.column () == m_object_column) { - - return escaped (str_from_names (termdefs, mp_indexer->is_single ())); - - } else if (index.column () == m_first_column || index.column () == m_second_column) { - - IndexedNetlistModel::net_pair nets = nets_from_device_terminals (devices, termdefs); - return make_link_to (nets, index.column ()); - - } - + NetlistModelItemData *d = (NetlistModelItemData *) (index.internalPointer ()); + if (! d) { + return QString (); + } else { + return d->text (index.column (), const_cast (this)); } - - return QString (); } static std::string combine_search_strings (const std::string &s1, const std::string &s2) @@ -1393,456 +583,171 @@ static std::string combine_search_strings (const std::string &s1, const std::str } } -template -static std::string search_string_from_expanded_names (const std::pair &objs) +static size_t rows_for (const db::Device *device) { - if (objs.first && objs.second) { - return combine_search_strings (objs.first->expanded_name (), objs.second->expanded_name ()); - } else if (objs.first) { - return objs.first->expanded_name (); - } else if (objs.second) { - return objs.second->expanded_name (); + if (! device || ! device->device_class ()) { + return 0; } else { - return std::string (); + return device->device_class ()->terminal_definitions ().size (); } } -template -static std::string search_string_from_names (const std::pair &objs) +static size_t rows_for (const db::NetTerminalRef *ref) { - if (objs.first && objs.second) { - return combine_search_strings (objs.first->name (), objs.second->name ()); - } else if (objs.first) { - return objs.first->name (); - } else if (objs.second) { - return objs.second->name (); + if (! ref || ! ref->device_class ()) { + return 0; } else { - return std::string (); + return ref->device_class ()->terminal_definitions ().size (); } } -bool -NetlistBrowserModel::is_valid_net_pair (const std::pair &nets) const -{ - if (! nets.first && ! nets.second) { - // this is a valid case: e.g. two matching subcircuit pins without nets attached - // to them - return true; - } else { - IndexedNetlistModel::circuit_pair net_parent = mp_indexer->parent_of (nets); - return (net_parent.first != 0 || net_parent.second != 0); - } -} - -db::NetlistCrossReference::Status -NetlistBrowserModel::status (const QModelIndex &index) const -{ - void *id = index.internalPointer (); - - if (is_id_circuit (id)) { - - size_t index = circuit_index_from_id (id); - return mp_indexer->circuit_from_index (index).second; - - } else if (is_id_circuit_pin (id)) { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - size_t index = circuit_pin_index_from_id (id); - return mp_indexer->pin_from_index (circuits, index).second; - - } else if (is_id_circuit_device (id)) { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - size_t index = circuit_device_index_from_id (id); - return mp_indexer->device_from_index (circuits, index).second; - - } else if (is_id_circuit_device_terminal (id)) { - - IndexedNetlistModel::device_pair devices = devices_from_id (id); - std::pair device_classes = device_classes_from_devices (devices); - size_t terminal = circuit_device_terminal_index_from_id (id); - - std::pair termdefs = terminal_defs_from_device_classes (device_classes, terminal); - - if (! is_valid_net_pair (nets_from_device_terminals (devices, termdefs))) { - // This indicates a wrong connection: the nets are associated in a way which is a not - // corresponding to a mapped net pair. Report Mismatch here. - return db::NetlistCrossReference::NoMatch; - } - - } else if (is_id_circuit_subcircuit (id)) { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - size_t index = circuit_subcircuit_index_from_id (id); - return mp_indexer->subcircuit_from_index (circuits, index).second; - - } else if (is_id_circuit_subcircuit_pin (id)) { - - IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_id (id); - IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits); - IndexedNetlistModel::pin_pair pins = pins_from_id (id); - - db::NetlistCrossReference::Status status = mp_indexer->pin_from_index (circuit_refs, mp_indexer->pin_index (pins, circuit_refs)).second; - if (status == db::NetlistCrossReference::Mismatch || status == db::NetlistCrossReference::NoMatch) { - return status; - } - - // Another test here is to check whether the pins may be attached to an invalid net pair - if (! is_valid_net_pair (nets_from_subcircuit_pins (subcircuits, pins))) { - // This indicates a wrong connection: the nets are associated in a way which is a not - // corresponding to a mapped net pair. Report Mismatch here. - return db::NetlistCrossReference::NoMatch; - } - - } else if (is_id_circuit_net (id)) { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - size_t index = circuit_net_index_from_id (id); - return mp_indexer->net_from_index (circuits, index).second; - - } else if (is_id_circuit_net_device_terminal (id)) { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - IndexedNetlistModel::net_terminal_pair termrefs = net_terminalrefs_from_id (id); - IndexedNetlistModel::device_pair devices = devices_from_termrefs (termrefs); - - return mp_indexer->device_from_index (circuits, mp_indexer->device_index (devices)).second; - - } else if (is_id_circuit_net_device_terminal_others (id)) { - - IndexedNetlistModel::net_terminal_pair termrefs = net_terminalrefs_from_id (id); - size_t other_index = circuit_net_device_terminal_other_index_from_id (id); - - IndexedNetlistModel::device_pair devices = devices_from_termrefs (termrefs); - std::pair device_classes = device_classes_from_devices (devices); - std::pair termdefs = terminal_defs_from_device_classes (device_classes, other_index); - - if (! is_valid_net_pair (nets_from_device_terminals (devices, termdefs))) { - // This indicates a wrong connection: the nets are associated in a way which is a not - // corresponding to a mapped net pair. Report Mismatch here. - return db::NetlistCrossReference::NoMatch; - } - - } else if (is_id_circuit_net_subcircuit_pin (id)) { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - IndexedNetlistModel::net_subcircuit_pin_pair pinrefs = net_subcircuit_pinrefs_from_id (id); - IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_pinrefs (pinrefs); - - return mp_indexer->subcircuit_from_index (circuits, mp_indexer->subcircuit_index (subcircuits)).second; - - } else if (is_id_circuit_net_subcircuit_pin_others (id)) { - - IndexedNetlistModel::net_subcircuit_pin_pair pinrefs = net_subcircuit_pinrefs_from_id (id); - IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_pinrefs (pinrefs); - size_t other_index = circuit_net_subcircuit_pin_other_index_from_id (id); - - IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits); - IndexedNetlistModel::pin_pair pins = mp_indexer->pin_from_index (circuit_refs, other_index).first; - - if (! is_valid_net_pair (nets_from_subcircuit_pins (subcircuits, pins))) { - // This indicates a wrong connection: the nets are associated in a way which is a not - // corresponding to a mapped net pair. Report Mismatch here. - return db::NetlistCrossReference::NoMatch; - } - - } - - return db::NetlistCrossReference::None; -} - -static std::string rewire_subcircuit_pins_status_hint () -{ - return tl::to_string (tr ("Either pins or nets don't form a good pair.\nThis means either pin swapping happens (in this case, the nets will still match)\nor the subcircuit wiring is not correct (you'll see an error on the net).")); -} - -QVariant -NetlistBrowserModel::tooltip (const QModelIndex &index) const -{ - void *id = index.internalPointer (); - std::string hint; - - if (is_id_circuit (id)) { - - size_t index = circuit_index_from_id (id); - hint = mp_indexer->circuit_status_hint (index); - - } else if (is_id_circuit_pin (id)) { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - size_t index = circuit_pin_index_from_id (id); - hint = mp_indexer->pin_status_hint (circuits, index); - - } else if (is_id_circuit_device (id)) { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - size_t index = circuit_device_index_from_id (id); - hint = mp_indexer->device_status_hint (circuits, index); - - } else if (is_id_circuit_subcircuit (id)) { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - size_t index = circuit_subcircuit_index_from_id (id); - hint = mp_indexer->subcircuit_status_hint (circuits, index); - - } else if (is_id_circuit_subcircuit_pin (id)) { - - IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_id (id); - IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits); - IndexedNetlistModel::pin_pair pins = pins_from_id (id); - - hint = mp_indexer->pin_status_hint (circuit_refs, mp_indexer->pin_index (pins, circuit_refs)); - if (hint.empty ()) { - - // Another test here is to check whether the pins may be attached to an invalid net pair - if (! is_valid_net_pair (nets_from_subcircuit_pins (subcircuits, pins))) { - hint = rewire_subcircuit_pins_status_hint (); - } - - } - - } else if (is_id_circuit_net (id)) { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - size_t index = circuit_net_index_from_id (id); - hint = mp_indexer->net_status_hint (circuits, index); - - } else if (is_id_circuit_net_device_terminal (id)) { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - IndexedNetlistModel::net_terminal_pair termrefs = net_terminalrefs_from_id (id); - IndexedNetlistModel::device_pair devices = devices_from_termrefs (termrefs); - - hint = mp_indexer->device_status_hint (circuits, mp_indexer->device_index (devices)); - - } else if (is_id_circuit_net_subcircuit_pin (id)) { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - IndexedNetlistModel::net_subcircuit_pin_pair pinrefs = net_subcircuit_pinrefs_from_id (id); - IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_pinrefs (pinrefs); - - hint = mp_indexer->subcircuit_status_hint (circuits, mp_indexer->subcircuit_index (subcircuits)); - - } else if (is_id_circuit_net_subcircuit_pin_others (id)) { - - IndexedNetlistModel::net_subcircuit_pin_pair pinrefs = net_subcircuit_pinrefs_from_id (id); - IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_pinrefs (pinrefs); - size_t other_index = circuit_net_subcircuit_pin_other_index_from_id (id); - - IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits); - IndexedNetlistModel::pin_pair pins = mp_indexer->pin_from_index (circuit_refs, other_index).first; - - if (! is_valid_net_pair (nets_from_subcircuit_pins (subcircuits, pins))) { - // This indicates a wrong connection: the nets are associated in a way which is a not - // corresponding to a mapped net pair. Report Mismatch here. - hint = rewire_subcircuit_pins_status_hint (); - } - - } - - if (hint.empty ()) { - return QVariant (); - } else { - return QVariant (tl::to_qstring (hint)); - } -} - -QString -NetlistBrowserModel::search_text (const QModelIndex &index) const -{ - void *id = index.internalPointer (); - - if (is_id_circuit (id)) { - - return tl::to_qstring (search_string_from_names (circuits_from_id (id))); - - } else if (is_id_circuit_pin (id)) { - - return tl::to_qstring (search_string_from_expanded_names (pins_from_id (id))); - - } else if (is_id_circuit_pin_net (id)) { - - return tl::to_qstring (search_string_from_expanded_names (nets_from_circuit_pins (circuits_from_id (id), pins_from_id (id)))); - - } else if (is_id_circuit_device (id)) { - - IndexedNetlistModel::device_pair devices = devices_from_id (id); - std::pair device_classes = device_classes_from_devices (devices); - return tl::to_qstring (combine_search_strings (search_string_from_expanded_names (devices), search_string_from_names (device_classes))); - - } else if (is_id_circuit_device_terminal (id)) { - - IndexedNetlistModel::device_pair devices = devices_from_id (id); - std::pair device_classes = device_classes_from_devices (devices); - size_t terminal = circuit_device_terminal_index_from_id (id); - - std::pair termdefs = terminal_defs_from_device_classes (device_classes, terminal); - IndexedNetlistModel::net_pair nets = nets_from_device_terminals (devices, termdefs); - - return tl::to_qstring (combine_search_strings (search_string_from_names (termdefs), search_string_from_expanded_names (nets))); - - } else if (is_id_circuit_subcircuit (id)) { - - IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_id (id); - IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits); - - return tl::to_qstring (combine_search_strings (search_string_from_names (circuit_refs), search_string_from_expanded_names (subcircuits))); - - } else if (is_id_circuit_subcircuit_pin (id)) { - - IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_id (id); - IndexedNetlistModel::pin_pair pins = pins_from_id (id); - IndexedNetlistModel::net_pair nets = nets_from_subcircuit_pins (subcircuits, pins); - - return tl::to_qstring (combine_search_strings (search_string_from_names (pins), search_string_from_expanded_names (nets))); - - } else if (is_id_circuit_net (id)) { - - return tl::to_qstring (search_string_from_expanded_names (nets_from_id (id))); - - } else if (is_id_circuit_net_pin (id)) { - - IndexedNetlistModel::net_pin_pair pinrefs = net_pinrefs_from_id (id); - IndexedNetlistModel::pin_pair pins = pins_from_pinrefs (pinrefs); - - return tl::to_qstring (search_string_from_names (pins)); - - } else if (is_id_circuit_net_subcircuit_pin (id)) { - - IndexedNetlistModel::net_subcircuit_pin_pair pinrefs = net_subcircuit_pinrefs_from_id (id); - IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_pinrefs (pinrefs); - IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits); - IndexedNetlistModel::pin_pair pins = pins_from_pinrefs (pinrefs); - - return tl::to_qstring (combine_search_strings (combine_search_strings (search_string_from_names (pins), search_string_from_names (circuit_refs)), search_string_from_expanded_names (subcircuits))); - - } else if (is_id_circuit_net_subcircuit_pin_others (id)) { - - IndexedNetlistModel::net_subcircuit_pin_pair pinrefs = net_subcircuit_pinrefs_from_id (id); - size_t other_index = circuit_net_subcircuit_pin_other_index_from_id (id); - - IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_pinrefs (pinrefs); - IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits); - - IndexedNetlistModel::pin_pair pins = mp_indexer->pin_from_index (circuit_refs, other_index).first; - IndexedNetlistModel::net_pair nets = nets_from_circuit_pins (circuit_refs, pins); - - return tl::to_qstring (combine_search_strings (search_string_from_names (pins), search_string_from_expanded_names (nets))); - - } else if (is_id_circuit_net_device_terminal (id)) { - - IndexedNetlistModel::net_terminal_pair termrefs = net_terminalrefs_from_id (id); - IndexedNetlistModel::device_pair devices = devices_from_termrefs (termrefs); - std::pair device_classes = device_classes_from_devices (devices); - std::pair termdefs = terminal_defs_from_terminal_refs (termrefs); - - return tl::to_qstring (combine_search_strings (combine_search_strings (search_string_from_names (termdefs), search_string_from_names (device_classes)), search_string_from_expanded_names (devices))); - - } else if (is_id_circuit_net_device_terminal_others (id)) { - - IndexedNetlistModel::net_terminal_pair termrefs = net_terminalrefs_from_id (id); - size_t other_index = circuit_net_device_terminal_other_index_from_id (id); - - IndexedNetlistModel::device_pair devices = devices_from_termrefs (termrefs); - std::pair device_classes = device_classes_from_devices (devices); - std::pair termdefs = terminal_defs_from_device_classes (device_classes, other_index); - - IndexedNetlistModel::net_pair nets = nets_from_device_terminals (devices, termdefs); - - return tl::to_qstring (combine_search_strings (search_string_from_names (termdefs), search_string_from_expanded_names (nets))); - - } - - return QString (); -} - static QIcon icon_for_net () { - QIcon icon; - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_net_48.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_net_32.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_net_24.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_net_16.png"))); + static QIcon icon; + if (icon.isNull ()) { + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_net_48.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_net_32.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_net_24.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_net_16.png"))); + } return icon; } static QIcon light_icon_for_net () { - QIcon icon; - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_net_light_48.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_net_light_32.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_net_light_24.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_net_light_16.png"))); + static QIcon icon; + if (icon.isNull ()) { + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_net_light_48.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_net_light_32.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_net_light_24.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_net_light_16.png"))); + } return icon; } static QIcon icon_for_connection () { - QIcon icon; - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_conn_48.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_conn_32.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_conn_24.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_conn_16.png"))); + static QIcon icon; + if (icon.isNull ()) { + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_conn_48.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_conn_32.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_conn_24.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_conn_16.png"))); + } return icon; } static QIcon light_icon_for_connection () { - QIcon icon; - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_conn_light_48.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_conn_light_32.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_conn_light_24.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_conn_light_16.png"))); + static QIcon icon; + if (icon.isNull ()) { + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_conn_light_48.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_conn_light_32.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_conn_light_24.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_conn_light_16.png"))); + } return icon; } static QIcon icon_for_pin () { - QIcon icon; - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_pin_48.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_pin_32.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_pin_24.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_pin_16.png"))); + static QIcon icon; + if (icon.isNull ()) { + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_pin_48.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_pin_32.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_pin_24.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_pin_16.png"))); + } return icon; } -static QIcon icon_for_device (const db::DeviceClass *dc) +static QIcon icon_for_device (const db::DeviceClass *dc, size_t term_id = 0) { - QIcon icon; - // TODO: inductor, generic device ... - if (dynamic_cast (dc)) { - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_48.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_32.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_24.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_16.png"))); - } else if (dynamic_cast (dc)) { - // fake ... - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_48.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_32.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_24.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_16.png"))); - } else if (dynamic_cast (dc)) { - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_cap_48.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_cap_32.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_cap_24.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_cap_16.png"))); - } else if (dynamic_cast (dc)) { - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_diode_48.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_diode_32.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_diode_24.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_diode_16.png"))); - } else if (dynamic_cast (dc)) { - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_bjt_48.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_bjt_32.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_bjt_24.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_bjt_16.png"))); - } else { - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_mos_48.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_mos_32.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_mos_24.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_mos_16.png"))); + static QIcon icon_for_res; + static QIcon icon_for_ind; + static QIcon icon_for_cap; + static QIcon icons_for_diode[2]; + static QIcon icons_for_bjt[4]; + static QIcon icons_for_mos[4]; + + if (icon_for_res.isNull ()) { + icon_for_res.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_48.png"))); + icon_for_res.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_32.png"))); + icon_for_res.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_24.png"))); + icon_for_res.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_16.png"))); + } + if (icon_for_ind.isNull ()) { + // fake ... + icon_for_ind.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_48.png"))); + icon_for_ind.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_32.png"))); + icon_for_ind.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_24.png"))); + icon_for_ind.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_res_16.png"))); + } + if (icon_for_cap.isNull ()) { + icon_for_cap.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_cap_48.png"))); + icon_for_cap.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_cap_32.png"))); + icon_for_cap.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_cap_24.png"))); + icon_for_cap.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_device_cap_16.png"))); + } + if (icons_for_diode[0].isNull ()) { + QImage i48 (QString::fromUtf8 (":/images/icon_device_diode_48.png")); + QImage i32 (QString::fromUtf8 (":/images/icon_device_diode_32.png")); + QImage i24 (QString::fromUtf8 (":/images/icon_device_diode_24.png")); + QImage i16 (QString::fromUtf8 (":/images/icon_device_diode_16.png")); + QTransform tr; + for (size_t i = 0; i < sizeof (icons_for_diode) / sizeof (icons_for_diode [0]); ++i) { + icons_for_diode[i].addPixmap (QPixmap::fromImage (i48.transformed (tr))); + icons_for_diode[i].addPixmap (QPixmap::fromImage (i32.transformed (tr))); + icons_for_diode[i].addPixmap (QPixmap::fromImage (i24.transformed (tr))); + icons_for_diode[i].addPixmap (QPixmap::fromImage (i16.transformed (tr))); + tr.rotate (180.0); + } + } + if (icons_for_bjt[0].isNull ()) { + QImage i48 (QString::fromUtf8 (":/images/icon_device_bjt_48.png")); + QImage i32 (QString::fromUtf8 (":/images/icon_device_bjt_32.png")); + QImage i24 (QString::fromUtf8 (":/images/icon_device_bjt_24.png")); + QImage i16 (QString::fromUtf8 (":/images/icon_device_bjt_16.png")); + QTransform tr; + for (size_t i = 0; i < sizeof (icons_for_bjt) / sizeof (icons_for_bjt [0]); ++i) { + icons_for_bjt[i].addPixmap (QPixmap::fromImage (i48.transformed (tr))); + icons_for_bjt[i].addPixmap (QPixmap::fromImage (i32.transformed (tr))); + icons_for_bjt[i].addPixmap (QPixmap::fromImage (i24.transformed (tr))); + icons_for_bjt[i].addPixmap (QPixmap::fromImage (i16.transformed (tr))); + tr.rotate (90.0); + } + } + if (icons_for_mos[0].isNull ()) { + QImage i48 (QString::fromUtf8 (":/images/icon_device_mos_48.png")); + QImage i32 (QString::fromUtf8 (":/images/icon_device_mos_32.png")); + QImage i24 (QString::fromUtf8 (":/images/icon_device_mos_24.png")); + QImage i16 (QString::fromUtf8 (":/images/icon_device_mos_16.png")); + QTransform tr; + for (size_t i = 0; i < sizeof (icons_for_mos) / sizeof (icons_for_mos [0]); ++i) { + icons_for_mos[i].addPixmap (QPixmap::fromImage (i48.transformed (tr))); + icons_for_mos[i].addPixmap (QPixmap::fromImage (i32.transformed (tr))); + icons_for_mos[i].addPixmap (QPixmap::fromImage (i24.transformed (tr))); + icons_for_mos[i].addPixmap (QPixmap::fromImage (i16.transformed (tr))); + tr.rotate (90.0); + } + } + + // TODO: generic device ... + if (dynamic_cast (dc)) { + return icon_for_res; + } else if (dynamic_cast (dc)) { + return icon_for_ind; + } else if (dynamic_cast (dc)) { + return icon_for_cap; + } else if (dynamic_cast (dc)) { + return icons_for_diode [term_id >= sizeof (icons_for_diode) / sizeof (icons_for_diode [0]) ? sizeof (icons_for_diode) / sizeof (icons_for_diode [0]) - 1 : term_id]; + } else if (dynamic_cast (dc) || dynamic_cast (dc)) { + return icons_for_bjt [term_id >= sizeof (icons_for_bjt) / sizeof (icons_for_bjt [0]) ? sizeof (icons_for_bjt) / sizeof (icons_for_bjt [0]) - 1 : term_id]; + } else if (dynamic_cast (dc) || dynamic_cast (dc)) { + return icons_for_mos [term_id >= sizeof (icons_for_mos) / sizeof (icons_for_mos [0]) ? sizeof (icons_for_mos) / sizeof (icons_for_mos [0]) - 1 : term_id]; + } else { + return icons_for_mos [0]; } - return icon; } static QIcon icon_for_devices (const std::pair &device_classes) @@ -1850,13 +755,35 @@ static QIcon icon_for_devices (const std::pair &device_classes, + const std::pair &terminal_defs) +{ + return icon_for_device (device_classes.first ? device_classes.first : device_classes.second, terminal_defs.first ? terminal_defs.first->id () : (terminal_defs.second ? terminal_defs.second->id () : 0)); +} + static QIcon icon_for_circuit () { - QIcon icon; - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_circuit_48.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_circuit_32.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_circuit_24.png"))); - icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_circuit_16.png"))); + static QIcon icon; + if (icon.isNull ()) { + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_circuit_48.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_circuit_32.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_circuit_24.png"))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/images/icon_circuit_16.png"))); + } + return icon; +} + +static QIcon icon_for_subcircuit () +{ + static QIcon icon; + if (icon.isNull ()) { + QTransform tr; + tr.rotate (90.0); + icon.addPixmap (QPixmap::fromImage (QImage (QString::fromUtf8 (":/images/icon_circuit_48.png"))).transformed (tr)); + icon.addPixmap (QPixmap::fromImage (QImage (QString::fromUtf8 (":/images/icon_circuit_32.png"))).transformed (tr)); + icon.addPixmap (QPixmap::fromImage (QImage (QString::fromUtf8 (":/images/icon_circuit_24.png"))).transformed (tr)); + icon.addPixmap (QPixmap::fromImage (QImage (QString::fromUtf8 (":/images/icon_circuit_16.png"))).transformed (tr)); + } return icon; } @@ -1904,6 +831,1942 @@ static QIcon connection_icon_with_color (const QColor &color) return colored_icon (color, light_icon_for_connection ()); } +template +static std::string search_string_from_expanded_names (const std::pair &objs) +{ + if (objs.first && objs.second) { + return combine_search_strings (objs.first->expanded_name (), objs.second->expanded_name ()); + } else if (objs.first) { + return objs.first->expanded_name (); + } else if (objs.second) { + return objs.second->expanded_name (); + } else { + return std::string (); + } +} + +template +static std::string search_string_from_names (const std::pair &objs) +{ + if (objs.first && objs.second) { + return combine_search_strings (objs.first->name (), objs.second->name ()); + } else if (objs.first) { + return objs.first->name (); + } else if (objs.second) { + return objs.second->name (); + } else { + return std::string (); + } +} + +// ---------------------------------------------------------------------------------- +// item class declarations + +class RootItemData + : public NetlistModelItemData +{ +public: + RootItemData (); + + virtual void do_ensure_children (NetlistBrowserModel *model); + virtual QIcon icon (NetlistBrowserModel *model); + virtual QString text (int column, NetlistBrowserModel *model); + virtual QString search_text (); + virtual std::string tooltip (NetlistBrowserModel *model); + virtual db::NetlistCrossReference::Status status (NetlistBrowserModel *model); + + CircuitItemData *circuit_item (NetlistBrowserModel *model, const IndexedNetlistModel::circuit_pair &cp); +}; + +// ---------------------------------------------------------------------------------- + +class CircuitItemData + : public NetlistModelItemData +{ +public: + CircuitItemData (NetlistModelItemData *parent, const IndexedNetlistModel::circuit_pair &cp); + + virtual void do_ensure_children (NetlistBrowserModel *model); + virtual QIcon icon (NetlistBrowserModel *model); + virtual QString text (int column, NetlistBrowserModel *model); + virtual QString search_text (); + virtual std::string tooltip (NetlistBrowserModel *model); + virtual db::NetlistCrossReference::Status status (NetlistBrowserModel *model); + + virtual std::pair circuits_of_this () + { + return m_cp; + } + + CircuitNetItemData *circuit_net_item (NetlistBrowserModel *model, const IndexedNetlistModel::net_pair &np); + CircuitDeviceItemData *circuit_device_item (NetlistBrowserModel *model, const IndexedNetlistModel::device_pair &dp); + CircuitSubCircuitItemData *circuit_subcircuit_item (NetlistBrowserModel *model, const IndexedNetlistModel::subcircuit_pair &sp); + +private: + IndexedNetlistModel::circuit_pair m_cp; +}; + +// ---------------------------------------------------------------------------------- + +class CircuitItemForSubCircuitData + : public CircuitItemData +{ +public: + CircuitItemForSubCircuitData (NetlistModelItemData *parent, const IndexedNetlistModel::subcircuit_pair &sp); + + virtual QString text (int column, NetlistBrowserModel *model); + virtual QString search_text (); + virtual std::string tooltip (NetlistBrowserModel *model); + virtual db::NetlistCrossReference::Status status (NetlistBrowserModel *model); + + virtual std::pair subcircuits_of_this () + { + return m_sp; + } + +private: + IndexedNetlistModel::subcircuit_pair m_sp; +}; + +// ---------------------------------------------------------------------------------- + +class CircuitItemNodeData + : public NetlistModelItemData +{ +public: + enum type { Nets, Devices, Pins, SubCircuits }; + + CircuitItemNodeData (NetlistModelItemData *parent, type t); + + virtual void do_ensure_children (NetlistBrowserModel *model); + virtual QIcon icon (NetlistBrowserModel *model); + virtual QString text (int column, NetlistBrowserModel *model); + virtual QString search_text (); + virtual std::string tooltip (NetlistBrowserModel *model); + virtual db::NetlistCrossReference::Status status (NetlistBrowserModel *model); + + CircuitNetItemData *circuit_net_item (NetlistBrowserModel *model, const IndexedNetlistModel::net_pair &np); + CircuitDeviceItemData *circuit_device_item (NetlistBrowserModel *model, const IndexedNetlistModel::device_pair &dp); + CircuitSubCircuitItemData *circuit_subcircuit_item (NetlistBrowserModel *model, const IndexedNetlistModel::subcircuit_pair &sp); + +private: + type m_type; +}; + +// ---------------------------------------------------------------------------------- + +class CircuitNetItemData + : public NetlistModelItemData +{ +public: + CircuitNetItemData (NetlistModelItemData *parent, const IndexedNetlistModel::net_pair &np); + + virtual void do_ensure_children (NetlistBrowserModel *model); + virtual QIcon icon (NetlistBrowserModel *model); + virtual QString text (int column, NetlistBrowserModel *model); + virtual QString search_text (); + virtual std::string tooltip (NetlistBrowserModel *model); + virtual db::NetlistCrossReference::Status status (NetlistBrowserModel *model); + + const IndexedNetlistModel::net_pair &np () + { + return m_np; + } + + virtual std::pair nets_of_this () + { + return m_np; + } + + bool seen () const + { + return m_seen; + } + +private: + IndexedNetlistModel::net_pair m_np; + bool m_seen; +}; + +// ---------------------------------------------------------------------------------- + +class CircuitNetDeviceTerminalItemData + : public NetlistModelItemData +{ +public: + CircuitNetDeviceTerminalItemData (NetlistModelItemData *parent, const IndexedNetlistModel::net_terminal_pair &tp); + + virtual void do_ensure_children (NetlistBrowserModel * /*model*/); + virtual QIcon icon (NetlistBrowserModel *model); + virtual QString text (int column, NetlistBrowserModel *model); + virtual QString search_text (); + virtual std::string tooltip (NetlistBrowserModel *model); + virtual db::NetlistCrossReference::Status status (NetlistBrowserModel *model); + + const IndexedNetlistModel::net_pair &np () + { + CircuitNetItemData *p = static_cast (parent ()); + return p->np (); + } + + IndexedNetlistModel::device_pair dp () + { + return devices_from_termrefs (tp ()); + } + + const IndexedNetlistModel::net_terminal_pair &tp () + { + return m_tp; + } + + virtual std::pair devices_of_this () + { + return dp (); + } + +private: + IndexedNetlistModel::net_terminal_pair m_tp; + bool m_device_seen; +}; + +// ---------------------------------------------------------------------------------- + +class CircuitNetDeviceTerminalOthersItemData + : public CircuitNetItemData +{ +public: + CircuitNetDeviceTerminalOthersItemData (NetlistModelItemData *parent, const IndexedNetlistModel::net_pair &np, const std::pair &tp); + + virtual QIcon icon (NetlistBrowserModel *model); + virtual QString text (int column, NetlistBrowserModel *model); + virtual QString search_text (); + +private: + std::pair m_tp; + IndexedNetlistModel::net_pair m_np; +}; + +// ---------------------------------------------------------------------------------- + +class CircuitNetSubCircuitPinItemData + : public NetlistModelItemData +{ +public: + CircuitNetSubCircuitPinItemData (NetlistModelItemData *parent, const IndexedNetlistModel::net_subcircuit_pin_pair &pp); + + virtual void do_ensure_children (NetlistBrowserModel *model); + virtual QIcon icon (NetlistBrowserModel *model); + virtual QString text (int column, NetlistBrowserModel *model); + virtual QString search_text (); + virtual std::string tooltip (NetlistBrowserModel *model); + virtual db::NetlistCrossReference::Status status (NetlistBrowserModel *model); + + const IndexedNetlistModel::net_pair &np () + { + CircuitNetItemData *p = static_cast (parent ()); + return p->np (); + } + + const IndexedNetlistModel::net_subcircuit_pin_pair &sp () + { + return m_sp; + } + + IndexedNetlistModel::pin_pair pp () + { + return pins_from_pinrefs (m_sp); + } + + virtual std::pair subcircuits_of_this () + { + return subcircuits_from_pinrefs (m_sp); + } + + // NOTE: this is important as this node acts as parent for nets inside this circuit + virtual std::pair circuits_of_this () + { + return circuit_refs_from_subcircuits (subcircuits_of_this ()); + } + + virtual std::pair pins_of_this () + { + return m_pp; + } + +private: + IndexedNetlistModel::net_subcircuit_pin_pair m_sp; + IndexedNetlistModel::pin_pair m_pp; + bool m_subcircuit_seen; +}; + +// ---------------------------------------------------------------------------------- + +class CircuitNetPinItemData + : public NetlistModelItemData +{ +public: + CircuitNetPinItemData (NetlistModelItemData *parent, const IndexedNetlistModel::net_pin_pair &pp); + + virtual void do_ensure_children (NetlistBrowserModel *); + virtual QIcon icon (NetlistBrowserModel *model); + virtual QString text (int column, NetlistBrowserModel *model); + virtual QString search_text (); + virtual std::string tooltip (NetlistBrowserModel *model); + virtual db::NetlistCrossReference::Status status (NetlistBrowserModel *model); + + virtual std::pair pins_of_this () + { + return pins_from_pinrefs (m_pp); + } + +private: + IndexedNetlistModel::net_pin_pair m_pp; +}; + +// ---------------------------------------------------------------------------------- + +class CircuitSubCircuitItemData + : public NetlistModelItemData +{ +public: + CircuitSubCircuitItemData (NetlistModelItemData *parent, const IndexedNetlistModel::subcircuit_pair &sp); + + virtual void do_ensure_children (NetlistBrowserModel *model); + virtual QIcon icon (NetlistBrowserModel *model); + virtual QString text (int column, NetlistBrowserModel *model); + virtual QString search_text (); + virtual std::string tooltip (NetlistBrowserModel *model); + virtual db::NetlistCrossReference::Status status (NetlistBrowserModel *model); + + const IndexedNetlistModel::subcircuit_pair &sp () + { + return m_sp; + } + + CircuitItemForSubCircuitData *circuit_item () + { + return mp_circuit_node; + } + +private: + IndexedNetlistModel::subcircuit_pair m_sp; + CircuitItemForSubCircuitData *mp_circuit_node; +}; + +// ---------------------------------------------------------------------------------- + +class CircuitPinItemData + : public CircuitNetItemData +{ +public: + CircuitPinItemData (NetlistModelItemData *parent, const IndexedNetlistModel::pin_pair &pp); + + virtual QIcon icon (NetlistBrowserModel *model); + virtual QString text (int column, NetlistBrowserModel *model); + virtual QString search_text (); + + virtual std::pair pins_of_this () + { + return m_pp; + } + +private: + IndexedNetlistModel::pin_pair m_pp; +}; + +// ---------------------------------------------------------------------------------- + +class CircuitSubCircuitPinsItemData + : public NetlistModelItemData +{ +public: + CircuitSubCircuitPinsItemData (NetlistModelItemData *parent, const IndexedNetlistModel::subcircuit_pair &sp); + + virtual void do_ensure_children (NetlistBrowserModel *model); + virtual QIcon icon (NetlistBrowserModel *model); + virtual QString text (int column, NetlistBrowserModel *model); + virtual QString search_text (); + virtual std::string tooltip (NetlistBrowserModel *model); + virtual db::NetlistCrossReference::Status status (NetlistBrowserModel *model); + + const IndexedNetlistModel::subcircuit_pair &sp () + { + return m_sp; + } + +private: + IndexedNetlistModel::subcircuit_pair m_sp; +}; + +// ---------------------------------------------------------------------------------- + +class CircuitSubCircuitPinItemData + : public CircuitNetItemData +{ +public: + CircuitSubCircuitPinItemData (NetlistModelItemData *parent, const IndexedNetlistModel::net_subcircuit_pin_pair &pp); + + virtual QIcon icon (NetlistBrowserModel *model); + virtual QString text (int column, NetlistBrowserModel *model); + virtual QString search_text (); + + IndexedNetlistModel::subcircuit_pair sp () + { + return subcircuits_from_pinrefs (m_pp); + } + + virtual std::pair pins_of_this () + { + return pins_from_netrefs (m_pp); + } + +private: + IndexedNetlistModel::net_subcircuit_pin_pair m_pp; +}; + +// ---------------------------------------------------------------------------------- + +class CircuitDeviceItemData + : public NetlistModelItemData +{ +public: + CircuitDeviceItemData (NetlistModelItemData *parent, const IndexedNetlistModel::device_pair &dp); + + virtual void do_ensure_children (NetlistBrowserModel * /*model*/); + virtual QIcon icon (NetlistBrowserModel *model); + virtual QString text (int column, NetlistBrowserModel *model); + virtual QString search_text (); + virtual std::string tooltip (NetlistBrowserModel *model); + virtual db::NetlistCrossReference::Status status (NetlistBrowserModel *model); + + const IndexedNetlistModel::device_pair &dp () + { + return m_dp; + } + + virtual std::pair devices_of_this () + { + return m_dp; + } + +private: + IndexedNetlistModel::device_pair m_dp; +}; + +// ---------------------------------------------------------------------------------- + +class CircuitDeviceTerminalItemData + : public CircuitNetItemData +{ +public: + CircuitDeviceTerminalItemData (NetlistModelItemData *parent, const std::pair &tp); + + virtual QIcon icon (NetlistBrowserModel *model); + virtual QString text (int column, NetlistBrowserModel *model); + virtual QString search_text (); + +private: + std::pair m_tp; +}; + +// ---------------------------------------------------------------------------------- +// item class implementations + +NetlistModelItemData::NetlistModelItemData () + : mp_parent (0), m_children_made (false), m_index (0) +{ } + +NetlistModelItemData::NetlistModelItemData (NetlistModelItemData *parent) + : mp_parent (parent), m_children_made (false), m_index (0) +{ } + +NetlistModelItemData::~NetlistModelItemData () +{ } + +void +NetlistModelItemData::ensure_children (NetlistBrowserModel *model) +{ + if (! m_children_made) { + + m_children.clear (); + m_children_per_index.clear (); + + do_ensure_children (model); + + size_t n = 0; + for (iterator i = begin (); i != end (); ++i) { + ++n; + } + m_children_per_index.reserve (n); + + size_t index = 0; + for (iterator i = begin (); i != end (); ++i) { + m_children_per_index.push_back (i.operator-> ()); + i->set_index (index++); + } + + m_children_made = true; + + } +} + +void +NetlistModelItemData::push_back (NetlistModelItemData *child) +{ + m_children.push_back (child); +} + +NetlistModelItemData * +NetlistModelItemData::child (size_t n) +{ + return (n < m_children_per_index.size () ? m_children_per_index [n] : 0); +} + +std::pair +NetlistModelItemData::circuits_of_this () +{ + return std::pair (0, 0); +} + +std::pair +NetlistModelItemData::circuits () +{ + std::pair r = circuits_of_this (); + if (! mp_parent || r.first || r.second) { + return r; + } else { + return mp_parent->circuits (); + } +} + +bool +NetlistModelItemData::derived_from_circuits (const std::pair &cp) +{ + if (! cp.first && ! cp.second) { + return false; + } else if (circuits_of_this () == cp) { + return true; + } else if (mp_parent) { + return mp_parent->derived_from_circuits (cp); + } else { + return false; + } +} + +std::pair +NetlistModelItemData::devices_of_this () +{ + return std::pair (0, 0); +} + +std::pair +NetlistModelItemData::devices () +{ + std::pair r = devices_of_this (); + if (! mp_parent || r.first || r.second) { + return r; + } else { + return mp_parent->devices (); + } +} + +bool +NetlistModelItemData::derived_from_devices (const std::pair &sp) +{ + if (! sp.first && ! sp.second) { + return false; + } else if (devices_of_this () == sp) { + return true; + } else if (mp_parent) { + return mp_parent->derived_from_devices (sp); + } else { + return false; + } +} + +std::pair +NetlistModelItemData::pins_of_this () +{ + return std::pair (0, 0); +} + +std::pair +NetlistModelItemData::pins () +{ + std::pair r = pins_of_this (); + if (! mp_parent || r.first || r.second) { + return r; + } else { + return mp_parent->pins (); + } +} + +bool +NetlistModelItemData::derived_from_pins (const std::pair &sp) +{ + if (! sp.first && ! sp.second) { + return false; + } else if (pins_of_this () == sp) { + return true; + } else if (mp_parent) { + return mp_parent->derived_from_pins (sp); + } else { + return false; + } +} + +std::pair +NetlistModelItemData::subcircuits_of_this () +{ + return std::pair (0, 0); +} + +std::pair +NetlistModelItemData::subcircuits () +{ + std::pair r = subcircuits_of_this (); + if (! mp_parent || r.first || r.second) { + return r; + } else { + return mp_parent->subcircuits (); + } +} + +bool +NetlistModelItemData::derived_from_subcircuits (const std::pair &sp) +{ + if (! sp.first && ! sp.second) { + return false; + } else if (subcircuits_of_this () == sp) { + return true; + } else if (mp_parent) { + return mp_parent->derived_from_subcircuits (sp); + } else { + return false; + } +} + +std::pair +NetlistModelItemData::nets_of_this () +{ + return std::pair (0, 0); +} + +std::pair +NetlistModelItemData::nets () +{ + std::pair r = nets_of_this (); + if (! mp_parent || r.first || r.second) { + return r; + } else { + return mp_parent->nets (); + } +} + +bool +NetlistModelItemData::derived_from_nets (const std::pair &np) +{ + if (! np.first && ! np.second) { + return false; + } else if (nets_of_this () == np) { + return true; + } else if (mp_parent) { + return mp_parent->derived_from_nets (np); + } else { + return false; + } +} + +// ---------------------------------------------------------------------------------- + +RootItemData::RootItemData () +{ + // .. nothing yet .. +} + +void +RootItemData::do_ensure_children (NetlistBrowserModel *model) +{ + size_t n = model->indexer ()->circuit_count (); + for (size_t i = 0; i < n; ++i) { + push_back (new CircuitItemData (0 /*intentionally*/, model->indexer ()->circuit_from_index (i).first)); + } +} + +QIcon +RootItemData::icon (NetlistBrowserModel * /*model*/) +{ + return QIcon (); +} + +QString +RootItemData::text (int /*column*/, NetlistBrowserModel * /*model*/) +{ + return QString (); +} + +QString +RootItemData::search_text () +{ + return QString (); +} + +std::string +RootItemData::tooltip (NetlistBrowserModel * /*model*/) +{ + return std::string (); +} + +db::NetlistCrossReference::Status +RootItemData::status (NetlistBrowserModel * /*model*/) +{ + return db::NetlistCrossReference::None; +} + +CircuitItemData * +RootItemData::circuit_item (NetlistBrowserModel *model, const IndexedNetlistModel::circuit_pair &cp) +{ + if (! cp.first && ! cp.second) { + return 0; + } + + size_t index = model->indexer ()->circuit_index (cp); + ensure_children (model); + return dynamic_cast (child (index)); +} + +// ---------------------------------------------------------------------------------- + +CircuitItemData::CircuitItemData (NetlistModelItemData *parent, const IndexedNetlistModel::circuit_pair &cp) + : NetlistModelItemData (parent), m_cp (cp) +{ } + +void +CircuitItemData::do_ensure_children (NetlistBrowserModel *model) +{ + if (model->indexer ()->pin_count (circuits ()) > 0) { + push_back (new CircuitItemNodeData (this, CircuitItemNodeData::Pins)); + } + if (model->indexer ()->net_count (circuits ()) > 0) { + push_back (new CircuitItemNodeData (this, CircuitItemNodeData::Nets)); + } + if (model->indexer ()->subcircuit_count (circuits ()) > 0) { + push_back (new CircuitItemNodeData (this, CircuitItemNodeData::SubCircuits)); + } + if (model->indexer ()->device_count (circuits ()) > 0) { + push_back (new CircuitItemNodeData (this, CircuitItemNodeData::Devices)); + } +} + +QIcon +CircuitItemData::icon (NetlistBrowserModel * /*model*/) +{ + return icon_for_circuit (); +} + +QString +CircuitItemData::text (int column, NetlistBrowserModel *model) +{ + // circuit: + // + single mode: name | | + // + dual mode: name(a)/name(b) | name(a) | name(b) + if (column == model->object_column ()) { + return escaped (str_from_names (m_cp, model->indexer ()->is_single ())); + } else if (!model->indexer ()->is_single () && (column == model->first_column () || column == model->second_column ())) { + return escaped (str_from_name (column == model->first_column () ? m_cp.first : m_cp.second)); + } else { + return QString (); + } +} + +QString +CircuitItemData::search_text () +{ + return tl::to_qstring (search_string_from_names (circuits ())); +} + +std::string +CircuitItemData::tooltip (NetlistBrowserModel *model) +{ + size_t index = model->indexer ()->circuit_index (m_cp); + return model->indexer ()->circuit_status_hint (index); +} + +db::NetlistCrossReference::Status +CircuitItemData::status (NetlistBrowserModel *model) +{ + size_t index = model->indexer ()->circuit_index (m_cp); + return model->indexer ()->circuit_from_index (index).second; +} + +CircuitNetItemData * +CircuitItemData::circuit_net_item (NetlistBrowserModel *model, const IndexedNetlistModel::net_pair &np) +{ + ensure_children (model); + + for (size_t i = 0; i < child_count (); ++i) { + CircuitNetItemData *d = static_cast (child (i))->circuit_net_item (model, np); + if (d) { + return d; + } + } + return 0; +} + +CircuitDeviceItemData * +CircuitItemData::circuit_device_item (NetlistBrowserModel *model, const IndexedNetlistModel::device_pair &dp) +{ + ensure_children (model); + + for (size_t i = 0; i < child_count (); ++i) { + CircuitDeviceItemData *d = static_cast (child (i))->circuit_device_item (model, dp); + if (d) { + return d; + } + } + return 0; +} + +CircuitSubCircuitItemData * +CircuitItemData::circuit_subcircuit_item (NetlistBrowserModel *model, const IndexedNetlistModel::subcircuit_pair &sp) +{ + ensure_children (model); + + for (size_t i = 0; i < child_count (); ++i) { + CircuitSubCircuitItemData *d = static_cast (child (i))->circuit_subcircuit_item (model, sp); + if (d) { + return d; + } + } + return 0; +} + +// ---------------------------------------------------------------------------------- + +CircuitItemForSubCircuitData::CircuitItemForSubCircuitData (NetlistModelItemData *parent, const IndexedNetlistModel::subcircuit_pair &sp) + : CircuitItemData (parent, circuit_refs_from_subcircuits (sp)), m_sp (sp) +{ } + +QString +CircuitItemForSubCircuitData::text (int column, NetlistBrowserModel *model) +{ + if (column == model->object_column ()) { + return tr ("Circuit"); + } else { + return QString (); + } +} + +QString +CircuitItemForSubCircuitData::search_text () +{ + return QString (); +} + +std::string +CircuitItemForSubCircuitData::tooltip (NetlistBrowserModel * /*model*/) +{ + return std::string (); +} + +db::NetlistCrossReference::Status +CircuitItemForSubCircuitData::status (NetlistBrowserModel * /*model*/) +{ + return db::NetlistCrossReference::None; +} + +// ---------------------------------------------------------------------------------- + +CircuitItemNodeData::CircuitItemNodeData (NetlistModelItemData *parent, CircuitItemNodeData::type t) + : NetlistModelItemData (parent), m_type (t) +{ } + +void +CircuitItemNodeData::do_ensure_children (NetlistBrowserModel *model) +{ + size_t n; + + if (m_type == Pins) { + + n = model->indexer ()->pin_count (circuits ()); + for (size_t i = 0; i < n; ++i) { + push_back (new CircuitPinItemData (this, model->indexer ()->pin_from_index (circuits (), i).first)); + } + + } else if (m_type == Nets) { + + n = model->indexer ()->net_count (circuits ()); + for (size_t i = 0; i < n; ++i) { + push_back (new CircuitNetItemData (this, model->indexer ()->net_from_index (circuits (), i).first)); + } + + } else if (m_type == SubCircuits) { + + n = model->indexer ()->subcircuit_count (circuits ()); + for (size_t i = 0; i < n; ++i) { + push_back (new CircuitSubCircuitItemData (this, model->indexer ()->subcircuit_from_index (circuits (), i).first)); + } + + } else if (m_type == Devices) { + + n = model->indexer ()->device_count (circuits ()); + for (size_t i = 0; i < n; ++i) { + push_back (new CircuitDeviceItemData (this, model->indexer ()->device_from_index (circuits (), i).first)); + } + + } +} + +QIcon +CircuitItemNodeData::icon (NetlistBrowserModel * /*model*/) +{ + if (m_type == Pins) { + return icon_for_pin (); + } else if (m_type == SubCircuits) { + return icon_for_circuit (); + } else if (m_type == Devices) { + return icon_for_device (0); + } else if (m_type == Nets) { + return icon_for_net (); + } else { + return QIcon (); + } +} + +QString +CircuitItemNodeData::text (int column, NetlistBrowserModel *model) +{ + if (column == model->object_column ()) { + if (m_type == Pins) { + return tr ("Pins"); + } else if (m_type == Devices) { + return tr ("Devices"); + } else if (m_type == Nets) { + return tr ("Nets"); + } else if (m_type == SubCircuits) { + return tr ("Subcircuits"); + } + } + return QString (); +} + +QString +CircuitItemNodeData::search_text () +{ + return QString (); +} + +std::string +CircuitItemNodeData::tooltip (NetlistBrowserModel * /*model*/) +{ + return std::string (); +} + +db::NetlistCrossReference::Status +CircuitItemNodeData::status (NetlistBrowserModel * /*model*/) +{ + return db::NetlistCrossReference::None; +} + +CircuitNetItemData * +CircuitItemNodeData::circuit_net_item (NetlistBrowserModel *model, const IndexedNetlistModel::net_pair &np) +{ + if (! np.first && ! np.second) { + return 0; + } + + ensure_children (model); + + if (m_type == Nets) { + ensure_children (model); + size_t index = model->indexer ()->net_index (np); + return dynamic_cast (child (index)); + } else { + return 0; + } +} + +CircuitDeviceItemData * +CircuitItemNodeData::circuit_device_item (NetlistBrowserModel *model, const IndexedNetlistModel::device_pair &dp) +{ + if (! dp.first && ! dp.second) { + return 0; + } + + ensure_children (model); + + if (m_type == Devices) { + ensure_children (model); + size_t index = model->indexer ()->device_index (dp); + return dynamic_cast (child (index)); + } else { + return 0; + } +} + +CircuitSubCircuitItemData * +CircuitItemNodeData::circuit_subcircuit_item (NetlistBrowserModel *model, const IndexedNetlistModel::subcircuit_pair &sp) +{ + if (! sp.first && ! sp.second) { + return 0; + } + + ensure_children (model); + + if (m_type == SubCircuits) { + ensure_children (model); + size_t index = model->indexer ()->subcircuit_index (sp); + return dynamic_cast (child (index)); + } else { + return 0; + } +} + +// ---------------------------------------------------------------------------------- + +CircuitPinItemData::CircuitPinItemData (NetlistModelItemData *parent, const IndexedNetlistModel::pin_pair &pp) + : CircuitNetItemData (parent, nets_from_circuit_pins (parent->circuits (), pp)), + m_pp (pp) +{ + // .. nothing yet .. +} + +QIcon +CircuitPinItemData::icon (NetlistBrowserModel * /*model*/) +{ + return icon_for_pin (); +} + +QString +CircuitPinItemData::text (int column, NetlistBrowserModel *model) +{ + if (column == model->object_column ()) { + std::string suffix; + if (seen ()) { + suffix = tl::to_string (tr (" (already seen)")); + } + return escaped (str_from_expanded_names (m_pp, model->indexer ()->is_single ()) + suffix); + } else { + return CircuitNetItemData::text (column, model); + } +} + +QString +CircuitPinItemData::search_text () +{ + return tl::to_qstring (combine_search_strings (search_string_from_expanded_names (m_pp), search_string_from_expanded_names (nets ()))); +} + +// ---------------------------------------------------------------------------------- + +CircuitNetItemData::CircuitNetItemData (NetlistModelItemData *parent, const IndexedNetlistModel::net_pair &np) + : NetlistModelItemData (parent), m_np (np), m_seen (parent && parent->derived_from_nets (np)) +{ } + +void +CircuitNetItemData::do_ensure_children (NetlistBrowserModel *model) +{ + // no subnodes if already seen + if (m_seen) { + return; + } + + size_t n; + + n = model->indexer ()->net_terminal_count (np ()); + for (size_t i = 0; i < n; ++i) { + push_back (new CircuitNetDeviceTerminalItemData (this, model->indexer ()->net_terminalref_from_index (np (), i))); + } + + n = model->indexer ()->net_pin_count (np ()); + for (size_t i = 0; i < n; ++i) { + push_back (new CircuitNetPinItemData (this, model->indexer ()->net_pinref_from_index (np (), i))); + } + + n = model->indexer ()->net_subcircuit_pin_count (np ()); + for (size_t i = 0; i < n; ++i) { + push_back (new CircuitNetSubCircuitPinItemData (this, model->indexer ()->net_subcircuit_pinref_from_index (np (), i))); + } +} + +QIcon +CircuitNetItemData::icon (NetlistBrowserModel *model) +{ + return model->icon_for_nets (m_np); +} + +QString +CircuitNetItemData::text (int column, NetlistBrowserModel *model) +{ + // circuit/net: header column = node count, second column net name + if (column == model->object_column ()) { + std::string suffix; + if (seen ()) { + suffix = tl::to_string (tr (" (already seen)")); + } + return escaped (str_from_expanded_names (m_np, model->indexer ()->is_single ()) + suffix); + } else if (column == model->first_column () && m_np.first) { + return escaped (m_np.first->expanded_name () + " (" + tl::to_string (m_np.first->pin_count () + m_np.first->terminal_count () + m_np.first->subcircuit_pin_count ()) + ")"); + } else if (column == model->second_column () && m_np.second) { + return escaped (m_np.second->expanded_name () + " (" + tl::to_string (m_np.second->pin_count () + m_np.second->terminal_count () + m_np.second->subcircuit_pin_count ()) + ")"); + } + + return QString (); +} + +QString +CircuitNetItemData::search_text () +{ + return tl::to_qstring (search_string_from_expanded_names (m_np)); +} + +std::string +CircuitNetItemData::tooltip (NetlistBrowserModel *model) +{ + if (m_np.first || m_np.second) { + size_t index = model->indexer ()->net_index (m_np); + return model->indexer ()->net_status_hint (circuits (), index); + } else { + return std::string (); + } +} + +db::NetlistCrossReference::Status +CircuitNetItemData::status (NetlistBrowserModel *model) +{ + if (m_np.first || m_np.second) { + size_t index = model->indexer ()->net_index (m_np); + return model->indexer ()->net_from_index (circuits (), index).second; + } else { + return db::NetlistCrossReference::None; + } +} + +// ---------------------------------------------------------------------------------- + +CircuitNetDeviceTerminalItemData::CircuitNetDeviceTerminalItemData (NetlistModelItemData *parent, const IndexedNetlistModel::net_terminal_pair &tp) + : NetlistModelItemData (parent), m_tp (tp), m_device_seen (parent && parent->derived_from_devices (dp ())) +{ } + +void +CircuitNetDeviceTerminalItemData::do_ensure_children (NetlistBrowserModel *model) +{ + if (m_device_seen) { + return; + } + + size_t n = std::max (rows_for (m_tp.first), rows_for (m_tp.second)); + for (size_t i = 0; i < n; ++i) { + std::pair device_classes = device_classes_from_devices (dp ()); + std::pair termdefs = terminal_defs_from_device_classes (model->indexer (), device_classes, dp (), i); + IndexedNetlistModel::net_pair nets = nets_from_device_terminals (dp (), termdefs); + push_back (new CircuitNetDeviceTerminalOthersItemData (this, nets, termdefs)); + } +} + +QIcon +CircuitNetDeviceTerminalItemData::icon (NetlistBrowserModel * /*model*/) +{ + std::pair device_classes = device_classes_from_devices (dp ()); + return icon_for_devices (device_classes, terminal_defs_from_terminal_refs (m_tp)); +} + +QString +CircuitNetDeviceTerminalItemData::text (int column, NetlistBrowserModel *model) +{ + // circuit/net/device terminal: header column = terminal and device string, second column = device name + if (column == model->object_column ()) { + + std::pair termdefs = terminal_defs_from_terminal_refs (m_tp); + + std::string suffix; + if (m_device_seen) { + suffix = tl::to_string (tr (" (already seen)")); + } + + if (model->indexer ()->is_single ()) { + return escaped (str_from_name (termdefs.first) + field_sep + device_string (dp ().first) + suffix); + } else { + return escaped (str_from_names (termdefs, model->indexer ()->is_single ()) + field_sep + devices_string (dp (), model->indexer ()->is_single (), true /*with parameters*/) + suffix); + } + + } else if (column == model->first_column () || column == model->second_column ()) { + return model->make_link_to (dp (), column); + } + + return QString (); +} + +QString +CircuitNetDeviceTerminalItemData::search_text () +{ + std::pair device_classes = device_classes_from_devices (dp ()); + std::pair termdefs = terminal_defs_from_terminal_refs (tp ()); + return tl::to_qstring (combine_search_strings (combine_search_strings (search_string_from_names (termdefs), search_string_from_names (device_classes)), search_string_from_expanded_names (dp ()))); +} + +std::string +CircuitNetDeviceTerminalItemData::tooltip (NetlistBrowserModel *model) +{ + return model->indexer ()->device_status_hint (circuits (), model->indexer ()->device_index (dp ())); +} + +db::NetlistCrossReference::Status +CircuitNetDeviceTerminalItemData::status (NetlistBrowserModel *model) +{ + return model->indexer ()->device_from_index (circuits (), model->indexer ()->device_index (dp ())).second; +} + +// ---------------------------------------------------------------------------------- + +CircuitNetDeviceTerminalOthersItemData::CircuitNetDeviceTerminalOthersItemData (NetlistModelItemData *parent, const IndexedNetlistModel::net_pair &np, const std::pair &tp) + : CircuitNetItemData (parent, nets_from_device_terminals (parent->devices (), tp)), m_tp (tp), m_np (np) +{ } + +QIcon +CircuitNetDeviceTerminalOthersItemData::icon (NetlistBrowserModel *model) +{ + return model->icon_for_connection (nets_from_device_terminals (devices (), m_tp)); +} + +QString +CircuitNetDeviceTerminalOthersItemData::text (int column, NetlistBrowserModel *model) +{ + // circuit/net/device terminal/more: header column = terminal name, second column = net link + if (column == model->object_column ()) { + return escaped (str_from_names (m_tp, model->indexer ()->is_single ()) + (seen () ? tl::to_string (tr (" (already seen)")) : std::string ())); + } else { + return CircuitNetItemData::text (column, model); + } +} + +QString +CircuitNetDeviceTerminalOthersItemData::search_text () +{ + return tl::to_qstring (combine_search_strings (search_string_from_names (m_tp), search_string_from_expanded_names (nets_of_this ()))); +} + +// ---------------------------------------------------------------------------------- + +CircuitNetSubCircuitPinItemData::CircuitNetSubCircuitPinItemData (NetlistModelItemData *parent, const IndexedNetlistModel::net_subcircuit_pin_pair &sp) + : NetlistModelItemData (parent), m_sp (sp), m_subcircuit_seen (parent && parent->derived_from_subcircuits (subcircuits_from_pinrefs (sp))) +{ } + +void +CircuitNetSubCircuitPinItemData::do_ensure_children (NetlistBrowserModel *model) +{ + if (m_subcircuit_seen) { + return; + } + + IndexedNetlistModel::pin_pair pins = pins_from_pinrefs (m_sp); + IndexedNetlistModel::net_pair nets = nets_from_circuit_pins (circuits (), pins); + + // Because of pin ambiguities the net identity might need to be fixed + if (nets.first) { + nets.second = model->indexer ()->second_net_for (nets.first); + } + + push_back (new CircuitNetItemData (this, nets)); +} + +QIcon +CircuitNetSubCircuitPinItemData::icon (NetlistBrowserModel * /*model*/) +{ + return icon_for_subcircuit (); +} + +QString +CircuitNetSubCircuitPinItemData::text (int column, NetlistBrowserModel *model) +{ + // circuit/net/pin: header column = pin name, second column empty (for now) + if (column == model->object_column ()) { + + QString suffix; + if (m_subcircuit_seen) { + suffix = tr (" (already seen)"); + } + + return model->make_link_to (pp (), circuits ()) + tl::to_qstring (field_sep) + model->make_link_to (circuits ()) + suffix; + + } else if (column == model->first_column () || column == model->second_column ()) { + return model->make_link_to (subcircuits (), column); + } + + return QString (); +} + +QString +CircuitNetSubCircuitPinItemData::search_text () +{ + return tl::to_qstring (combine_search_strings (combine_search_strings (search_string_from_names (pp ()), search_string_from_names (circuits ())), search_string_from_expanded_names (subcircuits ()))); +} + +std::string +CircuitNetSubCircuitPinItemData::tooltip (NetlistBrowserModel *model) +{ + return model->indexer ()->subcircuit_status_hint (parent ()->circuits (), model->indexer ()->subcircuit_index (subcircuits ())); +} + +db::NetlistCrossReference::Status +CircuitNetSubCircuitPinItemData::status (NetlistBrowserModel *model) +{ + return model->indexer ()->subcircuit_from_index (parent ()->circuits (), model->indexer ()->subcircuit_index (subcircuits ())).second; +} + +// ---------------------------------------------------------------------------------- + +CircuitNetPinItemData::CircuitNetPinItemData (NetlistModelItemData *parent, const IndexedNetlistModel::net_pin_pair &pp) + : NetlistModelItemData (parent), m_pp (pp) +{ } + +void +CircuitNetPinItemData::do_ensure_children (NetlistBrowserModel *) +{ + // nothing (leaf node) +} + +QIcon +CircuitNetPinItemData::icon (NetlistBrowserModel * /*model*/) +{ + return icon_for_pin (); +} + +QString +CircuitNetPinItemData::text (int column, NetlistBrowserModel *model) +{ + // circuit/net/pin: header column = pin name, second column empty (for now) + IndexedNetlistModel::circuit_pair circuits (m_pp.first && m_pp.first->net () ? m_pp.first->net ()->circuit () : 0, m_pp.second && m_pp.second->net () ? m_pp.second->net ()->circuit () : 0); + if (model->indexer ()->is_single () && column == model->object_column ()) { + return model->make_link_to (pins_from_pinrefs (m_pp), circuits); + } else if (! model->indexer ()->is_single () && (column == model->first_column () || column == model->second_column ())) { + return model->make_link_to (pins_from_pinrefs (m_pp), circuits, column); + } + + return QString (); +} + +QString +CircuitNetPinItemData::search_text () +{ + return tl::to_qstring (search_string_from_names (pins_from_pinrefs (m_pp))); +} + +std::string +CircuitNetPinItemData::tooltip (NetlistBrowserModel * /*model*/) +{ + return std::string (); +} + +db::NetlistCrossReference::Status +CircuitNetPinItemData::status (NetlistBrowserModel * /*model*/) +{ + return db::NetlistCrossReference::None; +} + +// ---------------------------------------------------------------------------------- + +CircuitSubCircuitPinsItemData::CircuitSubCircuitPinsItemData (NetlistModelItemData *parent, const IndexedNetlistModel::subcircuit_pair &sp) + : NetlistModelItemData (parent), m_sp (sp) +{ } + +void +CircuitSubCircuitPinsItemData::do_ensure_children (NetlistBrowserModel *model) +{ + size_t n = model->indexer ()->subcircuit_pin_count (sp ()); + for (size_t i = 0; i < n; ++i) { + IndexedNetlistModel::net_subcircuit_pin_pair pp = model->indexer ()->subcircuit_pinref_from_index (sp (), i); + push_back (new CircuitSubCircuitPinItemData (this, pp)); + } +} + +QIcon +CircuitSubCircuitPinsItemData::icon (NetlistBrowserModel * /*model*/) +{ + return icon_for_pin (); +} + +QString +CircuitSubCircuitPinsItemData::text (int column, NetlistBrowserModel *model) +{ + if (column == model->object_column ()) { + return tr ("Connections"); + } else { + return QString (); + } +} + +QString +CircuitSubCircuitPinsItemData::search_text () +{ + return QString (); +} + +std::string +CircuitSubCircuitPinsItemData::tooltip (NetlistBrowserModel * /*model*/) +{ + return std::string (); +} + +db::NetlistCrossReference::Status +CircuitSubCircuitPinsItemData::status (NetlistBrowserModel * /*model*/) +{ + return db::NetlistCrossReference::None; +} + +// ---------------------------------------------------------------------------------- + +CircuitSubCircuitItemData::CircuitSubCircuitItemData (NetlistModelItemData *parent, const IndexedNetlistModel::subcircuit_pair &sp) + : NetlistModelItemData (parent), m_sp (sp), mp_circuit_node (0) +{ } + +void +CircuitSubCircuitItemData::do_ensure_children (NetlistBrowserModel * /*model*/) +{ + push_back (new CircuitSubCircuitPinsItemData (this, m_sp)); + + // plus one item for the circuit reference + mp_circuit_node = new CircuitItemForSubCircuitData (this, m_sp); + push_back (mp_circuit_node); +} + +QIcon +CircuitSubCircuitItemData::icon (NetlistBrowserModel * /*model*/) +{ + return icon_for_subcircuit (); +} + +QString +CircuitSubCircuitItemData::text (int column, NetlistBrowserModel *model) +{ + // circuit/subcircuit: header column = circuit name, second column subcircuit name + IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (m_sp); + if (column == model->object_column ()) { + return model->make_link_to (circuit_refs); + } else if (column == model->first_column ()) { + return escaped (str_from_expanded_name (m_sp.first)); + } else if (column == model->second_column ()) { + return escaped (str_from_expanded_name (m_sp.second)); + } + + return QString (); +} + +QString +CircuitSubCircuitItemData::search_text () +{ + IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (sp ()); + return tl::to_qstring (combine_search_strings (search_string_from_names (circuit_refs), search_string_from_expanded_names (sp ()))); +} + +std::string +CircuitSubCircuitItemData::tooltip (NetlistBrowserModel *model) +{ + size_t index = model->indexer ()->subcircuit_index (sp ()); + return model->indexer ()->subcircuit_status_hint (circuits (), index); +} + +db::NetlistCrossReference::Status +CircuitSubCircuitItemData::status (NetlistBrowserModel *model) +{ + size_t index = model->indexer ()->subcircuit_index (sp ()); + return model->indexer ()->subcircuit_from_index (circuits (), index).second; +} + +// ---------------------------------------------------------------------------------- + +CircuitSubCircuitPinItemData::CircuitSubCircuitPinItemData (NetlistModelItemData *parent, const IndexedNetlistModel::net_subcircuit_pin_pair &pp) + : CircuitNetItemData (parent, nets_from_pinrefs (pp)), m_pp (pp) +{ } + +QIcon +CircuitSubCircuitPinItemData::icon (NetlistBrowserModel * /*model*/) +{ + return icon_for_pin (); +} + +QString +CircuitSubCircuitPinItemData::text (int column, NetlistBrowserModel *model) +{ + if (column == model->object_column ()) { + return model->make_link_to (pins (), circuit_refs_from_subcircuits (sp ())) + (seen () ? tr (" (already seen)") : QString ()); + } else { + return CircuitNetItemData::text (column, model); + } +} + +QString +CircuitSubCircuitPinItemData::search_text () +{ + return tl::to_qstring (combine_search_strings (search_string_from_names (pins ()), search_string_from_expanded_names (nets_from_pinrefs (m_pp)))); +} + +// ---------------------------------------------------------------------------------- + +CircuitDeviceItemData::CircuitDeviceItemData (NetlistModelItemData *parent, const IndexedNetlistModel::device_pair &dp) + : NetlistModelItemData (parent), m_dp (dp) +{ } + +void +CircuitDeviceItemData::do_ensure_children (NetlistBrowserModel *model) +{ + size_t n = std::max (rows_for (dp ().first), rows_for (dp ().second)); + for (size_t i = 0; i < n; ++i) { + std::pair tp = terminal_defs_from_device_classes (model->indexer (), device_classes_from_devices (dp ()), dp (), i); + push_back (new CircuitDeviceTerminalItemData (this, tp)); + } +} + +QIcon +CircuitDeviceItemData::icon (NetlistBrowserModel * /*model*/) +{ + std::pair device_classes = device_classes_from_devices (m_dp); + return icon_for_devices (device_classes); +} + +QString +CircuitDeviceItemData::text (int column, NetlistBrowserModel *model) +{ + // circuit/device: header column = class + parameters, second column device name + if (model->indexer ()->is_single ()) { + + if (column == model->object_column ()) { + return escaped (device_string (m_dp.first)); + } else if (column == model->first_column ()) { + return escaped (str_from_expanded_name (m_dp.first)); + } + + } else { + + if (column == model->object_column ()) { + return escaped (devices_string (m_dp, model->indexer ()->is_single (), false /*without parameters*/)); + } else if (column == model->first_column ()) { + return escaped (str_from_expanded_name (m_dp.first) + field_sep + device_string (m_dp.first)); + } else if (column == model->second_column ()) { + return escaped (str_from_expanded_name (m_dp.second) + field_sep + device_string (m_dp.second)); + } + + } + + return QString (); +} + +QString +CircuitDeviceItemData::search_text () +{ + std::pair device_classes = device_classes_from_devices (dp ()); + return tl::to_qstring (combine_search_strings (search_string_from_expanded_names (dp ()), search_string_from_names (device_classes))); +} + +std::string +CircuitDeviceItemData::tooltip (NetlistBrowserModel *model) +{ + size_t index = model->indexer ()->device_index (m_dp); + return model->indexer ()->device_status_hint (circuits (), index); +} + +db::NetlistCrossReference::Status +CircuitDeviceItemData::status (NetlistBrowserModel *model) +{ + size_t index = model->indexer ()->device_index (m_dp); + return model->indexer ()->device_from_index (circuits (), index).second; +} + +// ---------------------------------------------------------------------------------- + +CircuitDeviceTerminalItemData::CircuitDeviceTerminalItemData (NetlistModelItemData *parent, const std::pair &tp) + : CircuitNetItemData (parent, nets_from_device_terminals (parent->devices (), tp)), m_tp (tp) +{ } + +QIcon +CircuitDeviceTerminalItemData::icon (NetlistBrowserModel *model) +{ + return model->icon_for_connection (nets_of_this ()); +} + +QString +CircuitDeviceTerminalItemData::text (int column, NetlistBrowserModel *model) +{ + if (column == model->object_column ()) { + std::string suffix; + if (seen ()) { + suffix = tl::to_string (tr (" (already seen)")); + } + return escaped (str_from_names (m_tp, model->indexer ()->is_single ()) + suffix); + } else { + return CircuitNetItemData::text (column, model); + } +} + +QString +CircuitDeviceTerminalItemData::search_text () +{ + return tl::to_qstring (combine_search_strings (search_string_from_names (m_tp), search_string_from_expanded_names (nets_of_this ()))); +} + +// ---------------------------------------------------------------------------------- +// NetlistBrowserModel implementation + +NetlistBrowserModel::NetlistBrowserModel (QWidget *parent, db::LayoutToNetlist *l2ndb, NetColorizer *colorizer) + : QAbstractItemModel (parent), mp_l2ndb (l2ndb), mp_lvsdb (0), mp_colorizer (colorizer) +{ + mp_root.reset (new RootItemData ()); + mp_indexer.reset (new SingleIndexedNetlistModel (l2ndb->netlist ())); + connect (mp_colorizer, SIGNAL (colors_changed ()), this, SLOT (colors_changed ())); + + m_object_column = 0; + m_status_column = -1; + m_first_column = 2; + m_second_column = -1; +} + +NetlistBrowserModel::NetlistBrowserModel (QWidget *parent, db::LayoutVsSchematic *lvsdb, NetColorizer *colorizer) + : QAbstractItemModel (parent), mp_l2ndb (0), mp_lvsdb (lvsdb), mp_colorizer (colorizer) +{ + mp_root.reset (new RootItemData ()); + mp_indexer.reset (new NetlistCrossReferenceModel (lvsdb->cross_ref ())); + connect (mp_colorizer, SIGNAL (colors_changed ()), this, SLOT (colors_changed ())); + + m_object_column = 0; + m_status_column = 1; + m_first_column = 2; + m_second_column = 3; +} + +NetlistBrowserModel::~NetlistBrowserModel () +{ + // .. nothing yet .. +} + +RootItemData * +NetlistBrowserModel::root () const +{ + return dynamic_cast (mp_root.get ()); +} + +int +NetlistBrowserModel::columnCount (const QModelIndex & /*parent*/) const +{ + // Item type & icon, link or description + return mp_indexer->is_single () ? 3 : 4; +} + +QIcon icon_for_status (db::NetlistCrossReference::Status status) +{ + if (status == db::NetlistCrossReference::NoMatch || status == db::NetlistCrossReference::Mismatch) { + return QIcon (":/error2_16.png"); + } else if (status == db::NetlistCrossReference::MatchWithWarning || status == db::NetlistCrossReference::Skipped) { + return QIcon (":/warn_16.png"); + } else { + return QIcon (); + } +} + +QVariant +NetlistBrowserModel::data (const QModelIndex &index, int role) const +{ + if (! index.isValid ()) { + return QVariant (); + } + + if (role == Qt::DecorationRole && index.column () == m_object_column) { + return QVariant (icon (index)); + } else if (role == Qt::DecorationRole && index.column () == m_status_column) { + return QVariant (icon_for_status (status (index))); + } else if (role == Qt::DisplayRole) { + return QVariant (text (index)); + } else if (role == Qt::ToolTipRole && index.column () == m_status_column) { + return tooltip (index); + } else if (role == Qt::UserRole) { + return QVariant (search_text (index)); + } else if (role == Qt::FontRole) { + db::NetlistCrossReference::Status st = status (index); + if (st == db::NetlistCrossReference::NoMatch || st == db::NetlistCrossReference::Mismatch || st == db::NetlistCrossReference::Skipped) { + QFont font; + font.setWeight (QFont::Bold); + return QVariant (font); + } + } else if (role == Qt::ForegroundRole) { + db::NetlistCrossReference::Status st = status (index); + if (st == db::NetlistCrossReference::Match || st == db::NetlistCrossReference::MatchWithWarning) { + // taken from marker browser: + return QVariant (QColor (0, 192, 0)); + } + } + return QVariant (); +} + +NetlistObjectsPath +NetlistBrowserModel::path_from_index (const QModelIndex &index) const +{ + NetlistObjectsPath np; + np.net = net_from_index (index, false); + np.device = device_from_index (index, false); + + QModelIndex i = index; + while (i.isValid ()) { + + IndexedNetlistModel::subcircuit_pair sp = subcircuit_from_index (i, false); + if (sp.first || sp.second) { + np.path.push_front (sp); + } else { + IndexedNetlistModel::circuit_pair cp = circuit_from_index (i, false); + if (cp.first || cp.second) { + np.root = cp; + } + } + + i = parent (i); + + } + + return np; +} + +QModelIndex +NetlistBrowserModel::index_from_path (const NetlistObjectsPath &path) +{ + QModelIndex index = index_from_circuit (path.root); + + CircuitItemData *node = dynamic_cast ((NetlistModelItemData *) (index.internalPointer ())); + + for (std::list >::const_iterator p = path.path.begin (); p != path.path.end () && node; ++p) { + CircuitSubCircuitItemData *sc_node = node->circuit_subcircuit_item (this, *p); + if (sc_node) { + sc_node->ensure_children (this); + node = sc_node->circuit_item (); + } else { + node = 0; + } + } + + CircuitNetItemData *net_node = 0; + CircuitDeviceItemData *device_node = 0; + + if (node) { + net_node = node->circuit_net_item (const_cast (this), path.net); + device_node = node->circuit_device_item (const_cast (this), path.device); + } + + if (net_node) { + return createIndex (int (net_node->index ()), 0, (void *) net_node); + } else if (device_node) { + return createIndex (int (device_node->index ()), 0, (void *) device_node); + } else if (node) { + return createIndex (int (node->index ()), 0, (void *) node); + } else { + return QModelIndex (); + } +} + +QModelIndex +NetlistBrowserModel::index_from_url (const QString &a) const +{ + QUrl url (a); + + std::string ids; +#if QT_VERSION >= 0x050000 + ids = tl::to_string (QUrlQuery (url.query ()).queryItemValue (QString::fromUtf8 ("path"))); +#else + ids = tl::to_string (url.queryItemValue (QString::fromUtf8 ("path"))); +#endif + + QModelIndex idx; + + tl::Extractor ex (ids.c_str ()); + while (! ex.at_end ()) { + int n = 0; + if (! ex.try_read (n)) { + break; + } + idx = index (n, 0, idx); + ex.test (","); + } + + return idx; +} + +QString +NetlistBrowserModel::build_url (const QModelIndex &index, const std::string &title) const +{ + if (! index.isValid ()) { + // no link + return tl::to_qstring (tl::escaped_to_html (title)); + } + + QModelIndex i = index; + + std::string pstr; + while (i.isValid ()) { + if (pstr.empty ()) { + pstr = tl::to_string (i.row ()); + } else { + pstr = tl::to_string (i.row ()) + "," + pstr; + } + i = parent (i); + } + + std::string s = std::string (""; + + s += tl::escaped_to_html (title); + + s += ""; + + return tl::to_qstring (s); +} + +QString +NetlistBrowserModel::make_link_to (const std::pair &nets, int column) const +{ + if ((! nets.first || column == m_second_column) && (! nets.second || column == m_first_column)) { + return QString (); + } else { + + QModelIndex idx = index_from_net (nets); + + if (mp_indexer->is_single () || column == m_first_column) { + return build_url (idx, str_from_expanded_name (nets.first)); + } else if (column == m_second_column) { + return build_url (idx, str_from_expanded_name (nets.second)); + } else { + return build_url (idx, str_from_expanded_names (nets, mp_indexer->is_single ())); + } + + } +} + +QString +NetlistBrowserModel::make_link_to (const std::pair &devices, int column) const +{ + QModelIndex idx; + + if ((! devices.first || column == m_second_column) && (! devices.second || column == m_first_column)) { + return QString (); + } else { + + if (mp_indexer->is_single () || column == m_first_column) { + return build_url (idx, str_from_expanded_name (devices.first)); + } else if (column == m_second_column) { + return build_url (idx, str_from_expanded_name (devices.second)); + } else { + return build_url (idx, str_from_expanded_names (devices, mp_indexer->is_single ())); + } + + } +} + +QString +NetlistBrowserModel::make_link_to (const std::pair &pins, const std::pair & /*circuits*/, int column) const +{ + QModelIndex idx; + + if ((! pins.first || column == m_second_column) && (! pins.second || column == m_first_column)) { + return QString (); + } else { + if (mp_indexer->is_single () || column == m_first_column) { + return build_url (idx, str_from_expanded_name (pins.first)); + } else if (column == m_second_column) { + return build_url (idx, str_from_expanded_name (pins.second)); + } else { + return build_url (idx, str_from_expanded_names (pins, mp_indexer->is_single ())); + } + } +} + +QString +NetlistBrowserModel::make_link_to (const std::pair &circuits, int column) const +{ + if ((! circuits.first || column == m_second_column) && (! circuits.second || column == m_first_column)) { + return QString (); + } else { + + QModelIndex idx = index_from_circuit (circuits); + + if (mp_indexer->is_single () || column == m_first_column) { + return build_url (idx, str_from_name (circuits.first)); + } else if (column == m_second_column) { + return build_url (idx, str_from_name (circuits.second)); + } else { + return build_url (idx, str_from_names (circuits, mp_indexer->is_single ())); + } + + } +} + +QString +NetlistBrowserModel::make_link_to (const std::pair &subcircuits, int column) const +{ + if ((! subcircuits.first || column == m_second_column) && (! subcircuits.second || column == m_first_column)) { + return QString (); + } else { + + QModelIndex idx = index_from_subcircuit (subcircuits); + + if (mp_indexer->is_single () || column == m_first_column) { + return build_url (idx, str_from_expanded_name (subcircuits.first)); + } else if (column == m_second_column) { + return build_url (idx, str_from_expanded_name (subcircuits.second)); + } else { + return build_url (idx, str_from_expanded_names (subcircuits, mp_indexer->is_single ())); + } + + } +} + +bool +NetlistBrowserModel::is_valid_net_pair (const std::pair &nets) const +{ + if (! nets.first && ! nets.second) { + // this is a valid case: e.g. two matching subcircuit pins without nets attached + // to them + return true; + } else { + IndexedNetlistModel::circuit_pair net_parent = mp_indexer->parent_of (nets); + return (net_parent.first != 0 || net_parent.second != 0); + } +} + +db::NetlistCrossReference::Status +NetlistBrowserModel::status (const QModelIndex &index) const +{ + NetlistModelItemData *d = (NetlistModelItemData *) (index.internalPointer ()); + if (! d) { + return db::NetlistCrossReference::None; + } else { + return d->status (const_cast (this)); + } +} + +QVariant +NetlistBrowserModel::tooltip (const QModelIndex &index) const +{ + std::string hint; + NetlistModelItemData *d = (NetlistModelItemData *) (index.internalPointer ()); + if (d) { + hint = d->tooltip (const_cast (this)); + } + + if (hint.empty ()) { + return QVariant (); + } else { + return QVariant (tl::to_qstring (hint)); + } +} + +QString +NetlistBrowserModel::search_text (const QModelIndex &index) const +{ + NetlistModelItemData *d = (NetlistModelItemData *) (index.internalPointer ()); + if (d) { + return d->search_text (); + } else { + return QString (); + } +} + QIcon NetlistBrowserModel::icon_for_nets (const std::pair &nets) const { @@ -1951,46 +2814,12 @@ NetlistBrowserModel::icon_for_connection (const std::pair device_classes = device_classes_from_devices (devices); - - return icon_for_devices (device_classes); - - } else if (is_id_circuit_pin_net (id) || is_id_circuit_device_terminal (id) || is_id_circuit_net_device_terminal_others (id) || is_id_circuit_net_subcircuit_pin_others (id)) { - - IndexedNetlistModel::net_pair nets = net_from_index (index); - return icon_for_connection (nets); - - } else if (is_id_circuit_subcircuit (id)) { - return icon_for_circuit (); - } else if (is_id_circuit_subcircuit_pin (id) || is_id_circuit_net_pin (id)) { - return icon_for_pin (); - } else if (is_id_circuit_net_subcircuit_pin (id)) { - return icon_for_circuit (); - } else if (is_id_circuit_net_device_terminal (id)) { - - IndexedNetlistModel::net_terminal_pair termrefs = net_terminalrefs_from_id (id); - IndexedNetlistModel::device_pair devices = devices_from_termrefs (termrefs); - std::pair device_classes = device_classes_from_devices (devices); - - return icon_for_devices (device_classes); - + NetlistModelItemData *d = (NetlistModelItemData *) (index.internalPointer ()); + if (! d) { + return QIcon (); + } else { + return d->icon (const_cast (this)); } - - return QIcon (); } Qt::ItemFlags @@ -1999,96 +2828,20 @@ NetlistBrowserModel::flags (const QModelIndex & /*index*/) const return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } -static size_t rows_for (const db::Device *device) -{ - if (! device || ! device->device_class ()) { - return 0; - } else { - return device->device_class ()->terminal_definitions ().size (); - } -} - -static size_t rows_for (const db::SubCircuit *subcircuit) -{ - if (! subcircuit || ! subcircuit->circuit_ref ()) { - return 0; - } else { - return subcircuit->circuit_ref ()->pin_count (); - } -} - -static size_t rows_for (const db::NetSubcircuitPinRef *ref) -{ - if (! ref || ! ref->subcircuit () || ! ref->subcircuit ()->circuit_ref ()) { - return 0; - } else { - return ref->subcircuit ()->circuit_ref ()->pin_count (); - } -} - -static size_t rows_for (const db::NetTerminalRef *ref) -{ - if (! ref || ! ref->device_class ()) { - return 0; - } else { - return ref->device_class ()->terminal_definitions ().size (); - } -} - bool NetlistBrowserModel::hasChildren (const QModelIndex &parent) const { - if (! parent.isValid ()) { - - return mp_indexer.get () && mp_indexer->circuit_count () > 0; - + NetlistModelItemData *d = 0; + if (parent.isValid ()) { + d = (NetlistModelItemData *) (parent.internalPointer ()); } else { - - void *id = parent.internalPointer (); - - if (is_id_circuit (id)) { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - return mp_indexer->device_count (circuits) > 0 || - mp_indexer->subcircuit_count (circuits) > 0 || - mp_indexer->pin_count (circuits) > 0 || - mp_indexer->net_count (circuits) > 0; - - } else if (is_id_circuit_pin (id)) { - - return true; - - } else if (is_id_circuit_device (id)) { - - IndexedNetlistModel::device_pair devices = devices_from_id (id); - return rows_for (devices.first) > 0 || rows_for (devices.second) > 0; - - } else if (is_id_circuit_subcircuit (id)) { - - IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_id (id); - return rows_for (subcircuits.first) > 0 || rows_for (subcircuits.second) > 0; - - } else if (is_id_circuit_net (id)) { - - IndexedNetlistModel::net_pair nets = nets_from_id (id); - return mp_indexer->net_pin_count (nets) > 0 || - mp_indexer->net_terminal_count (nets) > 0 || - mp_indexer->net_subcircuit_pin_count (nets) > 0; - - } else if (is_id_circuit_net_subcircuit_pin (id)) { - - IndexedNetlistModel::net_subcircuit_pin_pair refs = net_subcircuit_pinrefs_from_id (id); - return rows_for (refs.first) > 0 || rows_for (refs.second) > 0; - - } else if (is_id_circuit_net_device_terminal (id)) { - - IndexedNetlistModel::net_terminal_pair refs = net_terminalrefs_from_id (id); - return rows_for (refs.first) > 0 || rows_for (refs.second) > 0; - - } else { - return false; - } - + d = mp_root.get (); + } + if (d) { + d->ensure_children (const_cast (this)); + return d->begin () != d->end (); + } else { + return false; } } @@ -2123,88 +2876,15 @@ NetlistBrowserModel::headerData (int section, Qt::Orientation /*orientation*/, i QModelIndex NetlistBrowserModel::index (int row, int column, const QModelIndex &parent) const { - void *new_id = no_id; - + NetlistModelItemData *d = 0; if (! parent.isValid ()) { - - new_id = make_id_circuit (row); - + d = mp_root.get (); } else { - - void *id = parent.internalPointer (); - - if (is_id_circuit (id)) { - - int r = row; - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - int rpins = int (mp_indexer->pin_count (circuits)); - if (r < rpins) { - new_id = make_id_circuit_pin (circuit_index_from_id (id), size_t (r)); - } else { - r -= rpins; - int rnets = int (mp_indexer->net_count (circuits)); - if (r < int (rnets)) { - new_id = make_id_circuit_net (circuit_index_from_id (id), size_t (r)); - } else { - r -= int (rnets); - int rsubcircuits = int (mp_indexer->subcircuit_count (circuits)); - if (r < rsubcircuits) { - new_id = make_id_circuit_subcircuit (circuit_index_from_id (id), size_t (r)); - } else { - r -= rsubcircuits; - if (r < int (mp_indexer->device_count (circuits))) { - new_id = make_id_circuit_device (circuit_index_from_id (id), size_t (r)); - } - } - } - } - - } else if (is_id_circuit_pin (id)) { - - new_id = make_id_circuit_pin_net (circuit_index_from_id (id), circuit_pin_index_from_id (id), size_t (row)); - - } else if (is_id_circuit_device (id)) { - - new_id = make_id_circuit_device_terminal (circuit_index_from_id (id), circuit_device_index_from_id (id), size_t (row)); - - } else if (is_id_circuit_subcircuit (id)) { - - new_id = make_id_circuit_subcircuit_pin (circuit_index_from_id (id), circuit_subcircuit_index_from_id (id), size_t (row)); - - } else if (is_id_circuit_net (id)) { - - int r = row; - IndexedNetlistModel::net_pair nets = nets_from_id (id); - int rterminals = int (mp_indexer->net_terminal_count (nets)); - if (r < rterminals){ - new_id = make_id_circuit_net_device_terminal (circuit_index_from_id (id), circuit_net_index_from_id (id), size_t (r)); - } else { - r -= rterminals; - int rpins = int (mp_indexer->net_pin_count (nets)); - if (r < rpins) { - new_id = make_id_circuit_net_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), size_t (r)); - } else { - r -= rpins; - if (r < int (mp_indexer->net_subcircuit_pin_count (nets))) { - new_id = make_id_circuit_net_subcircuit_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), size_t (r)); - } - } - } - - } else if (is_id_circuit_net_subcircuit_pin (id)) { - - new_id = 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), size_t (row)); - - } else if (is_id_circuit_net_device_terminal (id)) { - - new_id = 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), size_t (row)); - - } - + d = (NetlistModelItemData *) (parent.internalPointer ()); } - - if (new_id != no_id) { - return createIndex (row, column, new_id); + if (d) { + d->ensure_children (const_cast (this)); + return createIndex (row, column, (void *) d->child (size_t (row))); } else { return QModelIndex (); } @@ -2220,8 +2900,15 @@ QModelIndex NetlistBrowserModel::index_from_net (const std::pair &nets) const { IndexedNetlistModel::circuit_pair circuits (nets.first ? nets.first->circuit () : 0, nets.second ? nets.second->circuit () : 0); - void *id = make_id_circuit_net (mp_indexer->circuit_index (circuits), mp_indexer->net_index (nets)); - return index_from_id (id, 0); + CircuitItemData *ci = root ()->circuit_item (const_cast (this), circuits); + if (ci) { + CircuitNetItemData *ni = ci->circuit_net_item (const_cast (this), nets); + if (ni) { + return createIndex (int (ni->index ()), 0, (void *) ni); + } + } + + return QModelIndex (); } QModelIndex @@ -2233,8 +2920,27 @@ NetlistBrowserModel::index_from_net (const db::Net *net) const QModelIndex NetlistBrowserModel::index_from_circuit (const std::pair &circuits) const { - void *id = make_id_circuit (mp_indexer->circuit_index (circuits)); - return index_from_id (id, 0); + CircuitItemData *ci = root ()->circuit_item (const_cast (this), circuits); + if (ci) { + return createIndex (int (ci->index ()), 0, (void *) ci); + } + + return QModelIndex (); +} + +QModelIndex +NetlistBrowserModel::index_from_subcircuit (const std::pair &subcircuits) const +{ + IndexedNetlistModel::circuit_pair circuits (subcircuits.first ? subcircuits.first->circuit () : 0, subcircuits.second ? subcircuits.second->circuit () : 0); + CircuitItemData *ci = root ()->circuit_item (const_cast (this), circuits); + if (ci) { + CircuitSubCircuitItemData *si = ci->circuit_subcircuit_item (const_cast (this), subcircuits); + if (si) { + return createIndex (int (si->index ()), 0, (void *) si); + } + } + + return QModelIndex (); } QModelIndex @@ -2244,372 +2950,74 @@ NetlistBrowserModel::index_from_circuit (const db::Circuit *net) const } std::pair -NetlistBrowserModel::circuit_from_index (const QModelIndex &index) const +NetlistBrowserModel::circuit_from_index (const QModelIndex &index, bool include_parents) const { - return circuits_from_id (index.internalPointer ()); + NetlistModelItemData *d = (NetlistModelItemData *) (index.internalPointer ()); + if (! d) { + return std::pair (0, 0); + } else { + return include_parents ? d->circuits () : d->circuits_of_this (); + } } std::pair -NetlistBrowserModel::net_from_index (const QModelIndex &index) const +NetlistBrowserModel::net_from_index (const QModelIndex &index, bool include_parents) const { - void *id = index.internalPointer (); - if (is_id_circuit_net (id)) { - - return nets_from_id (id); - - } else if (is_id_circuit_device_terminal (id)) { - - IndexedNetlistModel::device_pair devices = devices_from_id (id); - std::pair device_classes = device_classes_from_devices (devices); - - size_t terminal = circuit_device_terminal_index_from_id (id); - std::pair termdefs = terminal_defs_from_device_classes (device_classes, terminal); - - return nets_from_device_terminals (devices, termdefs); - - } else if (is_id_circuit_pin_net (id)) { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - IndexedNetlistModel::pin_pair pins = pins_from_id (id); - return nets_from_circuit_pins (circuits, pins); - - } else if (is_id_circuit_subcircuit_pin (id)) { - - IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_id (id); - IndexedNetlistModel::pin_pair pins = pins_from_id (id); - return nets_from_subcircuit_pins (subcircuits, pins); - - } else if (is_id_circuit_net_subcircuit_pin_others (id)) { - - IndexedNetlistModel::net_subcircuit_pin_pair pinrefs = net_subcircuit_pinrefs_from_id (id); - size_t other_index = circuit_net_subcircuit_pin_other_index_from_id (id); - - IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_pinrefs (pinrefs); - IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits); - IndexedNetlistModel::pin_pair pins = mp_indexer->pin_from_index (circuit_refs, other_index).first; - - return nets_from_subcircuit_pins (subcircuits, pins); - - } else if (is_id_circuit_net_device_terminal_others (id)) { - - IndexedNetlistModel::net_terminal_pair termrefs = net_terminalrefs_from_id (id); - size_t other_index = circuit_net_device_terminal_other_index_from_id (id); - - IndexedNetlistModel::device_pair devices = devices_from_termrefs (termrefs); - std::pair device_classes = device_classes_from_devices (devices); - std::pair termdefs = terminal_defs_from_device_classes (device_classes, other_index); - - return nets_from_device_terminals (devices, termdefs); - + NetlistModelItemData *d = (NetlistModelItemData *) (index.internalPointer ()); + if (! d) { + return std::pair (0, 0); + } else { + return include_parents ? d->nets () : d->nets_of_this (); } - - return std::make_pair ((const db::Net *) 0, (const db::Net *) 0); } std::pair -NetlistBrowserModel::device_from_index (const QModelIndex &index) const +NetlistBrowserModel::device_from_index (const QModelIndex &index, bool include_parents) const { - void *id = index.internalPointer (); - - if (is_id_circuit_device (id)) { - - return devices_from_id (id); - - } else if (is_id_circuit_net_device_terminal (id)) { - - IndexedNetlistModel::net_terminal_pair termrefs = net_terminalrefs_from_id (id); - return devices_from_termrefs (termrefs); - + NetlistModelItemData *d = (NetlistModelItemData *) (index.internalPointer ()); + if (! d) { + return std::pair (0, 0); + } else { + return include_parents ? d->devices () : d->devices_of_this (); } - - return std::make_pair ((const db::Device *) 0, (const db::Device *) 0); } std::pair -NetlistBrowserModel::subcircuit_from_index (const QModelIndex &index) const +NetlistBrowserModel::subcircuit_from_index (const QModelIndex &index, bool include_parents) const { - void *id = index.internalPointer (); - - if (is_id_circuit_subcircuit (id)) { - - return subcircuits_from_id (id); - - } else if (is_id_circuit_net_subcircuit_pin (id)) { - - IndexedNetlistModel::net_subcircuit_pin_pair pinrefs = net_subcircuit_pinrefs_from_id (id); - return subcircuits_from_pinrefs (pinrefs); - + NetlistModelItemData *d = (NetlistModelItemData *) (index.internalPointer ()); + if (! d) { + return std::pair (0, 0); + } else { + return include_parents ? d->subcircuits () : d->subcircuits_of_this (); } - - return std::make_pair ((const db::SubCircuit *) 0, (const db::SubCircuit *) 0); -} - -QModelIndex -NetlistBrowserModel::index_from_id (void *id, int column) const -{ - if (id == no_id) { - - return QModelIndex (); - - } else if (is_id_circuit (id)) { - - return createIndex (circuit_index_from_id (id), column, id); - - } else if (is_id_circuit_pin (id)) { - - return createIndex (int (circuit_pin_index_from_id (id)), column, id); - - } else if (is_id_circuit_pin_net (id)) { - - return createIndex (0, column, id); - - } else if (is_id_circuit_net (id)) { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - return createIndex (int (mp_indexer->pin_count (circuits) + circuit_net_index_from_id (id)), column, id); - - } else if (is_id_circuit_net_device_terminal (id)) { - - return createIndex (circuit_net_device_terminal_index_from_id (id), column, id); - - } else if (is_id_circuit_net_device_terminal_others (id)) { - - return createIndex (circuit_net_device_terminal_other_index_from_id (id), column, id); - - } else if (is_id_circuit_net_pin (id)) { - - IndexedNetlistModel::net_pair nets = nets_from_id (id); - return createIndex (int (mp_indexer->net_terminal_count (nets) + circuit_net_pin_index_from_id (id)), column, id); - - } else if (is_id_circuit_net_subcircuit_pin (id)) { - - IndexedNetlistModel::net_pair nets = nets_from_id (id); - return createIndex (int (mp_indexer->net_terminal_count (nets) + mp_indexer->net_pin_count (nets) + circuit_net_subcircuit_pin_index_from_id (id)), column, id); - - } else if (is_id_circuit_net_subcircuit_pin_others (id)) { - - return createIndex (circuit_net_subcircuit_pin_other_index_from_id (id), column, id); - - } else if (is_id_circuit_subcircuit (id)) { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - return createIndex (int (mp_indexer->pin_count (circuits) + mp_indexer->net_count (circuits) + circuit_subcircuit_index_from_id (id)), column, id); - - } else if (is_id_circuit_subcircuit_pin (id)) { - - return createIndex (int (circuit_subcircuit_pin_index_from_id (id)), column, id); - - } else if (is_id_circuit_device (id)) { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - return createIndex (int (mp_indexer->pin_count (circuits) + mp_indexer->net_count (circuits) + mp_indexer->subcircuit_count (circuits) + circuit_device_index_from_id (id)), column, id); - - } else if (is_id_circuit_device_terminal (id)) { - - return createIndex (int (circuit_device_terminal_index_from_id (id)), column, id); - - } - - return QModelIndex (); } QModelIndex NetlistBrowserModel::parent (const QModelIndex &index) const { - if (! index.isValid ()) { - + NetlistModelItemData *d = (NetlistModelItemData *) (index.internalPointer ()); + if (! d || ! d->parent ()) { return QModelIndex (); - } else { - - void *id = index.internalPointer (); - int column = 0; - - 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)) { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - return createIndex (int (mp_indexer->pin_count (circuits) + 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)) { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - return createIndex (int (mp_indexer->pin_count (circuits) + mp_indexer->net_count (circuits) + 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)) { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - return createIndex (int (mp_indexer->pin_count (circuits) + mp_indexer->net_count (circuits) + mp_indexer->subcircuit_count (circuits) + circuit_device_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)) { - - IndexedNetlistModel::net_pair nets = nets_from_id (id); - return createIndex (size_t (mp_indexer->net_terminal_count (nets) + mp_indexer->net_pin_count (nets) + 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 createIndex (d->parent ()->index (), 0, (void *) d->parent ()); } - - return QModelIndex (); } int NetlistBrowserModel::rowCount (const QModelIndex &parent) const { - if (! parent.isValid ()) { - - return int (mp_indexer.get () ? mp_indexer->circuit_count () : 0); - + NetlistModelItemData *d = 0; + if (parent.isValid ()) { + d = (NetlistModelItemData *) (parent.internalPointer ()); } else { - - void *id = parent.internalPointer (); - - if (is_id_circuit (id)) { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - return int (mp_indexer->pin_count (circuits) + mp_indexer->net_count (circuits) + mp_indexer->subcircuit_count (circuits) + mp_indexer->device_count (circuits)); - - } else if (is_id_circuit_pin (id)) { - - return 1; - - } else if (is_id_circuit_device (id)) { - - IndexedNetlistModel::device_pair devices = devices_from_id (id); - return int (std::max (rows_for (devices.first), rows_for (devices.second))); - - } else if (is_id_circuit_subcircuit (id)) { - - IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_id (id); - return int (std::max (rows_for (subcircuits.first), rows_for (subcircuits.second))); - - } else if (is_id_circuit_net_subcircuit_pin (id)) { - - IndexedNetlistModel::net_subcircuit_pin_pair refs = net_subcircuit_pinrefs_from_id (id); - return std::max (rows_for (refs.first), rows_for (refs.second)); - - } else if (is_id_circuit_net_device_terminal (id)) { - - IndexedNetlistModel::net_terminal_pair refs = net_terminalrefs_from_id (id); - return std::max (rows_for (refs.first), rows_for (refs.second)); - - } else if (is_id_circuit_net (id)) { - - IndexedNetlistModel::net_pair nets = nets_from_id (id); - return int (mp_indexer->net_terminal_count (nets) + mp_indexer->net_pin_count (nets) + mp_indexer->net_subcircuit_pin_count (nets)); - - } - + d = mp_root.get (); } - - return 0; -} - -std::pair -NetlistBrowserModel::circuits_from_id (void *id) const -{ - size_t index = circuit_index_from_id (id); - return mp_indexer->circuit_from_index (index).first; -} - -std::pair -NetlistBrowserModel::nets_from_id (void *id) const -{ - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - size_t index = circuit_net_index_from_id (id); - - return mp_indexer->net_from_index (circuits, index).first; -} - -std::pair -NetlistBrowserModel::net_subcircuit_pinrefs_from_id (void *id) const -{ - IndexedNetlistModel::net_pair nets = nets_from_id (id); - size_t index = circuit_net_subcircuit_pin_index_from_id (id); - - return mp_indexer->net_subcircuit_pinref_from_index (nets, index); -} - -std::pair -NetlistBrowserModel::net_pinrefs_from_id (void *id) const -{ - IndexedNetlistModel::net_pair nets = nets_from_id (id); - size_t index = circuit_net_pin_index_from_id (id); - - return mp_indexer->net_pinref_from_index (nets, index); -} - -std::pair -NetlistBrowserModel::net_terminalrefs_from_id (void *id) const -{ - IndexedNetlistModel::net_pair nets = nets_from_id (id); - size_t index = circuit_net_device_terminal_index_from_id (id); - - return mp_indexer->net_terminalref_from_index (nets, index); -} - -std::pair -NetlistBrowserModel::devices_from_id (void *id) const -{ - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - size_t index = circuit_device_index_from_id (id); - - return mp_indexer->device_from_index (circuits, index).first; -} - -std::pair -NetlistBrowserModel::pins_from_id (void *id) const -{ - if (is_id_circuit_subcircuit_pin (id)) { - - IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_id (id); - IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits); - - size_t index = circuit_subcircuit_pin_index_from_id (id); - - return mp_indexer->pin_from_index (circuit_refs, index).first; - + if (d) { + d->ensure_children (const_cast (this)); + return int (d->child_count ()); } else { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - - size_t index = circuit_pin_index_from_id (id); - - return mp_indexer->pin_from_index (circuits, index).first; - - } -} - -std::pair -NetlistBrowserModel::subcircuits_from_id (void *id) const -{ - if (is_id_circuit_subcircuit_pin (id) || is_id_circuit_subcircuit (id)) { - - IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); - size_t index = circuit_subcircuit_index_from_id (id); - - return mp_indexer->subcircuit_from_index (circuits, index).first; - - } else { - - IndexedNetlistModel::net_subcircuit_pin_pair pinrefs = net_subcircuit_pinrefs_from_id (id); - return subcircuits_from_pinrefs (pinrefs); - + return 0; } } diff --git a/src/laybasic/laybasic/layNetlistBrowserModel.h b/src/laybasic/laybasic/layNetlistBrowserModel.h index ac38f461a..3d80362e7 100644 --- a/src/laybasic/laybasic/layNetlistBrowserModel.h +++ b/src/laybasic/laybasic/layNetlistBrowserModel.h @@ -30,6 +30,9 @@ #include "dbLayoutToNetlist.h" #include "dbLayoutVsSchematic.h" +#include "tlList.h" +#include "tlTypeTraits.h" + #include #include @@ -88,6 +91,167 @@ private: // ---------------------------------------------------------------------------------- // NetlistBrowserModel definition +class NetlistBrowserModel; +class NetlistModelItemData; +class RootItemData; +class CircuitItemData; +class CircuitNetItemData; +class CircuitDeviceItemData; +class CircuitSubCircuitItemData; + +} + +namespace tl { + // disable copying for NetlistModelItemData + template<> struct type_traits + { + typedef false_tag has_copy_constructor; + }; +} + +namespace lay +{ + +/** + * @brief A base class for the item data object + */ +class NetlistModelItemData + : public tl::list_node +{ +public: + typedef tl::list::iterator iterator; + + NetlistModelItemData (); + NetlistModelItemData (NetlistModelItemData *parent); + + virtual ~NetlistModelItemData (); + + virtual NetlistModelItemData *parent () { return mp_parent; } + + virtual QIcon icon (NetlistBrowserModel *model) = 0; + virtual QString text (int column, NetlistBrowserModel *model) = 0; + virtual QString search_text () = 0; + virtual std::string tooltip (NetlistBrowserModel *model) = 0; + virtual db::NetlistCrossReference::Status status (NetlistBrowserModel *model) = 0; + + void ensure_children (NetlistBrowserModel *model); + + void push_back (NetlistModelItemData *child); + + iterator begin () { return m_children.begin (); } + iterator end () { return m_children.end (); } + + size_t child_count () { return m_children_per_index.size (); } + size_t index () { return m_index; } + + NetlistModelItemData *child (size_t n); + + virtual std::pair circuits_of_this (); + std::pair circuits (); + bool derived_from_circuits (const std::pair &sp); + + virtual std::pair devices_of_this (); + std::pair devices (); + bool derived_from_devices (const std::pair &sp); + + virtual std::pair pins_of_this (); + std::pair pins (); + bool derived_from_pins (const std::pair &sp); + + virtual std::pair subcircuits_of_this (); + std::pair subcircuits (); + bool derived_from_subcircuits (const std::pair &sp); + + virtual std::pair nets_of_this (); + std::pair nets (); + bool derived_from_nets (const std::pair &np); + +private: + NetlistModelItemData *mp_parent; + tl::list m_children; + std::vector m_children_per_index; + bool m_children_made; + size_t m_index; + + void set_index (size_t index) { m_index = index; } + + virtual void do_ensure_children (NetlistBrowserModel *model) = 0; +}; + +/** + * @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 path_type::const_iterator path_iterator; + + NetlistObjectPath () : root (0), net (0), device (0) { } + + bool is_null () const + { + return ! root; + } + + bool operator== (const NetlistObjectPath &other) const + { + return root == other.root && path == other.path && net == other.net && device == other.device; + } + + bool operator!= (const NetlistObjectPath &other) const + { + 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; + std::pair device; +}; + /** * @brief The NetlistBrowserModel * @@ -125,31 +289,70 @@ public: virtual QModelIndex parent (const QModelIndex &index) const; virtual int rowCount (const QModelIndex &parent) const; - QModelIndex index_from_id (void *id, int column) const; - int status_column () const { return m_status_column; } - std::pair net_from_index (const QModelIndex &index) const; - QModelIndex index_from_net (const std::pair &net) const; - QModelIndex index_from_net (const db::Net *net) const; - std::pair circuit_from_index (const QModelIndex &index) const; - QModelIndex index_from_circuit (const std::pair &circuit) const; - QModelIndex index_from_circuit (const db::Circuit *circuit) const; - - std::pair subcircuit_from_index (const QModelIndex &index) const; - - std::pair device_from_index (const QModelIndex &index) const; - - bool is_circuit_index (const QModelIndex &index) const + int object_column () const { - return is_id_circuit (index.internalPointer ()); + return m_object_column; } + int first_column () const + { + return m_first_column; + } + + int second_column () const + { + return m_second_column; + } + + IndexedNetlistModel *indexer () + { + return mp_indexer.get (); + } + + std::pair net_from_index (const QModelIndex &index, bool include_parents = true) const; + QModelIndex index_from_net (const std::pair &net) const; + QModelIndex index_from_net (const db::Net *net) const; + std::pair circuit_from_index (const QModelIndex &index, bool include_parents = true) const; + QModelIndex index_from_circuit (const std::pair &circuit) const; + QModelIndex index_from_circuit (const db::Circuit *circuit) const; + QModelIndex index_from_subcircuit (const std::pair &subcircuits) const; + + std::pair subcircuit_from_index (const QModelIndex &index, bool include_parents = true) const; + + std::pair device_from_index (const QModelIndex &index, bool include_parents = true) const; + void set_item_visibility (QTreeView *view, bool show_all, bool with_warnings); + QString make_link_to (const std::pair &nets, int column = 0) const; + QString make_link_to (const std::pair &devices, int column = 0) const; + QString make_link_to (const std::pair &pins, const std::pair &circuits, int column = 0) const; + QString make_link_to (const std::pair &circuits, int column = 0) const; + QString make_link_to (const std::pair &sub_circuits, int column = 0) const; + + bool is_valid_net_pair (const std::pair &net) const; + + QIcon icon_for_nets (const std::pair &net) const; + QIcon icon_for_connection (const std::pair &net) const; + + QModelIndex index_from_url (const QString &url) const; + + 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 (); @@ -157,73 +360,18 @@ private: NetlistBrowserModel (const NetlistBrowserModel &); NetlistBrowserModel &operator= (const NetlistBrowserModel &); - void *make_id_circuit (size_t circuit_index) const; - void *make_id_circuit_pin (size_t circuit_index, size_t pin_index) const; - void *make_id_circuit_pin_net (size_t circuit_index, size_t pin_index, size_t net_index) const; - void *make_id_circuit_net (size_t circuit_index, size_t net_index) const; - void *make_id_circuit_net_device_terminal (size_t circuit_index, size_t net_index, size_t terminal_ref_index) const; - 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; - void *make_id_circuit_net_pin (size_t circuit_index, size_t net_index, size_t pin_index) const; - void *make_id_circuit_net_subcircuit_pin (size_t circuit_index, size_t net_index, size_t pin_ref_index) const; - 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; - void *make_id_circuit_subcircuit (size_t circuit_index, size_t subcircuit_index) const; - void *make_id_circuit_subcircuit_pin (size_t circuit_index, size_t subcircuit_index, size_t pin_index) const; - void *make_id_circuit_device (size_t circuit_index, size_t device_index) const; - void *make_id_circuit_device_terminal (size_t circuit_index, size_t device_index, size_t terminal_index) const; - bool is_id_circuit (void *id) const; - bool is_id_circuit_pin (void *id) const; - bool is_id_circuit_pin_net (void *id) const; - bool is_id_circuit_net (void *id) const; - bool is_id_circuit_net_device_terminal (void *id) const; - bool is_id_circuit_net_device_terminal_others (void *id) const; - bool is_id_circuit_net_pin (void *id) const; - bool is_id_circuit_net_subcircuit_pin (void *id) const; - bool is_id_circuit_net_subcircuit_pin_others (void *id) const; - bool is_id_circuit_subcircuit (void *id) const; - bool is_id_circuit_subcircuit_pin (void *id) const; - bool is_id_circuit_device (void *id) const; - bool is_id_circuit_device_terminal (void *id) const; - size_t circuit_index_from_id (void *id) const; - size_t circuit_pin_index_from_id (void *id) const; - size_t circuit_device_index_from_id (void *id) const; - size_t circuit_device_terminal_index_from_id (void *id) const; - size_t circuit_subcircuit_index_from_id (void *id) const; - size_t circuit_subcircuit_pin_index_from_id (void *id) const; - size_t circuit_net_index_from_id (void *id) const; - size_t circuit_net_pin_index_from_id (void *id) const; - size_t circuit_net_subcircuit_pin_index_from_id (void *id) const; - size_t circuit_net_subcircuit_pin_other_index_from_id (void *id) const; - size_t circuit_net_device_terminal_index_from_id (void *id) const; - size_t circuit_net_device_terminal_other_index_from_id (void *id) const; - std::pair circuits_from_id (void *id) const; - std::pair nets_from_id (void *id) const; - std::pair net_subcircuit_pinrefs_from_id (void *id) const; - std::pair net_terminalrefs_from_id (void *id) const; - std::pair net_pinrefs_from_id (void *id) const; - std::pair devices_from_id (void *id) const; - std::pair pins_from_id (void *id) const; - std::pair subcircuits_from_id (void *id) const; QString text (const QModelIndex &index) const; QVariant tooltip (const QModelIndex &index) const; QString search_text (const QModelIndex &index) const; db::NetlistCrossReference::Status status (const QModelIndex &index) const; QIcon icon (const QModelIndex &index) const; - QString make_link_to (const std::pair &nets, int column = 0) const; - QString make_link_to (const std::pair &devices, int column = 0) const; - QString make_link_to (const std::pair &pins, const std::pair &circuits, int column = 0) const; - QString make_link_to (const std::pair &circuits, int column = 0) const; - QString make_link_to (const std::pair &sub_circuits, int column = 0) const; + QString build_url (const QModelIndex &index, const std::string &title) const; std::pair netlists () const { return std::pair (mp_l2ndb->netlist (), (const db::Netlist *)0); } - bool is_valid_net_pair (const std::pair &net) const; - - QIcon icon_for_nets (const std::pair &net) const; - QIcon icon_for_connection (const std::pair &net) const; - void show_or_hide_items (QTreeView *view, const QModelIndex &parent, bool show_all, bool with_warnings, bool with_children); db::LayoutToNetlist *mp_l2ndb; @@ -236,6 +384,9 @@ private: int m_status_column; int m_first_column; int m_second_column; + std::auto_ptr mp_root; + + RootItemData *root () const; }; } // namespace lay diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index 3c0882ad0..cf055fe0c 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -69,7 +69,7 @@ inline const db::Circuit *deref_circuit (const db::Circuit *obj) } template -static db::ICplxTrans +static db::DCplxTrans trans_for (const Obj *objs, const db::Layout &ly, const db::Cell &cell, db::ContextCache &cc, const db::DCplxTrans &initial = db::DCplxTrans ()) { db::DCplxTrans t = initial; @@ -89,7 +89,6 @@ trans_for (const Obj *objs, const db::Layout &ly, const db::Cell &cell, db::Cont } db::CplxTrans dbu_trans (ly.dbu ()); - db::ICplxTrans it = dbu_trans.inverted () * t * dbu_trans; // The circuit may not be instantiated and still not be the top cell. // This happens if the subcell does not have connections. In this case @@ -98,11 +97,11 @@ trans_for (const Obj *objs, const db::Layout &ly, const db::Cell &cell, db::Cont if (circuit && ly.is_valid_cell_index (circuit->cell_index ())) { std::pair tc = cc.find_layout_context (circuit->cell_index (), cell.cell_index ()); if (tc.first) { - it = tc.second * it; + t = dbu_trans * tc.second * dbu_trans.inverted () * t; } } - return it; + return t; } NetlistBrowserPage::NetlistBrowserPage (QWidget * /*parent*/) @@ -142,7 +141,8 @@ NetlistBrowserPage::NetlistBrowserPage (QWidget * /*parent*/) QAction *sep; directory_tree->addAction (m_show_all_action); directory_tree->addAction (actionCollapseAll); - directory_tree->addAction (actionExpandAll); + // TODO: this gives a too big tree - confine to single branches? + // directory_tree->addAction (actionExpandAll); sep = new QAction (directory_tree); sep->setSeparator (true); directory_tree->addAction (sep); @@ -306,21 +306,10 @@ NetlistBrowserPage::layer_list_changed (int) void NetlistBrowserPage::anchor_clicked (const QString &a) { - QUrl url (a); - - QString ids; -#if QT_VERSION >= 0x050000 - ids = QUrlQuery (url.query ()).queryItemValue (QString::fromUtf8 ("id")); -#else - ids = url.queryItemValue (QString::fromUtf8 ("id")); -#endif - - if (ids.isEmpty ()) { - return; + NetlistBrowserModel *netlist_model = dynamic_cast (directory_tree->model ()); + if (netlist_model) { + navigate_to (netlist_model->index_from_url (a), true); } - - void *id = reinterpret_cast (ids.toULongLong ()); - navigate_to (id, true); } void @@ -334,6 +323,7 @@ NetlistBrowserPage::current_tree_index_changed (const QModelIndex &index) return; } + // TODO: this could give a path ... std::pair circuits = tree_model->circuits_from_index (index); QModelIndex circuit_index = netlist_model->index_from_circuit (circuits); @@ -355,11 +345,10 @@ NetlistBrowserPage::current_index_changed (const QModelIndex &index) return; } - void *id = index.internalPointer (); - add_to_history (id, true); + add_to_history (index, true); - std::pair circuits = netlist_model->circuit_from_index (index); - QModelIndex circuit_index = tree_model->index_from_circuits (circuits); + NetlistObjectsPath path = netlist_model->path_from_index (index); + QModelIndex circuit_index = tree_model->index_from_netpath (path); m_signals_enabled = false; hierarchy_tree->setCurrentIndex (circuit_index); @@ -380,6 +369,18 @@ NetlistBrowserPage::select_net (const db::Net *net) } } +void +NetlistBrowserPage::select_path (const lay::NetlistObjectsPath &path) +{ + if (path.is_null ()) { + directory_tree->clearSelection (); + } else { + NetlistBrowserModel *model = dynamic_cast (directory_tree->model ()); + tl_assert (model != 0); + directory_tree->setCurrentIndex (model->index_from_path (path)); + } +} + std::vector NetlistBrowserPage::selected_nets () { @@ -411,7 +412,7 @@ NetlistBrowserPage::selected_circuits () QModelIndexList selection = directory_tree->selectionModel ()->selectedIndexes (); for (QModelIndexList::const_iterator i = selection.begin (); i != selection.end (); ++i) { - if (i->column () == 0 && model->is_circuit_index (*i)) { + if (i->column () == 0) { const db::Circuit *circuit = model->circuit_from_index (*i).first; if (circuit) { circuits.push_back (circuit); @@ -467,18 +468,23 @@ NetlistBrowserPage::selected_devices () void NetlistBrowserPage::selection_changed () { - std::vector nets = selected_nets (); - if (mp_info_dialog) { - mp_info_dialog->set_nets (mp_database.get (), nets); + 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)); + } } - std::vector devices = selected_devices (); + QModelIndex current = directory_tree->selectionModel ()->currentIndex (); + highlight (model->path_from_index (current), selected_paths); - std::vector subcircuits = selected_subcircuits (); - - std::vector circuits = selected_circuits (); - - highlight (nets, devices, subcircuits, circuits); + selection_changed_event (); } void @@ -518,15 +524,8 @@ NetlistBrowserPage::select_color_for_net () } void -NetlistBrowserPage::navigate_to (void *id, bool fwd) +NetlistBrowserPage::navigate_to (const QModelIndex &index, bool fwd) { - NetlistBrowserTreeModel *tree_model = dynamic_cast (hierarchy_tree->model ()); - NetlistBrowserModel *netlist_model = dynamic_cast (directory_tree->model ()); - if (! tree_model || ! netlist_model) { - return; - } - - QModelIndex index = netlist_model->index_from_id (id, 0); if (! index.isValid ()) { return; } @@ -536,35 +535,42 @@ NetlistBrowserPage::navigate_to (void *id, bool fwd) directory_tree->setCurrentIndex (index); - std::pair circuits = netlist_model->circuit_from_index (index); - QModelIndex circuit_index = tree_model->index_from_circuits (circuits); + NetlistBrowserTreeModel *tree_model = dynamic_cast (hierarchy_tree->model ()); + NetlistBrowserModel *netlist_model = dynamic_cast (directory_tree->model ()); + if (! tree_model || ! netlist_model) { + return; + } + + lay::NetlistObjectsPath path = netlist_model->path_from_index (index); + QModelIndex circuit_index = tree_model->index_from_netpath (path); hierarchy_tree->setCurrentIndex (circuit_index); } catch (...) { } + m_signals_enabled = true; - add_to_history (id, fwd); + add_to_history (index, fwd); selection_changed (); } void -NetlistBrowserPage::add_to_history (void *id, bool fwd) +NetlistBrowserPage::add_to_history (const QModelIndex &index, bool fwd) { if (! fwd) { if (m_history_ptr > 1) { --m_history_ptr; - m_history [m_history_ptr - 1] = id; + m_history [m_history_ptr - 1] = index; } } else if (m_history_ptr >= m_history.size ()) { - m_history.push_back (id); + m_history.push_back (index); m_history_ptr = m_history.size (); } else { - if (m_history [m_history_ptr] != id) { + if (m_history [m_history_ptr] != index) { m_history.erase (m_history.begin () + m_history_ptr + 1, m_history.end ()); } - m_history [m_history_ptr] = id; + m_history [m_history_ptr] = index; ++m_history_ptr; } @@ -730,7 +736,7 @@ NetlistBrowserPage::find_button_pressed () QModelIndex next = find_next (directory_tree, directory_tree->model (), re, directory_tree->currentIndex ()); if (next.isValid ()) { - navigate_to (next.internalPointer ()); + navigate_to (next); } } @@ -795,11 +801,12 @@ NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb) m_signals_enabled = se; clear_markers (); - highlight (std::vector (), std::vector (), std::vector (), std::vector ()); m_cell_context_cache = db::ContextCache (mp_database.get () ? mp_database->internal_layout () : 0); setup_trees (); + + selection_changed_event (); } void @@ -886,21 +893,16 @@ NetlistBrowserPage::setup_trees () } void -NetlistBrowserPage::highlight (const std::vector &nets, const std::vector &devices, const std::vector &subcircuits, const std::vector &circuits) +NetlistBrowserPage::highlight (const NetlistObjectsPath ¤t_path, const std::vector &selected_paths) { - if (nets != m_current_nets || devices != m_current_devices || subcircuits != m_current_subcircuits || circuits != m_current_circuits) { + if (current_path != m_current_path && selected_paths != m_selected_paths) { - m_current_nets = nets; - m_current_devices = devices; - m_current_subcircuits = subcircuits; - m_current_circuits = circuits; + m_current_path = current_path; + m_selected_paths = selected_paths; clear_markers (); - - if (! nets.empty () || ! devices.empty () || ! subcircuits.empty () || ! circuits.empty ()) { - adjust_view (); - update_highlights (); - } + adjust_view (); + update_highlights (); } } @@ -928,7 +930,8 @@ bbox_for_device_abstract (const db::Layout *layout, const db::DeviceAbstract *de return db::Box (); } - return layout->cell (device_abstract->cell_index ()).bbox ().transformed (db::CplxTrans (layout->dbu ()).inverted () * trans * db::CplxTrans (layout->dbu ()));} + return layout->cell (device_abstract->cell_index ()).bbox ().transformed (db::CplxTrans (layout->dbu ()).inverted () * trans * db::CplxTrans (layout->dbu ())); +} static db::Box bbox_for_circuit (const db::Layout *layout, const db::Circuit *circuit) @@ -945,12 +948,6 @@ bbox_for_circuit (const db::Layout *layout, const db::Circuit *circuit) return layout->cell (circuit->cell_index ()).bbox (); } -static db::Box -bbox_for_subcircuit (const db::Layout *layout, const db::SubCircuit *subcircuit) -{ - return bbox_for_circuit (layout, subcircuit->circuit_ref ()); -} - void NetlistBrowserPage::adjust_view () { @@ -967,57 +964,80 @@ NetlistBrowserPage::adjust_view () return; } + 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::Layout *layout = mp_database->internal_layout (); - const db::Cell *cell = mp_database->internal_top_cell (); + 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::DBox bbox; - db::Box bbox; + for (std::vector::const_iterator path = m_selected_paths.begin (); path != m_selected_paths.end (); ++path) { - for (std::vector::const_iterator net = m_current_nets.begin (); net != m_current_nets.end (); ++net) { + const db::Circuit *circuit = path->root.first; + if (! circuit) { + continue; + } - db::ICplxTrans net_trans = trans_for (*net, *layout, *cell, m_cell_context_cache); + db::DCplxTrans trans; - db::cell_index_type cell_index = (*net)->circuit ()->cell_index (); - size_t cluster_id = (*net)->cluster_id (); + trans = trans_for (circuit, *layout, *cell, m_cell_context_cache, db::DCplxTrans ()); - const db::Connectivity &conn = mp_database->connectivity (); - for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) { + 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; + } + } - 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 (); - ++shapes; + if (! circuit) { + continue; + } + + db::Box ebox; + + const db::Device *device = path->device.first; + const db::Net *net = path->net.first; + + if (device) { + + ebox += bbox_for_device_abstract (layout, device->device_abstract (), db::DCplxTrans ()); + + const std::vector &oda = device->other_abstracts (); + for (std::vector::const_iterator a = oda.begin (); a != oda.end (); ++a) { + ebox += bbox_for_device_abstract (layout, a->device_abstract, a->trans); } - bbox += net_trans * layer_bbox; + } else if (net) { + db::cell_index_type cell_index = net->circuit ()->cell_index (); + size_t cluster_id = net->cluster_id (); + + const db::Connectivity &conn = mp_database->connectivity (); + for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) { + + 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 ().transformed (shapes.trans ()); + ++shapes; + } + + ebox += layer_bbox; + + } + + } else if (circuit) { + ebox += bbox_for_circuit (layout, circuit); } - } + bbox += trans * db::CplxTrans (layout->dbu ()) * ebox; - for (std::vector::const_iterator device = m_current_devices.begin (); device != m_current_devices.end (); ++device) { - - db::ICplxTrans trans = trans_for (*device, *layout, *cell, m_cell_context_cache, (*device)->trans ()); - - bbox += trans * bbox_for_device_abstract (layout, (*device)->device_abstract (), db::DCplxTrans ()); - - const std::vector &oda = (*device)->other_abstracts (); - for (std::vector::const_iterator a = oda.begin (); a != oda.end (); ++a) { - bbox += trans * bbox_for_device_abstract (layout, a->device_abstract, a->trans); - } - - } - - for (std::vector::const_iterator subcircuit = m_current_subcircuits.begin (); subcircuit != m_current_subcircuits.end (); ++subcircuit) { - bbox += trans_for (*subcircuit, *layout, *cell, m_cell_context_cache, (*subcircuit)->trans ()) * bbox_for_subcircuit (layout, *subcircuit); - } - - for (std::vector::const_iterator circuit = m_current_circuits.begin (); circuit != m_current_circuits.end (); ++circuit) { - bbox += trans_for (*circuit, *layout, *cell, m_cell_context_cache, db::DCplxTrans ()) * bbox_for_circuit (layout, *circuit); } if (! bbox.empty ()) { @@ -1025,9 +1045,8 @@ NetlistBrowserPage::adjust_view () std::vector tv = mp_view->cv_transform_variants (m_cv_index); db::DBox tv_bbox; - db::DBox dbu_bbox = db::CplxTrans (layout->dbu ()) * bbox; for (std::vector::const_iterator t = tv.begin (); t != tv.end (); ++t) { - tv_bbox += *t * dbu_bbox; + tv_bbox += *t * bbox; } if (m_window == lay::NetlistBrowserConfig::FitNet) { @@ -1065,12 +1084,10 @@ bool NetlistBrowserPage::produce_highlights_for_device (const db::Device *device, size_t &n_markers, const std::vector &tv) { const db::Layout *layout = mp_database->internal_layout (); - const db::Cell *cell = mp_database->internal_top_cell (); - db::ICplxTrans device_trans = trans_for (device, *layout, *cell, m_cell_context_cache, device->trans ()); QColor color = make_valid_color (m_colorizer.marker_color ()); - db::Box device_bbox = bbox_for_device_abstract (layout, device->device_abstract (), db::DCplxTrans ()); + db::Box device_bbox = bbox_for_device_abstract (layout, device->device_abstract (), device->trans ()); if (! device_bbox.empty ()) { if (n_markers == m_max_shape_count) { @@ -1080,7 +1097,7 @@ NetlistBrowserPage::produce_highlights_for_device (const db::Device *device, siz ++n_markers; mp_markers.push_back (new lay::Marker (mp_view, m_cv_index)); - mp_markers.back ()->set (device_bbox, device_trans, tv); + mp_markers.back ()->set (device_bbox, db::ICplxTrans (), tv); mp_markers.back ()->set_color (color); mp_markers.back ()->set_frame_color (color); configure_marker (mp_markers.back (), false); @@ -1090,7 +1107,7 @@ NetlistBrowserPage::produce_highlights_for_device (const db::Device *device, siz const std::vector &oda = device->other_abstracts (); for (std::vector::const_iterator a = oda.begin (); a != oda.end (); ++a) { - db::Box da_box = bbox_for_device_abstract (layout, a->device_abstract, a->trans); + db::Box da_box = bbox_for_device_abstract (layout, a->device_abstract, device->trans () * a->trans); if (! da_box.empty ()) { if (n_markers == m_max_shape_count) { @@ -1100,7 +1117,7 @@ NetlistBrowserPage::produce_highlights_for_device (const db::Device *device, siz ++n_markers; mp_markers.push_back (new lay::Marker (mp_view, m_cv_index)); - mp_markers.back ()->set (da_box, device_trans, tv); + mp_markers.back ()->set (da_box, db::ICplxTrans (), tv); mp_markers.back ()->set_color (color); mp_markers.back ()->set_frame_color (color); configure_marker (mp_markers.back (), false); @@ -1112,40 +1129,10 @@ NetlistBrowserPage::produce_highlights_for_device (const db::Device *device, siz return false; } -bool -NetlistBrowserPage::produce_highlights_for_subcircuit (const db::SubCircuit *subcircuit, size_t &n_markers, const std::vector &tv) -{ - const db::Layout *layout = mp_database->internal_layout (); - const db::Cell *cell = mp_database->internal_top_cell (); - db::ICplxTrans subcircuit_trans = trans_for (subcircuit, *layout, *cell, m_cell_context_cache, subcircuit->trans ()); - - QColor color = make_valid_color (m_colorizer.marker_color ()); - db::Box circuit_bbox = bbox_for_subcircuit (layout, subcircuit); - if (circuit_bbox.empty ()) { - return false; - } - - if (n_markers == m_max_shape_count) { - return true; - } - - ++n_markers; - - mp_markers.push_back (new lay::Marker (mp_view, m_cv_index)); - mp_markers.back ()->set (circuit_bbox, subcircuit_trans, tv); - mp_markers.back ()->set_color (color); - mp_markers.back ()->set_frame_color (color); - configure_marker (mp_markers.back (), false); - - return false; -} - bool NetlistBrowserPage::produce_highlights_for_circuit (const db::Circuit *circuit, size_t &n_markers, const std::vector &tv) { const db::Layout *layout = mp_database->internal_layout (); - const db::Cell *cell = mp_database->internal_top_cell (); - db::ICplxTrans circuit_trans = trans_for (circuit, *layout, *cell, m_cell_context_cache, db::DCplxTrans ()); QColor color = make_valid_color (m_colorizer.marker_color ()); db::Box circuit_bbox = bbox_for_circuit (layout, circuit); @@ -1160,7 +1147,7 @@ NetlistBrowserPage::produce_highlights_for_circuit (const db::Circuit *circuit, ++n_markers; mp_markers.push_back (new lay::Marker (mp_view, m_cv_index)); - mp_markers.back ()->set (circuit_bbox, circuit_trans, tv); + mp_markers.back ()->set (circuit_bbox, db::ICplxTrans (), tv); mp_markers.back ()->set_color (color); mp_markers.back ()->set_frame_color (color); configure_marker (mp_markers.back (), false); @@ -1172,8 +1159,6 @@ bool NetlistBrowserPage::produce_highlights_for_net (const db::Net *net, size_t &n_markers, const std::map &display_by_lp, const std::vector &tv) { const db::Layout *layout = mp_database->internal_layout (); - const db::Cell *cell = mp_database->internal_top_cell (); - db::ICplxTrans net_trans = trans_for (net, *layout, *cell, m_cell_context_cache); db::cell_index_type cell_index = net->circuit ()->cell_index (); size_t cluster_id = net->cluster_id (); @@ -1199,7 +1184,7 @@ NetlistBrowserPage::produce_highlights_for_net (const db::Net *net, size_t &n_ma } mp_markers.push_back (new lay::Marker (mp_view, m_cv_index)); - mp_markers.back ()->set (shapes->polygon_ref (), net_trans * shapes.trans (), tv); + mp_markers.back ()->set (shapes->polygon_ref (), shapes.trans (), tv); if (net_color.isValid ()) { @@ -1272,14 +1257,14 @@ 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::Layout *layout = mp_database->internal_layout (); - if (! 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; } - // 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 ()) { @@ -1287,36 +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 * db::DCplxTrans (layout->dbu () / original_layout.dbu ()); - } - size_t n_markers = 0; bool not_all_shapes_are_shown = false; - for (std::vector::const_iterator net = m_current_nets.begin (); net != m_current_nets.end () && ! not_all_shapes_are_shown; ++net) { - if ((*net)->circuit ()) { - not_all_shapes_are_shown = produce_highlights_for_net (*net, n_markers, display_by_lp, tv); - } - } + for (std::vector::const_iterator path = m_selected_paths.begin (); path != m_selected_paths.end (); ++path) { - for (std::vector::const_iterator device = m_current_devices.begin (); device != m_current_devices.end () && ! not_all_shapes_are_shown; ++device) { - if ((*device)->circuit ()) { - not_all_shapes_are_shown = produce_highlights_for_device (*device, n_markers, tv); + const db::Circuit *circuit = path->root.first; + if (! circuit) { + continue; } - } - for (std::vector::const_iterator subcircuit = m_current_subcircuits.begin (); subcircuit != m_current_subcircuits.end () && ! not_all_shapes_are_shown; ++subcircuit) { - if ((*subcircuit)->circuit ()) { - not_all_shapes_are_shown = produce_highlights_for_subcircuit (*subcircuit, n_markers, tv); + // 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; + } } - } - for (std::vector::const_iterator circuit = m_current_circuits.begin (); circuit != m_current_circuits.end () && ! not_all_shapes_are_shown; ++circuit) { - not_all_shapes_are_shown = produce_highlights_for_circuit (*circuit, n_markers, tv); } if (not_all_shapes_are_shown) { @@ -1327,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 9a1adccd6..11fb8418d 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.h +++ b/src/laybasic/laybasic/layNetlistBrowserPage.h @@ -33,6 +33,7 @@ #include "dbLayoutUtils.h" #include "tlObject.h" +#include "tlEvents.h" #include @@ -90,25 +91,14 @@ public: /** * @brief Attaches the page to a L2N DB */ - void set_l2ndb (db::LayoutToNetlist *database) - { - set_db (database); - } + void set_db (db::LayoutToNetlist *database); /** - * @brief Attaches the page to a LVS DB + * @brief Gets the database the page is connected to */ - void set_lvsdb (db::LayoutVsSchematic *database) + db::LayoutToNetlist *db () { - set_db (database); - } - - /** - * @brief Detaches the page from any DB - */ - void reset_db () - { - set_db (0); + return mp_database.get (); } /** @@ -116,6 +106,22 @@ public: */ void select_net (const db::Net *net); + /** + * @brief Selects a netlist object (a circuit, a subcircuit, a net or a device) + */ + void select_path (const lay::NetlistObjectPath &path) + { + select_path (lay::NetlistObjectsPath::from_first (path)); + } + + /** + * @brief Selects a netlist object (a circuit, a subcircuit, a net or a device) + * + * This variant allows specifying a paired path using either an object from the first, + * the second netlist of both. + */ + void select_path (const lay::NetlistObjectsPath &path); + /** * @brief Set the window type and window dimensions */ @@ -162,6 +168,27 @@ public: */ void update_highlights (); + /** + * @brief Gets the current object's path + */ + const lay::NetlistObjectsPath ¤t_path () const + { + return m_current_path; + } + + /** + * @brief Gets the selected nets + */ + const std::vector &selected_paths () const + { + return m_selected_paths; + } + + /** + * @brief An event indicating that the selection has changed + */ + tl::Event selection_changed_event; + public slots: void export_all (); void export_selected (); @@ -201,28 +228,25 @@ private: unsigned int m_cv_index; lay::Dispatcher *mp_plugin_root; tl::weak_ptr mp_database; - std::vector m_history; + std::vector m_history; size_t m_history_ptr; bool m_signals_enabled; std::vector mp_markers; bool m_enable_updates; bool m_update_needed; - std::vector m_current_nets; - std::vector m_current_devices; - std::vector m_current_subcircuits; - std::vector m_current_circuits; + lay::NetlistObjectsPath m_current_path; + std::vector m_selected_paths; lay::NetInfoDialog *mp_info_dialog; tl::DeferredMethod dm_update_highlights; tl::DeferredMethod dm_rerun_macro; db::ContextCache m_cell_context_cache; - void set_db (db::LayoutToNetlist *l2ndb); void setup_trees (); - void add_to_history (void *id, bool fwd); - void navigate_to (void *id, bool forward = true); + void add_to_history (const QModelIndex &index, bool fwd); + void navigate_to (const QModelIndex &index, bool forward = true); void adjust_view (); void clear_markers (); - void highlight (const std::vector &nets, const std::vector &devices, const std::vector &subcircuits, const std::vector &circuits); + void highlight (const NetlistObjectsPath ¤t_path, const std::vector &selected_paths); std::vector selected_nets (); std::vector selected_devices (); std::vector selected_subcircuits (); @@ -232,7 +256,6 @@ private: QColor make_valid_color (const QColor &color); bool produce_highlights_for_net(const db::Net *net, size_t &n_markers, const std::map &display_by_lp, const std::vector &tv); bool produce_highlights_for_device (const db::Device *device, size_t &n_markers, const std::vector &tv); - bool produce_highlights_for_subcircuit (const db::SubCircuit *subcircuit, size_t &n_markers, const std::vector &tv); bool produce_highlights_for_circuit (const db::Circuit *circuit, size_t &n_markers, const std::vector &tv); void configure_marker (lay::Marker *marker, bool with_fill); void rerun_macro (); diff --git a/src/laybasic/laybasic/layNetlistBrowserTreeModel.cc b/src/laybasic/laybasic/layNetlistBrowserTreeModel.cc index c8d26f5dd..f77138f8f 100644 --- a/src/laybasic/laybasic/layNetlistBrowserTreeModel.cc +++ b/src/laybasic/laybasic/layNetlistBrowserTreeModel.cc @@ -24,6 +24,7 @@ #include "layNetlistBrowserTreeModel.h" #include "layIndexedNetlistModel.h" #include "layNetlistCrossReferenceModel.h" +#include "layNetlistBrowserModel.h" #include #include @@ -257,6 +258,45 @@ NetlistBrowserTreeModel::build_circuits_to_index (size_t nprod, const std::pair< } } +static bool is_compatible (const std::pair &a, const std::pair &b) +{ + if (a.first && b.first && a.first == b.first) { + return true; + } else if (a.second && b.second && a.second == b.second) { + return true; + } else { + return false; + } +} + +QModelIndex +NetlistBrowserTreeModel::index_from_netpath (const NetlistObjectsPath &path) const +{ + QModelIndex idx; + + idx = index_from_circuits (path.root); + + for (NetlistObjectsPath::path_iterator p = path.path.begin (); p != path.path.end () && idx.isValid (); ++p) { + + std::pair sc (p->first ? p->first->circuit_ref () : 0, p->second ? p->second->circuit_ref (): 0); + std::pair circuit = circuits_from_index (idx); + + size_t count = mp_indexer->child_circuit_count (circuit); + for (size_t n = count; n > 0; ) { + --n; + std::pair cc = mp_indexer->child_circuit_from_index (circuit, n).first; + if (is_compatible (sc, cc)) { + circuit = cc; + idx = index (n, 0, idx); + break; + } + } + + } + + return idx; +} + QModelIndex NetlistBrowserTreeModel::index_from_circuits (const std::pair &circuits) const { @@ -382,7 +422,7 @@ NetlistBrowserTreeModel::parent (const QModelIndex &index) const nprod /= nnlast; - return createIndex (int (ids / nprod - 1), index.column (), reinterpret_cast (ids)); + return createIndex (int (ids / nprod - 1), 0, reinterpret_cast (ids)); } diff --git a/src/laybasic/laybasic/layNetlistBrowserTreeModel.h b/src/laybasic/laybasic/layNetlistBrowserTreeModel.h index 3ecff81f1..d0f182bfc 100644 --- a/src/laybasic/laybasic/layNetlistBrowserTreeModel.h +++ b/src/laybasic/laybasic/layNetlistBrowserTreeModel.h @@ -42,6 +42,7 @@ namespace lay { class IndexedNetlistModel; +struct NetlistObjectsPath; // ---------------------------------------------------------------------------------- // NetlistBrowserTreeModel definition @@ -77,6 +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 NetlistObjectsPath &path) const; private: NetlistBrowserTreeModel (const NetlistBrowserTreeModel &); diff --git a/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc b/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc index 6216c70f7..bf816b302 100644 --- a/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc +++ b/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc @@ -308,6 +308,161 @@ const db::Circuit *NetlistCrossReferenceModel::second_circuit_for (const db::Cir return mp_cross_ref->other_circuit_for (first); } +namespace { + + // TODO: borrowed from dbNetlistCrossReference.cc + + static int string_value_compare (const std::string &a, const std::string &b) + { + return a == b ? 0 : (a < b ? -1 : 1); + } + + template + struct by_expanded_name_value_compare + { + int operator() (const Obj &a, const Obj &b) const + { + return string_value_compare (a.expanded_name (), b.expanded_name ()); + } + }; + + template struct net_object_compare; + + template <> + struct net_object_compare + { + int operator() (const db::NetSubcircuitPinRef &a, const db::NetSubcircuitPinRef &b) const + { + int ct = by_expanded_name_value_compare () (*a.subcircuit (), *b.subcircuit ()); + if (ct == 0) { + return by_expanded_name_value_compare () (*a.pin (), *b.pin ()); + } else { + return ct; + } + } + }; + + template + struct two_pointer_compare + { + int operator() (const Obj *a, const Obj *b) const + { + if ((a == 0) != (b == 0)) { + return (a == 0) > (b == 0) ? -1 : 1; + } + if (a != 0) { + return ValueCompare () (*a, *b); + } else { + return 0; + } + } + }; + + template + struct two_pair_compare + { + bool operator() (const std::pair &a, const std::pair &b) + { + int ct = two_pointer_compare () (a.first, b.first); + if (ct != 0) { + return ct < 0; + } + return two_pointer_compare () (a.second, b.second) < 0; + } + }; + + struct SortNetSubCircuitPins + : public two_pair_compare > + { + // .. nothing yet .. + }; + +} + +void NetlistCrossReferenceModel::ensure_subcircuit_data_built () const +{ + if (! m_per_subcircuit_data.empty ()) { + return; + } + + // Build the net to subcircuit ref table + for (db::NetlistCrossReference::circuits_iterator c = mp_cross_ref->begin_circuits (); c != mp_cross_ref->end_circuits (); ++c) { + + const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (*c); + if (! data) { + continue; + } + + for (db::NetlistCrossReference::PerCircuitData::subcircuit_pairs_type::const_iterator sc = data->subcircuits.begin (); sc != data->subcircuits.end (); ++sc) { + + const std::pair &sc_pair = sc->pair; + if (sc_pair.first && sc_pair.second) { + + PerSubCircuitCacheData &sc_data = m_per_subcircuit_data [sc_pair]; + + std::multimap first_net_to_other_netref; + for (size_t i = 0; i < sc_pair.second->circuit_ref ()->pin_count (); ++i) { + const db::NetSubcircuitPinRef *n2 = sc_pair.second->netref_for_pin (i); + if (n2) { + const db::Net *n1 = mp_cross_ref->other_net_for (n2->net ()); + if (n1) { + first_net_to_other_netref.insert (std::make_pair (n1, n2)); + } else { + sc_data.nets_per_pins.push_back (std::pair (0, n2)); + } + } + } + + for (size_t i = 0; i < sc_pair.first->circuit_ref ()->pin_count (); ++i) { + const db::NetSubcircuitPinRef *n1 = sc_pair.first->netref_for_pin (i); + if (n1) { + const db::NetSubcircuitPinRef *n2 = 0; + std::multimap::iterator m = first_net_to_other_netref.find (n1->net ()); + if (m != first_net_to_other_netref.end () && m->first == n1->net ()) { + n2 = m->second; + first_net_to_other_netref.erase (m); + } + sc_data.nets_per_pins.push_back (std::make_pair (n1, n2)); + } + } + + std::sort (sc_data.nets_per_pins.begin (), sc_data.nets_per_pins.end (), SortNetSubCircuitPins ()); + + } + + } + + } +} + +size_t NetlistCrossReferenceModel::subcircuit_pin_count (const subcircuit_pair &subcircuits) const +{ + ensure_subcircuit_data_built (); + + std::map, PerSubCircuitCacheData>::const_iterator sc = m_per_subcircuit_data.find (subcircuits); + if (sc != m_per_subcircuit_data.end ()) { + return sc->second.nets_per_pins.size (); + } else { + return std::max (subcircuits.first ? subcircuits.first->circuit_ref ()->pin_count () : 0, subcircuits.second ? subcircuits.second->circuit_ref ()->pin_count () : 0); + } +} + +IndexedNetlistModel::net_subcircuit_pin_pair NetlistCrossReferenceModel::subcircuit_pinref_from_index (const subcircuit_pair &subcircuits, size_t index) const +{ + ensure_subcircuit_data_built (); + + std::map, PerSubCircuitCacheData>::const_iterator sc = m_per_subcircuit_data.find (subcircuits); + if (sc != m_per_subcircuit_data.end ()) { + if (index < sc->second.nets_per_pins.size ()) { + return sc->second.nets_per_pins [index]; + } else { + return IndexedNetlistModel::net_subcircuit_pin_pair (0, 0); + } + } else { + return IndexedNetlistModel::net_subcircuit_pin_pair (subcircuits.first ? subcircuits.first->netref_for_pin (index) : 0, subcircuits.second ? subcircuits.second->netref_for_pin (index) : 0); + } +} + IndexedNetlistModel::net_subcircuit_pin_pair NetlistCrossReferenceModel::net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const { const db::NetlistCrossReference::PerNetData *data = mp_cross_ref->per_net_data_for (nets); diff --git a/src/laybasic/laybasic/layNetlistCrossReferenceModel.h b/src/laybasic/laybasic/layNetlistCrossReferenceModel.h index 34eb8a571..43df8fb2a 100644 --- a/src/laybasic/laybasic/layNetlistCrossReferenceModel.h +++ b/src/laybasic/laybasic/layNetlistCrossReferenceModel.h @@ -48,6 +48,7 @@ public: virtual size_t net_count (const circuit_pair &circuits) const; virtual size_t net_terminal_count (const net_pair &nets) const; virtual size_t net_subcircuit_pin_count (const net_pair &nets) const; + virtual size_t subcircuit_pin_count (const subcircuit_pair &subcircuits) const; virtual size_t net_pin_count (const net_pair &nets) const; virtual size_t device_count (const circuit_pair &circuits) const; virtual size_t pin_count (const circuit_pair &circuits) const; @@ -65,6 +66,7 @@ public: virtual const db::Net *second_net_for (const db::Net *first) const; virtual const db::Circuit *second_circuit_for (const db::Circuit *first) const; virtual net_subcircuit_pin_pair net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const; + virtual net_subcircuit_pin_pair subcircuit_pinref_from_index (const subcircuit_pair &nets, size_t index) const; virtual net_terminal_pair net_terminalref_from_index (const net_pair &nets, size_t index) const; virtual net_pin_pair net_pinref_from_index (const net_pair &nets, size_t index) const; virtual std::pair device_from_index (const circuit_pair &circuits, size_t index) const; @@ -95,6 +97,11 @@ public: std::map, size_t> index_of_subcircuits; }; + struct PerSubCircuitCacheData + { + std::vector > nets_per_pins; + }; + tl::weak_ptr mp_cross_ref; mutable std::map m_parents_of_nets; mutable std::map m_parents_of_devices; @@ -104,6 +111,9 @@ public: mutable std::vector m_top_level_circuits; mutable std::map, PerCircuitCacheData> m_per_circuit_data; mutable std::map, size_t> m_index_of_circuits; + mutable std::map, PerSubCircuitCacheData> m_per_subcircuit_data; + + void ensure_subcircuit_data_built () const; }; } diff --git a/src/laybasic/laybasic/laybasic.pro b/src/laybasic/laybasic/laybasic.pro index 7a7c8a92e..2e3e2b4c3 100644 --- a/src/laybasic/laybasic/laybasic.pro +++ b/src/laybasic/laybasic/laybasic.pro @@ -183,7 +183,8 @@ SOURCES = \ layGenericSyntaxHighlighter.cc \ layDispatcher.cc \ laySelectCellViewForm.cc \ - layLayoutStatisticsForm.cc + layLayoutStatisticsForm.cc \ + gsiDeclLayNetlistBrowserDialog.cc HEADERS = \ gtf.h \ diff --git a/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc b/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc index c22a3ba73..3b951e718 100644 --- a/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc +++ b/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc @@ -44,90 +44,98 @@ TEST (1) QModelIndex inv2Index = model->index (0, 0, QModelIndex ()); EXPECT_EQ (model->hasChildren (inv2Index), true); + // 4 subnodes + EXPECT_EQ (model->rowCount (inv2Index), 3); // 5 pins, 5 nets, 0 subcircuits, 4 devices - EXPECT_EQ (model->rowCount (inv2Index), 14); + QModelIndex sn_pins = model->index (0, 0, inv2Index); + QModelIndex sn_nets = model->index (1, 0, inv2Index); + QModelIndex sn_devices = model->index (2, 0, inv2Index); // Pins - EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Index), Qt::UserRole).toString ()), "IN"); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Index), Qt::DisplayRole).toString ()), "IN"); - EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Index), Qt::DisplayRole).toString ()), "$1"); - EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, inv2Index), Qt::DisplayRole).toString ()), "OUT"); - EXPECT_EQ (tl::to_string (model->data (model->index (3, 0, inv2Index), Qt::DisplayRole).toString ()), "$3"); - EXPECT_EQ (tl::to_string (model->data (model->index (4, 0, inv2Index), Qt::DisplayRole).toString ()), "$4"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::UserRole).toString ()), "IN|NIN"); + EXPECT_EQ (model->parent (model->index (0, 0, sn_pins)) == model->parent (model->index (0, 3, sn_pins)), true); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::DisplayRole).toString ()), "IN"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, sn_pins), Qt::DisplayRole).toString ()), "$1"); + EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, sn_pins), Qt::DisplayRole).toString ()), "OUT"); + EXPECT_EQ (tl::to_string (model->data (model->index (3, 0, sn_pins), Qt::DisplayRole).toString ()), "$3"); + EXPECT_EQ (tl::to_string (model->data (model->index (4, 0, sn_pins), Qt::DisplayRole).toString ()), "$4"); // Nets - EXPECT_EQ (tl::to_string (model->data (model->index (5, 0, inv2Index), Qt::UserRole).toString ()), "NIN"); - EXPECT_EQ (tl::to_string (model->data (model->index (5, 0, inv2Index), Qt::DisplayRole).toString ()), "NIN"); - EXPECT_EQ (tl::to_string (model->data (model->index (5, 2, inv2Index), Qt::DisplayRole).toString ()), "NIN (3)"); - EXPECT_EQ (tl::to_string (model->data (model->index (6, 0, inv2Index), Qt::DisplayRole).toString ()), "NOUT"); - EXPECT_EQ (tl::to_string (model->data (model->index (6, 2, inv2Index), Qt::DisplayRole).toString ()), "NOUT (3)"); - EXPECT_EQ (tl::to_string (model->data (model->index (7, 0, inv2Index), Qt::DisplayRole).toString ()), "$2"); - EXPECT_EQ (tl::to_string (model->data (model->index (7, 2, inv2Index), Qt::DisplayRole).toString ()), "$2 (5)"); - EXPECT_EQ (tl::to_string (model->data (model->index (8, 0, inv2Index), Qt::DisplayRole).toString ()), "$4"); - EXPECT_EQ (tl::to_string (model->data (model->index (8, 2, inv2Index), Qt::DisplayRole).toString ()), "$4 (3)"); - EXPECT_EQ (tl::to_string (model->data (model->index (9, 0, inv2Index), Qt::DisplayRole).toString ()), "$5"); - EXPECT_EQ (tl::to_string (model->data (model->index (9, 2, inv2Index), Qt::DisplayRole).toString ()), "$5 (3)"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_nets), Qt::UserRole).toString ()), "NIN"); + EXPECT_EQ (model->parent (model->index (0, 0, sn_nets)) == model->parent (model->index (0, 3, sn_nets)), true); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_nets), Qt::DisplayRole).toString ()), "NIN"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_nets), Qt::DisplayRole).toString ()), "NIN (3)"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, sn_nets), Qt::DisplayRole).toString ()), "NOUT"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, sn_nets), Qt::DisplayRole).toString ()), "NOUT (3)"); + EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, sn_nets), Qt::DisplayRole).toString ()), "$2"); + EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, sn_nets), Qt::DisplayRole).toString ()), "$2 (5)"); + EXPECT_EQ (tl::to_string (model->data (model->index (3, 0, sn_nets), Qt::DisplayRole).toString ()), "$4"); + EXPECT_EQ (tl::to_string (model->data (model->index (3, 2, sn_nets), Qt::DisplayRole).toString ()), "$4 (3)"); + EXPECT_EQ (tl::to_string (model->data (model->index (4, 0, sn_nets), Qt::DisplayRole).toString ()), "$5"); + EXPECT_EQ (tl::to_string (model->data (model->index (4, 2, sn_nets), Qt::DisplayRole).toString ()), "$5 (3)"); // No Subcircuits // Devices - EXPECT_EQ (tl::to_string (model->data (model->index (10, 0, inv2Index), Qt::UserRole).toString ()), "$1|PMOS"); - EXPECT_EQ (tl::to_string (model->data (model->index (10, 0, inv2Index), Qt::DisplayRole).toString ()), "PMOS [L=0.25, W=0.95, AS=0.49875, AD=0.26125, PS=2.95, PD=1.5]"); - EXPECT_EQ (tl::to_string (model->data (model->index (10, 2, inv2Index), Qt::DisplayRole).toString ()), "$1"); - EXPECT_EQ (tl::to_string (model->data (model->index (11, 0, inv2Index), Qt::DisplayRole).toString ()), "PMOS [L=0.25, W=0.95, AS=0.26125, AD=0.49875, PS=1.5, PD=2.95]"); - EXPECT_EQ (tl::to_string (model->data (model->index (11, 2, inv2Index), Qt::DisplayRole).toString ()), "$2"); - EXPECT_EQ (tl::to_string (model->data (model->index (12, 0, inv2Index), Qt::DisplayRole).toString ()), "NMOS [L=0.25, W=0.95, AS=0.49875, AD=0.26125, PS=2.95, PD=1.5]"); - EXPECT_EQ (tl::to_string (model->data (model->index (12, 2, inv2Index), Qt::DisplayRole).toString ()), "$3"); - EXPECT_EQ (tl::to_string (model->data (model->index (13, 0, inv2Index), Qt::DisplayRole).toString ()), "NMOS [L=0.25, W=0.95, AS=0.26125, AD=0.49875, PS=1.5, PD=2.95]"); - EXPECT_EQ (tl::to_string (model->data (model->index (13, 2, inv2Index), Qt::DisplayRole).toString ()), "$4"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_devices), Qt::UserRole).toString ()), "$1|PMOS"); + EXPECT_EQ (model->parent (model->index (0, 0, sn_devices)) == model->parent (model->index (0, 3, sn_devices)), true); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_devices), Qt::DisplayRole).toString ()), "PMOS [L=0.25, W=0.95, AS=0.49875, AD=0.26125, PS=2.95, PD=1.5]"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_devices), Qt::DisplayRole).toString ()), "$1"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, sn_devices), Qt::DisplayRole).toString ()), "PMOS [L=0.25, W=0.95, AS=0.26125, AD=0.49875, PS=1.5, PD=2.95]"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, sn_devices), Qt::DisplayRole).toString ()), "$2"); + EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, sn_devices), Qt::DisplayRole).toString ()), "NMOS [L=0.25, W=0.95, AS=0.49875, AD=0.26125, PS=2.95, PD=1.5]"); + EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, sn_devices), Qt::DisplayRole).toString ()), "$3"); + EXPECT_EQ (tl::to_string (model->data (model->index (3, 0, sn_devices), Qt::DisplayRole).toString ()), "NMOS [L=0.25, W=0.95, AS=0.26125, AD=0.49875, PS=1.5, PD=2.95]"); + EXPECT_EQ (tl::to_string (model->data (model->index (3, 2, sn_devices), Qt::DisplayRole).toString ()), "$4"); EXPECT_EQ (model->hasChildren (ringoIndex), true); // 0 pins, 12 nets, 10 subcircuits, 0 devices - EXPECT_EQ (model->rowCount (ringoIndex), 22); + EXPECT_EQ (model->rowCount (ringoIndex), 2); + sn_nets = model->index (0, 0, ringoIndex); + QModelIndex sn_subcircuits = model->index (1, 0, ringoIndex); // Pins // Nets - EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoIndex), Qt::UserRole).toString ()), "FB"); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, ringoIndex), Qt::DisplayRole).toString ()), "FB (2)"); - EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, ringoIndex), Qt::DisplayRole).toString ()), "VDD (10)"); - EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, ringoIndex), Qt::DisplayRole).toString ()), "VSS (10)"); - EXPECT_EQ (tl::to_string (model->data (model->index (3, 2, ringoIndex), Qt::DisplayRole).toString ()), "$4 (2)"); - EXPECT_EQ (tl::to_string (model->data (model->index (4, 2, ringoIndex), Qt::DisplayRole).toString ()), "$5 (2)"); - EXPECT_EQ (tl::to_string (model->data (model->index (5, 2, ringoIndex), Qt::DisplayRole).toString ()), "$6 (2)"); - EXPECT_EQ (tl::to_string (model->data (model->index (6, 2, ringoIndex), Qt::DisplayRole).toString ()), "$7 (2)"); - EXPECT_EQ (tl::to_string (model->data (model->index (7, 2, ringoIndex), Qt::DisplayRole).toString ()), "$8 (2)"); - EXPECT_EQ (tl::to_string (model->data (model->index (8, 2, ringoIndex), Qt::DisplayRole).toString ()), "$9 (2)"); - EXPECT_EQ (tl::to_string (model->data (model->index (9, 2, ringoIndex), Qt::DisplayRole).toString ()), "$10 (2)"); - EXPECT_EQ (tl::to_string (model->data (model->index (10, 2, ringoIndex), Qt::DisplayRole).toString ()), "$11 (2)"); - EXPECT_EQ (tl::to_string (model->data (model->index (11, 2, ringoIndex), Qt::DisplayRole).toString ()), "$12 (2)"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_nets), Qt::UserRole).toString ()), "FB"); + EXPECT_EQ (model->parent (model->index (0, 0, sn_nets)) == model->parent (model->index (0, 3, sn_nets)), true); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_nets), Qt::DisplayRole).toString ()), "FB (2)"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, sn_nets), Qt::DisplayRole).toString ()), "VDD (10)"); + EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, sn_nets), Qt::DisplayRole).toString ()), "VSS (10)"); + EXPECT_EQ (tl::to_string (model->data (model->index (3, 2, sn_nets), Qt::DisplayRole).toString ()), "$4 (2)"); + EXPECT_EQ (tl::to_string (model->data (model->index (4, 2, sn_nets), Qt::DisplayRole).toString ()), "$5 (2)"); + EXPECT_EQ (tl::to_string (model->data (model->index (5, 2, sn_nets), Qt::DisplayRole).toString ()), "$6 (2)"); + EXPECT_EQ (tl::to_string (model->data (model->index (6, 2, sn_nets), Qt::DisplayRole).toString ()), "$7 (2)"); + EXPECT_EQ (tl::to_string (model->data (model->index (7, 2, sn_nets), Qt::DisplayRole).toString ()), "$8 (2)"); + EXPECT_EQ (tl::to_string (model->data (model->index (8, 2, sn_nets), Qt::DisplayRole).toString ()), "$9 (2)"); + EXPECT_EQ (tl::to_string (model->data (model->index (9, 2, sn_nets), Qt::DisplayRole).toString ()), "$10 (2)"); + EXPECT_EQ (tl::to_string (model->data (model->index (10, 2, sn_nets), Qt::DisplayRole).toString ()), "$11 (2)"); + EXPECT_EQ (tl::to_string (model->data (model->index (11, 2, sn_nets), Qt::DisplayRole).toString ()), "$12 (2)"); // Subcircuits - EXPECT_EQ (tl::to_string (model->data (model->index (12, 0, ringoIndex), Qt::UserRole).toString ()), "INV2|$1"); - EXPECT_EQ (tl::to_string (model->data (model->index (12, 0, ringoIndex), Qt::DisplayRole).toString ()), "INV2"); - EXPECT_EQ (tl::to_string (model->data (model->index (12, 2, ringoIndex), Qt::DisplayRole).toString ()), "$1"); - EXPECT_EQ (tl::to_string (model->data (model->index (21, 0, ringoIndex), Qt::DisplayRole).toString ()), "INV2"); - EXPECT_EQ (tl::to_string (model->data (model->index (21, 2, ringoIndex), Qt::DisplayRole).toString ()), "$10"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_subcircuits), Qt::UserRole).toString ()), "INV2|$1"); + EXPECT_EQ (model->parent (model->index (0, 0, sn_subcircuits)) == model->parent (model->index (0, 3, sn_subcircuits)), true); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_subcircuits), Qt::DisplayRole).toString ()), "INV2"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_subcircuits), Qt::DisplayRole).toString ()), "$1"); + EXPECT_EQ (tl::to_string (model->data (model->index (9, 0, sn_subcircuits), Qt::DisplayRole).toString ()), "INV2"); + EXPECT_EQ (tl::to_string (model->data (model->index (9, 2, sn_subcircuits), Qt::DisplayRole).toString ()), "$10"); // Devices - // OUT pin of INV2 has a single child node which is the "NOUT" net - QModelIndex inv2PinOutIndex = model->index (2, 0, inv2Index); - EXPECT_EQ (model->parent (inv2PinOutIndex) == inv2Index, true); + // OUT pin of INV2 is identical with the "NOUT" net + QModelIndex inv2PinOutIndex = model->index (2, 0, model->index (0, 0, inv2Index)); + EXPECT_EQ (model->parent (inv2PinOutIndex) == model->index (0, 0, inv2Index), true); EXPECT_EQ (model->hasChildren (inv2PinOutIndex), true); - EXPECT_EQ (model->rowCount (inv2PinOutIndex), 1); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PinOutIndex), Qt::DisplayRole).toString ()), "NOUT"); - - QModelIndex inv2PinOutIndexNet = model->index (0, 0, inv2PinOutIndex); - EXPECT_EQ (model->parent (inv2PinOutIndexNet) == inv2PinOutIndex, true); - EXPECT_EQ (model->hasChildren (inv2PinOutIndexNet), false); - EXPECT_EQ (model->rowCount (inv2PinOutIndexNet), 0); + EXPECT_EQ (model->rowCount (inv2PinOutIndex), 3); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PinOutIndex), Qt::DisplayRole).toString ()), "D / PMOS [L=0.25, W=0.95, AS=0.26125, AD=0.49875, PS=1.5, PD=2.95]"); // NOUT net has 1 pin, 2 devices, 0 subcircuits - QModelIndex inv2NOutIndex = model->index (6, 0, inv2Index); - EXPECT_EQ (model->parent (inv2NOutIndex) == inv2Index, true); + QModelIndex inv2NOutIndex = model->index (1, 0, model->index (1, 0, inv2Index)); + EXPECT_EQ (model->parent (inv2NOutIndex) == model->index (1, 0, inv2Index), true); EXPECT_EQ (model->hasChildren (inv2NOutIndex), true); EXPECT_EQ (model->rowCount (inv2NOutIndex), 3); EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2NOutIndex), Qt::UserRole).toString ()), "D|PMOS|$2"); + EXPECT_EQ (model->parent (model->index (0, 0, inv2NOutIndex)) == model->parent (model->index (0, 3, inv2NOutIndex)), true); EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2NOutIndex), Qt::DisplayRole).toString ()), "D / PMOS [L=0.25, W=0.95, AS=0.26125, AD=0.49875, PS=1.5, PD=2.95]"); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2NOutIndex), Qt::DisplayRole).toString ()), "$2"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2NOutIndex), Qt::DisplayRole).toString ()), "$2"); EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2NOutIndex), Qt::DisplayRole).toString ()), "D / NMOS [L=0.25, W=0.95, AS=0.26125, AD=0.49875, PS=1.5, PD=2.95]"); - EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2NOutIndex), Qt::DisplayRole).toString ()), "$4"); - EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, inv2NOutIndex), Qt::DisplayRole).toString ()), "OUT"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2NOutIndex), Qt::DisplayRole).toString ()), "$4"); + EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, inv2NOutIndex), Qt::DisplayRole).toString ()), "OUT"); EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, inv2NOutIndex), Qt::DisplayRole).toString ()), ""); + EXPECT_EQ (model->parent (model->index (2, 0, inv2NOutIndex)) == model->parent (model->index (2, 3, inv2NOutIndex)), true); // no children for pins on nets QModelIndex inv2NOutPinOutIndex = model->index (2, 0, inv2NOutIndex); @@ -137,6 +145,9 @@ TEST (1) // a MOS3 transistor has three other terminals QModelIndex inv2NOutDeviceIndex = model->index (0, 0, inv2NOutIndex); + QModelIndex b = model->index (0, 0, inv2NOutIndex); + EXPECT_EQ (b.parent () == inv2NOutDeviceIndex.parent (), true); + EXPECT_EQ (b.model () == inv2NOutDeviceIndex.model (), true); EXPECT_EQ (model->parent (inv2NOutDeviceIndex) == inv2NOutIndex, true); EXPECT_EQ (model->hasChildren (inv2NOutDeviceIndex), true); EXPECT_EQ (model->rowCount (inv2NOutDeviceIndex), 3); @@ -144,67 +155,76 @@ TEST (1) EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2NOutDeviceIndex), Qt::UserRole).toString ()), "S|$5"); EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2NOutDeviceIndex), Qt::DisplayRole).toString ()), "S"); EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2NOutDeviceIndex), Qt::DisplayRole).toString ()), "G"); - EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, inv2NOutDeviceIndex), Qt::DisplayRole).toString ()), "D"); + EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, inv2NOutDeviceIndex), Qt::DisplayRole).toString ()), "D (already seen)"); QModelIndex inv2NOutDeviceGateIndex = model->index (1, 0, inv2NOutDeviceIndex); EXPECT_EQ (model->parent (inv2NOutDeviceGateIndex) == inv2NOutDeviceIndex, true); - EXPECT_EQ (model->hasChildren (inv2NOutDeviceGateIndex), false); - EXPECT_EQ (model->rowCount (inv2NOutDeviceGateIndex), 0); + EXPECT_EQ (model->hasChildren (inv2NOutDeviceGateIndex), true); + EXPECT_EQ (model->rowCount (inv2NOutDeviceGateIndex), 5); // FB net has 0 pin, 0 devices, 2 subcircuits - QModelIndex ringoFbIndex = model->index (0, 0, ringoIndex); - EXPECT_EQ (model->parent (ringoFbIndex) == ringoIndex, true); + QModelIndex ringoFbIndex = model->index (0, 0, sn_nets); + EXPECT_EQ (model->parent (ringoFbIndex) == sn_nets, true); EXPECT_EQ (model->hasChildren (ringoFbIndex), true); EXPECT_EQ (model->rowCount (ringoFbIndex), 2); EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoFbIndex), Qt::UserRole).toString ()), "IN|INV2|$2"); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoFbIndex), Qt::DisplayRole).toString ()), "IN / INV2"); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, ringoFbIndex), Qt::DisplayRole).toString ()), "$2"); - EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, ringoFbIndex), Qt::DisplayRole).toString ()), "$1 / INV2"); - EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, ringoFbIndex), Qt::DisplayRole).toString ()), "$1"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoFbIndex), Qt::DisplayRole).toString ()), "IN / INV2"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, ringoFbIndex), Qt::DisplayRole).toString ()), "$2"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, ringoFbIndex), Qt::DisplayRole).toString ()), "$1 / INV2"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, ringoFbIndex), Qt::DisplayRole).toString ()), "$1"); QModelIndex ringoFbSubcircuit2Index = model->index (0, 0, ringoFbIndex); EXPECT_EQ (model->parent (ringoFbSubcircuit2Index) == ringoFbIndex, true); EXPECT_EQ (model->hasChildren (ringoFbSubcircuit2Index), true); - EXPECT_EQ (model->rowCount (ringoFbSubcircuit2Index), 5); + EXPECT_EQ (model->rowCount (ringoFbSubcircuit2Index), 1); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoFbSubcircuit2Index), Qt::UserRole).toString ()), "IN|NIN"); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "IN"); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "FB"); - EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "$1"); - EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), ""); - EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "OUT"); - EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "$4"); - EXPECT_EQ (tl::to_string (model->data (model->index (3, 0, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "$3"); - EXPECT_EQ (tl::to_string (model->data (model->index (3, 2, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "VSS"); - EXPECT_EQ (tl::to_string (model->data (model->index (4, 0, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "$4"); - EXPECT_EQ (tl::to_string (model->data (model->index (4, 2, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "VDD"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoFbSubcircuit2Index), Qt::UserRole).toString ()), "NIN"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "NIN"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "NIN (3)"); - QModelIndex ringoFbSubcircuit2InPinIndex = model->index (1, 0, ringoFbSubcircuit2Index); - EXPECT_EQ (model->parent (ringoFbSubcircuit2InPinIndex) == ringoFbSubcircuit2Index, true); - EXPECT_EQ (model->hasChildren (ringoFbSubcircuit2InPinIndex), false); - EXPECT_EQ (model->rowCount (ringoFbSubcircuit2InPinIndex), 0); + QModelIndex ringoFbSubcircuit2InsideNetIndex = model->index (0, 0, ringoFbSubcircuit2Index); + EXPECT_EQ (model->parent (ringoFbSubcircuit2InsideNetIndex) == ringoFbSubcircuit2Index, true); + EXPECT_EQ (model->hasChildren (ringoFbSubcircuit2InsideNetIndex), true); + EXPECT_EQ (model->rowCount (ringoFbSubcircuit2InsideNetIndex), 3); // Subcircuit 1 of RINGO has 5 pins - QModelIndex ringoSubcircuit1Index = model->index (12, 0, ringoIndex); - EXPECT_EQ (model->parent (ringoSubcircuit1Index) == ringoIndex, true); + QModelIndex ringoSubcircuit1Index = model->index (0, 0, sn_subcircuits); + EXPECT_EQ (model->parent (ringoSubcircuit1Index) == sn_subcircuits, true); EXPECT_EQ (model->hasChildren (ringoSubcircuit1Index), true); - EXPECT_EQ (model->rowCount (ringoSubcircuit1Index), 5); + EXPECT_EQ (model->rowCount (ringoSubcircuit1Index), 2); - EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoSubcircuit1Index), Qt::UserRole).toString ()), "OUT"); - EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoSubcircuit1Index), Qt::DisplayRole).toString ()), "OUT"); - EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, ringoSubcircuit1Index), Qt::DisplayRole).toString ()), ""); + QModelIndex ringoSubcircuit1PinsIndex = model->index (0, 0, ringoSubcircuit1Index); + EXPECT_EQ (model->rowCount (ringoSubcircuit1PinsIndex), 5); - QModelIndex ringoSubcircuit1OutPinIndex = model->index (2, 0, ringoSubcircuit1Index); - EXPECT_EQ (model->parent (ringoSubcircuit1OutPinIndex) == ringoSubcircuit1Index, true); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoSubcircuit1PinsIndex), Qt::UserRole).toString ()), "IN|$5"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, ringoSubcircuit1PinsIndex), Qt::UserRole).toString ()), "FB"); + EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoSubcircuit1PinsIndex), Qt::UserRole).toString ()), "OUT"); + EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoSubcircuit1PinsIndex), Qt::DisplayRole).toString ()), "OUT"); + EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, ringoSubcircuit1PinsIndex), Qt::DisplayRole).toString ()), ""); + + QModelIndex ringoSubcircuit1NodeIndex = model->index (1, 0, ringoSubcircuit1Index); + EXPECT_EQ (model->rowCount (ringoSubcircuit1NodeIndex), 3); + + QModelIndex ringoSubcircuit1InsidePinsIndex = model->index (0, 0, ringoSubcircuit1NodeIndex); + EXPECT_EQ (model->rowCount (ringoSubcircuit1InsidePinsIndex), 5); + + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoSubcircuit1InsidePinsIndex), Qt::UserRole).toString ()), "IN|NIN"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, ringoSubcircuit1InsidePinsIndex), Qt::UserRole).toString ()), "$1|$2"); + EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoSubcircuit1InsidePinsIndex), Qt::UserRole).toString ()), "OUT|NOUT"); + EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoSubcircuit1InsidePinsIndex), Qt::DisplayRole).toString ()), "OUT"); + EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, ringoSubcircuit1InsidePinsIndex), Qt::DisplayRole).toString ()), "NOUT (3)"); + + QModelIndex ringoSubcircuit1OutPinIndex = model->index (2, 0, ringoSubcircuit1PinsIndex); + EXPECT_EQ (model->parent (ringoSubcircuit1OutPinIndex) == ringoSubcircuit1PinsIndex, true); EXPECT_EQ (model->hasChildren (ringoSubcircuit1OutPinIndex), false); EXPECT_EQ (model->rowCount (ringoSubcircuit1OutPinIndex), 0); - // Device 1 of INV2 has 3 pins + // Device 1 of INV2 has 3 terminals - QModelIndex inv2Device1Index = model->index (10, 0, inv2Index); - EXPECT_EQ (model->parent (inv2Device1Index) == inv2Index, true); + QModelIndex inv2Device1Index = model->index (0, 0, sn_devices); + EXPECT_EQ (model->parent (inv2Device1Index) == sn_devices, true); EXPECT_EQ (model->hasChildren (inv2Device1Index), true); EXPECT_EQ (model->rowCount (inv2Device1Index), 3); @@ -213,8 +233,11 @@ TEST (1) QModelIndex inv2Device1GateIndex = model->index (1, 0, inv2Device1Index); EXPECT_EQ (model->parent (inv2Device1GateIndex) == inv2Device1Index, true); - EXPECT_EQ (model->hasChildren (inv2Device1GateIndex), false); - EXPECT_EQ (model->rowCount (inv2Device1GateIndex), 0); + EXPECT_EQ (model->hasChildren (inv2Device1GateIndex), true); + EXPECT_EQ (model->rowCount (inv2Device1GateIndex), 3); + + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Device1GateIndex), Qt::UserRole).toString ()), "G|PMOS|$1"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Device1GateIndex), Qt::DisplayRole).toString ()), "G / PMOS [L=0.25, W=0.95, AS=0.49875, AD=0.26125, PS=2.95, PD=1.5] (already seen)"); } TEST (2) @@ -228,6 +251,7 @@ TEST (2) EXPECT_EQ (model->hasChildren (QModelIndex ()), true); // two circuits EXPECT_EQ (model->rowCount (QModelIndex ()), 4); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, QModelIndex ()), Qt::UserRole).toString ()), "INV2PAIRX"); EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, QModelIndex ()), Qt::DisplayRole).toString ()), "- ⇔ INV2PAIRX"); EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, QModelIndex ()), Qt::DisplayRole).toString ()), ""); @@ -245,26 +269,33 @@ TEST (2) // INV2 circuit node EXPECT_EQ (model->hasChildren (inv2Index), true); - EXPECT_EQ (model->rowCount (inv2Index), 14); + EXPECT_EQ (model->rowCount (inv2Index), 3); EXPECT_EQ (model->parent (inv2Index).isValid (), false); + QModelIndex sn_pins = model->index (0, 0, inv2Index); + QModelIndex sn_nets = model->index (1, 0, inv2Index); + QModelIndex sn_devices = model->index (2, 0, inv2Index); + EXPECT_EQ (model->rowCount (sn_pins), 6); + EXPECT_EQ (model->rowCount (sn_nets), 6); + EXPECT_EQ (model->rowCount (sn_devices), 2); + // first of pins in INV2 circuit - EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Index), Qt::UserRole).toString ()), "$0|$0"); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Index), Qt::DisplayRole).toString ()), "$0"); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2Index), Qt::DisplayRole).toString ()), "$0"); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2Index), Qt::DisplayRole).toString ()), "$0"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::UserRole).toString ()), "$0|$0|$1|1"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::DisplayRole).toString ()), "$0"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_pins), Qt::DisplayRole).toString ()), "$1 (2)"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, sn_pins), Qt::DisplayRole).toString ()), "1 (2)"); // INV2, pin 0 node - QModelIndex inv2Pin0Index = model->index (0, 0, inv2Index); + QModelIndex inv2Pin0Index = model->index (0, 0, sn_pins); EXPECT_EQ (model->hasChildren (inv2Pin0Index), true); - EXPECT_EQ (model->rowCount (inv2Pin0Index), 1); - EXPECT_EQ (model->parent (inv2Pin0Index) == inv2Index, true); + EXPECT_EQ (model->rowCount (inv2Pin0Index), 2); + EXPECT_EQ (model->parent (inv2Pin0Index) == sn_pins, true); // INV2, pin 0 has one net node - EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Pin0Index), Qt::UserRole).toString ()), "$1|1"); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Pin0Index), Qt::DisplayRole).toString ()), "$1 ⇔ 1"); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2Pin0Index), Qt::DisplayRole).toString ()), "$1"); - std::pair nets = model->net_from_index (model->index_from_id ((void *) 9, 0)); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::UserRole).toString ()), "$0|$0|$1|1"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::DisplayRole).toString ()), "$0"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_pins), Qt::DisplayRole).toString ()), "$1 (2)"); + std::pair nets = model->net_from_index (model->index (0, 0, sn_pins)); EXPECT_EQ (nets.first != 0, true); if (nets.first != 0) { EXPECT_EQ (nets.first->expanded_name (), "$1"); @@ -273,25 +304,25 @@ TEST (2) if (nets.second != 0) { EXPECT_EQ (nets.second->expanded_name (), "1"); } - EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2Pin0Index), Qt::DisplayRole).toString ()), "1"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, sn_pins), Qt::DisplayRole).toString ()), "1 (2)"); // first of nets in INV2 circuit - EXPECT_EQ (tl::to_string (model->data (model->index (6, 0, inv2Index), Qt::UserRole).toString ()), "$1|1"); - EXPECT_EQ (tl::to_string (model->data (model->index (6, 0, inv2Index), Qt::DisplayRole).toString ()), "$1 ⇔ 1"); - EXPECT_EQ (tl::to_string (model->data (model->index (6, 2, inv2Index), Qt::DisplayRole).toString ()), "$1 (2)"); - EXPECT_EQ (tl::to_string (model->data (model->index (6, 3, inv2Index), Qt::DisplayRole).toString ()), "1 (2)"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_nets), Qt::UserRole).toString ()), "$1|1"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_nets), Qt::DisplayRole).toString ()), "$1 ⇔ 1"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_nets), Qt::DisplayRole).toString ()), "$1 (2)"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, sn_nets), Qt::DisplayRole).toString ()), "1 (2)"); // INV2, net 1 node - QModelIndex inv2Net0Index = model->index (6, 0, inv2Index); + QModelIndex inv2Net0Index = model->index (0, 0, sn_nets); EXPECT_EQ (model->hasChildren (inv2Net0Index), true); EXPECT_EQ (model->rowCount (inv2Net0Index), 2); - EXPECT_EQ (model->parent (inv2Net0Index) == inv2Index, true); + EXPECT_EQ (model->parent (inv2Net0Index) == sn_nets, true); // INV2, net 1 has one pin and one terminal at BULK EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Net0Index), Qt::UserRole).toString ()), "B|B|PMOS|PMOS|$1|$1"); EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Net0Index), Qt::DisplayRole).toString ()), "B / PMOS [L=0.25, W=3.5]"); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2Net0Index), Qt::DisplayRole).toString ()), "$1"); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2Net0Index), Qt::DisplayRole).toString ()), "$1"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2Net0Index), Qt::DisplayRole).toString ()), "$1"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2Net0Index), Qt::DisplayRole).toString ()), "$1"); // This terminal connects to a device with four other terminals .. QModelIndex inv2Net0TerminalIndex = model->index (0, 0, inv2Net0Index); @@ -301,14 +332,14 @@ TEST (2) // .. whose second terminal is gate EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Net0TerminalIndex), Qt::UserRole).toString ()), "G|G|IN|2"); EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Net0TerminalIndex), Qt::DisplayRole).toString ()), "G"); - EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2Net0TerminalIndex), Qt::DisplayRole).toString ()), "IN"); - EXPECT_EQ (tl::to_string (model->data (model->index (1, 3, inv2Net0TerminalIndex), Qt::DisplayRole).toString ()), "2"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2Net0TerminalIndex), Qt::DisplayRole).toString ()), "IN (3)"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 3, inv2Net0TerminalIndex), Qt::DisplayRole).toString ()), "2 (3)"); // The Pin EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Net0Index), Qt::UserRole).toString ()), ""); EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Net0Index), Qt::DisplayRole).toString ()), ""); - EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2Net0Index), Qt::DisplayRole).toString ()), "$0"); - EXPECT_EQ (tl::to_string (model->data (model->index (1, 3, inv2Net0Index), Qt::DisplayRole).toString ()), "$0"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2Net0Index), Qt::DisplayRole).toString ()), "$0"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 3, inv2Net0Index), Qt::DisplayRole).toString ()), "$0"); // This pin does not have children QModelIndex inv2Net0PinIndex = model->index (1, 0, inv2Net0Index); @@ -317,59 +348,49 @@ TEST (2) EXPECT_EQ (model->parent (inv2Net0PinIndex) == inv2Net0Index, true); // second of nets in INV2 circuit - EXPECT_EQ (tl::to_string (model->data (model->index (7, 0, inv2Index), Qt::UserRole).toString ()), "BULK|6"); - EXPECT_EQ (tl::to_string (model->data (model->index (7, 0, inv2Index), Qt::DisplayRole).toString ()), "BULK ⇔ 6"); - EXPECT_EQ (tl::to_string (model->data (model->index (7, 2, inv2Index), Qt::DisplayRole).toString ()), "BULK (2)"); - EXPECT_EQ (tl::to_string (model->data (model->index (7, 3, inv2Index), Qt::DisplayRole).toString ()), "6 (2)"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, sn_nets), Qt::UserRole).toString ()), "BULK|6"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, sn_nets), Qt::DisplayRole).toString ()), "BULK ⇔ 6"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, sn_nets), Qt::DisplayRole).toString ()), "BULK (2)"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 3, sn_nets), Qt::DisplayRole).toString ()), "6 (2)"); // first of devices in INV2 circuit - EXPECT_EQ (tl::to_string (model->data (model->index (12, 0, inv2Index), Qt::UserRole).toString ()), "$1|$1|PMOS|PMOS"); - EXPECT_EQ (tl::to_string (model->data (model->index (12, 0, inv2Index), Qt::DisplayRole).toString ()), "PMOS"); - EXPECT_EQ (tl::to_string (model->data (model->index (12, 2, inv2Index), Qt::DisplayRole).toString ()), "$1 / PMOS [L=0.25, W=3.5]"); - EXPECT_EQ (tl::to_string (model->data (model->index (12, 3, inv2Index), Qt::DisplayRole).toString ()), "$1 / PMOS [L=0.25, W=3.5]"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_devices), Qt::UserRole).toString ()), "$1|$1|PMOS|PMOS"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_devices), Qt::DisplayRole).toString ()), "PMOS"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_devices), Qt::DisplayRole).toString ()), "$1 / PMOS [L=0.25, W=3.5]"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, sn_devices), Qt::DisplayRole).toString ()), "$1 / PMOS [L=0.25, W=3.5]"); QModelIndex inv2PairIndex = model->index (2, 0, QModelIndex ()); EXPECT_EQ (model->parent (inv2PairIndex).isValid (), false); // INV2PAIR circuit node EXPECT_EQ (model->hasChildren (inv2PairIndex), true); - EXPECT_EQ (model->rowCount (inv2PairIndex), 18); + EXPECT_EQ (model->rowCount (inv2PairIndex), 3); + + sn_pins = model->index (0, 0, inv2PairIndex); + sn_nets = model->index (1, 0, inv2PairIndex); // first of pins in INV2 circuit - EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairIndex), Qt::UserRole).toString ()), "$4"); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairIndex), Qt::DisplayRole).toString ()), "- ⇔ $4"); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2PairIndex), Qt::DisplayRole).toString ()), ""); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2PairIndex), Qt::DisplayRole).toString ()), "$4"); - - // INV2, pin 0 node - QModelIndex inv2PairPin0Index = model->index (0, 0, inv2PairIndex); - EXPECT_EQ (model->hasChildren (inv2PairPin0Index), true); - EXPECT_EQ (model->rowCount (inv2PairPin0Index), 1); - EXPECT_EQ (model->parent (inv2PairPin0Index) == inv2PairIndex, true); - - // INV2, pin 0 has one net node - // The pin isnt't connected to any net, left side because there is no match, right side because the pin isn't connected - EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairPin0Index), Qt::UserRole).toString ()), ""); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairPin0Index), Qt::DisplayRole).toString ()), "-"); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2PairPin0Index), Qt::DisplayRole).toString ()), ""); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2PairPin0Index), Qt::DisplayRole).toString ()), ""); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::UserRole).toString ()), "$4"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::DisplayRole).toString ()), "- ⇔ $4"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_pins), Qt::DisplayRole).toString ()), ""); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, sn_pins), Qt::DisplayRole).toString ()), ""); // first of nets in INV2 circuit - EXPECT_EQ (tl::to_string (model->data (model->index (8, 0, inv2PairIndex), Qt::UserRole).toString ()), "$4"); - EXPECT_EQ (tl::to_string (model->data (model->index (8, 0, inv2PairIndex), Qt::DisplayRole).toString ()), "$4 ⇔ -"); - EXPECT_EQ (tl::to_string (model->data (model->index (8, 2, inv2PairIndex), Qt::DisplayRole).toString ()), "$4 (3)"); - EXPECT_EQ (tl::to_string (model->data (model->index (8, 3, inv2PairIndex), Qt::DisplayRole).toString ()), ""); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_nets), Qt::UserRole).toString ()), "$4"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_nets), Qt::DisplayRole).toString ()), "$4 ⇔ -"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_nets), Qt::DisplayRole).toString ()), "$4 (3)"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, sn_nets), Qt::DisplayRole).toString ()), ""); // This net has only left side which has one pin and two subcircuits - QModelIndex inv2PairNet0Index = model->index (8, 0, inv2PairIndex); + QModelIndex inv2PairNet0Index = model->index (0, 0, sn_nets); EXPECT_EQ (model->hasChildren (inv2PairNet0Index), true); EXPECT_EQ (model->rowCount (inv2PairNet0Index), 3); - EXPECT_EQ (model->parent (inv2PairNet0Index) == inv2PairIndex, true); + EXPECT_EQ (model->parent (inv2PairNet0Index) == sn_nets, true); // The pin EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairNet0Index), Qt::UserRole).toString ()), ""); EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairNet0Index), Qt::DisplayRole).toString ()), ""); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2PairNet0Index), Qt::DisplayRole).toString ()), "$3"); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2PairNet0Index), Qt::DisplayRole).toString ()), "$3"); EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2PairNet0Index), Qt::DisplayRole).toString ()), ""); // This pin does not have children @@ -380,18 +401,179 @@ TEST (2) // The first subcircuit EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2PairNet0Index), Qt::UserRole).toString ()), "OUT|INV2|$1"); - EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2PairNet0Index), Qt::DisplayRole).toString ()), "OUT ⇔ - / INV2 ⇔ -"); - EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2PairNet0Index), Qt::DisplayRole).toString ()), "$1"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2PairNet0Index), Qt::DisplayRole).toString ()), "OUT ⇔ - / INV2 ⇔ -"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2PairNet0Index), Qt::DisplayRole).toString ()), "$1"); EXPECT_EQ (tl::to_string (model->data (model->index (1, 3, inv2PairNet0Index), Qt::DisplayRole).toString ()), ""); - - // This subcircuit has 6 other pins - QModelIndex inv2PairNet0SubCircuit0Index = model->index (1, 0, inv2PairNet0Index); - EXPECT_EQ (model->hasChildren (inv2PairNet0SubCircuit0Index), true); - EXPECT_EQ (model->rowCount (inv2PairNet0SubCircuit0Index), 6); - EXPECT_EQ (model->parent (inv2PairNet0SubCircuit0Index) == inv2PairNet0Index, true); - - EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairNet0SubCircuit0Index), Qt::UserRole).toString ()), "$1"); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairNet0SubCircuit0Index), Qt::DisplayRole).toString ()), "$0"); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2PairNet0SubCircuit0Index), Qt::DisplayRole).toString ()), "$7"); - EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2PairNet0SubCircuit0Index), Qt::DisplayRole).toString ()), ""); +} + +TEST (3) +{ + db::LayoutToNetlist l2n; + l2n.load (tl::testsrc () + "/testdata/lay/l2n_browser.l2n"); + + lay::NetColorizer colorizer; + std::auto_ptr model (new lay::NetlistBrowserModel (0, &l2n, &colorizer)); + + db::Circuit *root = l2n.netlist ()->circuit_by_name ("RINGO"); + EXPECT_EQ (root != 0, true); + + lay::NetlistObjectsPath path; + EXPECT_EQ (model->index_from_path (path).isValid (), false); + + path.root.first = root; + + db::Net *net = root->net_by_name ("FB"); + EXPECT_EQ (net != 0, true); + + path.net.first = net; + + QModelIndex index = model->index_from_path (path); + EXPECT_EQ (index.isValid (), true); + + EXPECT_EQ (tl::to_string (model->data (index, Qt::UserRole).toString ()), "FB"); +} + +TEST (4) +{ + db::LayoutToNetlist l2n; + l2n.load (tl::testsrc () + "/testdata/lay/l2n_browser.l2n"); + + lay::NetColorizer colorizer; + std::auto_ptr model (new lay::NetlistBrowserModel (0, &l2n, &colorizer)); + + db::Circuit *root = l2n.netlist ()->circuit_by_name ("RINGO"); + EXPECT_EQ (root != 0, true); + + lay::NetlistObjectsPath path; + path.root.first = root; + + db::SubCircuit *sc1 = root->begin_subcircuits ().operator-> (); + EXPECT_EQ (sc1 != 0, true); + path.path.push_back (std::make_pair (sc1, (db::SubCircuit *) 0)); + + db::Net *net = sc1->circuit_ref ()->net_by_name ("NOUT"); + EXPECT_EQ (net != 0, true); + + path.net.first = net; + + 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); } diff --git a/src/pya/pya/pyaMarshal.cc b/src/pya/pya/pyaMarshal.cc index 029970e34..0cf4736b8 100644 --- a/src/pya/pya/pyaMarshal.cc +++ b/src/pya/pya/pyaMarshal.cc @@ -935,6 +935,12 @@ struct test_arg_func { void operator() (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose) { + if ((atype.is_cptr () || atype.is_ptr ()) && arg == Py_None) { + // for ptr or cptr, null is an allowed value + *ret = true; + return; + } + if (! PyTuple_Check (arg) && ! PyList_Check (arg)) { *ret = false; return; @@ -971,6 +977,12 @@ struct test_arg_func { void operator () (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose) { + if ((atype.is_cptr () || atype.is_ptr ()) && arg == Py_None) { + // for ptr or cptr, null is an allowed value + *ret = true; + return; + } + if (! PyDict_Check (arg)) { *ret = false; return; @@ -999,6 +1011,7 @@ struct test_arg_func } } }; + template <> struct test_arg_func { diff --git a/src/pya/pya/pyaSignalHandler.cc b/src/pya/pya/pyaSignalHandler.cc index 7ac472e62..b015e42e3 100644 --- a/src/pya/pya/pyaSignalHandler.cc +++ b/src/pya/pya/pyaSignalHandler.cc @@ -138,7 +138,10 @@ void SignalHandler::call (const gsi::MethodBase *meth, gsi::SerialArgs &args, gs std::vector callables; callables.reserve (m_cbfuncs.size ()); for (std::vector::const_iterator c = m_cbfuncs.begin (); c != m_cbfuncs.end (); ++c) { - callables.push_back (c->callable ()); + PythonRef callable = c->callable (); + if (callable) { + callables.push_back (c->callable ()); + } } PythonRef result; diff --git a/src/rba/rba/rbaMarshal.cc b/src/rba/rba/rbaMarshal.cc index 45963e4ac..631e58f63 100644 --- a/src/rba/rba/rbaMarshal.cc +++ b/src/rba/rba/rbaMarshal.cc @@ -956,7 +956,7 @@ struct test_arg_func if ((atype.is_cptr () || atype.is_ptr ()) && arg == Qnil) { // for pointers to vectors, nil is a valid value *ret = true; - } if (TYPE (arg) != T_ARRAY) { + } else if (TYPE (arg) != T_ARRAY) { *ret = false; } else { diff --git a/testdata/algo/device_extract_l1_with_inv_nodes.gds b/testdata/algo/device_extract_l1_with_inv_nodes.gds new file mode 100644 index 000000000..db58f6700 Binary files /dev/null and b/testdata/algo/device_extract_l1_with_inv_nodes.gds differ diff --git a/testdata/python/dbLayoutToNetlist.py b/testdata/python/dbLayoutToNetlist.py index 9532591cb..dc4095f19 100644 --- a/testdata/python/dbLayoutToNetlist.py +++ b/testdata/python/dbLayoutToNetlist.py @@ -69,7 +69,7 @@ class DBLayoutToNetlistTests(unittest.TestCase): ut_testsrc = os.getenv("TESTSRC") ly = pya.Layout() - ly.read(os.path.join(ut_testsrc, "testdata", "algo", "device_extract_l1.gds")) + ly.read(os.path.join(ut_testsrc, "testdata", "algo", "device_extract_l1_with_inv_nodes.gds")) l2n = pya.LayoutToNetlist(pya.RecursiveShapeIterator(ly, ly.top_cell(), [])) @@ -97,40 +97,56 @@ class DBLayoutToNetlistTests(unittest.TestCase): self.assertEqual(str(l2n.netlist()), """circuit TRANS ($1=$1,$2=$2); end; -circuit INV2 (OUT=OUT,$2=$2,$3=$3,$4=$4); +circuit INV2 (OUT=OUT,$2=$3,$3=$4); subcircuit TRANS $1 ($1=$4,$2=OUT); subcircuit TRANS $2 ($1=$3,$2=OUT); subcircuit TRANS $3 ($1=$2,$2=$4); subcircuit TRANS $4 ($1=$2,$2=$3); end; circuit RINGO (); - subcircuit INV2 $1 (OUT=OSC,$2=FB,$3=VSS,$4=VDD); - subcircuit INV2 $2 (OUT=$I29,$2=$I20,$3=VSS,$4=VDD); - subcircuit INV2 $3 (OUT=$I28,$2=$I19,$3=VSS,$4=VDD); - subcircuit INV2 $4 (OUT=$I30,$2=$I21,$3=VSS,$4=VDD); - subcircuit INV2 $5 (OUT=$I31,$2=$I22,$3=VSS,$4=VDD); - subcircuit INV2 $6 (OUT=$I32,$2=$I23,$3=VSS,$4=VDD); - subcircuit INV2 $7 (OUT=$I33,$2=$I24,$3=VSS,$4=VDD); - subcircuit INV2 $8 (OUT=$I34,$2=$I25,$3=VSS,$4=VDD); - subcircuit INV2 $9 (OUT=$I35,$2=$I26,$3=VSS,$4=VDD); - subcircuit INV2 $10 (OUT=$I36,$2=$I27,$3=VSS,$4=VDD); + subcircuit INV2 $1 (OUT='FB,OSC',$2=VSS,$3=VDD); + subcircuit INV2 $2 (OUT=$I20,$2=VSS,$3=VDD); + subcircuit INV2 $3 (OUT=$I19,$2=VSS,$3=VDD); + subcircuit INV2 $4 (OUT=$I21,$2=VSS,$3=VDD); + subcircuit INV2 $5 (OUT=$I22,$2=VSS,$3=VDD); + subcircuit INV2 $6 (OUT=$I23,$2=VSS,$3=VDD); + subcircuit INV2 $7 (OUT=$I24,$2=VSS,$3=VDD); + subcircuit INV2 $8 (OUT=$I25,$2=VSS,$3=VDD); + subcircuit INV2 $9 (OUT=$I26,$2=VSS,$3=VDD); + subcircuit INV2 $10 (OUT=$I27,$2=VSS,$3=VDD); end; """) - self.assertEqual(str(l2n.probe_net(rmetal2, pya.DPoint(0.0, 1.8))), "RINGO:FB") + self.assertEqual(str(l2n.probe_net(rmetal2, pya.DPoint(0.0, 1.8))), "RINGO:FB,OSC") + sc_path = [] + self.assertEqual(str(l2n.probe_net(rmetal2, pya.DPoint(0.0, 1.8), sc_path)), "RINGO:FB,OSC") + self.assertEqual(len(sc_path), 0) self.assertEqual(repr(l2n.probe_net(rmetal2, pya.DPoint(-2.0, 1.8))), "None") - n = l2n.probe_net(rmetal1, pya.Point(2600, 1000)) - self.assertEqual(str(n), "RINGO:$I20") + n = l2n.probe_net(rmetal1, pya.Point(2600, 1000), None) + self.assertEqual(str(n), "INV2:$2") + sc_path = [] + n = l2n.probe_net(rmetal1, pya.Point(2600, 1000), sc_path) + self.assertEqual(str(n), "INV2:$2") + self.assertEqual(len(sc_path), 1) + a = [] + t = pya.DCplxTrans() + for sc in sc_path: + a.append(sc.expanded_name()) + t = t * sc.trans + self.assertEqual(",".join(a), "$2") + self.assertEqual(str(t), "r0 *1 2.64,0") - self.assertEqual(str(l2n.shapes_of_net(n, rmetal1, True)), "(1660,-420;1660,2420;2020,2420;2020,-420);(1840,820;1840,1180;3220,1180;3220,820);(1660,2420;1660,3180;2020,3180;2020,2420);(1660,-380;1660,380;2020,380;2020,-380)") + self.assertEqual(str(l2n.shapes_of_net(n, rmetal1, True)), + "(-980,-420;-980,2420;-620,2420;-620,-420);(-800,820;-800,1180;580,1180;580,820);(-980,2420;-980,3180;-620,3180;-620,2420);(-980,-380;-980,380;-620,380;-620,-380)") shapes = pya.Shapes() l2n.shapes_of_net(n, rmetal1, True, shapes) r = pya.Region() - for s in shapes.each(): - r.insert(s.polygon) - self.assertEqual(str(r), "(1660,-420;1660,2420;2020,2420;2020,-420);(1840,820;1840,1180;3220,1180;3220,820);(1660,2420;1660,3180;2020,3180;2020,2420);(1660,-380;1660,380;2020,380;2020,-380)") + for s in shapes.each(): + r.insert(s.polygon) + self.assertEqual(str(r), + "(-980,-420;-980,2420;-620,2420;-620,-420);(-800,820;-800,1180;580,1180;580,820);(-980,2420;-980,3180;-620,3180;-620,2420);(-980,-380;-980,380;-620,380;-620,-380)") def test_10_LayoutToNetlistExtractionWithoutDevices(self): diff --git a/testdata/ruby/dbLayoutToNetlist.rb b/testdata/ruby/dbLayoutToNetlist.rb index 094eef598..9e61b84a9 100644 --- a/testdata/ruby/dbLayoutToNetlist.rb +++ b/testdata/ruby/dbLayoutToNetlist.rb @@ -104,7 +104,7 @@ class DBLayoutToNetlist_TestClass < TestBase def test_2_ShapesFromNet ly = RBA::Layout::new - ly.read(File.join($ut_testsrc, "testdata", "algo", "device_extract_l1.gds")) + ly.read(File.join($ut_testsrc, "testdata", "algo", "device_extract_l1_with_inv_nodes.gds")) l2n = RBA::LayoutToNetlist::new(RBA::RecursiveShapeIterator::new(ly, ly.top_cell, [])) @@ -133,39 +133,50 @@ class DBLayoutToNetlist_TestClass < TestBase assert_equal(l2n.netlist.to_s, <