From 8121f70e65921618aec5bdf1257f8af252b56db5 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 18 Apr 2019 00:01:21 +0200 Subject: [PATCH 001/229] Netlist compare: Net mismatches reported if nets don't match but we still will proceed --- src/db/db/dbNetlistCompare.cc | 225 ++++++++++++++++----- src/db/db/dbNetlistCompare.h | 3 + src/db/db/gsiDeclDbNetlistCompare.cc | 4 + src/db/unit_tests/dbNetlistCompareTests.cc | 72 +++---- testdata/ruby/dbNetlistCompare.rb | 16 +- 5 files changed, 230 insertions(+), 90 deletions(-) diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 20b5ac5ad..344f9e1b5 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -38,6 +38,13 @@ namespace db // -------------------------------------------------------------------------------------------------------------------- // DeviceCompare definition and implementation +/** + * @brief The device compare function with "less" (operator()) and "equal" predicates + * + * Device comparison is based on the equivalence of device classes (by category) and + * in a second step, by equivalence of the devices. The device class will implement + * the device equivalence function. + */ struct DeviceCompare { bool operator() (const std::pair &d1, const std::pair &d2) const @@ -60,6 +67,12 @@ struct DeviceCompare // -------------------------------------------------------------------------------------------------------------------- // SubCircuitCompare definition and implementation +/** + * @brief The compare function for subcircuits + * + * As Subcircuits are not parametrized, the comparison of subcircuits is only based on + * the circuit equivalence (via category). + */ struct SubCircuitCompare { bool operator() (const std::pair &sc1, const std::pair &sc2) const @@ -76,6 +89,14 @@ struct SubCircuitCompare // -------------------------------------------------------------------------------------------------------------------- // CircuitPinMapper definition and implementation +/** + * @brief The Circuit pin mapper handles swappable pin definitions per circuit + * + * Swappable pins are implemented by mapping a pin ID to an equivalent or + * effective ID which is shared by all swappable pins. + * + * This class manages swappable pins on a per-circuit basis. + */ class CircuitPinMapper { public: @@ -130,6 +151,15 @@ private: // -------------------------------------------------------------------------------------------------------------------- // CircuitMapper definition and implementation +/** + * @brief A circuit mapper + * + * The circuit mapper handles the circuit equivalence between the circuits of + * netlist A and B and also the pin mapping between the circuits from these netlists. + * + * The "other" attribute will hold the circuit for the other netlist. + * The other methods handle pin mapping from "other" into "this" pin space. + */ class CircuitMapper { public: @@ -187,6 +217,13 @@ private: // -------------------------------------------------------------------------------------------------------------------- // DeviceFilter definition and implementation +/** + * @brief A device filter class + * + * This class implements a device filter which is used to skip devices when + * generating the net graph. This is useful for stripping small caps or big + * resistors. + */ class DeviceFilter { public: @@ -221,6 +258,12 @@ private: // -------------------------------------------------------------------------------------------------------------------- // DeviceCategorizer definition and implementation +/** + * @brief A device categorizer + * + * The objective of this class is to supply a category ID for a given device class. + * The category ID also identities equivalent device classes from netlist A and B. + */ class DeviceCategorizer { public: @@ -280,6 +323,12 @@ public: // -------------------------------------------------------------------------------------------------------------------- // CircuitCategorizer definition and implementation +/** + * @brief A circuit categorizer + * + * The objective of this class is to supply a category ID for a given device circuit. + * The category ID also identities equivalent circuit from netlist A and B. + */ class CircuitCategorizer { public: @@ -332,19 +381,39 @@ public: }; // -------------------------------------------------------------------------------------------------------------------- -// NetDeviceGraphNode definition and implementation +// NetGraphNode definition and implementation static size_t translate_terminal_id (size_t tid, const db::Device *device) { return device->device_class () ? device->device_class ()->normalize_terminal_id (tid) : tid; } +/** + * @brief A node within the net graph + * + * This class represents a node and the edges leading from this node to + * other nodes. + * + * A graph edge is a collection of transitions, connecting terminals of + * devices or pins of subcircuits plus the index of node at the other end + * of the edge. + * + * Transitions are sorted within the edge. + */ class NetGraphNode { public: - struct EdgeDesc { + /** + * @brief Represents one transition within an edge_iterator + * + * Each transition connects two pins of subcircuits or terminals + * of devices. + * An edge is basically a collection of transitions. + */ + struct Transition + { - EdgeDesc (const db::Device *device, size_t device_category, size_t terminal1_id, size_t terminal2_id) + Transition (const db::Device *device, size_t device_category, size_t terminal1_id, size_t terminal2_id) { device_pair ().first = device; device_pair ().second = device_category; @@ -352,7 +421,7 @@ public: m_id2 = terminal2_id; } - EdgeDesc (const db::SubCircuit *subcircuit, size_t subcircuit_category, size_t pin1_id, size_t pin2_id) + Transition (const db::SubCircuit *subcircuit, size_t subcircuit_category, size_t pin1_id, size_t pin2_id) { subcircuit_pair ().first = subcircuit; subcircuit_pair ().second = subcircuit_category; @@ -360,7 +429,7 @@ public: m_id2 = pin2_id; } - bool operator< (const EdgeDesc &other) const + bool operator< (const Transition &other) const { if (is_for_subcircuit () != other.is_for_subcircuit ()) { return is_for_subcircuit () < other.is_for_subcircuit (); @@ -400,7 +469,7 @@ public: return m_id2 < other.m_id2; } - bool operator== (const EdgeDesc &other) const + bool operator== (const Transition &other) const { if (is_for_subcircuit () != other.is_for_subcircuit ()) { return false; @@ -469,13 +538,13 @@ public: struct EdgeToEdgeOnlyCompare { - bool operator() (const std::pair, std::pair > &a, const std::vector &b) const + bool operator() (const std::pair, std::pair > &a, const std::vector &b) const { return a.first < b; } }; - typedef std::vector, std::pair > >::const_iterator edge_iterator; + typedef std::vector, std::pair > >::const_iterator edge_iterator; NetGraphNode (const db::Net *net, DeviceCategorizer &device_categorizer, CircuitCategorizer &circuit_categorizer, const DeviceFilter &device_filter, const std::map *circuit_map, const CircuitPinMapper *pin_map) : mp_net (net), m_other_net_index (std::numeric_limits::max ()) @@ -560,14 +629,14 @@ public: // NOTE: if a pin mapping is given, EdgeDesc::pin1_id and EdgeDesc::pin2_id are given // as pin ID's of the other circuit. - EdgeDesc ed (sc, circuit_categorizer.cat_for_subcircuit (sc), pin_id, pin_map->normalize_pin_id (cr, pin2_id)); + Transition ed (sc, circuit_categorizer.cat_for_subcircuit (sc), pin_id, pin_map->normalize_pin_id (cr, pin2_id)); const db::Net *net2 = sc->net_for_pin (this_pin2_id); std::map::const_iterator in = n2entry.find (net2); if (in == n2entry.end ()) { in = n2entry.insert (std::make_pair (net2, m_edges.size ())).first; - m_edges.push_back (std::make_pair (std::vector (), std::make_pair (size_t (0), net2))); + m_edges.push_back (std::make_pair (std::vector (), std::make_pair (size_t (0), net2))); } m_edges [in->second].first.push_back (ed); @@ -592,14 +661,14 @@ public: if (it->id () != i->terminal_id ()) { size_t terminal2_id = translate_terminal_id (it->id (), d); - EdgeDesc ed2 (d, device_cat, terminal1_id, terminal2_id); + Transition ed2 (d, device_cat, terminal1_id, terminal2_id); const db::Net *net2 = d->net_for_terminal (it->id ()); std::map::const_iterator in = n2entry.find (net2); if (in == n2entry.end ()) { in = n2entry.insert (std::make_pair (net2, m_edges.size ())).first; - m_edges.push_back (std::make_pair (std::vector (), std::make_pair (size_t (0), net2))); + m_edges.push_back (std::make_pair (std::vector (), std::make_pair (size_t (0), net2))); } m_edges [in->second].first.push_back (ed2); @@ -643,14 +712,14 @@ public: void apply_net_index (const std::map &ni) { - for (std::vector, std::pair > >::iterator i = m_edges.begin (); i != m_edges.end (); ++i) { + for (std::vector, std::pair > >::iterator i = m_edges.begin (); i != m_edges.end (); ++i) { std::map::const_iterator j = ni.find (i->second.second); tl_assert (j != ni.end ()); i->second.first = j->second; } // "deep sorting" of the edge descriptor - for (std::vector, std::pair > >::iterator i = m_edges.begin (); i != m_edges.end (); ++i) { + for (std::vector, std::pair > >::iterator i = m_edges.begin (); i != m_edges.end (); ++i) { std::sort (i->first.begin (), i->first.end ()); } @@ -708,7 +777,7 @@ public: return m_edges.end (); } - edge_iterator find_edge (const std::vector &edge) const + edge_iterator find_edge (const std::vector &edge) const { edge_iterator res = std::lower_bound (begin (), end (), edge, NetGraphNode::EdgeToEdgeOnlyCompare ()); if (res == end () || res->first != edge) { @@ -721,7 +790,7 @@ public: private: const db::Net *mp_net; size_t m_other_net_index; - std::vector, std::pair > > m_edges; + std::vector, std::pair > > m_edges; /** * @brief Compares edges as "less" @@ -777,7 +846,7 @@ private: }; // -------------------------------------------------------------------------------------------------------------------- -// NetDeviceGraph definition and implementation +// NetGraph definition and implementation } @@ -802,18 +871,27 @@ struct CompareNodePtr class TentativeNodeMapping; -class NetDeviceGraph +/** + * @brief The net graph for the compare algorithm + */ +class NetGraph { public: typedef std::vector::const_iterator node_iterator; - NetDeviceGraph () + NetGraph () { // .. nothing yet .. } + /** + * @brief Builds the net graph + */ void build (const db::Circuit *c, DeviceCategorizer &device_categorizer, CircuitCategorizer &circuit_categorizer, const db::DeviceFilter &device_filter, const std::map *circuit_and_pin_mapping, const CircuitPinMapper *circuit_pin_mapper); + /** + * @brief Gets the node index for the given net + */ size_t node_index_for_net (const db::Net *net) const { std::map::const_iterator j = m_net_index.find (net); @@ -821,31 +899,65 @@ public: return j->second; } + /** + * @brief Gets the node for a given node index + */ + const db::NetGraphNode &node (size_t net_index) const + { + return m_nodes [net_index]; + } + + /** + * @brief Gets the node for a given node index (non-const version) + */ + db::NetGraphNode &node (size_t net_index) + { + return m_nodes [net_index]; + } + + /** + * @brief Gets the net for a given node index + */ const db::Net *net_by_node_index (size_t net_index) const { return m_nodes [net_index].net (); } + /** + * @brief Establishes an equivalence between two nodes of netlist A (this) and B (other) + */ void identify (size_t net_index, size_t other_net_index) { m_nodes [net_index].set_other_net (other_net_index); } + /** + * @brief Removes the equivalence from the node with the given index + */ void unidentify (size_t net_index) { m_nodes [net_index].unset_other_net (); } + /** + * @brief Iterator over the nodes in this graph (begin) + */ node_iterator begin () const { return m_nodes.begin (); } + /** + * @brief Iterator over the nodes in this graph (end) + */ node_iterator end () const { return m_nodes.end (); } + /** + * @brief The circuit this graph is associated with + */ const db::Circuit *circuit () const { return mp_circuit; @@ -870,14 +982,22 @@ public: * backtracking depth (number of graph jumps) and decision tree * branching complexity N (="n_branch", means: N*N decisions to be made). * - * The limits "depth_max" and "n_branch_max" are attributes of the graph. + * If "tentative" is non-null, assignments will be recorded in the TentativeMapping + * audit object and can be undone afterwards when backtracking recursion happens. * - * If tentative is true, assignments will not be retained and just the - * status is reported. + * If "with_ambiguous" is true, ambiguous matches are considered. This will happen + * in a second pass to give exact and unique matches priority over ambiguous matches. */ - size_t derive_node_identities (size_t net_index, NetDeviceGraph &other, size_t depth, size_t max_depth, size_t n_branch, size_t max_n_branch, NetlistCompareLogger *logger, CircuitPinMapper *circuit_pin_mapper, TentativeNodeMapping *tentative, bool with_ambiguous); + size_t derive_node_identities (size_t net_index, NetGraph &other, size_t depth, size_t max_depth, size_t n_branch, size_t max_n_branch, NetlistCompareLogger *logger, CircuitPinMapper *circuit_pin_mapper, TentativeNodeMapping *tentative, bool with_ambiguous); - size_t derive_node_identities_from_node_set (const std::vector &nodes, const std::vector &other_nodes, NetDeviceGraph &other, size_t depth, size_t max_depth, size_t n_branch, size_t max_n_branch, NetlistCompareLogger *logger, CircuitPinMapper *circuit_pin_mapper, TentativeNodeMapping *tentative, bool with_ambiguous); + /** + * @brief The backtracking driver + * + * This method will analyze the given nodes and call "derive_node_identities" for all nodes + * with a proposed identity. With "with_ambiguous", amiguities are resolved by trying + * different combinations in tentative mode and deciding for one combination if possible. + */ + size_t derive_node_identities_from_node_set (const std::vector &nodes, const std::vector &other_nodes, NetGraph &other, size_t depth, size_t max_depth, size_t n_branch, size_t max_n_branch, NetlistCompareLogger *logger, CircuitPinMapper *circuit_pin_mapper, TentativeNodeMapping *tentative, bool with_ambiguous); private: std::vector m_nodes; @@ -887,6 +1007,9 @@ private: // -------------------------------------------------------------------------------------------------------------------- +/** + * @brief Represents an interval of NetGraphNode objects in a node set + */ struct NodeRange { NodeRange (size_t _num, std::vector::const_iterator _n1, std::vector::const_iterator _nn1, std::vector::const_iterator _n2, std::vector::const_iterator _nn2) @@ -906,10 +1029,13 @@ struct NodeRange // -------------------------------------------------------------------------------------------------------------------- +/** + * @brief An audit object which allows reverting tentative node assignments + */ class TentativeNodeMapping { public: - TentativeNodeMapping (NetDeviceGraph *g1, NetDeviceGraph *g2) + TentativeNodeMapping (NetGraph *g1, NetGraph *g2) : mp_g1 (g1), mp_g2 (g2) { } @@ -921,7 +1047,7 @@ public: } } - static void map_pair (TentativeNodeMapping *nm, NetDeviceGraph *g1, size_t n1, NetDeviceGraph *g2, size_t n2) + static void map_pair (TentativeNodeMapping *nm, NetGraph *g1, size_t n1, NetGraph *g2, size_t n2) { g1->identify (n1, n2); g2->identify (n2, n1); @@ -932,7 +1058,7 @@ public: private: std::vector > m_to_undo; - NetDeviceGraph *mp_g1, *mp_g2; + NetGraph *mp_g1, *mp_g2; void keep (size_t n1, size_t n2) { @@ -941,9 +1067,10 @@ private: }; // -------------------------------------------------------------------------------------------------------------------- +// NetGraph implementation void -NetDeviceGraph::build (const db::Circuit *c, DeviceCategorizer &device_categorizer, CircuitCategorizer &circuit_categorizer, const db::DeviceFilter &device_filter, const std::map *circuit_and_pin_mapping, const CircuitPinMapper *circuit_pin_mapper) +NetGraph::build (const db::Circuit *c, DeviceCategorizer &device_categorizer, CircuitCategorizer &circuit_categorizer, const db::DeviceFilter &device_filter, const std::map *circuit_and_pin_mapping, const CircuitPinMapper *circuit_pin_mapper) { tl::SelfTimer timer (tl::verbosity () >= 31, tl::to_string (tr ("Building net graph for circuit: ")) + c->name ()); @@ -979,10 +1106,10 @@ NetDeviceGraph::build (const db::Circuit *c, DeviceCategorizer &device_categoriz } size_t -NetDeviceGraph::derive_node_identities (size_t net_index, NetDeviceGraph &other, size_t depth, size_t max_depth, size_t n_branch, size_t max_n_branch, NetlistCompareLogger *logger, CircuitPinMapper *circuit_pin_mapper, TentativeNodeMapping *tentative, bool with_ambiguous) +NetGraph::derive_node_identities (size_t net_index, NetGraph &other, size_t depth, size_t max_depth, size_t n_branch, size_t max_n_branch, NetlistCompareLogger *logger, CircuitPinMapper *circuit_pin_mapper, TentativeNodeMapping *tentative, bool with_ambiguous) { - NetGraphNode *n = & m_nodes[net_index]; - NetGraphNode *nother = & other.m_nodes[n->other_net_index ()]; + NetGraphNode *n = & node (net_index); + NetGraphNode *nother = & other.node (n->other_net_index ()); #if defined(PRINT_DEBUG_NETCOMPARE) std::string indent; @@ -1018,7 +1145,7 @@ NetDeviceGraph::derive_node_identities (size_t net_index, NetDeviceGraph &other, other_nodes.reserve (ee - e); for (NetGraphNode::edge_iterator i = e; i != ee; ++i) { - const NetGraphNode *n = &m_nodes[i->second.first]; + const NetGraphNode *n = &node (i->second.first); nodes.push_back (n); } @@ -1037,7 +1164,7 @@ NetDeviceGraph::derive_node_identities (size_t net_index, NetDeviceGraph &other, size_t count_other = 0; for (NetGraphNode::edge_iterator i = e_other; i != ee_other && count_other < 2; ++i) { - const NetGraphNode *n = &other.m_nodes[i->second.first]; + const NetGraphNode *n = &other.node (i->second.first); other_nodes.push_back (n); } @@ -1099,7 +1226,7 @@ NetDeviceGraph::derive_node_identities (size_t net_index, NetDeviceGraph &other, } size_t -NetDeviceGraph::derive_node_identities_from_node_set (const std::vector &nodes, const std::vector &other_nodes, NetDeviceGraph &other, size_t depth, size_t max_depth, size_t n_branch, size_t max_n_branch, NetlistCompareLogger *logger, CircuitPinMapper *circuit_pin_mapper, TentativeNodeMapping *tentative, bool with_ambiguous) +NetGraph::derive_node_identities_from_node_set (const std::vector &nodes, const std::vector &other_nodes, NetGraph &other, size_t depth, size_t max_depth, size_t n_branch, size_t max_n_branch, NetlistCompareLogger *logger, CircuitPinMapper *circuit_pin_mapper, TentativeNodeMapping *tentative, bool with_ambiguous) { #if defined(PRINT_DEBUG_NETCOMPARE) std::string indent; @@ -1133,8 +1260,11 @@ NetDeviceGraph::derive_node_identities_from_node_set (const std::vectornet ()->expanded_name () << " vs. " << other_nodes.front ()->net ()->expanded_name (); #endif - if (! tentative) { - if (logger) { + if (logger && ! tentative) { + if (! (node (ni) == other.node (other_ni))) { + // this is a mismatch but we continue, because that is the only candidate + logger->net_mismatch (nodes.front ()->net (), other_nodes.front ()->net ()); + } else { logger->match_nets (nodes.front ()->net (), other_nodes.front ()->net ()); } } @@ -1279,8 +1409,11 @@ NetDeviceGraph::derive_node_identities_from_node_set (const std::vectorn1)->net ()->expanded_name () << " vs. " << (*nr->n2)->net ()->expanded_name (); #endif - if (! tentative) { - if (logger) { + if (logger && ! tentative) { + if (! (node (ni) == other.node (other_ni))) { + // this is a mismatch, but we continue with this + logger->net_mismatch ((*nr->n1)->net (), (*nr->n2)->net ()); + } else { logger->match_nets ((*nr->n1)->net (), (*nr->n2)->net ()); } } @@ -1694,7 +1827,7 @@ NetlistComparer::all_subcircuits_verified (const db::Circuit *c, const std::set< } static std::vector > -compute_device_key (const db::Device &device, const db::NetDeviceGraph &g) +compute_device_key (const db::Device &device, const db::NetGraph &g) { std::vector > k; @@ -1712,7 +1845,7 @@ compute_device_key (const db::Device &device, const db::NetDeviceGraph &g) } static std::vector > -compute_subcircuit_key (const db::SubCircuit &subcircuit, const db::NetDeviceGraph &g, const std::map *circuit_map, const CircuitPinMapper *pin_map) +compute_subcircuit_key (const db::SubCircuit &subcircuit, const db::NetGraph &g, const std::map *circuit_map, const CircuitPinMapper *pin_map) { std::vector > k; @@ -1755,7 +1888,7 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, { db::DeviceFilter device_filter (m_cap_threshold, m_res_threshold); - db::NetDeviceGraph g1, g2; + db::NetGraph g1, g2; // NOTE: for normalization we map all subcircuits of c1 to c2. // Also, pin swapping will only happen there. @@ -1800,7 +1933,7 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, size_t new_identities = 0; - for (db::NetDeviceGraph::node_iterator i1 = g1.begin (); i1 != g1.end (); ++i1) { + for (db::NetGraph::node_iterator i1 = g1.begin (); i1 != g1.end (); ++i1) { if (i1->has_other () && i1->net ()) { size_t ni = g1.derive_node_identities (i1 - g1.begin (), g2, 0, m_max_depth, 1, m_max_n_branch, mp_logger, &circuit_pin_mapper, 0 /*not tentative*/, pass > 0 /*with ambiguities*/); if (ni > 0 && ni != std::numeric_limits::max ()) { @@ -1821,14 +1954,14 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, std::vector nodes, other_nodes; nodes.reserve (g1.end () - g1.begin ()); - for (db::NetDeviceGraph::node_iterator i1 = g1.begin (); i1 != g1.end (); ++i1) { + for (db::NetGraph::node_iterator i1 = g1.begin (); i1 != g1.end (); ++i1) { if (! i1->has_other () && i1->net ()) { nodes.push_back (i1.operator-> ()); } } other_nodes.reserve (g2.end () - g2.begin ()); - for (db::NetDeviceGraph::node_iterator i2 = g2.begin (); i2 != g2.end (); ++i2) { + for (db::NetGraph::node_iterator i2 = g2.begin (); i2 != g2.end (); ++i2) { if (! i2->has_other () && i2->net ()) { other_nodes.push_back (i2.operator-> ()); } @@ -1864,13 +1997,13 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, // Report missing net assignment - for (db::NetDeviceGraph::node_iterator i = g1.begin (); i != g1.end (); ++i) { + for (db::NetGraph::node_iterator i = g1.begin (); i != g1.end (); ++i) { if (! i->has_other () && mp_logger) { mp_logger->net_mismatch (i->net (), 0); } } - for (db::NetDeviceGraph::node_iterator i = g2.begin (); i != g2.end (); ++i) { + for (db::NetGraph::node_iterator i = g2.begin (); i != g2.end (); ++i) { if (! i->has_other () && mp_logger) { mp_logger->net_mismatch (0, i->net ()); } diff --git a/src/db/db/dbNetlistCompare.h b/src/db/db/dbNetlistCompare.h index c2946a997..1de9af01c 100644 --- a/src/db/db/dbNetlistCompare.h +++ b/src/db/db/dbNetlistCompare.h @@ -99,6 +99,9 @@ public: /** * @brief Net a or b doesn't match * "a" is null if there is no match for b and vice versa. + * In some cases, a mismatch is reported with two nets given. This means, + * nets are known not to match. Still the compare algorithm will proceed as + * if these nets were equivalent to derive further matches. */ virtual void net_mismatch (const db::Net * /*a*/, const db::Net * /*b*/) { } diff --git a/src/db/db/gsiDeclDbNetlistCompare.cc b/src/db/db/gsiDeclDbNetlistCompare.cc index e5a652ecb..773b7cccc 100644 --- a/src/db/db/gsiDeclDbNetlistCompare.cc +++ b/src/db/db/gsiDeclDbNetlistCompare.cc @@ -374,6 +374,10 @@ Class decl_GenericNetlistCompareLogger ("db", "Gene "@brief This function is called when a net can't be paired.\n" "This method will be called, if a net cannot be identified as identical with another net. The corresponding argument " "will identify the net and source netlist. The other argument will be nil.\n" + "\n" + "In some cases, a mismatch is reported with two nets given. This means,\n" + "nets are known not to match. Still the compare algorithm will proceed as\n" + "if these nets were equivalent to derive further matches.\n" ) + gsi::callback ("match_devices", &GenericNetlistCompareLogger::match_devices, &GenericNetlistCompareLogger::cb_match_devices, gsi::arg ("a"), gsi::arg ("b"), "@brief This function is called when two devices are identified.\n" diff --git a/src/db/unit_tests/dbNetlistCompareTests.cc b/src/db/unit_tests/dbNetlistCompareTests.cc index 289bec5c5..bd6476908 100644 --- a/src/db/unit_tests/dbNetlistCompareTests.cc +++ b/src/db/unit_tests/dbNetlistCompareTests.cc @@ -438,9 +438,9 @@ TEST(1_SimpleInverterSkippedDevices) EXPECT_EQ (logger.text (), "begin_circuit INV INV\n" "match_nets VDD VDD\n" - "match_nets OUT OUT\n" + "net_mismatch OUT OUT\n" "match_nets VSS VSS\n" - "match_nets IN IN\n" + "net_mismatch IN IN\n" "match_pins $0 $1\n" "match_pins $1 $3\n" "match_pins $2 $0\n" @@ -670,8 +670,8 @@ TEST(5_BufferTwoPathsDifferentParameters) "begin_circuit BUF BUF\n" "match_nets OUT OUT\n" "match_nets INT $10\n" - "match_nets IN IN\n" - "match_nets INT2 $11\n" + "net_mismatch IN IN\n" + "net_mismatch INT2 $11\n" "match_pins $0 $1\n" "match_pins $1 $3\n" "match_pins $2 $0\n" @@ -722,8 +722,8 @@ TEST(5_BufferTwoPathsDifferentParameters) "begin_circuit BUF BUF\n" "match_nets OUT OUT\n" "match_nets INT $10\n" - "match_nets IN IN\n" - "match_nets INT2 $11\n" + "net_mismatch IN IN\n" + "net_mismatch INT2 $11\n" "match_pins $0 $1\n" "match_pins $1 $3\n" "match_pins $2 $0\n" @@ -748,8 +748,8 @@ TEST(5_BufferTwoPathsDifferentParameters) "begin_circuit BUF BUF\n" "match_nets OUT OUT\n" "match_nets INT $10\n" - "match_nets IN IN\n" - "match_nets INT2 $11\n" + "net_mismatch IN IN\n" + "net_mismatch INT2 $11\n" "match_pins $0 $1\n" "match_pins $1 $3\n" "match_pins $2 $0\n" @@ -828,8 +828,8 @@ TEST(5_BufferTwoPathsDifferentParameters) "begin_circuit BUF BUF\n" "match_nets OUT OUT\n" "match_nets INT $10\n" - "match_nets IN IN\n" - "match_nets INT2 $11\n" + "net_mismatch IN IN\n" + "net_mismatch INT2 $11\n" "match_pins $0 $1\n" "match_pins $1 $3\n" "match_pins $2 $0\n" @@ -892,8 +892,8 @@ TEST(5_BufferTwoPathsDifferentDeviceClasses) "begin_circuit BUF BUF\n" "match_nets INT $10\n" "match_nets IN IN\n" - "match_nets OUT OUT\n" - "match_nets INT2 $11\n" + "net_mismatch OUT OUT\n" + "net_mismatch INT2 $11\n" "match_pins $0 $1\n" "match_pins $1 $3\n" "match_pins $2 $0\n" @@ -955,10 +955,10 @@ TEST(6_BufferTwoPathsAdditionalResistor) EXPECT_EQ (logger.text (), "begin_circuit BUF BUF\n" - "match_nets INT $10\n" + "net_mismatch INT $10\n" "match_nets IN IN\n" "match_nets OUT OUT\n" - "match_nets INT2 $11\n" + "net_mismatch INT2 $11\n" "match_pins $0 $1\n" "match_pins $1 $3\n" "match_pins $2 $0\n" @@ -1017,11 +1017,11 @@ TEST(6_BufferTwoPathsAdditionalDevices) EXPECT_EQ (logger.text (), "begin_circuit BUF BUF\n" "match_nets INT $11\n" - "match_nets VDD VDD\n" + "net_mismatch VDD VDD\n" "match_nets IN IN\n" - "match_nets VSS VSS\n" - "match_nets OUT OUT\n" - "match_nets INT2 $10\n" + "net_mismatch VSS VSS\n" + "net_mismatch OUT OUT\n" + "net_mismatch INT2 $10\n" "match_pins $0 $1\n" "match_pins $1 $3\n" "match_pins $2 $0\n" @@ -1110,8 +1110,8 @@ TEST(7_ResistorsParameterMismatch) EXPECT_EQ (logger.text (), "begin_circuit TRIANGLE TRIANGLE\n" "match_nets P2 P2\n" - "match_nets P1 P1\n" - "match_nets P3 P3\n" + "net_mismatch P1 P1\n" + "net_mismatch P3 P3\n" "match_pins $0 $0\n" "match_pins $1 $1\n" "match_pins $2 $2\n" @@ -1152,8 +1152,8 @@ TEST(7_ResistorsPlusOneDevice) EXPECT_EQ (logger.text (), "begin_circuit TRIANGLE TRIANGLE\n" "match_nets P3 P3\n" - "match_nets P2 P2\n" - "match_nets P1 P1\n" + "net_mismatch P2 P2\n" + "net_mismatch P1 P1\n" "match_pins $0 $0\n" "match_pins $1 $1\n" "match_pins $2 $2\n" @@ -1235,8 +1235,8 @@ TEST(8_DiodesDontMatchOnSwappedPins) EXPECT_EQ (logger.text (), "begin_circuit TRIANGLE TRIANGLE\n" "match_nets P1 P3\n" - "match_nets P2 P1\n" - "match_nets P3 P2\n" + "net_mismatch P2 P1\n" + "net_mismatch P3 P2\n" "match_pins $0 $2\n" "match_pins $1 $0\n" "match_pins $2 $1\n" @@ -1413,9 +1413,9 @@ TEST(11_MismatchingSubcircuits) EXPECT_EQ (logger.text (), "begin_circuit INV INV\n" "match_nets VSS VSS\n" - "match_nets OUT OUT\n" - "match_nets IN IN\n" - "match_nets VDD VDD\n" + "net_mismatch OUT OUT\n" + "net_mismatch IN IN\n" + "net_mismatch VDD VDD\n" "match_pins $0 $1\n" "match_pins $1 $3\n" "match_pins $2 $0\n" @@ -1489,10 +1489,10 @@ TEST(12_MismatchingSubcircuitsDuplicates) "end_circuit INV INV MATCH\n" "begin_circuit TOP TOP\n" "match_nets IN IN\n" - "match_nets VDD VDD\n" - "match_nets VSS VSS\n" - "match_nets INT INT\n" - "match_nets OUT OUT\n" + "net_mismatch VDD VDD\n" + "net_mismatch VSS VSS\n" + "net_mismatch INT INT\n" + "net_mismatch OUT OUT\n" "match_pins $0 $1\n" "match_pins $1 $0\n" "match_pins $2 $2\n" @@ -1703,11 +1703,11 @@ TEST(14_Subcircuit2NandMismatchNoSwap) "end_circuit NAND NAND MATCH\n" "begin_circuit TOP TOP\n" "match_nets OUT OUT\n" - "match_nets IN1 INT\n" - "match_nets INT IN1\n" - "match_nets VDD VDD\n" - "match_nets VSS VSS\n" - "match_nets IN2 IN2\n" + "net_mismatch IN1 INT\n" + "net_mismatch INT IN1\n" + "net_mismatch VDD VDD\n" + "net_mismatch VSS VSS\n" + "net_mismatch IN2 IN2\n" "pin_mismatch $0 (null)\n" "match_pins $1 $1\n" "match_pins $2 $2\n" diff --git a/testdata/ruby/dbNetlistCompare.rb b/testdata/ruby/dbNetlistCompare.rb index f51bfd979..59a6910c9 100644 --- a/testdata/ruby/dbNetlistCompare.rb +++ b/testdata/ruby/dbNetlistCompare.rb @@ -461,8 +461,8 @@ END begin_circuit BUF BUF match_nets OUT OUT match_nets INT $10 -match_nets IN IN -match_nets INT2 $11 +net_mismatch IN IN +net_mismatch INT2 $11 match_pins $0 $1 match_pins $1 $3 match_pins $2 $0 @@ -616,8 +616,8 @@ END begin_circuit BUF BUF match_nets INT $10 match_nets IN IN -match_nets OUT OUT -match_nets INT2 $11 +net_mismatch OUT OUT +net_mismatch INT2 $11 match_pins $0 $1 match_pins $1 $3 match_pins $2 $0 @@ -684,10 +684,10 @@ END assert_equal(logger.text, <<"END") begin_circuit BUF BUF -match_nets INT $10 +net_mismatch INT $10 match_nets IN IN match_nets OUT OUT -match_nets INT2 $11 +net_mismatch INT2 $11 match_pins $0 $1 match_pins $1 $3 match_pins $2 $0 @@ -945,9 +945,9 @@ END assert_equal(logger.text(), <<"END") begin_circuit INV INV match_nets VDD VDD -match_nets OUT OUT +net_mismatch OUT OUT match_nets VSS VSS -match_nets IN IN +net_mismatch IN IN match_pins $0 $1 match_pins $1 $3 match_pins $2 $0 From 767f6a7c48628e7fcf926f1262141dfb03457356 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 20 Apr 2019 10:33:56 +0200 Subject: [PATCH 002/229] WIP: first code pieces --- src/klayout.pro | 4 + .../laybasic/MarkerBrowserConfigPage2.ui | 2 +- src/laybasic/laybasic/MarkerBrowserPage.ui | 86 ++- .../laybasic/NetlistBrowserConfigPage.ui | 155 +++++ .../laybasic/NetlistBrowserConfigPage2.ui | 166 +++++ src/laybasic/laybasic/NetlistBrowserDialog.ui | 347 ++++++++++ src/laybasic/laybasic/NetlistBrowserPage.ui | 226 +++++++ src/laybasic/laybasic/layNetlistBrowser.cc | 309 +++++++++ src/laybasic/laybasic/layNetlistBrowser.h | 90 +++ .../laybasic/layNetlistBrowserDialog.cc | 628 ++++++++++++++++++ .../laybasic/layNetlistBrowserDialog.h | 101 +++ .../laybasic/layNetlistBrowserPage.cc | 172 +++++ src/laybasic/laybasic/layNetlistBrowserPage.h | 149 +++++ src/laybasic/laybasic/laybasic.pro | 14 +- src/laybasic/laybasic/rdbMarkerBrowserPage.h | 2 +- 15 files changed, 2431 insertions(+), 20 deletions(-) create mode 100644 src/laybasic/laybasic/NetlistBrowserConfigPage.ui create mode 100644 src/laybasic/laybasic/NetlistBrowserConfigPage2.ui create mode 100644 src/laybasic/laybasic/NetlistBrowserDialog.ui create mode 100644 src/laybasic/laybasic/NetlistBrowserPage.ui create mode 100644 src/laybasic/laybasic/layNetlistBrowser.cc create mode 100644 src/laybasic/laybasic/layNetlistBrowser.h create mode 100644 src/laybasic/laybasic/layNetlistBrowserDialog.cc create mode 100644 src/laybasic/laybasic/layNetlistBrowserDialog.h create mode 100644 src/laybasic/laybasic/layNetlistBrowserPage.cc create mode 100644 src/laybasic/laybasic/layNetlistBrowserPage.h diff --git a/src/klayout.pro b/src/klayout.pro index 60855e611..196fd9638 100644 --- a/src/klayout.pro +++ b/src/klayout.pro @@ -98,3 +98,7 @@ plugins.depends += lib rdb db } unit_tests.depends += plugins $$MAIN_DEPENDS + +RESOURCES += \ + laybasic/laybasic/layResources.qrc \ + laybasic/laybasic/layResources.qrc diff --git a/src/laybasic/laybasic/MarkerBrowserConfigPage2.ui b/src/laybasic/laybasic/MarkerBrowserConfigPage2.ui index 27e576e68..94b14426c 100644 --- a/src/laybasic/laybasic/MarkerBrowserConfigPage2.ui +++ b/src/laybasic/laybasic/MarkerBrowserConfigPage2.ui @@ -115,7 +115,7 @@ - The color in which the rulers are drawn + The color in which the markers are drawn diff --git a/src/laybasic/laybasic/MarkerBrowserPage.ui b/src/laybasic/laybasic/MarkerBrowserPage.ui index 8d6c61387..682d9ae9c 100644 --- a/src/laybasic/laybasic/MarkerBrowserPage.ui +++ b/src/laybasic/laybasic/MarkerBrowserPage.ui @@ -17,7 +17,16 @@ 6 - + + 0 + + + 0 + + + 0 + + 0 @@ -39,7 +48,16 @@ QFrame::Raised - + + 0 + + + 0 + + + 0 + + 0 @@ -51,7 +69,7 @@ ... - + :/down.png:/down.png @@ -62,7 +80,7 @@ ... - + :/up.png:/up.png @@ -129,7 +147,16 @@ QFrame::Raised - + + 0 + + + 0 + + + 0 + + 0 @@ -157,7 +184,7 @@ - :/find.png + :/find.png @@ -230,7 +257,16 @@ QFrame::Raised - + + 0 + + + 0 + + + 0 + + 0 @@ -252,7 +288,7 @@ ... - + :/up.png:/up.png @@ -270,7 +306,7 @@ ... - + :/down.png:/down.png @@ -363,7 +399,16 @@ QFrame::Raised - + + 0 + + + 0 + + + 0 + + 0 @@ -385,7 +430,7 @@ Photo - + :/photo.png:/photo.png @@ -399,7 +444,7 @@ W - + :/waived.png:/waived.png @@ -433,7 +478,7 @@ Imp - + :/important.png:/important.png @@ -450,7 +495,7 @@ p, li { white-space: pre-wrap; } ... - + :/nophoto.png:/nophoto.png @@ -473,7 +518,16 @@ p, li { white-space: pre-wrap; } 0 - + + 0 + + + 0 + + + 0 + + 0 @@ -523,7 +577,7 @@ p, li { white-space: pre-wrap; } photo_pb - + diff --git a/src/laybasic/laybasic/NetlistBrowserConfigPage.ui b/src/laybasic/laybasic/NetlistBrowserConfigPage.ui new file mode 100644 index 000000000..857fe8996 --- /dev/null +++ b/src/laybasic/laybasic/NetlistBrowserConfigPage.ui @@ -0,0 +1,155 @@ + + + NetlistBrowserConfigPage + + + + 0 + 0 + 571 + 162 + + + + Netlist Database Browser + + + + 6 + + + 9 + + + + + Netlist Browser + + + + 9 + + + 6 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 10 + 20 + + + + + + + + Window + + + + + + + + Don't change + + + + + Fit context cell + + + + + Fit marker with margin .. + + + + + Center marker + + + + + Center marker with size .. + + + + + + + + + Any Cell + + + + + Netlist Top Circuit + + + + + Current Cell + + + + + Current or Any Cell + + + + + Net's Circuit + + + + + + + + false + + + + + + + Maximum number of shapes to show for net + + + + + + + Context + + + + + + + µm + + + + + + + + + + + + diff --git a/src/laybasic/laybasic/NetlistBrowserConfigPage2.ui b/src/laybasic/laybasic/NetlistBrowserConfigPage2.ui new file mode 100644 index 000000000..c0ac46fd7 --- /dev/null +++ b/src/laybasic/laybasic/NetlistBrowserConfigPage2.ui @@ -0,0 +1,166 @@ + + NetlistBrowserConfigPage2 + + + + 0 + 0 + 571 + 174 + + + + Netlist Browser + + + + 9 + + + 6 + + + + + Net Appearance + + + + 9 + + + 6 + + + + + With halo + + + true + + + + + + + + + + + + + pixel + + + + + + + Qt::Horizontal + + + + 71 + 31 + + + + + + + + + 0 + 0 + 0 + 0 + + + + pixel + + + + + + + Line width + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 41 + 31 + + + + + + + + Vertex size + + + + + + + The color in which the nets are drawn + + + + + + + + + + Net color + + + + + + + Stipple + + + + + + + + + + + + + + + + + + + lay::DitherPatternSelectionButton + QPushButton +
layWidgets.h
+
+ + lay::ColorButton + QPushButton +
layWidgets.h
+
+
+ + +
diff --git a/src/laybasic/laybasic/NetlistBrowserDialog.ui b/src/laybasic/laybasic/NetlistBrowserDialog.ui new file mode 100644 index 000000000..c8be982eb --- /dev/null +++ b/src/laybasic/laybasic/NetlistBrowserDialog.ui @@ -0,0 +1,347 @@ + + + NetlistBrowserDialog + + + + 0 + 0 + 515 + 553 + + + + Netlist Database Browser + + + + 6 + + + 9 + + + 9 + + + 9 + + + 9 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 6 + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 1 + 0 + + + + QComboBox::AdjustToContentsOnFirstShow + + + + + + + Netlist + + + + + + + ... on layout + + + + + + + + 1 + 0 + + + + QComboBox::AdjustToContentsOnFirstShow + + + + + + + File ... + + + QToolButton::InstantPopup + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + + + + Qt::Horizontal + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 1 + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Choose "Open" from the "File ..." menu +to load a netlist, a net database +or a LVS cross-reference + + + Qt::AlignCenter + + + true + + + + + + + + + + + + + + Qt::Horizontal + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Configure + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Close + + + + + + + + + + + lay::NetlistBrowserPage + QFrame +
layNetlistBrowserPage.h
+ 1 +
+
+ + l2ndb_cb + layout_cb + configure_pb + pushButton_2 + + + + + pushButton_2 + clicked() + NetlistBrowserDialog + accept() + + + 837 + 441 + + + 881 + 387 + + + + +
diff --git a/src/laybasic/laybasic/NetlistBrowserPage.ui b/src/laybasic/laybasic/NetlistBrowserPage.ui new file mode 100644 index 000000000..6d4dff2ca --- /dev/null +++ b/src/laybasic/laybasic/NetlistBrowserPage.ui @@ -0,0 +1,226 @@ + + + NetlistBrowserPage + + + + 0 + 0 + 650 + 570 + + + + Form + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + + 1 + 0 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 6 + + + + + ... + + + + :/down.png:/down.png + + + + + + + ... + + + + :/up.png:/up.png + + + + + + + + 0 + 0 + + + + + 0 + 4 + + + + Qt::ActionsContextMenu + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows + + + true + + + true + + + true + + + + + + + Netlist + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 20 + + + + + + + + Configure filters + + + + + + :/find.png + + + + + + + + 1 + 0 + + + + + 0 + 0 + + + + + + + + + + + + + + + directory_tree + dir_up_pb + dir_down_pb + filter + + + + + + diff --git a/src/laybasic/laybasic/layNetlistBrowser.cc b/src/laybasic/laybasic/layNetlistBrowser.cc new file mode 100644 index 000000000..1afa98b86 --- /dev/null +++ b/src/laybasic/laybasic/layNetlistBrowser.cc @@ -0,0 +1,309 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2019 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 "layNetlistBrowserDialog.h" + +#include "layConverters.h" + +#include + +namespace lay +{ + +// ------------------------------------------------------------ +// Declaration of the configuration options + +std::string cfg_l2n_context_mode ("l2n-context-mode"); +std::string cfg_l2n_show_all ("l2n-show-all"); +std::string cfg_l2n_window_state ("l2n-window-state"); +std::string cfg_l2n_window_mode ("l2n-window-mode"); +std::string cfg_l2n_window_dim ("l2n-window-dim"); +std::string cfg_l2n_max_marker_count ("l2n-max-marker-count"); +std::string cfg_l2n_highlight_color ("l2n-highlight-color"); +std::string cfg_l2n_highlight_line_width ("l2n-highlight-line-width"); +std::string cfg_l2n_highlight_vertex_size ("l2n-highlight-vertex-size"); +std::string cfg_l2n_highlight_halo ("l2n-highlight-halo"); +std::string cfg_l2n_highlight_dither_pattern ("l2n-highlight-dither-pattern"); + +// ------------------------------------------------------------ + +static struct { + lay::NetlistBrowserConfig::net_context_mode_type mode; + const char *string; +} context_modes [] = { + { lay::NetlistBrowserConfig::AnyCell, "any-cell" }, + { lay::NetlistBrowserConfig::NetlistTop, "netlist-top" }, + { lay::NetlistBrowserConfig::Current, "current-cell" }, + { lay::NetlistBrowserConfig::CurrentOrAny, "current-or-any-cell" }, + { lay::NetlistBrowserConfig::Local, "local-cell" }, +}; + +void +NetlistBrowserContextModeConverter::from_string (const std::string &value, lay::NetlistBrowserConfig::net_context_mode_type &mode) +{ + for (unsigned int i = 0; i < sizeof (context_modes) / sizeof (context_modes [0]); ++i) { + if (value == context_modes [i].string) { + mode = context_modes [i].mode; + return; + } + } + throw tl::Exception (tl::to_string (QObject::tr ("Invalid marker database browser context mode: ")) + value); +} + +std::string +NetlistBrowserContextModeConverter::to_string (lay::NetlistBrowserConfig::net_context_mode_type mode) +{ + for (unsigned int i = 0; i < sizeof (context_modes) / sizeof (context_modes [0]); ++i) { + if (mode == context_modes [i].mode) { + return context_modes [i].string; + } + } + return ""; +} + + +// ------------------------------------------------------------ + +static struct { + lay::NetlistBrowserConfig::net_window_type mode; + const char *string; +} window_modes [] = { + { lay::NetlistBrowserConfig::DontChange, "dont-change" }, + { lay::NetlistBrowserConfig::FitCell, "fit-cell" }, + { lay::NetlistBrowserConfig::FitNet, "fit-net" }, + { lay::NetlistBrowserConfig::Center, "center" }, + { lay::NetlistBrowserConfig::CenterSize, "center-size" } +}; + +void +NetlistBrowserWindowModeConverter::from_string (const std::string &value, lay::NetlistBrowserConfig::net_window_type &mode) +{ + for (unsigned int i = 0; i < sizeof (window_modes) / sizeof (window_modes [0]); ++i) { + if (value == window_modes [i].string) { + mode = window_modes [i].mode; + return; + } + } + throw tl::Exception (tl::to_string (QObject::tr ("Invalid marker database browser window mode: ")) + value); +} + +std::string +NetlistBrowserWindowModeConverter::to_string (lay::NetlistBrowserConfig::net_window_type mode) +{ + for (unsigned int i = 0; i < sizeof (window_modes) / sizeof (window_modes [0]); ++i) { + if (mode == window_modes [i].mode) { + return window_modes [i].string; + } + } + return ""; +} + + +// ------------------------------------------------------------ +// Implementation of NetlistBrowserConfigPage + +NetlistBrowserConfigPage::NetlistBrowserConfigPage (QWidget *parent) + : lay::ConfigPage (parent) +{ + Ui::NetlistBrowserConfigPage::setupUi (this); + + connect (cbx_window, SIGNAL (currentIndexChanged (int)), this, SLOT (window_changed (int))); +} + +void +NetlistBrowserConfigPage::setup (lay::PluginRoot *root) +{ + // context mode + lay::NetlistBrowserConfig::net_context_mode_type cmode = lay::NetlistBrowserConfig::NetlistTop; + root->config_get (cfg_l2n_context_mode, cmode, NetlistBrowserContextModeConverter ()); + cbx_context->setCurrentIndex (int (cmode)); + + // window mode + lay::NetlistBrowserConfig::net_window_type wmode = lay::NetlistBrowserConfig::FitNet; + root->config_get (cfg_l2n_window_mode, wmode, NetlistBrowserWindowModeConverter ()); + cbx_window->setCurrentIndex (int (wmode)); + + // window dimension + double wdim = 1.0; + root->config_get (cfg_l2n_window_dim, wdim); + le_window->setText (tl::to_qstring (tl::to_string (wdim))); + + // max. marker count + unsigned int max_marker_count = 1000; + root->config_get (cfg_l2n_max_marker_count, max_marker_count); + le_max_markers->setText (tl::to_qstring (tl::to_string (max_marker_count))); + + // enable controls + window_changed (int (wmode)); +} + +void +NetlistBrowserConfigPage::window_changed (int m) +{ + le_window->setEnabled (m == int (lay::NetlistBrowserConfig::FitNet) || m == int (lay::NetlistBrowserConfig::CenterSize)); +} + +void +NetlistBrowserConfigPage::commit (lay::PluginRoot *root) +{ + double dim = 1.0; + tl::from_string (tl::to_string (le_window->text ()), dim); + + unsigned int max_markers_count = 1000; + tl::from_string (tl::to_string (le_max_markers->text ()), max_markers_count); + + root->config_set (cfg_l2n_context_mode, lay::NetlistBrowserConfig::net_context_mode_type (cbx_context->currentIndex ()), NetlistBrowserContextModeConverter ()); + root->config_set (cfg_l2n_window_mode, lay::NetlistBrowserConfig::net_window_type (cbx_window->currentIndex ()), NetlistBrowserWindowModeConverter ()); + root->config_set (cfg_l2n_window_dim, dim); + root->config_set (cfg_l2n_max_marker_count, max_markers_count); +} + +// ------------------------------------------------------------ +// Implementation of NetlistBrowserConfigPage2 + +NetlistBrowserConfigPage2::NetlistBrowserConfigPage2 (QWidget *parent) + : lay::ConfigPage (parent) +{ + Ui::NetlistBrowserConfigPage2::setupUi (this); +} + +void +NetlistBrowserConfigPage2::setup (lay::PluginRoot *root) +{ + // marker color + QColor color; + root->config_get (cfg_l2n_highlight_color, color, lay::ColorConverter ()); + color_pb->set_color (color); + + // marker line width + int lw = 0; + root->config_get (cfg_l2n_highlight_line_width, lw); + if (lw < 0) { + lw_le->setText (QString ()); + } else { + lw_le->setText (tl::to_qstring (tl::to_string (lw))); + } + + // marker vertex size + int vs = 0; + root->config_get (cfg_l2n_highlight_vertex_size, vs); + if (vs < 0) { + vs_le->setText (QString ()); + } else { + vs_le->setText (tl::to_qstring (tl::to_string (vs))); + } + + // stipple pattern + int dp = 0; + root->config_get (cfg_l2n_highlight_dither_pattern, dp); + stipple_pb->set_dither_pattern (dp); + + // halo + int halo = 0; + root->config_get (cfg_l2n_highlight_halo, halo); + halo_cb->setCheckState (halo < 0 ? Qt::PartiallyChecked : (halo ? Qt::Checked : Qt::Unchecked)); +} + +void +NetlistBrowserConfigPage2::commit (lay::PluginRoot *root) +{ + QColor color (color_pb->get_color ()); + root->config_set (cfg_l2n_highlight_color, color, lay::ColorConverter ()); + + if (lw_le->text ().isEmpty ()) { + root->config_set (cfg_l2n_highlight_line_width, -1); + } else { + try { + int s; + tl::from_string (tl::to_string (lw_le->text ()), s); + root->config_set (cfg_l2n_highlight_line_width, s); + } catch (...) { } + } + + if (vs_le->text ().isEmpty ()) { + root->config_set (cfg_l2n_highlight_vertex_size, -1); + } else { + try { + int s; + tl::from_string (tl::to_string (vs_le->text ()), s); + root->config_set (cfg_l2n_highlight_vertex_size, s); + } catch (...) { } + } + + root->config_set (cfg_l2n_highlight_dither_pattern, stipple_pb->dither_pattern ()); + + if (halo_cb->checkState () == Qt::PartiallyChecked) { + root->config_set (cfg_l2n_highlight_halo, -1); + } else if (halo_cb->checkState () == Qt::Unchecked) { + root->config_set (cfg_l2n_highlight_halo, 0); + } else if (halo_cb->checkState () == Qt::Checked) { + root->config_set (cfg_l2n_highlight_halo, 1); + } +} + +// ------------------------------------------------------------ +// Declaration and implementation of the browser plugin declaration object + +class NetlistBrowserPluginDeclaration + : public lay::PluginDeclaration +{ +public: + virtual void get_options (std::vector < std::pair > &options) const + { + options.push_back (std::pair (cfg_l2n_context_mode, "netlist-top")); + options.push_back (std::pair (cfg_l2n_window_mode, "fit-net")); + options.push_back (std::pair (cfg_l2n_window_state, "")); + options.push_back (std::pair (cfg_l2n_window_dim, "1.0")); + options.push_back (std::pair (cfg_l2n_max_marker_count, "1000")); + options.push_back (std::pair (cfg_l2n_highlight_color, lay::ColorConverter ().to_string (QColor ()))); + options.push_back (std::pair (cfg_l2n_highlight_line_width, "-1")); + options.push_back (std::pair (cfg_l2n_highlight_vertex_size, "-1")); + options.push_back (std::pair (cfg_l2n_highlight_halo, "-1")); + options.push_back (std::pair (cfg_l2n_highlight_dither_pattern, "-1")); + } + + virtual std::vector > config_pages (QWidget *parent) const + { + std::vector > pages; + pages.push_back (std::make_pair (tl::to_string (QObject::tr ("Netlist Browser|Setup")), new NetlistBrowserConfigPage (parent))); + pages.push_back (std::make_pair (tl::to_string (QObject::tr ("Netlist Browser|Net Appearance")), new NetlistBrowserConfigPage2 (parent))); + return pages; + } + + virtual void get_menu_entries (std::vector &menu_entries) const + { + lay::PluginDeclaration::get_menu_entries (menu_entries); + menu_entries.push_back (lay::MenuEntry ("netlist_browser::show", "browse_netlists", "tools_menu.end", tl::to_string (QObject::tr ("Netlist Browser")))); + } + + virtual lay::Plugin *create_plugin (db::Manager *, lay::PluginRoot *root, lay::LayoutView *view) const + { + return new lay::NetlistBrowserDialog (root, view); + } +}; + +static tl::RegisteredClass config_decl (new NetlistBrowserPluginDeclaration (), 12100, "NetlistBrowserPlugin"); + +} + diff --git a/src/laybasic/laybasic/layNetlistBrowser.h b/src/laybasic/laybasic/layNetlistBrowser.h new file mode 100644 index 000000000..10b1372fe --- /dev/null +++ b/src/laybasic/laybasic/layNetlistBrowser.h @@ -0,0 +1,90 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2019 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 + +*/ + + +#ifndef HDR_layNetlistBrowser +#define HDR_layNetlistBrowser + +#include "layPlugin.h" +#include "ui_NetlistBrowserConfigPage.h" +#include "ui_NetlistBrowserConfigPage2.h" + +#include "dbTrans.h" + +#include + +namespace lay +{ + +struct NetlistBrowserConfig +{ + enum net_context_mode_type { AnyCell = 0, NetlistTop, Current, CurrentOrAny, Local }; + enum net_window_type { DontChange = 0, FitCell, FitNet, Center, CenterSize }; +}; + +class NetlistBrowserConfigPage + : public lay::ConfigPage, + private Ui::NetlistBrowserConfigPage +{ + Q_OBJECT + +public: + NetlistBrowserConfigPage (QWidget *parent); + + virtual void setup (lay::PluginRoot *root); + virtual void commit (lay::PluginRoot *root); + +public slots: + void window_changed (int); +}; + +class NetlistBrowserConfigPage2 + : public lay::ConfigPage, + private Ui::NetlistBrowserConfigPage2 +{ + Q_OBJECT + +public: + NetlistBrowserConfigPage2 (QWidget *parent); + + virtual void setup (lay::PluginRoot *root); + virtual void commit (lay::PluginRoot *root); +}; + +class NetlistBrowserContextModeConverter +{ +public: + void from_string (const std::string &value, lay::NetlistBrowserConfig::net_context_mode_type &mode); + std::string to_string (lay::NetlistBrowserConfig::net_context_mode_type mode); +}; + +class NetlistBrowserWindowModeConverter +{ +public: + void from_string (const std::string &value, lay::NetlistBrowserConfig::net_window_type &mode); + std::string to_string (lay::NetlistBrowserConfig::net_window_type mode); +}; + +} + +#endif + diff --git a/src/laybasic/laybasic/layNetlistBrowserDialog.cc b/src/laybasic/laybasic/layNetlistBrowserDialog.cc new file mode 100644 index 000000000..177d40b6f --- /dev/null +++ b/src/laybasic/laybasic/layNetlistBrowserDialog.cc @@ -0,0 +1,628 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2019 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 "layNetlistBrowserDialog.h" +#include "tlProgress.h" +#include "layLayoutView.h" +#include "tlExceptions.h" +#include "layFileDialog.h" +#include "layConverters.h" +#include "layQtTools.h" +#include "layConfigurationDialog.h" +#include "dbLayoutUtils.h" +#include "dbRecursiveShapeIterator.h" + +#include +#include + +#include + +namespace lay +{ + +extern std::string cfg_l2n_context_mode; +extern std::string cfg_l2n_show_all; +extern std::string cfg_l2n_window_state; +extern std::string cfg_l2n_window_mode; +extern std::string cfg_l2n_window_dim; +extern std::string cfg_l2n_max_marker_count; +extern std::string cfg_l2n_highlight_color; +extern std::string cfg_l2n_highlight_line_width; +extern std::string cfg_l2n_highlight_vertex_size; +extern std::string cfg_l2n_highlight_halo; +extern std::string cfg_l2n_highlight_dither_pattern; + +NetlistBrowserDialog::NetlistBrowserDialog (lay::PluginRoot *root, lay::LayoutView *vw) + : lay::Browser (root, vw), + Ui::NetlistBrowserDialog (), + m_context (lay::NetlistBrowserConfig::AnyCell), + m_window (lay::NetlistBrowserConfig::FitNet), + m_window_dim (0.0), + m_max_shape_count (0), + m_marker_line_width (-1), + m_marker_vertex_size (-1), + m_marker_halo (-1), + m_marker_dither_pattern (-1), + m_cv_index (-1), + m_l2n_index (-1) +{ + Ui::NetlistBrowserDialog::setupUi (this); + + browser_frame->set_plugin_root (root); + + if (view ()) { + view ()->cellviews_changed_event.add (this, &NetlistBrowserDialog::cellviews_changed); + view ()->cellview_changed_event.add (this, &NetlistBrowserDialog::cellview_changed); + // @@@view ()->l2n_list_changed_event.add (this, &NetlistBrowserDialog::l2ndbs_changed); + } + + m_open_action = new QAction (QObject::tr ("Open"), file_menu); + m_saveas_action = new QAction (QObject::tr ("Save As"), file_menu); + m_export_action = new QAction (QObject::tr ("Export To Layout"), file_menu); + m_reload_action = new QAction (QObject::tr ("Reload"), file_menu); + m_unload_action = new QAction (QObject::tr ("Unload"), file_menu); + m_unload_all_action = new QAction (QObject::tr ("Unload All"), file_menu); + + connect (m_open_action, SIGNAL (triggered ()), this, SLOT (open_clicked ())); + connect (m_saveas_action, SIGNAL (triggered ()), this, SLOT (saveas_clicked ())); + connect (m_export_action, SIGNAL (triggered ()), this, SLOT (export_clicked ())); + connect (m_reload_action, SIGNAL (triggered ()), this, SLOT (reload_clicked ())); + connect (m_unload_action, SIGNAL (triggered ()), this, SLOT (unload_clicked ())); + connect (m_unload_all_action, SIGNAL (triggered ()), this, SLOT (unload_all_clicked ())); + + file_menu->addAction (m_open_action); + file_menu->addAction (m_saveas_action); + QAction *sep0 = new QAction (file_menu); + sep0->setSeparator (true); + file_menu->addAction (m_export_action); + QAction *sep1 = new QAction (file_menu); + sep1->setSeparator (true); + file_menu->addAction (sep1); + file_menu->addAction (m_reload_action); + QAction *sep2 = new QAction (file_menu); + sep2->setSeparator (true); + file_menu->addAction (sep2); + file_menu->addAction (m_unload_action); + file_menu->addAction (m_unload_all_action); + + connect (layout_cb, SIGNAL (activated (int)), this, SLOT (cv_index_changed (int))); + connect (l2ndb_cb, SIGNAL (activated (int)), this, SLOT (l2ndb_index_changed (int))); + connect (configure_pb, SIGNAL (clicked ()), this, SLOT (configure_clicked ())); + + cellviews_changed (); +} + +NetlistBrowserDialog::~NetlistBrowserDialog () +{ + tl::Object::detach_from_all_events (); +} + +void +NetlistBrowserDialog::configure_clicked () +{ + lay::ConfigurationDialog config_dialog (this, lay::PluginRoot::instance (), "NetlistBrowserPlugin"); + config_dialog.exec (); +} + +void +NetlistBrowserDialog::unload_all_clicked () +{ +BEGIN_PROTECTED + +#if 0 // @@@ + bool modified = false; + for (int i = 0; i < int (view ()->num_rdbs ()); ++i) { + rdb::Database *rdb = view ()->get_rdb (i); + if (rdb && rdb->is_modified ()) { + modified = true; + break; + } + } + + if (modified) { + + QMessageBox msgbox (QMessageBox::Question, QObject::tr ("Unload Without Saving"), + QObject::tr ("At least one database was not saved.\nPress 'Continue' to continue anyway or 'Cancel' for not unloading the database.")); + QPushButton *ok = msgbox.addButton (QObject::tr ("Continue"), QMessageBox::AcceptRole); + msgbox.setDefaultButton (msgbox.addButton (QMessageBox::Cancel)); + + msgbox.exec (); + + if (msgbox.clickedButton () != ok) { + return; + } + + } + + while (view ()->num_rdbs () > 0) { + view ()->remove_rdb (0); + } + + l2ndb_index_changed (-1); +#endif + +END_PROTECTED +} + +void +NetlistBrowserDialog::unload_clicked () +{ +BEGIN_PROTECTED + +#if 0 // @@@ + if (m_l2n_index < int (view ()->num_rdbs ()) && m_l2n_index >= 0) { + + rdb::Database *rdb = view ()->get_rdb (m_l2n_index); + if (rdb && rdb->is_modified ()) { + + QMessageBox msgbox (QMessageBox::Question, QObject::tr ("Unload Without Saving"), + QObject::tr ("The database was not saved.\nPress 'Continue' to continue anyway or 'Cancel' for not unloading the database.")); + QPushButton *ok = msgbox.addButton (QObject::tr ("Continue"), QMessageBox::AcceptRole); + msgbox.setDefaultButton (msgbox.addButton (QMessageBox::Cancel)); + + msgbox.exec (); + + if (msgbox.clickedButton () != ok) { + return; + } + + } + + int new_l2n_index = m_l2n_index; + + view ()->remove_rdb (m_l2n_index); + + // try to use another rbd ... + if (new_l2n_index >= int (view ()->num_rdbs ())) { + --new_l2n_index; + } + if (new_l2n_index < int (view ()->num_rdbs ()) && new_l2n_index >= 0) { + l2ndb_index_changed (new_l2n_index); + } + + } +#endif + +END_PROTECTED +} + +void +NetlistBrowserDialog::export_clicked () +{ +BEGIN_PROTECTED + +#if 0 // @@@ + if (m_l2n_index >= int (view ()->num_rdbs ()) || m_l2n_index < 0) { + return; + } + + const rdb::Database *rdb = view ()->get_rdb (m_l2n_index); + if (! rdb) { + return; + } + + const lay::CellView &cv = view ()->cellview (m_cv_index); + if (! cv.is_valid ()) { + return; + } + + try { + + view ()->manager ()->transaction (tl::to_string (QObject::tr ("Export Net"))); + + // .... + + view ()->manager ()->commit (); + view ()->update_content (); + + } catch (...) { + view ()->manager ()->commit (); + view ()->update_content (); + throw; + } +#endif + +END_PROTECTED +} + +void +NetlistBrowserDialog::saveas_clicked () +{ +BEGIN_PROTECTED + +#if 0 // @@@ + if (m_l2n_index < int (view ()->num_rdbs ()) && m_l2n_index >= 0) { + + rdb::Database *rdb = view ()->get_rdb (m_l2n_index); + if (rdb) { + + // prepare and open the file dialog + lay::FileDialog save_dialog (this, tl::to_string (QObject::tr ("Save Net Database")), "KLayout RDB files (*.lyrdb)"); + std::string fn (rdb->filename ()); + if (save_dialog.get_save (fn)) { + + rdb->save (fn); + rdb->reset_modified (); + + } + + } + + } +#endif + +END_PROTECTED +} + +void +NetlistBrowserDialog::reload_clicked () +{ +BEGIN_PROTECTED + +#if 0 // @@@ + if (m_l2n_index < int (view ()->num_rdbs ()) && m_l2n_index >= 0) { + + rdb::Database *rdb = view ()->get_rdb (m_l2n_index); + if (rdb && ! rdb->filename ().empty ()) { + + browser_frame->set_rdb (0); + rdb->load (rdb->filename ()); + browser_frame->set_rdb (rdb); + + } + + } +#endif + +END_PROTECTED +} + +void +NetlistBrowserDialog::open_clicked () +{ +BEGIN_PROTECTED + +#if 0 // @@@ + // collect the formats available ... + std::string fmts = tl::to_string (QObject::tr ("All files (*)")); + for (tl::Registrar::iterator rdr = tl::Registrar::begin (); rdr != tl::Registrar::end (); ++rdr) { + fmts += ";;" + rdr->file_format (); + } + + // prepare and open the file dialog + lay::FileDialog open_dialog (this, tl::to_string (QObject::tr ("Marker Database File")), fmts); + if (open_dialog.get_open (m_open_filename)) { + + std::auto_ptr db (new rdb::Database ()); + db->load (m_open_filename); + + int l2n_index = view ()->add_rdb (db.release ()); + l2n_cb->setCurrentIndex (l2n_index); + // it looks like the setCurrentIndex does not issue this signal: + l2ndb_index_changed (l2n_index); + + } +#endif + +END_PROTECTED +} + +bool +NetlistBrowserDialog::configure (const std::string &name, const std::string &value) +{ + bool need_update = false; + bool taken = true; + bool show_all = browser_frame->show_all (); + + if (name == cfg_l2n_context_mode) { + + NetlistBrowserConfig::net_context_mode_type context = m_context; + NetlistBrowserContextModeConverter ().from_string (value, context); + need_update = lay::test_and_set (m_context, context); + + } else if (name == cfg_l2n_show_all) { + + tl::from_string (value, show_all); + + } else if (name == cfg_l2n_window_mode) { + + NetlistBrowserConfig::net_window_type window = m_window; + NetlistBrowserWindowModeConverter ().from_string (value, window); + need_update = lay::test_and_set (m_window, window); + + } else if (name == cfg_l2n_window_dim) { + + double wdim = m_window_dim; + tl::from_string (value, wdim); + if (fabs (wdim - m_window_dim) > 1e-6) { + m_window_dim = wdim; + need_update = true; + } + + } else if (name == cfg_l2n_max_marker_count) { + + unsigned int mc = 0; + tl::from_string (value, mc); + need_update = lay::test_and_set (m_max_shape_count, mc); + + } else if (name == cfg_l2n_highlight_color) { + + QColor color; + if (! value.empty ()) { + lay::ColorConverter ().from_string (value, color); + } + + if (color != m_marker_color) { + m_marker_color = color; + need_update = true; + } + + } else if (name == cfg_l2n_highlight_line_width) { + + int lw = 0; + tl::from_string (value, lw); + + if (lw != m_marker_line_width) { + m_marker_line_width = lw; + need_update = true; + } + + } else if (name == cfg_l2n_highlight_vertex_size) { + + int vs = 0; + tl::from_string (value, vs); + + if (vs != m_marker_vertex_size) { + m_marker_vertex_size = vs; + need_update = true; + } + + } else if (name == cfg_l2n_highlight_halo) { + + int halo = 0; + tl::from_string (value, halo); + + if (halo != m_marker_halo) { + m_marker_halo = halo; + need_update = true; + } + + } else if (name == cfg_l2n_highlight_dither_pattern) { + + int dp = 0; + tl::from_string (value, dp); + + if (dp != m_marker_dither_pattern) { + m_marker_dither_pattern = dp; + need_update = true; + } + + } else { + taken = false; + } + + if (active () && need_update) { + browser_frame->set_max_shape_count (m_max_shape_count); + browser_frame->set_window (m_window, m_window_dim, m_context); + browser_frame->set_highlight_style (m_marker_color, m_marker_line_width, m_marker_vertex_size, m_marker_halo, m_marker_dither_pattern); + } + + browser_frame->show_all (show_all); + + return taken; +} + +void +NetlistBrowserDialog::load (int l2n_index, int cv_index) +{ +#if 0 // @@@ TODO: implement + if (! view ()->get_rdb (l2n_index)) { + return; + } + + if (! view ()->cellview (cv_index).is_valid ()) { + m_layout_name = std::string (); + } else { + m_layout_name = view ()->cellview (cv_index)->name (); + } + + // set the new references (by name) + m_l2n_name = view ()->get_rdb (l2n_index)->name (); + + // force an update + rdbs_changed (); + cellviews_changed (); + + activate (); +#endif +} + +void +NetlistBrowserDialog::l2ndbs_changed () +{ +#if 0 // @@@ TODO: implement + int l2n_index = -1; + + l2n_cb->clear (); + + for (unsigned int i = 0; i < view ()->num_rdbs (); ++i) { + const rdb::Database *rdb = view ()->get_rdb (i); + l2n_cb->addItem (tl::to_qstring (rdb->name ())); + if (rdb->name () == m_l2n_name) { + l2n_index = i; + } + } + + // force an update + m_l2n_index = l2n_index; + l2n_cb->setCurrentIndex (l2n_index); + if (active ()) { + update_content (); + } +#endif +} + +void +NetlistBrowserDialog::cellview_changed (int) +{ + browser_frame->update_highlights (); +} + +void +NetlistBrowserDialog::cellviews_changed () +{ + int cv_index = -1; + + layout_cb->clear (); + + for (unsigned int i = 0; i < view ()->cellviews (); ++i) { + const lay::CellView &cv = view ()->cellview (i); + layout_cb->addItem (tl::to_qstring (cv->name ())); + if (cv.is_valid () && cv->name () == m_layout_name) { + cv_index = i; + } + } + + layout_cb->setCurrentIndex (cv_index); + cv_index_changed (cv_index); +} + +void +NetlistBrowserDialog::l2ndb_index_changed (int index) +{ + if (m_l2n_index != index) { + m_l2n_index = index; + if (active ()) { + update_content (); + } + } +} + +void +NetlistBrowserDialog::cv_index_changed (int index) +{ + if (m_cv_index != index) { + m_cv_index = index; + if (active ()) { + update_content (); + } + } +} + +void +NetlistBrowserDialog::activated () +{ +#if 0 // @@@ TODO: implement + std::string state; + if (lay::PluginRoot::instance ()) { + lay::PluginRoot::instance ()->config_get (cfg_l2n_window_state, state); + } + lay::restore_dialog_state (this, state); + + // Switch to the active cellview index when no valid one is set. + lay::CellView cv = view ()->cellview (m_cv_index); + if (! cv.is_valid ()) { + m_cv_index = view ()->active_cellview_index (); + } + + if (m_l2n_index < 0 && view ()->get_rdb (0) != 0) { + + m_l2n_name = view ()->get_rdb (0)->name (); + rdbs_changed (); + + } else { + update_content (); + } +#endif +} + +void +NetlistBrowserDialog::update_content () +{ +#if 0 // @@@ TODO: implement + rdb::Database *rdb = view ()->get_rdb (m_l2n_index); + + if (!rdb ) { + central_stack->setCurrentIndex (1); + } + + m_saveas_action->setEnabled (rdb != 0); + m_export_action->setEnabled (rdb != 0); + m_unload_action->setEnabled (rdb != 0); + m_unload_all_action->setEnabled (rdb != 0); + m_reload_action->setEnabled (rdb != 0); + + browser_frame->enable_updates (false); // Avoid building the internal lists several times ... + browser_frame->set_rdb (rdb); + browser_frame->set_max_marker_count (m_max_marker_count); + browser_frame->set_marker_style (m_marker_color, m_marker_line_width, m_marker_vertex_size, m_marker_halo, m_marker_dither_pattern); + browser_frame->set_window (m_window, m_window_dim, m_context); + browser_frame->set_view (view (), m_cv_index); + browser_frame->enable_updates (true); + + if (rdb) { + // Note: it appears to be required to show the browser page after it has been configured. + // Otherwise the header gets messed up and the configuration is reset. + central_stack->setCurrentIndex (0); + } + + lay::CellView cv = view ()->cellview (m_cv_index); + m_layout_name = std::string (); + if (cv.is_valid ()) { + m_layout_name = cv->name (); + } + + if (layout_cb->currentIndex () != m_cv_index) { + layout_cb->setCurrentIndex (m_cv_index); + } + + if (l2n_cb->currentIndex () != m_l2n_index) { + l2n_cb->setCurrentIndex (m_l2n_index); + } +#endif +} + +void +NetlistBrowserDialog::deactivated () +{ + if (lay::PluginRoot::instance ()) { + lay::PluginRoot::instance ()->config_set (cfg_l2n_window_state, lay::save_dialog_state (this).c_str ()); + } + + // @@@ browser_frame->set_rdb (0); + browser_frame->set_view (0, 0); +} + +void +NetlistBrowserDialog::menu_activated (const std::string &symbol) +{ + if (symbol == "marker_browser::show") { + view ()->deactivate_all_browsers (); + activate (); + } else { + lay::Browser::menu_activated (symbol); + } +} + +} + diff --git a/src/laybasic/laybasic/layNetlistBrowserDialog.h b/src/laybasic/laybasic/layNetlistBrowserDialog.h new file mode 100644 index 000000000..cd46df0b6 --- /dev/null +++ b/src/laybasic/laybasic/layNetlistBrowserDialog.h @@ -0,0 +1,101 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2019 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 + +*/ + + +#ifndef HDR_layNetlistBrowserDialog +#define HDR_layNetlistBrowserDialog + +#include "ui_NetlistBrowserDialog.h" +#include "layBrowser.h" +#include "layNetlistBrowser.h" + +namespace lay +{ + +class NetlistBrowserDialog + : public lay::Browser, + private Ui::NetlistBrowserDialog +{ + Q_OBJECT + +public: + NetlistBrowserDialog (lay::PluginRoot *root, lay::LayoutView *view); + ~NetlistBrowserDialog (); + + void load (int lay_index, int cv_index); + +private: + // implementation of the lay::Browser interface + virtual void activated (); + virtual void deactivated (); + + bool configure (const std::string &name, const std::string &value); + + // implementation of the lay::Plugin interface + virtual void menu_activated (const std::string &symbol); + + void cellviews_changed (); + void cellview_changed (int index); + void l2ndbs_changed (); + +public slots: + void cv_index_changed (int); + void l2ndb_index_changed (int); + void saveas_clicked (); + void export_clicked (); + void reload_clicked (); + void open_clicked (); + void unload_clicked (); + void unload_all_clicked (); + void configure_clicked (); + +private: + lay::NetlistBrowserConfig::net_context_mode_type m_context; + lay::NetlistBrowserConfig::net_window_type m_window; + double m_window_dim; + unsigned int m_max_shape_count; + QColor m_marker_color; + int m_marker_line_width; + int m_marker_vertex_size; + int m_marker_halo; + int m_marker_dither_pattern; + std::string m_layout_name; + int m_cv_index; + std::string m_lay_name; + int m_l2n_index; + std::string m_open_filename; + QAction *m_open_action; + QAction *m_saveas_action; + QAction *m_export_action; + QAction *m_unload_action; + QAction *m_unload_all_action; + QAction *m_reload_action; + + void update_content (); + void scan_layer (); + void scan_layer_flat (); +}; + +} + +#endif + diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc new file mode 100644 index 000000000..c1dab5d06 --- /dev/null +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -0,0 +1,172 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2019 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 "layNetlistBrowserPage.h" + +namespace lay +{ + +extern std::string cfg_l2n_show_all; + +// ---------------------------------------------------------------------------------- +// NetlistBrowserPage implementation + +NetlistBrowserPage::NetlistBrowserPage (QWidget * /*parent*/) + : m_show_all (true), + m_context (lay::NetlistBrowserConfig::NetlistTop), + m_window (lay::NetlistBrowserConfig::FitNet), + m_window_dim (0.0), + m_max_shape_count (1000), + m_marker_line_width (-1), + m_marker_vertex_size (-1), + m_marker_halo (-1), + m_marker_dither_pattern (-1), + mp_view (0), + m_cv_index (0), + mp_plugin_root (0) +{ + Ui::NetlistBrowserPage::setupUi (this); + + m_show_all_action = new QAction (QObject::tr ("Show All"), this); + m_show_all_action->setCheckable (true); + m_show_all_action->setChecked (m_show_all); + + connect (m_show_all_action, SIGNAL (triggered ()), this, SLOT (show_all_clicked ())); + connect (filter, SIGNAL (textEdited (const QString &)), this, SLOT (filter_changed ())); +} + +NetlistBrowserPage::~NetlistBrowserPage () +{ + // @@@ +} + +void +NetlistBrowserPage::set_plugin_root (lay::PluginRoot *pr) +{ + mp_plugin_root = pr; +} + +void +NetlistBrowserPage::set_highlight_style (QColor color, int line_width, int vertex_size, int halo, int dither_pattern) +{ + m_marker_color = color; + m_marker_line_width = line_width; + m_marker_vertex_size = vertex_size; + m_marker_halo = halo; + m_marker_dither_pattern = dither_pattern; + update_highlights (); +} + +void +NetlistBrowserPage::set_view (lay::LayoutView *view, unsigned int cv_index) +{ + mp_view = view; + m_cv_index = cv_index; + update_highlights (); +} + +void +NetlistBrowserPage::set_window (lay::NetlistBrowserConfig::net_window_type window, double window_dim, lay::NetlistBrowserConfig::net_context_mode_type context) +{ + if (window != m_window || window_dim != m_window_dim || context != m_context) { + m_window = window; + m_window_dim = window_dim; + m_context = context; + } +} + +void +NetlistBrowserPage::set_max_shape_count (size_t max_shape_count) +{ + if (m_max_shape_count != max_shape_count) { + m_max_shape_count = max_shape_count; +#if 0 // @@@ + update_marker_list (1 /*select first*/); +#endif + } +} + +void +NetlistBrowserPage::filter_changed () +{ +#if 0 // @@@ + MarkerBrowserTreeViewModel *tree_model = dynamic_cast (directory_tree->model ()); + if (tree_model) { + set_hidden_rec (tree_model, directory_tree, QModelIndex (), m_show_all, cat_filter->text (), cell_filter->text ()); + } + update_highlights (2 /*select all*/); +#endif +} + +void +NetlistBrowserPage::show_all_clicked () +{ + if (mp_plugin_root) { + mp_plugin_root->config_set (cfg_l2n_show_all, tl::to_string (m_show_all_action->isChecked ())); + } +} + +void +NetlistBrowserPage::show_all (bool f) +{ + if (f != m_show_all) { + + m_show_all = f; + m_show_all_action->setChecked (f); + +#if 0 // @@@ + MarkerBrowserTreeViewModel *tree_model = dynamic_cast (directory_tree->model ()); + if (tree_model) { + set_hidden_rec (tree_model, directory_tree, QModelIndex (), m_show_all, cat_filter->text (), cell_filter->text ()); + } +#endif + + } +} + +void +NetlistBrowserPage::update_highlights () +{ +#if 0 + if (! m_enable_updates) { + m_update_needed = true; + return; + } + + if (m_recursion_sentinel) { + return; + } + + m_recursion_sentinel = true; + try { + do_update_markers (); + } catch (...) { + m_recursion_sentinel = false; + throw; + } + m_recursion_sentinel = false; +#endif +} + +} + diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.h b/src/laybasic/laybasic/layNetlistBrowserPage.h new file mode 100644 index 000000000..4bf02c324 --- /dev/null +++ b/src/laybasic/laybasic/layNetlistBrowserPage.h @@ -0,0 +1,149 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2019 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 + +*/ + + +#ifndef HDR_layNetlistBrowserPage +#define HDR_layNetlistBrowserPage + +#include "ui_NetlistBrowserPage.h" +#include "layNetlistBrowser.h" +#include "dbBox.h" + +#include + +class QAction; + +namespace lay +{ + class LayoutView; + class DMarker; + class PluginRoot; +} + +namespace lay +{ + +class Database; + +/** + * @brief A marker browser page + */ +class NetlistBrowserPage + : public QFrame, + public Ui::NetlistBrowserPage +{ +Q_OBJECT + +public: + /** + * @brief Constructor + */ + NetlistBrowserPage (QWidget *parent); + + /** + * @brief Destructor + */ + ~NetlistBrowserPage (); + + /** + * @brief Sets the plugin root object for this object + */ + void set_plugin_root (lay::PluginRoot *pr); + + /** + * @brief Attaches the page to a view + * + * This method can be given a layout view object. + * If that pointer is non-null, the browser will attach itself to + * the view and provide highlights for the selected markers inside the given cellview. + */ + void set_view (lay::LayoutView *view, unsigned int cv_index); + + /** + * @brief Set the window type and window dimensions + */ + void set_window (lay::NetlistBrowserConfig::net_window_type window_type, double window_dim, lay::NetlistBrowserConfig::net_context_mode_type context); + + /** + * @brief Update the net highlights + * + * This method should be called if the cellview has changed so the highlights can + * be recomputed and shown in the new cell context. + */ + void update_highlights (); + + /** + * @brief Set the maximum number of shapes highlighted for a net + */ + void set_max_shape_count (size_t max_shape_count); + + /** + * @brief Set the highlight style + * + * @param color The color or an invalid color to take the default color for selection + * @param line_width The line width or negative for the default line width + * @param vertex_size The vertex size or negative for the default vertex size + * @param halo The halo flag or -1 for default + * @param dither_pattern The dither pattern index of -1 to take the default + */ + void set_highlight_style (QColor color, int line_width, int vertex_size, int halo, int dither_pattern); + + /** + * @brief Gets a value indicating whether all items in the netlist tree are shown (specifically for cross-reference DBs) + */ + bool show_all () const + { + return m_show_all; + } + + /** + * @brief Sets a value indicating whether all items in the netlist tree are shown (specifically for cross-reference DBs) + * + * If this property is set to false, only cross-reference entries with error are shown. + */ + void show_all (bool f); + +private slots: + void show_all_clicked (); + void filter_changed (); + +private: + bool m_show_all; + QAction *m_show_all_action; + NetlistBrowserConfig::net_context_mode_type m_context; + NetlistBrowserConfig::net_window_type m_window; + double m_window_dim; + size_t m_max_shape_count; + QColor m_marker_color; + int m_marker_line_width; + int m_marker_vertex_size; + int m_marker_halo; + int m_marker_dither_pattern; + lay::LayoutView *mp_view; + unsigned int m_cv_index; + lay::PluginRoot *mp_plugin_root; +}; + +} // namespace lay + +#endif + diff --git a/src/laybasic/laybasic/laybasic.pro b/src/laybasic/laybasic/laybasic.pro index 316d434e8..a76210d9a 100644 --- a/src/laybasic/laybasic/laybasic.pro +++ b/src/laybasic/laybasic/laybasic.pro @@ -65,7 +65,11 @@ FORMS = \ SpecificLoadLayoutOptionsDialog.ui \ SelectLineStyleForm.ui \ LayoutViewConfigPage6a.ui \ - EditLineStylesForm.ui + EditLineStylesForm.ui \ + NetlistBrowserPage.ui \ + NetlistBrowserConfigPage.ui \ + NetlistBrowserConfigPage2.ui \ + NetlistBrowserDialog.ui RESOURCES = \ @@ -159,6 +163,9 @@ SOURCES = \ layEditLineStylesForm.cc \ layEditLineStyleWidget.cc \ layBackgroundAwareTreeStyle.cc \ + layNetlistBrowser.cc \ + layNetlistBrowserDialog.cc \ + layNetlistBrowserPage.cc HEADERS = \ gtf.h \ @@ -244,7 +251,10 @@ HEADERS = \ layEditLineStyleWidget.h \ laybasicCommon.h \ laybasicConfig.h \ - layBackgroundAwareTreeStyle.h + layBackgroundAwareTreeStyle.h \ + layNetlistBrowser.h \ + layNetlistBrowserDialog.h \ + layNetlistBrowserPage.h INCLUDEPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC DEPENDPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC diff --git a/src/laybasic/laybasic/rdbMarkerBrowserPage.h b/src/laybasic/laybasic/rdbMarkerBrowserPage.h index 982395720..66cd279a9 100644 --- a/src/laybasic/laybasic/rdbMarkerBrowserPage.h +++ b/src/laybasic/laybasic/rdbMarkerBrowserPage.h @@ -69,7 +69,7 @@ public: */ void set_plugin_root (lay::PluginRoot *pr); - /* + /** * @brief Attach the page to a view * * This method can be given a layout view object. From 20b984cc50dc596db98b07c6b5a3a1d07681bda0 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 20 Apr 2019 20:30:12 +0200 Subject: [PATCH 003/229] Naming of layers isn't required anymore for connect et al: names are given automatically now. --- src/db/db/dbLayoutToNetlist.cc | 59 ++++- src/db/db/dbLayoutToNetlist.h | 95 +++++++- src/db/db/dbLayoutToNetlistWriter.cc | 22 +- src/db/db/dbLayoutToNetlistWriter.h | 15 +- src/db/db/gsiDeclDbLayoutToNetlist.cc | 52 +++-- src/laybasic/laybasic/gsiDeclLayLayoutView.cc | 50 ++++ src/laybasic/laybasic/layLayoutView.cc | 85 ++++++- src/laybasic/laybasic/layLayoutView.h | 59 ++++- src/laybasic/laybasic/layNetlistBrowser.cc | 86 +++---- .../laybasic/layNetlistBrowserDialog.cc | 214 +++++++----------- .../laybasic/layNetlistBrowserDialog.h | 2 +- .../laybasic/layNetlistBrowserPage.cc | 67 +++++- src/laybasic/laybasic/layNetlistBrowserPage.h | 22 +- 13 files changed, 592 insertions(+), 236 deletions(-) diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index b9bb376ca..34d23c88e 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -26,6 +26,8 @@ #include "dbDeepRegion.h" #include "dbShapeRepository.h" #include "dbCellMapping.h" +#include "dbLayoutToNetlistWriter.h" +#include "dbLayoutToNetlistReader.h" namespace db { @@ -155,7 +157,9 @@ db::Region *LayoutToNetlist::make_text_layer (unsigned int layer_index, const st si.shape_flags (db::ShapeIterator::Texts); std::auto_ptr region (new db::Region (si, dss ())); - register_layer (*region, n); + if (! n.empty ()) { + register_layer (*region, n); + } return region.release (); } @@ -166,7 +170,9 @@ db::Region *LayoutToNetlist::make_polygon_layer (unsigned int layer_index, const si.shape_flags (db::ShapeIterator::Paths | db::ShapeIterator::Polygons | db::ShapeIterator::Boxes); std::auto_ptr region (new db::Region (si, dss ())); - register_layer (*region, n); + if (! n.empty ()) { + register_layer (*region, n); + } return region.release (); } @@ -188,7 +194,7 @@ void LayoutToNetlist::connect (const db::Region &l) } if (! is_persisted (l)) { - throw (tl::Exception (tl::to_string (tr ("Only named layers can be used in intra-layer connectivity for netlist extraction")))); + register_layer (l, make_new_name ()); } // we need to keep a reference, so we can safely delete the region @@ -204,10 +210,10 @@ void LayoutToNetlist::connect (const db::Region &a, const db::Region &b) throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted"))); } if (! is_persisted (a)) { - throw (tl::Exception (tl::to_string (tr ("Only named layers can be used in inter-layer connectivity (first layer) for netlist extraction")))); + register_layer (a, make_new_name ()); } if (! is_persisted (b)) { - throw (tl::Exception (tl::to_string (tr ("Only named layers can be used in inter-layer connectivity (second layer) for netlist extraction")))); + register_layer (b, make_new_name ()); } // we need to keep a reference, so we can safely delete the region @@ -225,7 +231,7 @@ size_t LayoutToNetlist::connect_global (const db::Region &l, const std::string & throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted"))); } if (! is_persisted (l)) { - throw (tl::Exception (tl::to_string (tr ("Only named layers can be used in global connectivity for netlist extraction")))); + register_layer (l, make_new_name ()); } // we need to keep a reference, so we can safely delete the region @@ -343,6 +349,29 @@ void LayoutToNetlist::register_layer (const db::Region ®ion, const std::strin m_name_of_layer [dl.layer ()] = n; } +std::string LayoutToNetlist::make_new_name (const std::string &stem) +{ + int m = std::numeric_limits::max () / 2 + 1; + int n = m; + + std::string name; + while (m > 0) { + + m /= 2; + + name = stem; + name += std::string ("$"); + name += tl::to_string (n - m); + + if (m_named_regions.find (name) == m_named_regions.end ()) { + n -= m; + } + + } + + return name; +} + std::string LayoutToNetlist::name (const db::Region ®ion) const { std::map::const_iterator n = m_name_of_layer.find (layer_of (region)); @@ -939,4 +968,22 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, const db::Reg return db::Region (new db::DeepRegion (dl)); } + +void db::LayoutToNetlist::save (const std::string &path, bool short_format) +{ + tl::OutputStream stream (path); + db::LayoutToNetlistStandardWriter writer (stream, short_format); + set_filename (path); + writer.write (this); +} + +void db::LayoutToNetlist::load (const std::string &path) +{ + tl::InputStream stream (path); + db::LayoutToNetlistStandardReader reader (stream); + set_filename (path); + set_name (stream.filename ()); + reader.read (this); +} + } diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 5003deb03..53c048c15 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -114,6 +114,73 @@ public: */ ~LayoutToNetlist (); + /** + * @brief Gets the database description + */ + const std::string &description () const + { + return m_description; + } + + /** + * @brief Sets the database description + */ + void set_description (const std::string &description) + { + m_description = description; + } + + /** + * @brief Gets the original file + * + * The original file describes what original file the netlist database + * was derived from. + */ + const std::string &original_file () const + { + return m_original_file; + } + + /** + * @brief Sets the database original file + */ + void set_original_file (const std::string &original_file) + { + m_original_file = original_file; + } + + /** + * @brief Gets the database name + */ + const std::string &name () const + { + return m_name; + } + + /** + * @brief Sets the database name + */ + void set_name (const std::string &name) + { + m_name = name; + } + + /** + * @brief Gets the file name + */ + const std::string &filename () const + { + return m_filename; + } + + /** + * @brief Sets the file name + */ + void set_filename (const std::string &filename) + { + m_filename = filename; + } + /** * @brief Sets the number of threads to use for operations which support multiple threads */ @@ -154,8 +221,7 @@ public: * (see below) enhances readability of backannotated information * if layers are involved. Use this method to attach a name to a region * derived by boolean operations for example. - * Named regions are persisted inside the LayoutToNetlist object. Only - * named regions can be put into "connect". + * Named regions are persisted inside the LayoutToNetlist object. */ void register_layer (const db::Region ®ion, const std::string &name); @@ -264,21 +330,18 @@ public: * a derived layer. Certain limitations apply. It's safe to use * boolean operations for deriving layers. Other operations are applicable as long as they are * capable of delivering hierarchical layers. - * Regions put into "connect" need to be named. */ void connect (const db::Region &l); /** * @brief Defines an inter-layer connection for the given layers. * The conditions mentioned with intra-layer "connect" apply for this method too. - * Regions put into "connect" need to be named. */ void connect (const db::Region &a, const db::Region &b); /** * @brief Connects the given layer with a global net with the given name * Returns the global net ID - * Regions put into "connect" need to be named. */ size_t connect_global (const db::Region &l, const std::string &gn); @@ -531,11 +594,32 @@ public: */ db::Region antenna_check (const db::Region &gate, const db::Region &metal, double ratio, const std::vector > &diodes = std::vector > ()); + /** + * @brief Saves the database to the given path + * + * Currently, the internal format will be used. If "short_format" is true, the short version + * of the format is used. + * + * This is a convenience method. The low-level functionality is the LayoutToNetlistWriter. + */ + void save (const std::string &path, bool short_format); + + /** + * @brief Loads the database from the given path + * + * This is a convenience method. The low-level functionality is the LayoutToNetlistReader. + */ + void load (const std::string &path); + private: // no copying LayoutToNetlist (const db::LayoutToNetlist &other); LayoutToNetlist &operator= (const db::LayoutToNetlist &other); + std::string m_description; + std::string m_name; + std::string m_original_file; + std::string m_filename; db::RecursiveShapeIterator m_iter; std::auto_ptr mp_internal_dss; tl::weak_ptr mp_dss; @@ -556,6 +640,7 @@ private: void build_net_rec (db::cell_index_type ci, size_t cid, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const Net *net, const char *net_cell_name_prefix, const char *cell_name_prefix, const char *device_cell_name_prefix, std::map, db::cell_index_type> &cmap, const ICplxTrans &tr) const; db::DeepLayer deep_layer_of (const db::Region ®ion) const; void ensure_layout () const; + std::string make_new_name (const std::string &stem = std::string ()); }; } diff --git a/src/db/db/dbLayoutToNetlistWriter.cc b/src/db/db/dbLayoutToNetlistWriter.cc index 9508c2fb8..b26a0fa51 100644 --- a/src/db/db/dbLayoutToNetlistWriter.cc +++ b/src/db/db/dbLayoutToNetlistWriter.cc @@ -27,6 +27,26 @@ namespace db { +// ------------------------------------------------------------------------------------------- +// LayoutToNetlistWriterBase implementation + +LayoutToNetlistWriterBase::LayoutToNetlistWriterBase () +{ + // .. nothing yet .. +} + +LayoutToNetlistWriterBase::~LayoutToNetlistWriterBase () +{ + // .. nothing yet .. +} + +void LayoutToNetlistWriterBase::write (const db::LayoutToNetlist *l2n) +{ + do_write (l2n); +} + +// ------------------------------------------------------------------------------------------- + namespace l2n_std_format { @@ -464,7 +484,7 @@ LayoutToNetlistStandardWriter::LayoutToNetlistStandardWriter (tl::OutputStream & // .. nothing yet .. } -void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n) +void LayoutToNetlistStandardWriter::do_write (const db::LayoutToNetlist *l2n) { if (m_short_version) { l2n_std_format::std_writer_impl > writer (*mp_stream); diff --git a/src/db/db/dbLayoutToNetlistWriter.h b/src/db/db/dbLayoutToNetlistWriter.h index 117cf62a3..b8f08a844 100644 --- a/src/db/db/dbLayoutToNetlistWriter.h +++ b/src/db/db/dbLayoutToNetlistWriter.h @@ -37,10 +37,16 @@ class LayoutToNetlist; class DB_PUBLIC LayoutToNetlistWriterBase { public: - LayoutToNetlistWriterBase () { } - virtual ~LayoutToNetlistWriterBase () { } + LayoutToNetlistWriterBase (); + virtual ~LayoutToNetlistWriterBase (); - virtual void write (const db::LayoutToNetlist *l2n) = 0; + void write (const db::LayoutToNetlist *l2n); + +protected: + virtual void do_write (const db::LayoutToNetlist *l2n) = 0; + +private: + std::string m_filename; }; /** @@ -52,7 +58,8 @@ class DB_PUBLIC LayoutToNetlistStandardWriter public: LayoutToNetlistStandardWriter (tl::OutputStream &stream, bool short_version); - void write (const db::LayoutToNetlist *l2n); +protected: + void do_write (const db::LayoutToNetlist *l2n); private: tl::OutputStream *mp_stream; diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index 070980970..4ad93e599 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -22,8 +22,6 @@ #include "gsiDecl.h" #include "dbLayoutToNetlist.h" -#include "dbLayoutToNetlistWriter.h" -#include "dbLayoutToNetlistReader.h" #include "tlStream.h" #include "tlVariant.h" @@ -82,20 +80,6 @@ static void build_all_nets (const db::LayoutToNetlist *l2n, const db::CellMappin l2n->build_all_nets (cmap, target, lmap, net_cell_name_prefix.is_nil () ? 0 : np.c_str (), circuit_cell_name_prefix.is_nil () ? 0 : cp.c_str (), device_cell_name_prefix.is_nil () ? 0 : dp.c_str ()); } -static void write_l2n (const db::LayoutToNetlist *l2n, const std::string &path, bool short_format) -{ - tl::OutputStream stream (path); - db::LayoutToNetlistStandardWriter writer (stream, short_format); - writer.write (l2n); -} - -static void read_l2n (db::LayoutToNetlist *l2n, const std::string &path) -{ - tl::InputStream stream (path); - db::LayoutToNetlistStandardReader reader (stream); - reader.read (l2n); -} - static std::vector l2n_layer_names (const db::LayoutToNetlist *l2n) { std::vector ln; @@ -197,11 +181,34 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", gsi::method ("max_vertex_count", &db::LayoutToNetlist::max_vertex_count, "See \\max_vertex_count= for details about this attribute." ) + + gsi::method ("name", (const std::string &(db::LayoutToNetlist::*) () const) &db::LayoutToNetlist::name, + "@brief Gets the name of the database\n" + ) + + gsi::method ("name=", &db::LayoutToNetlist::set_name, + "@brief Sets the name of the database\n" + ) + + gsi::method ("description", (const std::string &(db::LayoutToNetlist::*) () const) &db::LayoutToNetlist::name, + "@brief Gets the description of the database\n" + ) + + gsi::method ("description=", &db::LayoutToNetlist::set_name, + "@brief Sets the description of the database\n" + ) + + gsi::method ("filename", &db::LayoutToNetlist::filename, + "@brief Gets the file name of the database\n" + "The filename is the name under which the database is stored or empty if it is not associated with a file." + ) + + gsi::method ("original_file", &db::LayoutToNetlist::original_file, + "@brief Gets the original file name of the database\n" + "The original filename is the layout file from which the netlist DB was created." + ) + + gsi::method ("original_file=", &db::LayoutToNetlist::set_original_file, + "@brief Sets the original file name of the database\n" + ) + gsi::method ("name", (std::string (db::LayoutToNetlist::*) (const db::Region ®ion) const) &db::LayoutToNetlist::name, gsi::arg ("l"), - "@brief Get the name of the given layer\n" + "@brief Gets the name of the given layer\n" ) + gsi::method ("name", (std::string (db::LayoutToNetlist::*) (unsigned int) const) &db::LayoutToNetlist::name, gsi::arg ("l"), - "@brief Get the name of the given layer (by index)\n" + "@brief Gets the name of the given layer (by index)\n" ) + gsi::method ("register", (void (db::LayoutToNetlist::*) (const db::Region ®ion, const std::string &)) &db::LayoutToNetlist::register_layer, gsi::arg ("l"), gsi::arg ("n"), "@brief Names the given layer\n" @@ -210,8 +217,9 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "\n" "Naming a layer allows the system to indicate the layer in various contexts, i.e. " "when writing the data to a file. Named layers are also persisted inside the LayoutToNetlist object. " - "They are not discarded when the Region object is destroyed. Only named layers can be put into " - "\\connect.\n" + "They are not discarded when the Region object is destroyed.\n" + "\n" + "If required, the system will assign a name automatically." ) + gsi::method_ext ("layer_names", &l2n_layer_names, "@brief Returns a list of names of the layer kept inside the LayoutToNetlist object." @@ -425,11 +433,11 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "This variant accepts a database-unit location. The location is given in the\n" "coordinate space of the initial cell.\n" ) + - gsi::method_ext ("write", &write_l2n, gsi::arg ("path"), gsi::arg ("short_format", false), + gsi::method ("write", &db::LayoutToNetlist::save, gsi::arg ("path"), gsi::arg ("short_format", false), "@brief Writes the extracted netlist to a file.\n" "This method employs the native format of KLayout.\n" ) + - gsi::method_ext ("read", &read_l2n, gsi::arg ("path"), + gsi::method ("read", &db::LayoutToNetlist::load, gsi::arg ("path"), "@brief Reads the extracted netlist from the file.\n" "This method employs the native format of KLayout.\n" ) + diff --git a/src/laybasic/laybasic/gsiDeclLayLayoutView.cc b/src/laybasic/laybasic/gsiDeclLayLayoutView.cc index 77ae960f4..f4093f94c 100644 --- a/src/laybasic/laybasic/gsiDeclLayLayoutView.cc +++ b/src/laybasic/laybasic/gsiDeclLayLayoutView.cc @@ -28,6 +28,7 @@ #include "layDitherPattern.h" #include "layLineStyles.h" #include "dbSaveLayoutOptions.h" +#include "dbLayoutToNetlist.h" #include "tlStream.h" #if defined(HAVE_QTBINDINGS) @@ -196,6 +197,13 @@ static unsigned int create_rdb (lay::LayoutView *view, const std::string &name) return view->add_rdb (db); } +static unsigned int create_l2ndb (lay::LayoutView *view, const std::string &name) +{ + db::LayoutToNetlist *db = new db::LayoutToNetlist (); + db->set_name (name); + return view->add_l2ndb (db); +} + // this binding returns a const pointer which is not converted into a copy by RBA static lay::LayerPropertiesNodeRef insert_layer1 (lay::LayoutView *view, const lay::LayerPropertiesConstIterator &iter, const lay::LayerProperties &props) { @@ -1427,6 +1435,48 @@ Class decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou "The marker browser is opened showing the report database with the index given by \"rdb_index\".\n" "It will be attached (i.e. navigate to) the layout with the given cellview index in \"cv_index\".\n" ) + + gsi::event ("on_l2ndb_list_changed", &lay::LayoutView::l2ndb_list_changed_event, + "@brief An event that is triggered the list of netlist databases is changed\n" + "\n" + "If a netlist database is added or removed, this event is triggered.\n" + "\n" + "This method has been added in version 0.26." + ) + + gsi::method ("num_l2ndbs", &lay::LayoutView::num_l2ndbs, + "@brief Gets the number of netlist databases loaded into this view\n" + "@return The number of \\LayoutToNetlist objects present in this view\n" + "\n" + "This method has been added in version 0.26." + ) + + gsi::method ("remove_l2ndb", &lay::LayoutView::remove_l2ndb, gsi::arg ("index"), + "@brief Removes a netlist database with the given index\n" + "@param The index of the netlist database to remove from this view" + "\n" + "This method has been added in version 0.26." + ) + + gsi::method ("l2ndb", (db::LayoutToNetlist *(lay::LayoutView::*) (int index)) &lay::LayoutView::get_l2ndb, gsi::arg ("index"), + "@brief Gets the netlist database with the given index\n" + "@return The \\LayoutToNetlist object or nil if the index is not valid" + "\n" + "This method has been added in version 0.26." + ) + + gsi::method_ext ("create_l2ndb", &create_l2ndb, gsi::arg ("name"), + "@brief Creates a new netlist database and returns the index of the new database\n" + "@param name The name of the new netlist database\n" + "@return The index of the new database\n" + "This method returns an index of the new netlist database. Use \\l2ndb to get the actual object. " + "If a netlist database with the given name already exists, a unique name will be created.\n" + "The name will be replaced by the file name when a file is loaded into the netlist database.\n" + "\n" + "This method has been added in version 0.26." + ) + + gsi::method ("show_l2ndb", &lay::LayoutView::open_l2ndb_browser, gsi::arg ("l2ndb_index"), gsi::arg ("cv_index"), + "@brief Shows a netlist database in the marker browser on a certain layout\n" + "The netlist browser is opened showing the netlist database with the index given by \"l2ndb_index\".\n" + "It will be attached (i.e. navigate to) the layout with the given cellview index in \"cv_index\".\n" + "\n" + "This method has been added in version 0.26." + ) + // HINT: the cast is important to direct GSI to the LayoutView method rather than the // Plugin method (in which case we get a segmentation violation ..) // TODO: this method belongs to the Plugin interface and should be located there. diff --git a/src/laybasic/laybasic/layLayoutView.cc b/src/laybasic/laybasic/layLayoutView.cc index 9f6b1513a..92b128231 100644 --- a/src/laybasic/laybasic/layLayoutView.cc +++ b/src/laybasic/laybasic/layLayoutView.cc @@ -66,6 +66,7 @@ #include "layRedrawThreadWorker.h" #include "layParsedLayerSource.h" #include "layBookmarkManagementForm.h" +#include "layNetlistBrowserDialog.h" #include "dbLayout.h" #include "dbLayoutUtils.h" #include "dbRecursiveShapeIterator.h" @@ -73,6 +74,7 @@ #include "dbEdgeProcessor.h" #include "rdb.h" #include "rdbMarkerBrowserDialog.h" +#include "dbLayoutToNetlist.h" #include "tlXMLParser.h" #include "gsi.h" #include "gtf.h" @@ -568,6 +570,7 @@ LayoutView::~LayoutView () cellviews_changed_event.clear (); cellview_changed_event.clear (); rdb_list_changed_event.clear (); + l2ndb_list_changed_event.clear (); file_open_event.clear (); hier_changed_event.clear (); geom_changed_event.clear (); @@ -581,6 +584,11 @@ LayoutView::~LayoutView () remove_rdb (0); } + // remove all L2N DB's + while (num_l2ndbs () > 0) { + remove_l2ndb (0); + } + // delete layer lists std::vector layer_properties_lists; layer_properties_lists.swap (m_layer_properties_lists); @@ -7074,19 +7082,17 @@ LayoutView::cm_clear_layer () } } -unsigned int -LayoutView::add_rdb (rdb::Database *rdb) +template +static void make_unique_name (T *object, Iter from, Iter to) { - // make the name unique - - std::string n (rdb->name ()); + std::string n (object->name ()); int nn = 0; do { bool found = false; - for (unsigned int i = 0; i < num_rdbs () && !found; ++i) { - if (get_rdb (i)->name () == n) { + for (Iter i = from; i != to && !found; ++i) { + if ((*i)->name () == n) { found = true; } } @@ -7095,12 +7101,67 @@ LayoutView::add_rdb (rdb::Database *rdb) break; } - n = rdb->name () + tl::sprintf ("[%d]", ++nn); + n = object->name () + tl::sprintf ("[%d]", ++nn); } while (1); - rdb->set_name (n); + object->set_name (n); +} +unsigned int +LayoutView::add_l2ndb (db::LayoutToNetlist *l2ndb) +{ + make_unique_name (l2ndb, m_l2ndbs.begin (), m_l2ndbs.end ()); + m_l2ndbs.push_back (l2ndb); + + l2ndb_list_changed_event (); + + return (unsigned int)(m_l2ndbs.size () - 1); +} + +db::LayoutToNetlist * +LayoutView::get_l2ndb (int index) +{ + if (index >= 0 && index < int (m_l2ndbs.size ())) { + return m_l2ndbs [index]; + } else { + return 0; + } +} + +void +LayoutView::open_l2ndb_browser (int l2ndb_index, int cv_index) +{ + lay::NetlistBrowserDialog *l2ndb_browser = get_plugin (); + if (l2ndb_browser) { + l2ndb_browser->load (l2ndb_index, cv_index); + } +} + +const db::LayoutToNetlist * +LayoutView::get_l2ndb (int index) const +{ + if (index >= 0 && index < int (m_l2ndbs.size ())) { + return m_l2ndbs [index]; + } else { + return 0; + } +} + +void +LayoutView::remove_l2ndb (unsigned int index) +{ + if (index < (unsigned int) (m_l2ndbs.size ())) { + delete m_l2ndbs [index]; + m_l2ndbs.erase (m_l2ndbs.begin () + index); + l2ndb_list_changed_event (); + } +} + +unsigned int +LayoutView::add_rdb (rdb::Database *rdb) +{ + make_unique_name (rdb, m_l2ndbs.begin (), m_l2ndbs.end ()); m_rdbs.push_back (rdb); rdb_list_changed_event (); @@ -7118,7 +7179,7 @@ LayoutView::get_rdb (int index) } } -void +void LayoutView::open_rdb_browser (int rdb_index, int cv_index) { rdb::MarkerBrowserDialog *rdb_browser = get_plugin (); @@ -7137,7 +7198,7 @@ LayoutView::get_rdb (int index) const } } -void +void LayoutView::remove_rdb (unsigned int index) { if (index < (unsigned int) (m_rdbs.size ())) { @@ -7147,7 +7208,7 @@ LayoutView::remove_rdb (unsigned int index) } } -QSize +QSize LayoutView::sizeHint () const { if ((m_options & LV_Naked) != 0) { diff --git a/src/laybasic/laybasic/layLayoutView.h b/src/laybasic/laybasic/layLayoutView.h index 8802dc72d..c2e3caf0b 100644 --- a/src/laybasic/laybasic/layLayoutView.h +++ b/src/laybasic/laybasic/layLayoutView.h @@ -62,6 +62,7 @@ namespace db { class Layout; class Manager; class SaveLayoutOptions; + class LayoutToNetlist; } namespace lay { @@ -2293,7 +2294,7 @@ public: void remove_rdb (unsigned int index); /** - * @brief Get the number of databases + * @brief Get the number of marker databases */ unsigned int num_rdbs () const { @@ -2307,6 +2308,61 @@ public: */ tl::Event rdb_list_changed_event; + /** + * @brief Add a Netlist database + * + * The layout view will become owner of the database. + * + * @param l2ndb The database to add + * @return The index of the database + */ + unsigned int add_l2ndb (db::LayoutToNetlist *l2ndb); + + /** + * @brief Get the netlist database by index + * + * @param index The index of the database + * @return A pointer to the database or 0 if the index was not valid. + */ + db::LayoutToNetlist *get_l2ndb (int index); + + /** + * @brief Get the netlist database by index (const version) + * + * @param index The index of the database + * @return A pointer to the database or 0 if the index was not valid. + */ + const db::LayoutToNetlist *get_l2ndb (int index) const; + + /** + * @brief Open the L2NDB browser for a given database and associated cv index + */ + void open_l2ndb_browser (int l2ndb_index, int cv_index); + + /** + * @brief Remove the netlist database with the given index + * + * This will release the netlist database at the given index. The list + * will be reduced by that element. This means, that the following elements + * will have different indicies. + */ + void remove_l2ndb (unsigned int index); + + /** + * @brief Get the number of netlist databases + */ + unsigned int num_l2ndbs () const + { + return (unsigned int) m_l2ndbs.size (); + } + + /** + * @brief An event signalling a change in the netlist database list + * + * If netlist databases are added or removed, this event is triggered. + */ + tl::Event l2ndb_list_changed_event; + /** * @brief Deliver a size hint (reimplementation of QWidget) */ @@ -2635,6 +2691,7 @@ private: std::vector > m_hidden_cells; std::string m_title; tl::vector m_rdbs; + tl::vector m_l2ndbs; std::string m_def_lyp_file; bool m_add_other_layers; bool m_always_show_source; diff --git a/src/laybasic/laybasic/layNetlistBrowser.cc b/src/laybasic/laybasic/layNetlistBrowser.cc index 1afa98b86..b9f388fc4 100644 --- a/src/laybasic/laybasic/layNetlistBrowser.cc +++ b/src/laybasic/laybasic/layNetlistBrowser.cc @@ -34,17 +34,17 @@ namespace lay // ------------------------------------------------------------ // Declaration of the configuration options -std::string cfg_l2n_context_mode ("l2n-context-mode"); -std::string cfg_l2n_show_all ("l2n-show-all"); -std::string cfg_l2n_window_state ("l2n-window-state"); -std::string cfg_l2n_window_mode ("l2n-window-mode"); -std::string cfg_l2n_window_dim ("l2n-window-dim"); -std::string cfg_l2n_max_marker_count ("l2n-max-marker-count"); -std::string cfg_l2n_highlight_color ("l2n-highlight-color"); -std::string cfg_l2n_highlight_line_width ("l2n-highlight-line-width"); -std::string cfg_l2n_highlight_vertex_size ("l2n-highlight-vertex-size"); -std::string cfg_l2n_highlight_halo ("l2n-highlight-halo"); -std::string cfg_l2n_highlight_dither_pattern ("l2n-highlight-dither-pattern"); +std::string cfg_l2ndb_context_mode ("l2n-context-mode"); +std::string cfg_l2ndb_show_all ("l2n-show-all"); +std::string cfg_l2ndb_window_state ("l2n-window-state"); +std::string cfg_l2ndb_window_mode ("l2n-window-mode"); +std::string cfg_l2ndb_window_dim ("l2n-window-dim"); +std::string cfg_l2ndb_max_marker_count ("l2n-max-marker-count"); +std::string cfg_l2ndb_highlight_color ("l2n-highlight-color"); +std::string cfg_l2ndb_highlight_line_width ("l2n-highlight-line-width"); +std::string cfg_l2ndb_highlight_vertex_size ("l2n-highlight-vertex-size"); +std::string cfg_l2ndb_highlight_halo ("l2n-highlight-halo"); +std::string cfg_l2ndb_highlight_dither_pattern ("l2n-highlight-dither-pattern"); // ------------------------------------------------------------ @@ -136,22 +136,22 @@ NetlistBrowserConfigPage::setup (lay::PluginRoot *root) { // context mode lay::NetlistBrowserConfig::net_context_mode_type cmode = lay::NetlistBrowserConfig::NetlistTop; - root->config_get (cfg_l2n_context_mode, cmode, NetlistBrowserContextModeConverter ()); + root->config_get (cfg_l2ndb_context_mode, cmode, NetlistBrowserContextModeConverter ()); cbx_context->setCurrentIndex (int (cmode)); // window mode lay::NetlistBrowserConfig::net_window_type wmode = lay::NetlistBrowserConfig::FitNet; - root->config_get (cfg_l2n_window_mode, wmode, NetlistBrowserWindowModeConverter ()); + root->config_get (cfg_l2ndb_window_mode, wmode, NetlistBrowserWindowModeConverter ()); cbx_window->setCurrentIndex (int (wmode)); // window dimension double wdim = 1.0; - root->config_get (cfg_l2n_window_dim, wdim); + root->config_get (cfg_l2ndb_window_dim, wdim); le_window->setText (tl::to_qstring (tl::to_string (wdim))); // max. marker count unsigned int max_marker_count = 1000; - root->config_get (cfg_l2n_max_marker_count, max_marker_count); + root->config_get (cfg_l2ndb_max_marker_count, max_marker_count); le_max_markers->setText (tl::to_qstring (tl::to_string (max_marker_count))); // enable controls @@ -173,10 +173,10 @@ NetlistBrowserConfigPage::commit (lay::PluginRoot *root) unsigned int max_markers_count = 1000; tl::from_string (tl::to_string (le_max_markers->text ()), max_markers_count); - root->config_set (cfg_l2n_context_mode, lay::NetlistBrowserConfig::net_context_mode_type (cbx_context->currentIndex ()), NetlistBrowserContextModeConverter ()); - root->config_set (cfg_l2n_window_mode, lay::NetlistBrowserConfig::net_window_type (cbx_window->currentIndex ()), NetlistBrowserWindowModeConverter ()); - root->config_set (cfg_l2n_window_dim, dim); - root->config_set (cfg_l2n_max_marker_count, max_markers_count); + root->config_set (cfg_l2ndb_context_mode, lay::NetlistBrowserConfig::net_context_mode_type (cbx_context->currentIndex ()), NetlistBrowserContextModeConverter ()); + root->config_set (cfg_l2ndb_window_mode, lay::NetlistBrowserConfig::net_window_type (cbx_window->currentIndex ()), NetlistBrowserWindowModeConverter ()); + root->config_set (cfg_l2ndb_window_dim, dim); + root->config_set (cfg_l2ndb_max_marker_count, max_markers_count); } // ------------------------------------------------------------ @@ -193,12 +193,12 @@ NetlistBrowserConfigPage2::setup (lay::PluginRoot *root) { // marker color QColor color; - root->config_get (cfg_l2n_highlight_color, color, lay::ColorConverter ()); + root->config_get (cfg_l2ndb_highlight_color, color, lay::ColorConverter ()); color_pb->set_color (color); // marker line width int lw = 0; - root->config_get (cfg_l2n_highlight_line_width, lw); + root->config_get (cfg_l2ndb_highlight_line_width, lw); if (lw < 0) { lw_le->setText (QString ()); } else { @@ -207,7 +207,7 @@ NetlistBrowserConfigPage2::setup (lay::PluginRoot *root) // marker vertex size int vs = 0; - root->config_get (cfg_l2n_highlight_vertex_size, vs); + root->config_get (cfg_l2ndb_highlight_vertex_size, vs); if (vs < 0) { vs_le->setText (QString ()); } else { @@ -216,12 +216,12 @@ NetlistBrowserConfigPage2::setup (lay::PluginRoot *root) // stipple pattern int dp = 0; - root->config_get (cfg_l2n_highlight_dither_pattern, dp); + root->config_get (cfg_l2ndb_highlight_dither_pattern, dp); stipple_pb->set_dither_pattern (dp); // halo int halo = 0; - root->config_get (cfg_l2n_highlight_halo, halo); + root->config_get (cfg_l2ndb_highlight_halo, halo); halo_cb->setCheckState (halo < 0 ? Qt::PartiallyChecked : (halo ? Qt::Checked : Qt::Unchecked)); } @@ -229,36 +229,36 @@ void NetlistBrowserConfigPage2::commit (lay::PluginRoot *root) { QColor color (color_pb->get_color ()); - root->config_set (cfg_l2n_highlight_color, color, lay::ColorConverter ()); + root->config_set (cfg_l2ndb_highlight_color, color, lay::ColorConverter ()); if (lw_le->text ().isEmpty ()) { - root->config_set (cfg_l2n_highlight_line_width, -1); + root->config_set (cfg_l2ndb_highlight_line_width, -1); } else { try { int s; tl::from_string (tl::to_string (lw_le->text ()), s); - root->config_set (cfg_l2n_highlight_line_width, s); + root->config_set (cfg_l2ndb_highlight_line_width, s); } catch (...) { } } if (vs_le->text ().isEmpty ()) { - root->config_set (cfg_l2n_highlight_vertex_size, -1); + root->config_set (cfg_l2ndb_highlight_vertex_size, -1); } else { try { int s; tl::from_string (tl::to_string (vs_le->text ()), s); - root->config_set (cfg_l2n_highlight_vertex_size, s); + root->config_set (cfg_l2ndb_highlight_vertex_size, s); } catch (...) { } } - root->config_set (cfg_l2n_highlight_dither_pattern, stipple_pb->dither_pattern ()); + root->config_set (cfg_l2ndb_highlight_dither_pattern, stipple_pb->dither_pattern ()); if (halo_cb->checkState () == Qt::PartiallyChecked) { - root->config_set (cfg_l2n_highlight_halo, -1); + root->config_set (cfg_l2ndb_highlight_halo, -1); } else if (halo_cb->checkState () == Qt::Unchecked) { - root->config_set (cfg_l2n_highlight_halo, 0); + root->config_set (cfg_l2ndb_highlight_halo, 0); } else if (halo_cb->checkState () == Qt::Checked) { - root->config_set (cfg_l2n_highlight_halo, 1); + root->config_set (cfg_l2ndb_highlight_halo, 1); } } @@ -271,16 +271,16 @@ class NetlistBrowserPluginDeclaration public: virtual void get_options (std::vector < std::pair > &options) const { - options.push_back (std::pair (cfg_l2n_context_mode, "netlist-top")); - options.push_back (std::pair (cfg_l2n_window_mode, "fit-net")); - options.push_back (std::pair (cfg_l2n_window_state, "")); - options.push_back (std::pair (cfg_l2n_window_dim, "1.0")); - options.push_back (std::pair (cfg_l2n_max_marker_count, "1000")); - options.push_back (std::pair (cfg_l2n_highlight_color, lay::ColorConverter ().to_string (QColor ()))); - options.push_back (std::pair (cfg_l2n_highlight_line_width, "-1")); - options.push_back (std::pair (cfg_l2n_highlight_vertex_size, "-1")); - options.push_back (std::pair (cfg_l2n_highlight_halo, "-1")); - options.push_back (std::pair (cfg_l2n_highlight_dither_pattern, "-1")); + options.push_back (std::pair (cfg_l2ndb_context_mode, "netlist-top")); + options.push_back (std::pair (cfg_l2ndb_window_mode, "fit-net")); + options.push_back (std::pair (cfg_l2ndb_window_state, "")); + options.push_back (std::pair (cfg_l2ndb_window_dim, "1.0")); + options.push_back (std::pair (cfg_l2ndb_max_marker_count, "1000")); + options.push_back (std::pair (cfg_l2ndb_highlight_color, lay::ColorConverter ().to_string (QColor ()))); + options.push_back (std::pair (cfg_l2ndb_highlight_line_width, "-1")); + options.push_back (std::pair (cfg_l2ndb_highlight_vertex_size, "-1")); + options.push_back (std::pair (cfg_l2ndb_highlight_halo, "-1")); + options.push_back (std::pair (cfg_l2ndb_highlight_dither_pattern, "-1")); } virtual std::vector > config_pages (QWidget *parent) const diff --git a/src/laybasic/laybasic/layNetlistBrowserDialog.cc b/src/laybasic/laybasic/layNetlistBrowserDialog.cc index 177d40b6f..65949b6fc 100644 --- a/src/laybasic/laybasic/layNetlistBrowserDialog.cc +++ b/src/laybasic/laybasic/layNetlistBrowserDialog.cc @@ -29,7 +29,7 @@ #include "layConverters.h" #include "layQtTools.h" #include "layConfigurationDialog.h" -#include "dbLayoutUtils.h" +#include "dbLayoutToNetlist.h" #include "dbRecursiveShapeIterator.h" #include @@ -40,17 +40,17 @@ namespace lay { -extern std::string cfg_l2n_context_mode; -extern std::string cfg_l2n_show_all; -extern std::string cfg_l2n_window_state; -extern std::string cfg_l2n_window_mode; -extern std::string cfg_l2n_window_dim; -extern std::string cfg_l2n_max_marker_count; -extern std::string cfg_l2n_highlight_color; -extern std::string cfg_l2n_highlight_line_width; -extern std::string cfg_l2n_highlight_vertex_size; -extern std::string cfg_l2n_highlight_halo; -extern std::string cfg_l2n_highlight_dither_pattern; +extern std::string cfg_l2ndb_context_mode; +extern std::string cfg_l2ndb_show_all; +extern std::string cfg_l2ndb_window_state; +extern std::string cfg_l2ndb_window_mode; +extern std::string cfg_l2ndb_window_dim; +extern std::string cfg_l2ndb_max_marker_count; +extern std::string cfg_l2ndb_highlight_color; +extern std::string cfg_l2ndb_highlight_line_width; +extern std::string cfg_l2ndb_highlight_vertex_size; +extern std::string cfg_l2ndb_highlight_halo; +extern std::string cfg_l2ndb_highlight_dither_pattern; NetlistBrowserDialog::NetlistBrowserDialog (lay::PluginRoot *root, lay::LayoutView *vw) : lay::Browser (root, vw), @@ -73,7 +73,7 @@ NetlistBrowserDialog::NetlistBrowserDialog (lay::PluginRoot *root, lay::LayoutVi if (view ()) { view ()->cellviews_changed_event.add (this, &NetlistBrowserDialog::cellviews_changed); view ()->cellview_changed_event.add (this, &NetlistBrowserDialog::cellview_changed); - // @@@view ()->l2n_list_changed_event.add (this, &NetlistBrowserDialog::l2ndbs_changed); + view ()->l2ndb_list_changed_event.add (this, &NetlistBrowserDialog::l2ndbs_changed); } m_open_action = new QAction (QObject::tr ("Open"), file_menu); @@ -129,37 +129,11 @@ NetlistBrowserDialog::unload_all_clicked () { BEGIN_PROTECTED -#if 0 // @@@ - bool modified = false; - for (int i = 0; i < int (view ()->num_rdbs ()); ++i) { - rdb::Database *rdb = view ()->get_rdb (i); - if (rdb && rdb->is_modified ()) { - modified = true; - break; - } - } - - if (modified) { - - QMessageBox msgbox (QMessageBox::Question, QObject::tr ("Unload Without Saving"), - QObject::tr ("At least one database was not saved.\nPress 'Continue' to continue anyway or 'Cancel' for not unloading the database.")); - QPushButton *ok = msgbox.addButton (QObject::tr ("Continue"), QMessageBox::AcceptRole); - msgbox.setDefaultButton (msgbox.addButton (QMessageBox::Cancel)); - - msgbox.exec (); - - if (msgbox.clickedButton () != ok) { - return; - } - - } - - while (view ()->num_rdbs () > 0) { - view ()->remove_rdb (0); + while (view ()->num_l2ndbs () > 0) { + view ()->remove_l2ndb (0); } l2ndb_index_changed (-1); -#endif END_PROTECTED } @@ -169,39 +143,21 @@ NetlistBrowserDialog::unload_clicked () { BEGIN_PROTECTED -#if 0 // @@@ - if (m_l2n_index < int (view ()->num_rdbs ()) && m_l2n_index >= 0) { - - rdb::Database *rdb = view ()->get_rdb (m_l2n_index); - if (rdb && rdb->is_modified ()) { - - QMessageBox msgbox (QMessageBox::Question, QObject::tr ("Unload Without Saving"), - QObject::tr ("The database was not saved.\nPress 'Continue' to continue anyway or 'Cancel' for not unloading the database.")); - QPushButton *ok = msgbox.addButton (QObject::tr ("Continue"), QMessageBox::AcceptRole); - msgbox.setDefaultButton (msgbox.addButton (QMessageBox::Cancel)); - - msgbox.exec (); - - if (msgbox.clickedButton () != ok) { - return; - } - - } + if (m_l2n_index < int (view ()->num_l2ndbs ()) && m_l2n_index >= 0) { int new_l2n_index = m_l2n_index; - view ()->remove_rdb (m_l2n_index); + view ()->remove_l2ndb (m_l2n_index); // try to use another rbd ... - if (new_l2n_index >= int (view ()->num_rdbs ())) { + if (new_l2n_index >= int (view ()->num_l2ndbs ())) { --new_l2n_index; } - if (new_l2n_index < int (view ()->num_rdbs ()) && new_l2n_index >= 0) { + if (new_l2n_index < int (view ()->num_l2ndbs ()) && new_l2n_index >= 0) { l2ndb_index_changed (new_l2n_index); } } -#endif END_PROTECTED } @@ -250,26 +206,23 @@ NetlistBrowserDialog::saveas_clicked () { BEGIN_PROTECTED -#if 0 // @@@ - if (m_l2n_index < int (view ()->num_rdbs ()) && m_l2n_index >= 0) { + if (m_l2n_index < int (view ()->num_l2ndbs ()) && m_l2n_index >= 0) { - rdb::Database *rdb = view ()->get_rdb (m_l2n_index); - if (rdb) { + db::LayoutToNetlist *l2ndb = view ()->get_l2ndb (m_l2n_index); + if (l2ndb) { // prepare and open the file dialog - lay::FileDialog save_dialog (this, tl::to_string (QObject::tr ("Save Net Database")), "KLayout RDB files (*.lyrdb)"); - std::string fn (rdb->filename ()); + lay::FileDialog save_dialog (this, tl::to_string (QObject::tr ("Save Netlist Database")), "KLayout L2N DB files (*.l2n)"); + std::string fn (l2ndb->filename ()); if (save_dialog.get_save (fn)) { - rdb->save (fn); - rdb->reset_modified (); + l2ndb->save (fn, true); } } } -#endif END_PROTECTED } @@ -279,20 +232,18 @@ NetlistBrowserDialog::reload_clicked () { BEGIN_PROTECTED -#if 0 // @@@ - if (m_l2n_index < int (view ()->num_rdbs ()) && m_l2n_index >= 0) { + if (m_l2n_index < int (view ()->num_l2ndbs ()) && m_l2n_index >= 0) { - rdb::Database *rdb = view ()->get_rdb (m_l2n_index); - if (rdb && ! rdb->filename ().empty ()) { + db::LayoutToNetlist *l2ndb = view ()->get_l2ndb (m_l2n_index); + if (l2ndb && ! l2ndb->filename ().empty ()) { - browser_frame->set_rdb (0); - rdb->load (rdb->filename ()); - browser_frame->set_rdb (rdb); + browser_frame->set_l2ndb (0); + l2ndb->load (l2ndb->filename ()); + browser_frame->set_l2ndb (l2ndb); } } -#endif END_PROTECTED } @@ -302,27 +253,30 @@ NetlistBrowserDialog::open_clicked () { BEGIN_PROTECTED -#if 0 // @@@ - // collect the formats available ... std::string fmts = tl::to_string (QObject::tr ("All files (*)")); +#if 0 // @@@ would be good to have this: + // collect the formats available ... for (tl::Registrar::iterator rdr = tl::Registrar::begin (); rdr != tl::Registrar::end (); ++rdr) { fmts += ";;" + rdr->file_format (); } +#else + fmts += ";;L2N DB files (*.l2n)"; + // @@@ TODO: add plain spice +#endif // prepare and open the file dialog - lay::FileDialog open_dialog (this, tl::to_string (QObject::tr ("Marker Database File")), fmts); + lay::FileDialog open_dialog (this, tl::to_string (QObject::tr ("Netlist Database File")), fmts); if (open_dialog.get_open (m_open_filename)) { - std::auto_ptr db (new rdb::Database ()); + std::auto_ptr db (new db::LayoutToNetlist ()); db->load (m_open_filename); - int l2n_index = view ()->add_rdb (db.release ()); - l2n_cb->setCurrentIndex (l2n_index); + int l2n_index = view ()->add_l2ndb (db.release ()); + l2ndb_cb->setCurrentIndex (l2n_index); // it looks like the setCurrentIndex does not issue this signal: l2ndb_index_changed (l2n_index); } -#endif END_PROTECTED } @@ -334,23 +288,23 @@ NetlistBrowserDialog::configure (const std::string &name, const std::string &val bool taken = true; bool show_all = browser_frame->show_all (); - if (name == cfg_l2n_context_mode) { + if (name == cfg_l2ndb_context_mode) { NetlistBrowserConfig::net_context_mode_type context = m_context; NetlistBrowserContextModeConverter ().from_string (value, context); need_update = lay::test_and_set (m_context, context); - } else if (name == cfg_l2n_show_all) { + } else if (name == cfg_l2ndb_show_all) { tl::from_string (value, show_all); - } else if (name == cfg_l2n_window_mode) { + } else if (name == cfg_l2ndb_window_mode) { NetlistBrowserConfig::net_window_type window = m_window; NetlistBrowserWindowModeConverter ().from_string (value, window); need_update = lay::test_and_set (m_window, window); - } else if (name == cfg_l2n_window_dim) { + } else if (name == cfg_l2ndb_window_dim) { double wdim = m_window_dim; tl::from_string (value, wdim); @@ -359,13 +313,13 @@ NetlistBrowserDialog::configure (const std::string &name, const std::string &val need_update = true; } - } else if (name == cfg_l2n_max_marker_count) { + } else if (name == cfg_l2ndb_max_marker_count) { unsigned int mc = 0; tl::from_string (value, mc); need_update = lay::test_and_set (m_max_shape_count, mc); - } else if (name == cfg_l2n_highlight_color) { + } else if (name == cfg_l2ndb_highlight_color) { QColor color; if (! value.empty ()) { @@ -377,7 +331,7 @@ NetlistBrowserDialog::configure (const std::string &name, const std::string &val need_update = true; } - } else if (name == cfg_l2n_highlight_line_width) { + } else if (name == cfg_l2ndb_highlight_line_width) { int lw = 0; tl::from_string (value, lw); @@ -387,7 +341,7 @@ NetlistBrowserDialog::configure (const std::string &name, const std::string &val need_update = true; } - } else if (name == cfg_l2n_highlight_vertex_size) { + } else if (name == cfg_l2ndb_highlight_vertex_size) { int vs = 0; tl::from_string (value, vs); @@ -397,7 +351,7 @@ NetlistBrowserDialog::configure (const std::string &name, const std::string &val need_update = true; } - } else if (name == cfg_l2n_highlight_halo) { + } else if (name == cfg_l2ndb_highlight_halo) { int halo = 0; tl::from_string (value, halo); @@ -407,7 +361,7 @@ NetlistBrowserDialog::configure (const std::string &name, const std::string &val need_update = true; } - } else if (name == cfg_l2n_highlight_dither_pattern) { + } else if (name == cfg_l2ndb_highlight_dither_pattern) { int dp = 0; tl::from_string (value, dp); @@ -433,10 +387,9 @@ NetlistBrowserDialog::configure (const std::string &name, const std::string &val } void -NetlistBrowserDialog::load (int l2n_index, int cv_index) +NetlistBrowserDialog::load (int l2ndb_index, int cv_index) { -#if 0 // @@@ TODO: implement - if (! view ()->get_rdb (l2n_index)) { + if (! view ()->get_l2ndb (l2ndb_index)) { return; } @@ -447,39 +400,36 @@ NetlistBrowserDialog::load (int l2n_index, int cv_index) } // set the new references (by name) - m_l2n_name = view ()->get_rdb (l2n_index)->name (); + m_l2ndb_name = view ()->get_l2ndb (l2ndb_index)->name (); // force an update - rdbs_changed (); + l2ndbs_changed (); cellviews_changed (); activate (); -#endif } void NetlistBrowserDialog::l2ndbs_changed () { -#if 0 // @@@ TODO: implement int l2n_index = -1; - l2n_cb->clear (); + l2ndb_cb->clear (); - for (unsigned int i = 0; i < view ()->num_rdbs (); ++i) { - const rdb::Database *rdb = view ()->get_rdb (i); - l2n_cb->addItem (tl::to_qstring (rdb->name ())); - if (rdb->name () == m_l2n_name) { + for (unsigned int i = 0; i < view ()->num_l2ndbs (); ++i) { + const db::LayoutToNetlist *l2ndb = view ()->get_l2ndb (i); + l2ndb_cb->addItem (tl::to_qstring (l2ndb->name ())); + if (l2ndb->name () == m_l2ndb_name) { l2n_index = i; } } // force an update m_l2n_index = l2n_index; - l2n_cb->setCurrentIndex (l2n_index); + l2ndb_cb->setCurrentIndex (l2n_index); if (active ()) { update_content (); } -#endif } void @@ -532,10 +482,9 @@ NetlistBrowserDialog::cv_index_changed (int index) void NetlistBrowserDialog::activated () { -#if 0 // @@@ TODO: implement std::string state; if (lay::PluginRoot::instance ()) { - lay::PluginRoot::instance ()->config_get (cfg_l2n_window_state, state); + lay::PluginRoot::instance ()->config_get (cfg_l2ndb_window_state, state); } lay::restore_dialog_state (this, state); @@ -545,42 +494,40 @@ NetlistBrowserDialog::activated () m_cv_index = view ()->active_cellview_index (); } - if (m_l2n_index < 0 && view ()->get_rdb (0) != 0) { + if (m_l2n_index < 0 && view ()->get_l2ndb (0) != 0) { - m_l2n_name = view ()->get_rdb (0)->name (); - rdbs_changed (); + m_l2ndb_name = view ()->get_l2ndb (0)->name (); + l2ndbs_changed (); } else { update_content (); } -#endif } void NetlistBrowserDialog::update_content () { -#if 0 // @@@ TODO: implement - rdb::Database *rdb = view ()->get_rdb (m_l2n_index); + db::LayoutToNetlist *l2ndb = view ()->get_l2ndb (m_l2n_index); - if (!rdb ) { + if (! l2ndb) { central_stack->setCurrentIndex (1); } - m_saveas_action->setEnabled (rdb != 0); - m_export_action->setEnabled (rdb != 0); - m_unload_action->setEnabled (rdb != 0); - m_unload_all_action->setEnabled (rdb != 0); - m_reload_action->setEnabled (rdb != 0); + m_saveas_action->setEnabled (l2ndb != 0); + m_export_action->setEnabled (l2ndb != 0); + m_unload_action->setEnabled (l2ndb != 0); + m_unload_all_action->setEnabled (l2ndb != 0); + m_reload_action->setEnabled (l2ndb != 0); browser_frame->enable_updates (false); // Avoid building the internal lists several times ... - browser_frame->set_rdb (rdb); - browser_frame->set_max_marker_count (m_max_marker_count); - browser_frame->set_marker_style (m_marker_color, m_marker_line_width, m_marker_vertex_size, m_marker_halo, m_marker_dither_pattern); + browser_frame->set_l2ndb (l2ndb); + browser_frame->set_max_shape_count (m_max_shape_count); + browser_frame->set_highlight_style (m_marker_color, m_marker_line_width, m_marker_vertex_size, m_marker_halo, m_marker_dither_pattern); browser_frame->set_window (m_window, m_window_dim, m_context); browser_frame->set_view (view (), m_cv_index); browser_frame->enable_updates (true); - if (rdb) { + if (l2ndb) { // Note: it appears to be required to show the browser page after it has been configured. // Otherwise the header gets messed up and the configuration is reset. central_stack->setCurrentIndex (0); @@ -596,20 +543,19 @@ NetlistBrowserDialog::update_content () layout_cb->setCurrentIndex (m_cv_index); } - if (l2n_cb->currentIndex () != m_l2n_index) { - l2n_cb->setCurrentIndex (m_l2n_index); + if (l2ndb_cb->currentIndex () != m_l2n_index) { + l2ndb_cb->setCurrentIndex (m_l2n_index); } -#endif } void NetlistBrowserDialog::deactivated () { if (lay::PluginRoot::instance ()) { - lay::PluginRoot::instance ()->config_set (cfg_l2n_window_state, lay::save_dialog_state (this).c_str ()); + lay::PluginRoot::instance ()->config_set (cfg_l2ndb_window_state, lay::save_dialog_state (this).c_str ()); } - // @@@ browser_frame->set_rdb (0); + browser_frame->set_l2ndb (0); browser_frame->set_view (0, 0); } diff --git a/src/laybasic/laybasic/layNetlistBrowserDialog.h b/src/laybasic/laybasic/layNetlistBrowserDialog.h index cd46df0b6..1f5e12c19 100644 --- a/src/laybasic/laybasic/layNetlistBrowserDialog.h +++ b/src/laybasic/laybasic/layNetlistBrowserDialog.h @@ -80,7 +80,7 @@ private: int m_marker_dither_pattern; std::string m_layout_name; int m_cv_index; - std::string m_lay_name; + std::string m_l2ndb_name; int m_l2n_index; std::string m_open_filename; QAction *m_open_action; diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index c1dab5d06..9de2c56f4 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -26,7 +26,7 @@ namespace lay { -extern std::string cfg_l2n_show_all; +extern std::string cfg_l2ndb_show_all; // ---------------------------------------------------------------------------------- // NetlistBrowserPage implementation @@ -122,7 +122,7 @@ void NetlistBrowserPage::show_all_clicked () { if (mp_plugin_root) { - mp_plugin_root->config_set (cfg_l2n_show_all, tl::to_string (m_show_all_action->isChecked ())); + mp_plugin_root->config_set (cfg_l2ndb_show_all, tl::to_string (m_show_all_action->isChecked ())); } } @@ -168,5 +168,68 @@ NetlistBrowserPage::update_highlights () #endif } +void +NetlistBrowserPage::set_l2ndb (db::LayoutToNetlist *database) +{ +#if 0 // @@@ + if (database != mp_database) { + + release_markers (); + + mp_database = database; + + QAbstractItemModel *tree_model = directory_tree->model (); + + MarkerBrowserTreeViewModel *new_model = new MarkerBrowserTreeViewModel (); + new_model->set_show_empty_ones (true); + new_model->set_database (database); + directory_tree->setModel (new_model); + connect (directory_tree->selectionModel (), SIGNAL (selectionChanged (const QItemSelection &, const QItemSelection &)), this, SLOT (directory_selection_changed (const QItemSelection &, const QItemSelection &))); + + directory_tree->header ()->setSortIndicatorShown (true); + + cat_filter->setText (QString ()); + cell_filter->setText (QString ()); + set_hidden_rec (new_model, directory_tree, QModelIndex (), m_show_all, QString (), QString ()); + + if (tree_model) { + delete tree_model; + } + + QAbstractItemModel *list_model = markers_list->model (); + + MarkerBrowserListViewModel *new_list_model = new MarkerBrowserListViewModel (); + new_list_model->set_database (database); + markers_list->setModel (new_list_model); + connect (markers_list->selectionModel (), SIGNAL (selectionChanged (const QItemSelection &, const QItemSelection &)), this, SLOT (markers_selection_changed (const QItemSelection &, const QItemSelection &))); + connect (markers_list->selectionModel (), SIGNAL (currentChanged (const QModelIndex &, const QModelIndex &)), this, SLOT (markers_current_changed (const QModelIndex &, const QModelIndex &))); + + if (list_model) { + delete list_model; + } + + } +#endif +} + +void +NetlistBrowserPage::enable_updates (bool f) +{ +#if 0 // @@@ + if (f != m_enable_updates) { + + m_enable_updates = f; + + if (f && m_update_needed) { + update_markers (); + update_info_text (); + } + + m_update_needed = false; + + } +#endif +} + } diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.h b/src/laybasic/laybasic/layNetlistBrowserPage.h index 4bf02c324..083c20929 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.h +++ b/src/laybasic/laybasic/layNetlistBrowserPage.h @@ -32,17 +32,16 @@ class QAction; -namespace lay +namespace db { - class LayoutView; - class DMarker; - class PluginRoot; + class LayoutToNetlist; } namespace lay { -class Database; +class LayoutView; +class PluginRoot; /** * @brief A marker browser page @@ -78,6 +77,14 @@ public: */ void set_view (lay::LayoutView *view, unsigned int cv_index); + /** + * @brief Attach the page to a L2N DB + * + * To detach the page from any L2N DB, pass 0 for the pointer. + */ + void set_l2ndb (db::LayoutToNetlist *database); + + /** * @brief Set the window type and window dimensions */ @@ -122,6 +129,11 @@ public: */ void show_all (bool f); + /** + * @brief Enable or disable updates + */ + void enable_updates (bool f); + private slots: void show_all_clicked (); void filter_changed (); From ae9064021ccd21cc90a361fc3b8b2dad57b62a61 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 21 Apr 2019 10:41:20 +0200 Subject: [PATCH 004/229] WIP: netlist browser. --- src/db/db/dbCircuit.h | 24 + src/db/db/dbNetlist.h | 8 + src/laybasic/laybasic/NetlistBrowserDialog.ui | 3 +- src/laybasic/laybasic/gsiDeclLayLayoutView.cc | 20 + src/laybasic/laybasic/layLayoutView.cc | 8 +- .../laybasic/layNetlistBrowserDialog.cc | 2 +- .../laybasic/layNetlistBrowserPage.cc | 913 ++++++++++++++++++ 7 files changed, 974 insertions(+), 4 deletions(-) diff --git a/src/db/db/dbCircuit.h b/src/db/db/dbCircuit.h index 042a3e144..021b0e97a 100644 --- a/src/db/db/dbCircuit.h +++ b/src/db/db/dbCircuit.h @@ -309,6 +309,14 @@ public: */ void remove_net (Net *net); + /** + * @brief Gets the number of nets + */ + size_t net_count () const + { + return m_nets.size (); + } + /** * @brief Begin iterator for the nets of the circuit (non-const version) */ @@ -393,6 +401,14 @@ public: */ void remove_device (Device *device); + /** + * @brief Gets the number of devices + */ + size_t device_count () const + { + return m_nets.size (); + } + /** * @brief Gets the device from a given ID (const version) * @@ -477,6 +493,14 @@ public: */ void remove_subcircuit (SubCircuit *subcircuit); + /** + * @brief Gets the number of subcircuits + */ + size_t subcircuit_count () const + { + return m_subcircuits.size (); + } + /** * @brief Gets the subcircuit from a given ID (const version) * diff --git a/src/db/db/dbNetlist.h b/src/db/db/dbNetlist.h index 95555d29c..3dd848b86 100644 --- a/src/db/db/dbNetlist.h +++ b/src/db/db/dbNetlist.h @@ -138,6 +138,14 @@ public: */ void remove_circuit (Circuit *circuit); + /** + * @brief Gets the number of circuits + */ + size_t circuit_count () const + { + return m_circuits.size (); + } + /** * @brief Flattens the given circuit * All subcircuit references are replaced by the content of this circuit. diff --git a/src/laybasic/laybasic/NetlistBrowserDialog.ui b/src/laybasic/laybasic/NetlistBrowserDialog.ui index c8be982eb..7cde819e6 100644 --- a/src/laybasic/laybasic/NetlistBrowserDialog.ui +++ b/src/laybasic/laybasic/NetlistBrowserDialog.ui @@ -230,8 +230,7 @@ Choose "Open" from the "File ..." menu -to load a netlist, a net database -or a LVS cross-reference +to load a netlist or a netlist/LVS database Qt::AlignCenter diff --git a/src/laybasic/laybasic/gsiDeclLayLayoutView.cc b/src/laybasic/laybasic/gsiDeclLayLayoutView.cc index f4093f94c..f60483dbb 100644 --- a/src/laybasic/laybasic/gsiDeclLayLayoutView.cc +++ b/src/laybasic/laybasic/gsiDeclLayLayoutView.cc @@ -1422,6 +1422,16 @@ Class decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou "@brief Gets the report database with the given index\n" "@return The \\ReportDatabase object or nil if the index is not valid" ) + + gsi::method ("add_rdb", &lay::LayoutView::add_rdb, gsi::arg ("db"), + "@brief Adds the given database to the view\n" + "\n" + "This method will add an existing database to the view. It will then appear in the marker database browser.\n" + "A similar method is \\create_rdb which will create a new database within the view.\n" + "\n" + "@return The index of the database within the view (see \\rdb)\n" + "\n" + "This method has been added in version 0.26." + ) + gsi::method_ext ("create_rdb", &create_rdb, gsi::arg ("name"), "@brief Creates a new report database and returns the index of the new database\n" "@param name The name of the new report database\n" @@ -1460,6 +1470,16 @@ Class decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou "\n" "This method has been added in version 0.26." ) + + gsi::method ("add_l2ndb", &lay::LayoutView::add_l2ndb, gsi::arg ("db"), + "@brief Adds the given database to the view\n" + "\n" + "This method will add an existing database to the view. It will then appear in the netlist database browser.\n" + "A similar method is \\create_l2ndb which will create a new database within the view.\n" + "\n" + "@return The index of the database within the view (see \\l2ndb)\n" + "\n" + "This method has been added in version 0.26." + ) + gsi::method_ext ("create_l2ndb", &create_l2ndb, gsi::arg ("name"), "@brief Creates a new netlist database and returns the index of the new database\n" "@param name The name of the new netlist database\n" diff --git a/src/laybasic/laybasic/layLayoutView.cc b/src/laybasic/laybasic/layLayoutView.cc index 92b128231..a59d02907 100644 --- a/src/laybasic/laybasic/layLayoutView.cc +++ b/src/laybasic/laybasic/layLayoutView.cc @@ -7090,7 +7090,7 @@ static void make_unique_name (T *object, Iter from, Iter to) do { - bool found = false; + bool found = n.empty (); for (Iter i = from; i != to && !found; ++i) { if ((*i)->name () == n) { found = true; @@ -7114,6 +7114,9 @@ LayoutView::add_l2ndb (db::LayoutToNetlist *l2ndb) make_unique_name (l2ndb, m_l2ndbs.begin (), m_l2ndbs.end ()); m_l2ndbs.push_back (l2ndb); + // Mark this object as owned by us (for GSI) + l2ndb->keep (); + l2ndb_list_changed_event (); return (unsigned int)(m_l2ndbs.size () - 1); @@ -7164,6 +7167,9 @@ LayoutView::add_rdb (rdb::Database *rdb) make_unique_name (rdb, m_l2ndbs.begin (), m_l2ndbs.end ()); m_rdbs.push_back (rdb); + // Mark this object as owned by us (for GSI) + rdb->keep (); + rdb_list_changed_event (); return (unsigned int)(m_rdbs.size () - 1); diff --git a/src/laybasic/laybasic/layNetlistBrowserDialog.cc b/src/laybasic/laybasic/layNetlistBrowserDialog.cc index 65949b6fc..072b3c6b6 100644 --- a/src/laybasic/laybasic/layNetlistBrowserDialog.cc +++ b/src/laybasic/laybasic/layNetlistBrowserDialog.cc @@ -562,7 +562,7 @@ NetlistBrowserDialog::deactivated () void NetlistBrowserDialog::menu_activated (const std::string &symbol) { - if (symbol == "marker_browser::show") { + if (symbol == "netlist_browser::show") { view ()->deactivate_all_browsers (); activate (); } else { diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index 9de2c56f4..a24d779cb 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -22,12 +22,925 @@ #include "layNetlistBrowserPage.h" +#include "dbLayoutToNetlist.h" namespace lay { extern std::string cfg_l2ndb_show_all; +// ---------------------------------------------------------------------------------- +// NetlistBrowserModel definition and implementation + +/** + * @brief The NetlistBrowserModel + * + * The model hierarchy is the following + * - circuits + * - 0..#pins: pins + * - net (1x) + * - #pins..#pins+#nets: nets + * - 0..#devices: terminals + * - other terminals and nets + * - #devices..#devices+#pins: pins + * - #devices+#pins..: subcircuit pins + * - other pins and nets + * - #pins+#nets..#pins+#nets+#subcircuits: subcircuits + * - pins and nets + * - #pins+#nets+#subcircuits..: devices + * - terminals and nets + */ +class NetlistBrowserModel + : public QAbstractItemModel +{ +public: + NetlistBrowserModel (db::LayoutToNetlist *l2ndb); + + virtual int columnCount (const QModelIndex &parent) const; + virtual QVariant data (const QModelIndex &index, int role) const; + virtual Qt::ItemFlags flags (const QModelIndex &index) const; + virtual bool hasChildren (const QModelIndex &parent) const; + virtual QVariant headerData (int section, Qt::Orientation orientation, int role) const; + virtual QModelIndex index (int row, int column, const QModelIndex &parent) const; + virtual QModelIndex parent (const QModelIndex &index) const; + virtual int rowCount (const QModelIndex &parent) const; + +private: + + static inline void *make_id (size_t i1) + { + return reinterpret_cast (i1); + } + + static inline void *make_id (size_t i1, size_t n1, size_t i2) + { + return reinterpret_cast (i1 + n1 * i2); + } + + static inline void *make_id (size_t i1, size_t n1, size_t i2, size_t n2, size_t i3) + { + return reinterpret_cast (i1 + n1 * (i2 + n2 * i3)); + } + + static inline void *make_id (size_t i1, size_t n1, size_t i2, size_t n2, size_t i3, size_t n3, size_t i4) + { + return reinterpret_cast (i1 + n1 * (i2 + n2 * (i3 + n3 * i4))); + } + + static inline void *make_id (size_t i1, size_t n1, size_t i2, size_t n2, size_t i3, size_t n3, size_t i4, size_t n4, size_t i5) + { + return reinterpret_cast (i1 + n1 * (i2 + n2 * (i3 + n3 * (i4 + n4 * i5)))); + } + + static inline void *make_id (size_t i1, size_t n1, size_t i2, size_t n2, size_t i3, size_t n3, size_t i4, size_t n4, size_t i5, size_t n5, size_t i6) + { + return reinterpret_cast (i1 + n1 * (i2 + n2 * (i3 + n3 * (i4 + n4 * (i5 + n5 * i6))))); + } + + static inline size_t pop (void *&idp, size_t n) + { + size_t id = reinterpret_cast (idp); + size_t i = id % n; + id /= n; + idp = reinterpret_cast (id); + return i; + } + + static inline bool always (bool) + { + return true; + } + + virtual void *make_id_circuit (size_t circuit_index) const + { + return make_id (circuit_index); + } + + virtual void *make_id_circuit_pin (size_t circuit_index, size_t pin_index) const + { + return make_id (circuit_index, netlist ()->circuit_count (), 1, 8, pin_index); + } + + void *make_id_circuit_pin_net (size_t circuit_index, size_t pin_index, size_t net_index) const + { + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 1, 8, pin_index, circuit->pin_count (), net_index); + } + + void *make_id_circuit_net (size_t circuit_index, size_t net_index) const + { + return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index); + } + + void *make_id_circuit_net_device_terminal (size_t circuit_index, size_t net_index, size_t terminal_ref_index) const + { + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index, circuit->net_count (), 1, 4, terminal_ref_index); + } + + void *make_id_circuit_net_device_terminal_others (size_t circuit_index, size_t net_index, size_t terminal_ref_index, size_t other_index) const + { + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + db::Net *net = net_from_id (make_id_circuit_net (circuit_index, net_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index, circuit->net_count (), 1, 4, terminal_ref_index, net->terminal_count (), other_index + 1); + } + + void *make_id_circuit_net_pin (size_t circuit_index, size_t net_index, size_t pin_index) const + { + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index, circuit->net_count (), 2, 4, pin_index); + } + + void *make_id_circuit_net_subcircuit_pin (size_t circuit_index, size_t net_index, size_t pin_ref_index) const + { + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index, circuit->net_count (), 3, 4, pin_ref_index); + } + + void *make_id_circuit_net_subcircuit_pin_others (size_t circuit_index, size_t net_index, size_t pin_ref_index, size_t other_index) const + { + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + db::Net *net = net_from_id (make_id_circuit_net (circuit_index, net_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index, circuit->net_count (), 3, 4, pin_ref_index, net->subcircuit_pin_count (), other_index + 1); + } + + void *make_id_circuit_subcircuit (size_t circuit_index, size_t subcircuit_index) const + { + return make_id (circuit_index, netlist ()->circuit_count (), 3, 8, subcircuit_index); + } + + void *make_id_circuit_subcircuit_pin (size_t circuit_index, size_t subcircuit_index, size_t pin_index) const + { + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 3, 8, subcircuit_index, circuit->subcircuit_count (), pin_index + 1); + } + + void *make_id_circuit_device (size_t circuit_index, size_t device_index) const + { + return make_id (circuit_index, netlist ()->circuit_count (), 4, 8, device_index); + } + + void *make_id_circuit_device_terminal (size_t circuit_index, size_t device_index, size_t terminal_index) const + { + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 4, 8, device_index, circuit->device_count (), terminal_index + 1); + } + + bool is_id_circuit (void *id) const + { + pop (id, netlist ()->circuit_count ()); + return id == 0; + } + + bool is_id_circuit_pin (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 1 && always (pop (id, circuit->pin_count ())) && id == 0); + } + + bool is_id_circuit_pin_net (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 1 && always (pop (id, circuit->pin_count ())) && id != 0); + } + + bool is_id_circuit_net (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && id == 0); + } + + bool is_id_circuit_net_device_terminal (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && pop (id, 4) == 1 && always (pop (id, net->terminal_count ())) && id == 0); + } + + bool is_id_circuit_net_device_terminal_others (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && pop (id, 4) == 1 && always (pop (id, net->terminal_count ())) && id != 0); + } + + bool is_id_circuit_net_pin (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && pop (id, 4) == 2); + } + + bool is_id_circuit_net_subcircuit_pin (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && pop (id, 4) == 3 && always (pop (id, net->subcircuit_pin_count ())) && id == 0); + } + + bool is_id_circuit_net_subcircuit_pin_others (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && pop (id, 4) == 3 && always (pop (id, net->subcircuit_pin_count ())) && id != 0); + } + + bool is_id_circuit_subcircuit (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 3 && always (pop (id, circuit->subcircuit_count ())) && id == 0); + } + + bool is_id_circuit_subcircuit_pin (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 3 && always (pop (id, circuit->subcircuit_count ())) && id != 0); + } + + bool is_id_circuit_device (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 4 && always (pop (id, circuit->device_count ())) && id == 0); + } + + bool is_id_circuit_device_terminal (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 4 && always (pop (id, circuit->device_count ())) && id != 0); + } + + size_t circuit_index_from_id (void *id) const + { + return pop (id, netlist ()->circuit_count ()); + } + + size_t circuit_pin_index_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + return pop (id, circuit->pin_count ()); + } + + size_t circuit_device_index_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + return pop (id, circuit->device_count ()); + } + + size_t circuit_device_terminal_index_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + pop (id, circuit->device_count ()); + return reinterpret_cast (id) - 1; + } + + size_t circuit_subcircuit_index_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + return pop (id, circuit->subcircuit_count ()); + } + + size_t circuit_subcircuit_pin_index_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + pop (id, circuit->subcircuit_count ()); + return reinterpret_cast (id) - 1; + } + + size_t circuit_net_index_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + return pop (id, circuit->net_count ()); + } + + size_t circuit_net_subcircuit_pin_index_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + pop (id, circuit->net_count ()); + pop (id, 4); + return pop (id, net->subcircuit_pin_count ()); + } + + size_t circuit_net_subcircuit_pin_other_index_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + pop (id, circuit->net_count ()); + pop (id, 4); + pop (id, net->subcircuit_pin_count ()); + return reinterpret_cast (id) - 1; + } + + size_t circuit_net_device_terminal_index_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + pop (id, circuit->net_count ()); + pop (id, 4); + return pop (id, net->terminal_count ()); + } + + size_t circuit_net_device_terminal_other_index_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + pop (id, circuit->net_count ()); + pop (id, 4); + pop (id, net->terminal_count ()); + return reinterpret_cast (id) - 1; + } + + db::Circuit *circuit_from_id (void *id) const + { + size_t index = circuit_index_from_id (id); + + std::map::iterator c = m_circuit_by_index.find (index); + if (c == m_circuit_by_index.end ()) { + + c = m_circuit_by_index.insert (std::make_pair (index, (db::Circuit *) 0)).first; + for (db::Netlist::circuit_iterator i = netlist ()->begin_circuits (); i != netlist ()->end_circuits (); ++i) { + if (index-- == 0) { + c->second = i.operator-> (); + break; + } + } + + } + + return c->second; + } + + db::Net *net_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + size_t index = circuit_net_index_from_id (id); + + std::map >::iterator cc = m_net_by_circuit_and_index.find (circuit); + if (cc != m_net_by_circuit_and_index.end ()) { + cc = m_net_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; + } + + std::map::iterator c = cc->second.find (index); + if (c == cc->second.end ()) { + + c = cc->second.insert (std::make_pair (index, (db::Net *) 0)).first; + for (db::Circuit::net_iterator i = circuit->begin_nets (); i != circuit->end_nets (); ++i) { + if (index-- == 0) { + c->second = i.operator-> (); + break; + } + } + + } + + return c->second; + } + + const db::NetSubcircuitPinRef *net_pinref_from_id (void *id) const + { + db::Net *net = net_from_id (id); + size_t index = circuit_net_subcircuit_pin_index_from_id (id); + + std::map >::iterator cc = m_pinref_by_net_and_index.find (net); + if (cc != m_pinref_by_net_and_index.end ()) { + cc = m_pinref_by_net_and_index.insert (std::make_pair (net, std::map ())).first; + } + + std::map::iterator c = cc->second.find (index); + if (c == cc->second.end ()) { + + c = cc->second.insert (std::make_pair (index, (db::NetSubcircuitPinRef *) 0)).first; + for (db::Net::subcircuit_pin_iterator i = net->begin_subcircuit_pins (); i != net->end_subcircuit_pins (); ++i) { + if (index-- == 0) { + c->second = i.operator-> (); + break; + } + } + + } + + return c->second; + } + + const db::NetTerminalRef *net_terminalref_from_id (void *id) const + { + db::Net *net = net_from_id (id); + size_t index = circuit_net_device_terminal_index_from_id (id); + + std::map >::iterator cc = m_terminalref_by_net_and_index.find (net); + if (cc != m_terminalref_by_net_and_index.end ()) { + cc = m_terminalref_by_net_and_index.insert (std::make_pair (net, std::map ())).first; + } + + std::map::iterator c = cc->second.find (index); + if (c == cc->second.end ()) { + + c = cc->second.insert (std::make_pair (index, (db::NetTerminalRef *) 0)).first; + for (db::Net::terminal_iterator i = net->begin_terminals (); i != net->end_terminals (); ++i) { + if (index-- == 0) { + c->second = i.operator-> (); + break; + } + } + + } + + return c->second; + } + + db::Device *device_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + size_t index = circuit_device_index_from_id (id); + + std::map >::iterator cc = m_device_by_circuit_and_index.find (circuit); + if (cc != m_device_by_circuit_and_index.end ()) { + cc = m_device_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; + } + + std::map::iterator c = cc->second.find (index); + if (c == cc->second.end ()) { + + c = cc->second.insert (std::make_pair (index, (db::Device *) 0)).first; + for (db::Circuit::device_iterator i = circuit->begin_devices (); i != circuit->end_devices (); ++i) { + if (index-- == 0) { + c->second = i.operator-> (); + break; + } + } + + } + + return c->second; + } + + db::Pin *pin_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + size_t index = circuit_pin_index_from_id (id); + + std::map >::iterator cc = m_pin_by_circuit_and_index.find (circuit); + if (cc != m_pin_by_circuit_and_index.end ()) { + cc = m_pin_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; + } + + std::map::iterator c = cc->second.find (index); + if (c == cc->second.end ()) { + + c = cc->second.insert (std::make_pair (index, (db::Pin *) 0)).first; + for (db::Circuit::pin_iterator i = circuit->begin_pins (); i != circuit->end_pins (); ++i) { + if (index-- == 0) { + c->second = i.operator-> (); + break; + } + } + + } + + return c->second; + } + + db::SubCircuit *subcircuit_from_id (void *id) const + { + db::Circuit *circuit = circuit_from_id (id); + size_t index = circuit_subcircuit_index_from_id (id); + + std::map >::iterator cc = m_subcircuit_by_circuit_and_index.find (circuit); + if (cc != m_subcircuit_by_circuit_and_index.end ()) { + cc = m_subcircuit_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; + } + + std::map::iterator c = cc->second.find (index); + if (c == cc->second.end ()) { + + c = cc->second.insert (std::make_pair (index, (db::SubCircuit *) 0)).first; + for (db::Circuit::subcircuit_iterator i = circuit->begin_subcircuits (); i != circuit->end_subcircuits (); ++i) { + if (index-- == 0) { + c->second = i.operator-> (); + break; + } + } + + } + + return c->second; + } + + db::Netlist *netlist () const + { + return const_cast (mp_l2ndb->netlist ()); + } + + db::LayoutToNetlist *mp_l2ndb; + mutable std::map m_circuit_by_index; + mutable std::map > m_net_by_circuit_and_index; + mutable std::map > m_pinref_by_net_and_index; + mutable std::map > m_terminalref_by_net_and_index; + mutable std::map > m_device_by_circuit_and_index; + mutable std::map > m_pin_by_circuit_and_index; + mutable std::map > m_subcircuit_by_circuit_and_index; +}; + +NetlistBrowserModel::NetlistBrowserModel (db::LayoutToNetlist *l2ndb) + : mp_l2ndb (l2ndb) +{ + // .. nothing yet .. +} + +int +NetlistBrowserModel::columnCount (const QModelIndex & /*parent*/) const +{ + // Item type & icon, link or description + return 2; +} + +QVariant +NetlistBrowserModel::data (const QModelIndex &index, int role) const +{ + if (role != Qt::DisplayRole || ! index.isValid ()) { + return QVariant (); + } + + void *id = index.internalPointer (); + + /* + * - circuits + * - 0..#pins: pins + * - net (1x) + * - #pins..#pins+#nets: nets + * - 0..#devices: terminals + * - other terminals and nets + * - #devices..#devices+#pins: pins + * - #devices+#pins..: subcircuit pins + * - other pins and nets + * - #pins+#nets..#pins+#nets+#subcircuits: subcircuits + * - pins and nets + * - #pins+#nets+#subcircuits..: devices + * - terminals and nets + */ + + if (is_id_circuit (id)) { + + db::Circuit *circuit = circuit_from_id (id); + if (circuit) { + return tl::to_qstring (circuit->name ()); + } + + } else if (is_id_circuit_pin (id) || is_id_circuit_net_subcircuit_pin_others (id)) { + + db::Pin *pin = pin_from_id (id); + if (pin) { + return tl::to_qstring (pin->expanded_name ()); + } + + } else if (is_id_circuit_device (id)) { + + db::Device *device = device_from_id (id); + if (device) { + return tl::to_qstring (device->expanded_name ()); + } + + } else if (is_id_circuit_subcircuit (id)) { + + db::SubCircuit *subcircuit = subcircuit_from_id (id); + if (subcircuit) { + return tl::to_qstring (subcircuit->expanded_name ()); + } + + } else if (is_id_circuit_net (id)) { + + db::Net *net = net_from_id (id); + if (net) { + return tl::to_qstring (net->expanded_name ()); + } + + } else if (is_id_circuit_net_subcircuit_pin (id)) { + + const db::NetSubcircuitPinRef *ref = net_pinref_from_id (id); + if (ref && ref->pin ()) { + return tl::to_qstring (ref->pin ()->expanded_name ()); + } + + } else if (is_id_circuit_net_device_terminal (id)) { + + const db::NetTerminalRef *ref = net_terminalref_from_id (id); + if (ref && ref->terminal_def ()) { + return tl::to_qstring (ref->terminal_def ()->name ()); + } + + } else if (is_id_circuit_net_device_terminal_others (id)) { + + const db::NetTerminalRef *ref = net_terminalref_from_id (id); + size_t other_index = circuit_net_device_terminal_other_index_from_id (id); + + if (ref && ref->device_class () && ref->device_class ()->terminal_definitions ().size () > other_index) { + const db::DeviceTerminalDefinition &def = ref->device_class ()->terminal_definitions ()[other_index]; + return tl::to_qstring (def.name ()); + } + + } + + return QVariant (); +} + +Qt::ItemFlags +NetlistBrowserModel::flags (const QModelIndex & /*index*/) const +{ + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; +} + +bool +NetlistBrowserModel::hasChildren (const QModelIndex &parent) const +{ + if (! parent.isValid ()) { + + return mp_l2ndb->netlist () && mp_l2ndb->netlist ()->circuit_count () > 0; + + } else { + + void *id = parent.internalPointer (); + + if (is_id_circuit (id)) { + db::Circuit *circuit = circuit_from_id (id); + return circuit->device_count () + circuit->pin_count () + circuit->net_count () + circuit->subcircuit_count () > 0; + } else if (is_id_circuit_pin (id)) { + return true; + } else if (is_id_circuit_device (id)) { + db::Device *device = device_from_id (id); + return device->device_class () && ! device->device_class ()->terminal_definitions ().empty (); + } else if (is_id_circuit_subcircuit (id)) { + db::SubCircuit *subcircuit = subcircuit_from_id (id); + return subcircuit->circuit_ref () && subcircuit->circuit_ref ()->pin_count () > 0; + } else if (is_id_circuit_net (id)) { + db::Net *net = net_from_id (id); + return net->pin_count () + net->subcircuit_pin_count () + net->terminal_count () > 0; + } else if (is_id_circuit_net_subcircuit_pin (id)) { + const db::NetSubcircuitPinRef *ref = net_pinref_from_id (id); + return ref->subcircuit ()->circuit_ref () && ref->subcircuit ()->circuit_ref ()->pin_count () > 0; + } else if (is_id_circuit_net_device_terminal (id)) { + const db::NetTerminalRef *ref = net_terminalref_from_id (id); + return ref->device_class () && ! ref->device_class ()->terminal_definitions ().empty (); + } else { + return false; + } + + } +} + +QVariant +NetlistBrowserModel::headerData (int /*section*/, Qt::Orientation /*orientation*/, int /*role*/) const +{ + return QVariant (); +} + +QModelIndex +NetlistBrowserModel::index (int row, int column, const QModelIndex &parent) const +{ + if (! parent.isValid ()) { + + return createIndex (row, column, make_id_circuit (row)); + + } else { + + void *id = parent.internalPointer (); + + /* + * - circuits + * - 0..#pins: pins + * - net (1x) + * - #pins..#pins+#nets: nets + * - 0..#devices: terminals + * - other terminals and nets + * - #devices..#devices+#pins: pins + * - #devices+#pins..: subcircuit pins + * - other pins and nets + * - #pins+#nets..#pins+#nets+#subcircuits: subcircuits + * - pins and nets + * - #pins+#nets+#subcircuits..: devices + * - terminals and nets + */ + + if (is_id_circuit (id)) { + + db::Circuit *circuit = circuit_from_id (id); + if (size_t (row) < circuit->pin_count ()) { + return createIndex (row, column, make_id_circuit_pin (circuit_index_from_id (id), row)); + } + row -= int (circuit->pin_count ()); + if (size_t (row) < circuit->net_count ()) { + return createIndex (row, column, make_id_circuit_net (circuit_index_from_id (id), row)); + } + row -= int (circuit->net_count ()); + if (size_t (row) < circuit->subcircuit_count ()) { + return createIndex (row, column, make_id_circuit_subcircuit (circuit_index_from_id (id), row)); + } + row -= int (circuit->subcircuit_count ()); + if (size_t (row) < circuit->device_count ()) { + return createIndex (row, column, make_id_circuit_device (circuit_index_from_id (id), row)); + } + + } else if (is_id_circuit_pin (id)) { + + return createIndex (row, column, make_id_circuit_pin_net (circuit_index_from_id (id), circuit_pin_index_from_id (id), row)); + + } else if (is_id_circuit_device (id)) { + + return createIndex (row, column, make_id_circuit_device_terminal (circuit_index_from_id (id), circuit_device_index_from_id (id), row)); + + } else if (is_id_circuit_subcircuit (id)) { + + return createIndex (row, column, make_id_circuit_subcircuit_pin (circuit_index_from_id (id), circuit_subcircuit_index_from_id (id), row)); + + } else if (is_id_circuit_net (id)) { + + db::Net *net = net_from_id (id); + if (size_t (row) < net->terminal_count ()) { + return createIndex (row, column, make_id_circuit_net_device_terminal (circuit_index_from_id (id), circuit_net_index_from_id (id), row)); + } + row -= int (net->terminal_count ()); + if (size_t (row) < net->pin_count ()) { + return createIndex (row, column, make_id_circuit_net_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), row)); + } + row -= int (net->pin_count ()); + if (size_t (row) < net->subcircuit_pin_count ()) { + return createIndex (row, column, make_id_circuit_net_subcircuit_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), row)); + } + + } else if (is_id_circuit_net_subcircuit_pin (id)) { + + return createIndex (row, column, make_id_circuit_net_subcircuit_pin_others (circuit_index_from_id (id), circuit_net_index_from_id (id), circuit_net_subcircuit_pin_index_from_id (id), row)); + + } else if (is_id_circuit_net_device_terminal (id)) { + + return createIndex (row, column, make_id_circuit_net_device_terminal_others (circuit_index_from_id (id), circuit_net_index_from_id (id), circuit_net_device_terminal_index_from_id (id), row)); + + } + + } + + return QModelIndex (); +} + +QModelIndex +NetlistBrowserModel::parent (const QModelIndex &index) const +{ + if (! index.isValid ()) { + + return QModelIndex (); + + } else { + + void *id = index.internalPointer (); + int column = index.column (); + + /* + * - circuits + * - 0..#pins: pins + * - net (1x) + * - #pins..#pins+#nets: nets + * - 0..#devices: terminals + * - other terminals and nets + * - #devices..#devices+#pins: pins + * - #devices+#pins..: subcircuit pins + * - other pins and nets + * - #pins+#nets..#pins+#nets+#subcircuits: subcircuits + * - pins and nets + * - #pins+#nets+#subcircuits..: devices + * - terminals and nets + */ + + if (is_id_circuit (id)) { + + return QModelIndex (); + + } else if (is_id_circuit_pin (id) || is_id_circuit_net (id) || is_id_circuit_device (id) || is_id_circuit_subcircuit (id)) { + + return createIndex (int (circuit_index_from_id (id)), column, make_id_circuit (circuit_index_from_id (id))); + + } else if (is_id_circuit_pin_net (id)) { + + return createIndex (int (circuit_pin_index_from_id (id)), column, make_id_circuit_pin (circuit_index_from_id (id), circuit_pin_index_from_id (id))); + + } else if (is_id_circuit_net_device_terminal (id) || is_id_circuit_net_pin (id) || is_id_circuit_net_subcircuit_pin (id)) { + + db::Circuit *circuit = circuit_from_id (id); + return createIndex (int (circuit->pin_count () + circuit_net_index_from_id (id)), column, make_id_circuit_net (circuit_index_from_id (id), circuit_net_index_from_id (id))); + + } else if (is_id_circuit_subcircuit_pin (id)) { + + db::Circuit *circuit = circuit_from_id (id); + return createIndex (int (circuit->pin_count () + circuit->net_count () + circuit_subcircuit_index_from_id (id)), column, make_id_circuit_subcircuit (circuit_index_from_id (id), circuit_subcircuit_index_from_id (id))); + + } else if (is_id_circuit_device_terminal (id)) { + + db::Circuit *circuit = circuit_from_id (id); + return createIndex (int (circuit->pin_count () + circuit->net_count () + circuit->subcircuit_count () + circuit_device_terminal_index_from_id (id)), column, make_id_circuit_device (circuit_index_from_id (id), circuit_device_index_from_id (id))); + + } else if (is_id_circuit_net_device_terminal_others (id)) { + + return createIndex (circuit_net_device_terminal_index_from_id (id), column, make_id_circuit_net_device_terminal (circuit_index_from_id (id), circuit_net_index_from_id (id), circuit_net_device_terminal_index_from_id (id))); + + } else if (is_id_circuit_net_subcircuit_pin_others (id)) { + + db::Net *net = net_from_id (id); + return createIndex (size_t (net->terminal_count () + net->pin_count () + circuit_net_subcircuit_pin_index_from_id (id)), column, make_id_circuit_net_subcircuit_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), circuit_net_subcircuit_pin_index_from_id (id))); + + } + + } + + return QModelIndex (); +} + +int +NetlistBrowserModel::rowCount (const QModelIndex &parent) const +{ + if (! parent.isValid ()) { + + return int (mp_l2ndb->netlist ()->circuit_count ()); + + } else { + + void *id = parent.internalPointer (); + + /* + * - circuits + * - 0..#pins: pins + * - net (1x) + * - #pins..#pins+#nets: nets + * - 0..#devices: terminals + * - other terminals and nets + * - #devices..#devices+#pins: pins + * - #devices+#pins..: subcircuit pins + * - other pins and nets + * - #pins+#nets..#pins+#nets+#subcircuits: subcircuits + * - pins and nets + * - #pins+#nets+#subcircuits..: devices + * - terminals and nets + */ + + if (is_id_circuit (id)) { + + db::Circuit *circuit = circuit_from_id (id); + return int (circuit->pin_count () + circuit->net_count () + circuit->subcircuit_count () + circuit->device_count ()); + + } else if (is_id_circuit_pin (id)) { + + return 1; + + } else if (is_id_circuit_device (id) || is_id_circuit_net_device_terminal (id)) { + + db::Device *device = device_from_id (id); + return int (device->device_class () ? device->device_class ()->terminal_definitions ().size () : 0); + + } else if (is_id_circuit_subcircuit (id) || is_id_circuit_net_subcircuit_pin (id)) { + + db::SubCircuit *subcircuit = subcircuit_from_id (id); + return int (subcircuit->circuit_ref () ? subcircuit->circuit_ref ()->pin_count () : 0); + + } else if (is_id_circuit_net (id)) { + + db::Net *net = net_from_id (id); + return int (net->terminal_count () + net->pin_count () + net->subcircuit_pin_count ()); + + } + + } + + return 0; +} + // ---------------------------------------------------------------------------------- // NetlistBrowserPage implementation From 59aa5758f53152f67a0787add00f869f23df0414 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 21 Apr 2019 10:54:25 +0200 Subject: [PATCH 005/229] WIP: netlist browser. --- .../laybasic/layNetlistBrowserPage.cc | 439 ++++++++++-------- src/laybasic/laybasic/layNetlistBrowserPage.h | 1 + 2 files changed, 241 insertions(+), 199 deletions(-) diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index a24d779cb..86c7ea498 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -65,6 +65,8 @@ public: virtual QModelIndex parent (const QModelIndex &index) const; virtual int rowCount (const QModelIndex &parent) const; + void self_test (const QModelIndex &index = QModelIndex ()); + private: static inline void *make_id (size_t i1) @@ -381,181 +383,13 @@ private: return reinterpret_cast (id) - 1; } - db::Circuit *circuit_from_id (void *id) const - { - size_t index = circuit_index_from_id (id); - - std::map::iterator c = m_circuit_by_index.find (index); - if (c == m_circuit_by_index.end ()) { - - c = m_circuit_by_index.insert (std::make_pair (index, (db::Circuit *) 0)).first; - for (db::Netlist::circuit_iterator i = netlist ()->begin_circuits (); i != netlist ()->end_circuits (); ++i) { - if (index-- == 0) { - c->second = i.operator-> (); - break; - } - } - - } - - return c->second; - } - - db::Net *net_from_id (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - size_t index = circuit_net_index_from_id (id); - - std::map >::iterator cc = m_net_by_circuit_and_index.find (circuit); - if (cc != m_net_by_circuit_and_index.end ()) { - cc = m_net_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; - } - - std::map::iterator c = cc->second.find (index); - if (c == cc->second.end ()) { - - c = cc->second.insert (std::make_pair (index, (db::Net *) 0)).first; - for (db::Circuit::net_iterator i = circuit->begin_nets (); i != circuit->end_nets (); ++i) { - if (index-- == 0) { - c->second = i.operator-> (); - break; - } - } - - } - - return c->second; - } - - const db::NetSubcircuitPinRef *net_pinref_from_id (void *id) const - { - db::Net *net = net_from_id (id); - size_t index = circuit_net_subcircuit_pin_index_from_id (id); - - std::map >::iterator cc = m_pinref_by_net_and_index.find (net); - if (cc != m_pinref_by_net_and_index.end ()) { - cc = m_pinref_by_net_and_index.insert (std::make_pair (net, std::map ())).first; - } - - std::map::iterator c = cc->second.find (index); - if (c == cc->second.end ()) { - - c = cc->second.insert (std::make_pair (index, (db::NetSubcircuitPinRef *) 0)).first; - for (db::Net::subcircuit_pin_iterator i = net->begin_subcircuit_pins (); i != net->end_subcircuit_pins (); ++i) { - if (index-- == 0) { - c->second = i.operator-> (); - break; - } - } - - } - - return c->second; - } - - const db::NetTerminalRef *net_terminalref_from_id (void *id) const - { - db::Net *net = net_from_id (id); - size_t index = circuit_net_device_terminal_index_from_id (id); - - std::map >::iterator cc = m_terminalref_by_net_and_index.find (net); - if (cc != m_terminalref_by_net_and_index.end ()) { - cc = m_terminalref_by_net_and_index.insert (std::make_pair (net, std::map ())).first; - } - - std::map::iterator c = cc->second.find (index); - if (c == cc->second.end ()) { - - c = cc->second.insert (std::make_pair (index, (db::NetTerminalRef *) 0)).first; - for (db::Net::terminal_iterator i = net->begin_terminals (); i != net->end_terminals (); ++i) { - if (index-- == 0) { - c->second = i.operator-> (); - break; - } - } - - } - - return c->second; - } - - db::Device *device_from_id (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - size_t index = circuit_device_index_from_id (id); - - std::map >::iterator cc = m_device_by_circuit_and_index.find (circuit); - if (cc != m_device_by_circuit_and_index.end ()) { - cc = m_device_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; - } - - std::map::iterator c = cc->second.find (index); - if (c == cc->second.end ()) { - - c = cc->second.insert (std::make_pair (index, (db::Device *) 0)).first; - for (db::Circuit::device_iterator i = circuit->begin_devices (); i != circuit->end_devices (); ++i) { - if (index-- == 0) { - c->second = i.operator-> (); - break; - } - } - - } - - return c->second; - } - - db::Pin *pin_from_id (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - size_t index = circuit_pin_index_from_id (id); - - std::map >::iterator cc = m_pin_by_circuit_and_index.find (circuit); - if (cc != m_pin_by_circuit_and_index.end ()) { - cc = m_pin_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; - } - - std::map::iterator c = cc->second.find (index); - if (c == cc->second.end ()) { - - c = cc->second.insert (std::make_pair (index, (db::Pin *) 0)).first; - for (db::Circuit::pin_iterator i = circuit->begin_pins (); i != circuit->end_pins (); ++i) { - if (index-- == 0) { - c->second = i.operator-> (); - break; - } - } - - } - - return c->second; - } - - db::SubCircuit *subcircuit_from_id (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - size_t index = circuit_subcircuit_index_from_id (id); - - std::map >::iterator cc = m_subcircuit_by_circuit_and_index.find (circuit); - if (cc != m_subcircuit_by_circuit_and_index.end ()) { - cc = m_subcircuit_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; - } - - std::map::iterator c = cc->second.find (index); - if (c == cc->second.end ()) { - - c = cc->second.insert (std::make_pair (index, (db::SubCircuit *) 0)).first; - for (db::Circuit::subcircuit_iterator i = circuit->begin_subcircuits (); i != circuit->end_subcircuits (); ++i) { - if (index-- == 0) { - c->second = i.operator-> (); - break; - } - } - - } - - return c->second; - } + db::Circuit *circuit_from_id (void *id) const; + db::Net *net_from_id (void *id) const; + const db::NetSubcircuitPinRef *net_pinref_from_id (void *id) const; + const db::NetTerminalRef *net_terminalref_from_id (void *id) const; + db::Device *device_from_id (void *id) const; + db::Pin *pin_from_id (void *id) const; + db::SubCircuit *subcircuit_from_id (void *id) const; db::Netlist *netlist () const { @@ -578,6 +412,44 @@ NetlistBrowserModel::NetlistBrowserModel (db::LayoutToNetlist *l2ndb) // .. nothing yet .. } +void +NetlistBrowserModel::self_test (const QModelIndex &p) +{ + int rows = rowCount (p); + for (int r = 0; r != rows; ++r) { + + QModelIndex c, pp; + + c = index (r, 0, p); + if (c.column () != 0) { + tl_assert (false); + } + pp = parent (c); + if (pp.column () != 0) { + tl_assert (false); + } + if (pp.row () != r) { + tl_assert (false); + } + if (pp.internalId () != p.internalId ()) { + tl_assert (false); + } + + c = index (r, 1, p); + if (c.column () != 1) { + tl_assert (false); + } + pp = parent (c); + if (pp.column () != 1) { + tl_assert (false); + } + + self_test (c); + + } +} + + int NetlistBrowserModel::columnCount (const QModelIndex & /*parent*/) const { @@ -941,6 +813,189 @@ NetlistBrowserModel::rowCount (const QModelIndex &parent) const return 0; } +db::Circuit * +NetlistBrowserModel::circuit_from_id (void *id) const +{ + size_t index = circuit_index_from_id (id); + + std::map::iterator c = m_circuit_by_index.find (index); + if (c == m_circuit_by_index.end ()) { + + c = m_circuit_by_index.insert (std::make_pair (index, (db::Circuit *) 0)).first; + for (db::Netlist::circuit_iterator i = netlist ()->begin_circuits (); i != netlist ()->end_circuits (); ++i) { + if (index-- == 0) { + c->second = i.operator-> (); + break; + } + } + + } + + return c->second; +} + +db::Net * +NetlistBrowserModel::net_from_id (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + size_t index = circuit_net_index_from_id (id); + + std::map >::iterator cc = m_net_by_circuit_and_index.find (circuit); + if (cc != m_net_by_circuit_and_index.end ()) { + cc = m_net_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; + } + + std::map::iterator c = cc->second.find (index); + if (c == cc->second.end ()) { + + c = cc->second.insert (std::make_pair (index, (db::Net *) 0)).first; + for (db::Circuit::net_iterator i = circuit->begin_nets (); i != circuit->end_nets (); ++i) { + if (index-- == 0) { + c->second = i.operator-> (); + break; + } + } + + } + + return c->second; +} + +const db::NetSubcircuitPinRef * +NetlistBrowserModel::net_pinref_from_id (void *id) const +{ + db::Net *net = net_from_id (id); + size_t index = circuit_net_subcircuit_pin_index_from_id (id); + + std::map >::iterator cc = m_pinref_by_net_and_index.find (net); + if (cc != m_pinref_by_net_and_index.end ()) { + cc = m_pinref_by_net_and_index.insert (std::make_pair (net, std::map ())).first; + } + + std::map::iterator c = cc->second.find (index); + if (c == cc->second.end ()) { + + c = cc->second.insert (std::make_pair (index, (db::NetSubcircuitPinRef *) 0)).first; + for (db::Net::subcircuit_pin_iterator i = net->begin_subcircuit_pins (); i != net->end_subcircuit_pins (); ++i) { + if (index-- == 0) { + c->second = i.operator-> (); + break; + } + } + + } + + return c->second; +} + +const db::NetTerminalRef * +NetlistBrowserModel::net_terminalref_from_id (void *id) const +{ + db::Net *net = net_from_id (id); + size_t index = circuit_net_device_terminal_index_from_id (id); + + std::map >::iterator cc = m_terminalref_by_net_and_index.find (net); + if (cc != m_terminalref_by_net_and_index.end ()) { + cc = m_terminalref_by_net_and_index.insert (std::make_pair (net, std::map ())).first; + } + + std::map::iterator c = cc->second.find (index); + if (c == cc->second.end ()) { + + c = cc->second.insert (std::make_pair (index, (db::NetTerminalRef *) 0)).first; + for (db::Net::terminal_iterator i = net->begin_terminals (); i != net->end_terminals (); ++i) { + if (index-- == 0) { + c->second = i.operator-> (); + break; + } + } + + } + + return c->second; +} + +db::Device * +NetlistBrowserModel::device_from_id (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + size_t index = circuit_device_index_from_id (id); + + std::map >::iterator cc = m_device_by_circuit_and_index.find (circuit); + if (cc != m_device_by_circuit_and_index.end ()) { + cc = m_device_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; + } + + std::map::iterator c = cc->second.find (index); + if (c == cc->second.end ()) { + + c = cc->second.insert (std::make_pair (index, (db::Device *) 0)).first; + for (db::Circuit::device_iterator i = circuit->begin_devices (); i != circuit->end_devices (); ++i) { + if (index-- == 0) { + c->second = i.operator-> (); + break; + } + } + + } + + return c->second; +} + +db::Pin * +NetlistBrowserModel::pin_from_id (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + size_t index = circuit_pin_index_from_id (id); + + std::map >::iterator cc = m_pin_by_circuit_and_index.find (circuit); + if (cc != m_pin_by_circuit_and_index.end ()) { + cc = m_pin_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; + } + + std::map::iterator c = cc->second.find (index); + if (c == cc->second.end ()) { + + c = cc->second.insert (std::make_pair (index, (db::Pin *) 0)).first; + for (db::Circuit::pin_iterator i = circuit->begin_pins (); i != circuit->end_pins (); ++i) { + if (index-- == 0) { + c->second = i.operator-> (); + break; + } + } + + } + + return c->second; +} + +db::SubCircuit * +NetlistBrowserModel::subcircuit_from_id (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + size_t index = circuit_subcircuit_index_from_id (id); + + std::map >::iterator cc = m_subcircuit_by_circuit_and_index.find (circuit); + if (cc != m_subcircuit_by_circuit_and_index.end ()) { + cc = m_subcircuit_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; + } + + std::map::iterator c = cc->second.find (index); + if (c == cc->second.end ()) { + + c = cc->second.insert (std::make_pair (index, (db::SubCircuit *) 0)).first; + for (db::Circuit::subcircuit_iterator i = circuit->begin_subcircuits (); i != circuit->end_subcircuits (); ++i) { + if (index-- == 0) { + c->second = i.operator-> (); + break; + } + } + + } + + return c->second; +} + // ---------------------------------------------------------------------------------- // NetlistBrowserPage implementation @@ -1084,45 +1139,31 @@ NetlistBrowserPage::update_highlights () void NetlistBrowserPage::set_l2ndb (db::LayoutToNetlist *database) { -#if 0 // @@@ - if (database != mp_database) { + if (database != mp_database.get ()) { - release_markers (); + // @@@ release_markers (); - mp_database = database; + mp_database.reset (database); QAbstractItemModel *tree_model = directory_tree->model (); - MarkerBrowserTreeViewModel *new_model = new MarkerBrowserTreeViewModel (); - new_model->set_show_empty_ones (true); - new_model->set_database (database); + NetlistBrowserModel *new_model = new NetlistBrowserModel (database); +#if !defined(NDEBUG) + new_model->self_test (); +#endif + directory_tree->setModel (new_model); - connect (directory_tree->selectionModel (), SIGNAL (selectionChanged (const QItemSelection &, const QItemSelection &)), this, SLOT (directory_selection_changed (const QItemSelection &, const QItemSelection &))); + // @@@ connect (directory_tree->selectionModel (), SIGNAL (selectionChanged (const QItemSelection &, const QItemSelection &)), this, SLOT (directory_selection_changed (const QItemSelection &, const QItemSelection &))); directory_tree->header ()->setSortIndicatorShown (true); - cat_filter->setText (QString ()); - cell_filter->setText (QString ()); - set_hidden_rec (new_model, directory_tree, QModelIndex (), m_show_all, QString (), QString ()); + filter->setText (QString ()); if (tree_model) { delete tree_model; } - QAbstractItemModel *list_model = markers_list->model (); - - MarkerBrowserListViewModel *new_list_model = new MarkerBrowserListViewModel (); - new_list_model->set_database (database); - markers_list->setModel (new_list_model); - connect (markers_list->selectionModel (), SIGNAL (selectionChanged (const QItemSelection &, const QItemSelection &)), this, SLOT (markers_selection_changed (const QItemSelection &, const QItemSelection &))); - connect (markers_list->selectionModel (), SIGNAL (currentChanged (const QModelIndex &, const QModelIndex &)), this, SLOT (markers_current_changed (const QModelIndex &, const QModelIndex &))); - - if (list_model) { - delete list_model; - } - } -#endif } void diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.h b/src/laybasic/laybasic/layNetlistBrowserPage.h index 083c20929..c8be1d4fd 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.h +++ b/src/laybasic/laybasic/layNetlistBrowserPage.h @@ -153,6 +153,7 @@ private: lay::LayoutView *mp_view; unsigned int m_cv_index; lay::PluginRoot *mp_plugin_root; + tl::weak_ptr mp_database; }; } // namespace lay From 5b8a9cf49c6c730eaba9910a9bcdbd76329e27b4 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 22 Apr 2019 01:25:48 +0200 Subject: [PATCH 006/229] WIP: netlist browser --- src/db/db/dbCircuit.h | 2 +- .../laybasic/layNetlistBrowserPage.cc | 981 +++++++++--------- src/laybasic/laybasic/layNetlistBrowserPage.h | 111 +- .../unit_tests/layNetlistBrowserModelTests.cc | 111 ++ src/laybasic/unit_tests/unit_tests.pro | 7 +- src/tl/unit_tests/unit_tests.pro | 6 +- 6 files changed, 712 insertions(+), 506 deletions(-) create mode 100644 src/laybasic/unit_tests/layNetlistBrowserModelTests.cc diff --git a/src/db/db/dbCircuit.h b/src/db/db/dbCircuit.h index 021b0e97a..d905cc300 100644 --- a/src/db/db/dbCircuit.h +++ b/src/db/db/dbCircuit.h @@ -406,7 +406,7 @@ public: */ size_t device_count () const { - return m_nets.size (); + return m_devices.size (); } /** diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index 86c7ea498..0b92c9741 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -30,388 +30,381 @@ namespace lay extern std::string cfg_l2ndb_show_all; // ---------------------------------------------------------------------------------- -// NetlistBrowserModel definition and implementation +// NetlistBrowserModel implementation -/** - * @brief The NetlistBrowserModel - * - * The model hierarchy is the following - * - circuits - * - 0..#pins: pins - * - net (1x) - * - #pins..#pins+#nets: nets - * - 0..#devices: terminals - * - other terminals and nets - * - #devices..#devices+#pins: pins - * - #devices+#pins..: subcircuit pins - * - other pins and nets - * - #pins+#nets..#pins+#nets+#subcircuits: subcircuits - * - pins and nets - * - #pins+#nets+#subcircuits..: devices - * - terminals and nets - */ -class NetlistBrowserModel - : public QAbstractItemModel +static inline void *make_id (size_t i1) { -public: - NetlistBrowserModel (db::LayoutToNetlist *l2ndb); + return reinterpret_cast (i1); +} - virtual int columnCount (const QModelIndex &parent) const; - virtual QVariant data (const QModelIndex &index, int role) const; - virtual Qt::ItemFlags flags (const QModelIndex &index) const; - virtual bool hasChildren (const QModelIndex &parent) const; - virtual QVariant headerData (int section, Qt::Orientation orientation, int role) const; - virtual QModelIndex index (int row, int column, const QModelIndex &parent) const; - virtual QModelIndex parent (const QModelIndex &index) const; - virtual int rowCount (const QModelIndex &parent) const; +static inline void *make_id (size_t i1, size_t n1, size_t i2) +{ + return reinterpret_cast (i1 + n1 * i2); +} - void self_test (const QModelIndex &index = QModelIndex ()); +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)); +} -private: +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) - { - return reinterpret_cast (i1); - } +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) - { - 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, 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 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 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 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 bool always (bool) +{ + return true; +} - static inline void *make_id (size_t i1, size_t n1, size_t i2, size_t n2, size_t i3, size_t n3, size_t i4, size_t n4, size_t i5) - { - return reinterpret_cast (i1 + n1 * (i2 + n2 * (i3 + n3 * (i4 + n4 * i5)))); - } - - static inline void *make_id (size_t i1, size_t n1, size_t i2, size_t n2, size_t i3, size_t n3, size_t i4, size_t n4, size_t i5, size_t n5, size_t i6) - { - return reinterpret_cast (i1 + n1 * (i2 + n2 * (i3 + n3 * (i4 + n4 * (i5 + n5 * i6))))); - } - - static inline size_t pop (void *&idp, size_t n) - { - size_t id = reinterpret_cast (idp); - size_t i = id % n; - id /= n; - idp = reinterpret_cast (id); - return i; - } - - static inline bool always (bool) - { - return true; - } - - virtual void *make_id_circuit (size_t circuit_index) const - { - return make_id (circuit_index); - } - - virtual void *make_id_circuit_pin (size_t circuit_index, size_t pin_index) const - { - return make_id (circuit_index, netlist ()->circuit_count (), 1, 8, pin_index); - } - - void *make_id_circuit_pin_net (size_t circuit_index, size_t pin_index, size_t net_index) const - { - db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); - return make_id (circuit_index, netlist ()->circuit_count (), 1, 8, pin_index, circuit->pin_count (), net_index); - } - - void *make_id_circuit_net (size_t circuit_index, size_t net_index) const - { - return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index); - } - - void *make_id_circuit_net_device_terminal (size_t circuit_index, size_t net_index, size_t terminal_ref_index) const - { - db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); - return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index, circuit->net_count (), 1, 4, terminal_ref_index); - } - - void *make_id_circuit_net_device_terminal_others (size_t circuit_index, size_t net_index, size_t terminal_ref_index, size_t other_index) const - { - db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); - db::Net *net = net_from_id (make_id_circuit_net (circuit_index, net_index)); - return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index, circuit->net_count (), 1, 4, terminal_ref_index, net->terminal_count (), other_index + 1); - } - - void *make_id_circuit_net_pin (size_t circuit_index, size_t net_index, size_t pin_index) const - { - db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); - return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index, circuit->net_count (), 2, 4, pin_index); - } - - void *make_id_circuit_net_subcircuit_pin (size_t circuit_index, size_t net_index, size_t pin_ref_index) const - { - db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); - return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index, circuit->net_count (), 3, 4, pin_ref_index); - } - - void *make_id_circuit_net_subcircuit_pin_others (size_t circuit_index, size_t net_index, size_t pin_ref_index, size_t other_index) const - { - db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); - db::Net *net = net_from_id (make_id_circuit_net (circuit_index, net_index)); - return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index, circuit->net_count (), 3, 4, pin_ref_index, net->subcircuit_pin_count (), other_index + 1); - } - - void *make_id_circuit_subcircuit (size_t circuit_index, size_t subcircuit_index) const - { - return make_id (circuit_index, netlist ()->circuit_count (), 3, 8, subcircuit_index); - } - - void *make_id_circuit_subcircuit_pin (size_t circuit_index, size_t subcircuit_index, size_t pin_index) const - { - db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); - return make_id (circuit_index, netlist ()->circuit_count (), 3, 8, subcircuit_index, circuit->subcircuit_count (), pin_index + 1); - } - - void *make_id_circuit_device (size_t circuit_index, size_t device_index) const - { - return make_id (circuit_index, netlist ()->circuit_count (), 4, 8, device_index); - } - - void *make_id_circuit_device_terminal (size_t circuit_index, size_t device_index, size_t terminal_index) const - { - db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); - return make_id (circuit_index, netlist ()->circuit_count (), 4, 8, device_index, circuit->device_count (), terminal_index + 1); - } - - bool is_id_circuit (void *id) const - { - pop (id, netlist ()->circuit_count ()); - return id == 0; - } - - bool is_id_circuit_pin (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - pop (id, netlist ()->circuit_count ()); - return (pop (id, 8) == 1 && always (pop (id, circuit->pin_count ())) && id == 0); - } - - bool is_id_circuit_pin_net (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - pop (id, netlist ()->circuit_count ()); - return (pop (id, 8) == 1 && always (pop (id, circuit->pin_count ())) && id != 0); - } - - bool is_id_circuit_net (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - pop (id, netlist ()->circuit_count ()); - return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && id == 0); - } - - bool is_id_circuit_net_device_terminal (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - db::Net *net = net_from_id (id); - pop (id, netlist ()->circuit_count ()); - return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && pop (id, 4) == 1 && always (pop (id, net->terminal_count ())) && id == 0); - } - - bool is_id_circuit_net_device_terminal_others (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - db::Net *net = net_from_id (id); - pop (id, netlist ()->circuit_count ()); - return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && pop (id, 4) == 1 && always (pop (id, net->terminal_count ())) && id != 0); - } - - bool is_id_circuit_net_pin (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - pop (id, netlist ()->circuit_count ()); - return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && pop (id, 4) == 2); - } - - bool is_id_circuit_net_subcircuit_pin (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - db::Net *net = net_from_id (id); - pop (id, netlist ()->circuit_count ()); - return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && pop (id, 4) == 3 && always (pop (id, net->subcircuit_pin_count ())) && id == 0); - } - - bool is_id_circuit_net_subcircuit_pin_others (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - db::Net *net = net_from_id (id); - pop (id, netlist ()->circuit_count ()); - return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && pop (id, 4) == 3 && always (pop (id, net->subcircuit_pin_count ())) && id != 0); - } - - bool is_id_circuit_subcircuit (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - pop (id, netlist ()->circuit_count ()); - return (pop (id, 8) == 3 && always (pop (id, circuit->subcircuit_count ())) && id == 0); - } - - bool is_id_circuit_subcircuit_pin (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - pop (id, netlist ()->circuit_count ()); - return (pop (id, 8) == 3 && always (pop (id, circuit->subcircuit_count ())) && id != 0); - } - - bool is_id_circuit_device (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - pop (id, netlist ()->circuit_count ()); - return (pop (id, 8) == 4 && always (pop (id, circuit->device_count ())) && id == 0); - } - - bool is_id_circuit_device_terminal (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - pop (id, netlist ()->circuit_count ()); - return (pop (id, 8) == 4 && always (pop (id, circuit->device_count ())) && id != 0); - } - - size_t circuit_index_from_id (void *id) const - { - return pop (id, netlist ()->circuit_count ()); - } - - size_t circuit_pin_index_from_id (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - pop (id, netlist ()->circuit_count ()); - pop (id, 8); - return pop (id, circuit->pin_count ()); - } - - size_t circuit_device_index_from_id (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - pop (id, netlist ()->circuit_count ()); - pop (id, 8); - return pop (id, circuit->device_count ()); - } - - size_t circuit_device_terminal_index_from_id (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - pop (id, netlist ()->circuit_count ()); - pop (id, 8); - pop (id, circuit->device_count ()); - return reinterpret_cast (id) - 1; - } - - size_t circuit_subcircuit_index_from_id (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - pop (id, netlist ()->circuit_count ()); - pop (id, 8); - return pop (id, circuit->subcircuit_count ()); - } - - size_t circuit_subcircuit_pin_index_from_id (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - pop (id, netlist ()->circuit_count ()); - pop (id, 8); - pop (id, circuit->subcircuit_count ()); - return reinterpret_cast (id) - 1; - } - - size_t circuit_net_index_from_id (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - pop (id, netlist ()->circuit_count ()); - pop (id, 8); - return pop (id, circuit->net_count ()); - } - - size_t circuit_net_subcircuit_pin_index_from_id (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - db::Net *net = net_from_id (id); - pop (id, netlist ()->circuit_count ()); - pop (id, 8); - pop (id, circuit->net_count ()); - pop (id, 4); - return pop (id, net->subcircuit_pin_count ()); - } - - size_t circuit_net_subcircuit_pin_other_index_from_id (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - db::Net *net = net_from_id (id); - pop (id, netlist ()->circuit_count ()); - pop (id, 8); - pop (id, circuit->net_count ()); - pop (id, 4); - pop (id, net->subcircuit_pin_count ()); - return reinterpret_cast (id) - 1; - } - - size_t circuit_net_device_terminal_index_from_id (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - db::Net *net = net_from_id (id); - pop (id, netlist ()->circuit_count ()); - pop (id, 8); - pop (id, circuit->net_count ()); - pop (id, 4); - return pop (id, net->terminal_count ()); - } - - size_t circuit_net_device_terminal_other_index_from_id (void *id) const - { - db::Circuit *circuit = circuit_from_id (id); - db::Net *net = net_from_id (id); - pop (id, netlist ()->circuit_count ()); - pop (id, 8); - pop (id, circuit->net_count ()); - pop (id, 4); - pop (id, net->terminal_count ()); - return reinterpret_cast (id) - 1; - } - - db::Circuit *circuit_from_id (void *id) const; - db::Net *net_from_id (void *id) const; - const db::NetSubcircuitPinRef *net_pinref_from_id (void *id) const; - const db::NetTerminalRef *net_terminalref_from_id (void *id) const; - db::Device *device_from_id (void *id) const; - db::Pin *pin_from_id (void *id) const; - db::SubCircuit *subcircuit_from_id (void *id) const; - - db::Netlist *netlist () const - { - return const_cast (mp_l2ndb->netlist ()); - } - - db::LayoutToNetlist *mp_l2ndb; - mutable std::map m_circuit_by_index; - mutable std::map > m_net_by_circuit_and_index; - mutable std::map > m_pinref_by_net_and_index; - mutable std::map > m_terminalref_by_net_and_index; - mutable std::map > m_device_by_circuit_and_index; - mutable std::map > m_pin_by_circuit_and_index; - mutable std::map > m_subcircuit_by_circuit_and_index; -}; - -NetlistBrowserModel::NetlistBrowserModel (db::LayoutToNetlist *l2ndb) - : mp_l2ndb (l2ndb) +NetlistBrowserModel::NetlistBrowserModel (QWidget *parent, db::LayoutToNetlist *l2ndb) + : QAbstractItemModel (parent), mp_l2ndb (l2ndb) { // .. nothing yet .. } +NetlistBrowserModel::~NetlistBrowserModel () +{ + // .. nothing yet .. +} + +void * +NetlistBrowserModel::make_id_circuit (size_t circuit_index) const +{ + return make_id (circuit_index); +} + +void * +NetlistBrowserModel::make_id_circuit_pin (size_t circuit_index, size_t pin_index) const +{ + return make_id (circuit_index, netlist ()->circuit_count (), 1, 8, pin_index); +} + +void * +NetlistBrowserModel::make_id_circuit_pin_net (size_t circuit_index, size_t pin_index, size_t net_index) const +{ + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 1, 8, pin_index, circuit->pin_count (), net_index + 1); +} + +void * +NetlistBrowserModel::make_id_circuit_net (size_t circuit_index, size_t net_index) const +{ + return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index); +} + +void * +NetlistBrowserModel::make_id_circuit_net_device_terminal (size_t circuit_index, size_t net_index, size_t terminal_ref_index) const +{ + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index, circuit->net_count (), 1, 4, terminal_ref_index); +} + +void * +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 +{ + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + db::Net *net = net_from_id (make_id_circuit_net (circuit_index, net_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index, circuit->net_count (), 1, 4, terminal_ref_index, net->terminal_count (), other_index + 1); +} + +void * +NetlistBrowserModel::make_id_circuit_net_pin (size_t circuit_index, size_t net_index, size_t pin_index) const +{ + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index, circuit->net_count (), 2, 4, pin_index); +} + +void * +NetlistBrowserModel::make_id_circuit_net_subcircuit_pin (size_t circuit_index, size_t net_index, size_t pin_ref_index) const +{ + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index, circuit->net_count (), 3, 4, pin_ref_index); +} + +void * +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 +{ + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + db::Net *net = net_from_id (make_id_circuit_net (circuit_index, net_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 2, 8, net_index, circuit->net_count (), 3, 4, pin_ref_index, net->subcircuit_pin_count (), other_index + 1); +} + +void * +NetlistBrowserModel::make_id_circuit_subcircuit (size_t circuit_index, size_t subcircuit_index) const +{ + return make_id (circuit_index, netlist ()->circuit_count (), 3, 8, subcircuit_index); +} + +void * +NetlistBrowserModel::make_id_circuit_subcircuit_pin (size_t circuit_index, size_t subcircuit_index, size_t pin_index) const +{ + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 3, 8, subcircuit_index, circuit->subcircuit_count (), pin_index + 1); +} + +void * +NetlistBrowserModel::make_id_circuit_device (size_t circuit_index, size_t device_index) const +{ + return make_id (circuit_index, netlist ()->circuit_count (), 4, 8, device_index); +} + +void * +NetlistBrowserModel::make_id_circuit_device_terminal (size_t circuit_index, size_t device_index, size_t terminal_index) const +{ + db::Circuit *circuit = circuit_from_id (make_id_circuit (circuit_index)); + return make_id (circuit_index, netlist ()->circuit_count (), 4, 8, device_index, circuit->device_count (), terminal_index + 1); +} + +bool +NetlistBrowserModel::is_id_circuit (void *id) const +{ + pop (id, netlist ()->circuit_count ()); + return id == 0; +} + +bool +NetlistBrowserModel::is_id_circuit_pin (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 1 && always (pop (id, circuit->pin_count ())) && id == 0); +} + +bool +NetlistBrowserModel::is_id_circuit_pin_net (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 1 && always (pop (id, circuit->pin_count ())) && id != 0); +} + +bool +NetlistBrowserModel::is_id_circuit_net (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && id == 0); +} + +bool +NetlistBrowserModel::is_id_circuit_net_device_terminal (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && pop (id, 4) == 1 && always (pop (id, net->terminal_count ())) && id == 0); +} + +bool +NetlistBrowserModel::is_id_circuit_net_device_terminal_others (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && pop (id, 4) == 1 && always (pop (id, net->terminal_count ())) && id != 0); +} + +bool +NetlistBrowserModel::is_id_circuit_net_pin (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && pop (id, 4) == 2); +} + +bool +NetlistBrowserModel::is_id_circuit_net_subcircuit_pin (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && pop (id, 4) == 3 && always (pop (id, net->subcircuit_pin_count ())) && id == 0); +} + +bool +NetlistBrowserModel::is_id_circuit_net_subcircuit_pin_others (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 2 && always (pop (id, circuit->net_count ())) && pop (id, 4) == 3 && always (pop (id, net->subcircuit_pin_count ())) && id != 0); +} + +bool +NetlistBrowserModel::is_id_circuit_subcircuit (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 3 && always (pop (id, circuit->subcircuit_count ())) && id == 0); +} + +bool +NetlistBrowserModel::is_id_circuit_subcircuit_pin (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 3 && always (pop (id, circuit->subcircuit_count ())) && id != 0); +} + +bool +NetlistBrowserModel::is_id_circuit_device (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 4 && always (pop (id, circuit->device_count ())) && id == 0); +} + +bool +NetlistBrowserModel::is_id_circuit_device_terminal (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + return (pop (id, 8) == 4 && always (pop (id, circuit->device_count ())) && id != 0); +} + +size_t +NetlistBrowserModel::circuit_index_from_id (void *id) const +{ + return pop (id, netlist ()->circuit_count ()); +} + +size_t +NetlistBrowserModel::circuit_pin_index_from_id (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + return pop (id, circuit->pin_count ()); +} + +size_t +NetlistBrowserModel::circuit_device_index_from_id (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + return pop (id, circuit->device_count ()); +} + +size_t +NetlistBrowserModel::circuit_device_terminal_index_from_id (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + pop (id, circuit->device_count ()); + return reinterpret_cast (id) - 1; +} + +size_t +NetlistBrowserModel::circuit_subcircuit_index_from_id (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + return pop (id, circuit->subcircuit_count ()); +} + +size_t +NetlistBrowserModel::circuit_subcircuit_pin_index_from_id (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + pop (id, circuit->subcircuit_count ()); + return reinterpret_cast (id) - 1; +} + +size_t +NetlistBrowserModel::circuit_net_index_from_id (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + return pop (id, circuit->net_count ()); +} + +size_t +NetlistBrowserModel::circuit_net_pin_index_from_id (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + pop (id, circuit->net_count ()); + pop (id, 4); + return reinterpret_cast (id); +} + +size_t +NetlistBrowserModel::circuit_net_subcircuit_pin_index_from_id (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + pop (id, circuit->net_count ()); + pop (id, 4); + return pop (id, net->subcircuit_pin_count ()); +} + +size_t +NetlistBrowserModel::circuit_net_subcircuit_pin_other_index_from_id (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + pop (id, circuit->net_count ()); + pop (id, 4); + pop (id, net->subcircuit_pin_count ()); + return reinterpret_cast (id) - 1; +} + +size_t +NetlistBrowserModel::circuit_net_device_terminal_index_from_id (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + pop (id, circuit->net_count ()); + pop (id, 4); + return pop (id, net->terminal_count ()); +} + +size_t +NetlistBrowserModel::circuit_net_device_terminal_other_index_from_id (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + db::Net *net = net_from_id (id); + pop (id, netlist ()->circuit_count ()); + pop (id, 8); + pop (id, circuit->net_count ()); + pop (id, 4); + pop (id, net->terminal_count ()); + return reinterpret_cast (id) - 1; +} + void NetlistBrowserModel::self_test (const QModelIndex &p) { @@ -425,13 +418,13 @@ NetlistBrowserModel::self_test (const QModelIndex &p) tl_assert (false); } pp = parent (c); - if (pp.column () != 0) { + if (pp.isValid () && pp.column () != 0) { tl_assert (false); } - if (pp.row () != r) { + if (pp.isValid () && pp.row () != r) { tl_assert (false); } - if (pp.internalId () != p.internalId ()) { + if (pp.isValid () && pp.internalId () != p.internalId ()) { tl_assert (false); } @@ -440,7 +433,7 @@ NetlistBrowserModel::self_test (const QModelIndex &p) tl_assert (false); } pp = parent (c); - if (pp.column () != 1) { + if (pp.isValid () && pp.column () != 1) { tl_assert (false); } @@ -466,22 +459,6 @@ NetlistBrowserModel::data (const QModelIndex &index, int role) const void *id = index.internalPointer (); - /* - * - circuits - * - 0..#pins: pins - * - net (1x) - * - #pins..#pins+#nets: nets - * - 0..#devices: terminals - * - other terminals and nets - * - #devices..#devices+#pins: pins - * - #devices+#pins..: subcircuit pins - * - other pins and nets - * - #pins+#nets..#pins+#nets+#subcircuits: subcircuits - * - pins and nets - * - #pins+#nets+#subcircuits..: devices - * - terminals and nets - */ - if (is_id_circuit (id)) { db::Circuit *circuit = circuit_from_id (id); @@ -489,13 +466,24 @@ NetlistBrowserModel::data (const QModelIndex &index, int role) const return tl::to_qstring (circuit->name ()); } - } else if (is_id_circuit_pin (id) || is_id_circuit_net_subcircuit_pin_others (id)) { + } else if (is_id_circuit_pin (id) || is_id_circuit_net_pin (id)) { db::Pin *pin = pin_from_id (id); if (pin) { return tl::to_qstring (pin->expanded_name ()); } + } else if (is_id_circuit_pin_net (id)) { + + db::Circuit *circuit = circuit_from_id (id); + db::Pin *pin = pin_from_id (id); + if (pin) { + db::Net *net = circuit->net_for_pin (pin->id ()); + if (net) { + return tl::to_qstring (net->expanded_name ()); + } + } + } else if (is_id_circuit_device (id)) { db::Device *device = device_from_id (id); @@ -524,6 +512,17 @@ NetlistBrowserModel::data (const QModelIndex &index, int role) const return tl::to_qstring (ref->pin ()->expanded_name ()); } + } else if (is_id_circuit_net_subcircuit_pin_others (id)) { + + const db::NetSubcircuitPinRef *ref = net_pinref_from_id (id); + size_t other_index = circuit_net_device_terminal_other_index_from_id (id); + + if (ref && ref->pin () && ref->subcircuit () && ref->subcircuit ()->circuit_ref () && ref->subcircuit ()->circuit_ref ()->pin_by_id (other_index)) { + + const db::Pin *pin = ref->subcircuit ()->circuit_ref ()->pin_by_id (other_index); + return tl::to_qstring (pin->expanded_name ()); + } + } else if (is_id_circuit_net_device_terminal (id)) { const db::NetTerminalRef *ref = net_terminalref_from_id (id); @@ -599,89 +598,80 @@ NetlistBrowserModel::headerData (int /*section*/, Qt::Orientation /*orientation* QModelIndex NetlistBrowserModel::index (int row, int column, const QModelIndex &parent) const { + void *new_id = 0; + if (! parent.isValid ()) { - return createIndex (row, column, make_id_circuit (row)); + new_id = make_id_circuit (row); } else { void *id = parent.internalPointer (); - /* - * - circuits - * - 0..#pins: pins - * - net (1x) - * - #pins..#pins+#nets: nets - * - 0..#devices: terminals - * - other terminals and nets - * - #devices..#devices+#pins: pins - * - #devices+#pins..: subcircuit pins - * - other pins and nets - * - #pins+#nets..#pins+#nets+#subcircuits: subcircuits - * - pins and nets - * - #pins+#nets+#subcircuits..: devices - * - terminals and nets - */ - if (is_id_circuit (id)) { db::Circuit *circuit = circuit_from_id (id); - if (size_t (row) < circuit->pin_count ()) { - return createIndex (row, column, make_id_circuit_pin (circuit_index_from_id (id), row)); - } - row -= int (circuit->pin_count ()); - if (size_t (row) < circuit->net_count ()) { - return createIndex (row, column, make_id_circuit_net (circuit_index_from_id (id), row)); - } - row -= int (circuit->net_count ()); - if (size_t (row) < circuit->subcircuit_count ()) { - return createIndex (row, column, make_id_circuit_subcircuit (circuit_index_from_id (id), row)); - } - row -= int (circuit->subcircuit_count ()); - if (size_t (row) < circuit->device_count ()) { - return createIndex (row, column, make_id_circuit_device (circuit_index_from_id (id), row)); + if (row < int (circuit->pin_count ())) { + new_id = make_id_circuit_pin (circuit_index_from_id (id), row); + } else { + row -= int (circuit->pin_count ()); + if (row < int (circuit->net_count ())) { + new_id = make_id_circuit_net (circuit_index_from_id (id), row); + } else { + row -= int (circuit->net_count ()); + if (row < int (circuit->subcircuit_count ())) { + new_id = make_id_circuit_subcircuit (circuit_index_from_id (id), row); + } else { + row -= int (circuit->subcircuit_count ()); + if (row < int (circuit->device_count ())) { + new_id = make_id_circuit_device (circuit_index_from_id (id), row); + } + } + } } } else if (is_id_circuit_pin (id)) { - return createIndex (row, column, make_id_circuit_pin_net (circuit_index_from_id (id), circuit_pin_index_from_id (id), row)); + new_id = make_id_circuit_pin_net (circuit_index_from_id (id), circuit_pin_index_from_id (id), row); } else if (is_id_circuit_device (id)) { - return createIndex (row, column, make_id_circuit_device_terminal (circuit_index_from_id (id), circuit_device_index_from_id (id), row)); + new_id = make_id_circuit_device_terminal (circuit_index_from_id (id), circuit_device_index_from_id (id), row); } else if (is_id_circuit_subcircuit (id)) { - return createIndex (row, column, make_id_circuit_subcircuit_pin (circuit_index_from_id (id), circuit_subcircuit_index_from_id (id), row)); + new_id = make_id_circuit_subcircuit_pin (circuit_index_from_id (id), circuit_subcircuit_index_from_id (id), row); } else if (is_id_circuit_net (id)) { db::Net *net = net_from_id (id); - if (size_t (row) < net->terminal_count ()) { - return createIndex (row, column, make_id_circuit_net_device_terminal (circuit_index_from_id (id), circuit_net_index_from_id (id), row)); - } - row -= int (net->terminal_count ()); - if (size_t (row) < net->pin_count ()) { - return createIndex (row, column, make_id_circuit_net_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), row)); - } - row -= int (net->pin_count ()); - if (size_t (row) < net->subcircuit_pin_count ()) { - return createIndex (row, column, make_id_circuit_net_subcircuit_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), row)); + if (row < int (net->terminal_count ())) { + new_id = make_id_circuit_net_device_terminal (circuit_index_from_id (id), circuit_net_index_from_id (id), row); + } else { + row -= int (net->terminal_count ()); + if (row < int (net->pin_count ())) { + new_id = make_id_circuit_net_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), row); + } else { + row -= int (net->pin_count ()); + if (row < int (net->subcircuit_pin_count ())) { + new_id = make_id_circuit_net_subcircuit_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), row); + } + } } } else if (is_id_circuit_net_subcircuit_pin (id)) { - return createIndex (row, column, make_id_circuit_net_subcircuit_pin_others (circuit_index_from_id (id), circuit_net_index_from_id (id), circuit_net_subcircuit_pin_index_from_id (id), row)); + 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), row); } else if (is_id_circuit_net_device_terminal (id)) { - return createIndex (row, column, make_id_circuit_net_device_terminal_others (circuit_index_from_id (id), circuit_net_index_from_id (id), circuit_net_device_terminal_index_from_id (id), row)); + 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), row); } } - return QModelIndex (); + return createIndex (row, column, new_id); } QModelIndex @@ -696,22 +686,6 @@ NetlistBrowserModel::parent (const QModelIndex &index) const void *id = index.internalPointer (); int column = index.column (); - /* - * - circuits - * - 0..#pins: pins - * - net (1x) - * - #pins..#pins+#nets: nets - * - 0..#devices: terminals - * - other terminals and nets - * - #devices..#devices+#pins: pins - * - #devices+#pins..: subcircuit pins - * - other pins and nets - * - #pins+#nets..#pins+#nets+#subcircuits: subcircuits - * - pins and nets - * - #pins+#nets+#subcircuits..: devices - * - terminals and nets - */ - if (is_id_circuit (id)) { return QModelIndex (); @@ -766,22 +740,6 @@ NetlistBrowserModel::rowCount (const QModelIndex &parent) const void *id = parent.internalPointer (); - /* - * - circuits - * - 0..#pins: pins - * - net (1x) - * - #pins..#pins+#nets: nets - * - 0..#devices: terminals - * - other terminals and nets - * - #devices..#devices+#pins: pins - * - #devices+#pins..: subcircuit pins - * - other pins and nets - * - #pins+#nets..#pins+#nets+#subcircuits: subcircuits - * - pins and nets - * - #pins+#nets+#subcircuits..: devices - * - terminals and nets - */ - if (is_id_circuit (id)) { db::Circuit *circuit = circuit_from_id (id); @@ -841,7 +799,7 @@ NetlistBrowserModel::net_from_id (void *id) const size_t index = circuit_net_index_from_id (id); std::map >::iterator cc = m_net_by_circuit_and_index.find (circuit); - if (cc != m_net_by_circuit_and_index.end ()) { + if (cc == m_net_by_circuit_and_index.end ()) { cc = m_net_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; } @@ -868,7 +826,7 @@ NetlistBrowserModel::net_pinref_from_id (void *id) const size_t index = circuit_net_subcircuit_pin_index_from_id (id); std::map >::iterator cc = m_pinref_by_net_and_index.find (net); - if (cc != m_pinref_by_net_and_index.end ()) { + if (cc == m_pinref_by_net_and_index.end ()) { cc = m_pinref_by_net_and_index.insert (std::make_pair (net, std::map ())).first; } @@ -895,7 +853,7 @@ NetlistBrowserModel::net_terminalref_from_id (void *id) const size_t index = circuit_net_device_terminal_index_from_id (id); std::map >::iterator cc = m_terminalref_by_net_and_index.find (net); - if (cc != m_terminalref_by_net_and_index.end ()) { + if (cc == m_terminalref_by_net_and_index.end ()) { cc = m_terminalref_by_net_and_index.insert (std::make_pair (net, std::map ())).first; } @@ -922,7 +880,7 @@ NetlistBrowserModel::device_from_id (void *id) const size_t index = circuit_device_index_from_id (id); std::map >::iterator cc = m_device_by_circuit_and_index.find (circuit); - if (cc != m_device_by_circuit_and_index.end ()) { + if (cc == m_device_by_circuit_and_index.end ()) { cc = m_device_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; } @@ -945,28 +903,57 @@ NetlistBrowserModel::device_from_id (void *id) const db::Pin * NetlistBrowserModel::pin_from_id (void *id) const { - db::Circuit *circuit = circuit_from_id (id); - size_t index = circuit_pin_index_from_id (id); + if (is_id_circuit_net_pin (id)) { - std::map >::iterator cc = m_pin_by_circuit_and_index.find (circuit); - if (cc != m_pin_by_circuit_and_index.end ()) { - cc = m_pin_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; - } + db::Net *net = net_from_id (id); + size_t index = circuit_net_pin_index_from_id (id); - std::map::iterator c = cc->second.find (index); - if (c == cc->second.end ()) { - - c = cc->second.insert (std::make_pair (index, (db::Pin *) 0)).first; - for (db::Circuit::pin_iterator i = circuit->begin_pins (); i != circuit->end_pins (); ++i) { - if (index-- == 0) { - c->second = i.operator-> (); - break; - } + std::map >::iterator cc = m_pin_by_net_and_index.find (net); + if (cc == m_pin_by_net_and_index.end ()) { + cc = m_pin_by_net_and_index.insert (std::make_pair (net, std::map ())).first; } - } + std::map::iterator c = cc->second.find (index); + if (c == cc->second.end ()) { - return c->second; + c = cc->second.insert (std::make_pair (index, (db::Pin *) 0)).first; + for (db::Net::pin_iterator i = net->begin_pins (); i != net->end_pins (); ++i) { + if (index-- == 0) { + c->second = const_cast (i->pin ()); + break; + } + } + + } + + return c->second; + + } else { + + db::Circuit *circuit = circuit_from_id (id); + size_t index = circuit_pin_index_from_id (id); + + std::map >::iterator cc = m_pin_by_circuit_and_index.find (circuit); + if (cc == m_pin_by_circuit_and_index.end ()) { + cc = m_pin_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; + } + + std::map::iterator c = cc->second.find (index); + if (c == cc->second.end ()) { + + c = cc->second.insert (std::make_pair (index, (db::Pin *) 0)).first; + for (db::Circuit::pin_iterator i = circuit->begin_pins (); i != circuit->end_pins (); ++i) { + if (index-- == 0) { + c->second = i.operator-> (); + break; + } + } + + } + + return c->second; + + } } db::SubCircuit * @@ -976,7 +963,7 @@ NetlistBrowserModel::subcircuit_from_id (void *id) const size_t index = circuit_subcircuit_index_from_id (id); std::map >::iterator cc = m_subcircuit_by_circuit_and_index.find (circuit); - if (cc != m_subcircuit_by_circuit_and_index.end ()) { + if (cc == m_subcircuit_by_circuit_and_index.end ()) { cc = m_subcircuit_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; } @@ -1141,15 +1128,21 @@ NetlistBrowserPage::set_l2ndb (db::LayoutToNetlist *database) { if (database != mp_database.get ()) { - // @@@ release_markers (); - mp_database.reset (database); + // @@@ release_markers (); + QAbstractItemModel *tree_model = directory_tree->model (); - NetlistBrowserModel *new_model = new NetlistBrowserModel (database); + NetlistBrowserModel *new_model = new NetlistBrowserModel (this, database); #if !defined(NDEBUG) - new_model->self_test (); + try { + new_model->self_test (); // might throw an exception! + } catch (...) { + delete new_model; + mp_database.reset (0); + throw; + } #endif directory_tree->setModel (new_model); diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.h b/src/laybasic/laybasic/layNetlistBrowserPage.h index c8be1d4fd..6a7fe39a1 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.h +++ b/src/laybasic/laybasic/layNetlistBrowserPage.h @@ -26,23 +26,124 @@ #include "ui_NetlistBrowserPage.h" #include "layNetlistBrowser.h" +#include "laybasicCommon.h" #include "dbBox.h" +#include "dbLayoutToNetlist.h" #include +#include class QAction; -namespace db -{ - class LayoutToNetlist; -} - namespace lay { class LayoutView; class PluginRoot; +// ---------------------------------------------------------------------------------- +// NetlistBrowserModel definition + +/** + * @brief The NetlistBrowserModel + * + * The model hierarchy is the following + * - circuits + * - 0..#pins: pins + * - net (1x) + * - #pins..#pins+#nets: nets + * - 0..#devices: terminals + * - other terminals and nets + * - #devices..#devices+#pins: pins + * - #devices+#pins..: subcircuit pins + * - other pins and nets + * - #pins+#nets..#pins+#nets+#subcircuits: subcircuits + * - pins and nets + * - #pins+#nets+#subcircuits..: devices + * - terminals and nets + */ +class LAYBASIC_PUBLIC NetlistBrowserModel + : public QAbstractItemModel +{ +public: + NetlistBrowserModel (QWidget *parent, db::LayoutToNetlist *l2ndb); + ~NetlistBrowserModel (); + + virtual int columnCount (const QModelIndex &parent) const; + virtual QVariant data (const QModelIndex &index, int role) const; + virtual Qt::ItemFlags flags (const QModelIndex &index) const; + virtual bool hasChildren (const QModelIndex &parent) const; + virtual QVariant headerData (int section, Qt::Orientation orientation, int role) const; + virtual QModelIndex index (int row, int column, const QModelIndex &parent) const; + virtual QModelIndex parent (const QModelIndex &index) const; + virtual int rowCount (const QModelIndex &parent) const; + + void self_test (const QModelIndex &index = QModelIndex ()); + +private: + + 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; + db::Circuit *circuit_from_id (void *id) const; + db::Net *net_from_id (void *id) const; + const db::NetSubcircuitPinRef *net_pinref_from_id (void *id) const; + const db::NetTerminalRef *net_terminalref_from_id (void *id) const; + db::Device *device_from_id (void *id) const; + db::Pin *pin_from_id (void *id) const; + db::SubCircuit *subcircuit_from_id (void *id) const; + + db::Netlist *netlist () const + { + return const_cast (mp_l2ndb->netlist ()); + } + + db::LayoutToNetlist *mp_l2ndb; + mutable std::map m_circuit_by_index; + mutable std::map > m_net_by_circuit_and_index; + mutable std::map > m_pinref_by_net_and_index; + mutable std::map > m_terminalref_by_net_and_index; + mutable std::map > m_pin_by_net_and_index; + mutable std::map > m_device_by_circuit_and_index; + mutable std::map > m_pin_by_circuit_and_index; + mutable std::map > m_subcircuit_by_circuit_and_index; +}; + /** * @brief A marker browser page */ diff --git a/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc b/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc new file mode 100644 index 000000000..b62d24ea9 --- /dev/null +++ b/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc @@ -0,0 +1,111 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2019 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 "layNetlistBrowserPage.h" +#include "tlUnitTest.h" + +TEST (1) +{ + db::LayoutToNetlist l2n; + l2n.load (tl::testsrc () + "/testdata/lay/l2n_browser.l2n"); + + std::auto_ptr model (new lay::NetlistBrowserModel (0, &l2n)); + + EXPECT_EQ (model->hasChildren (QModelIndex ()), true); + // two circuits + EXPECT_EQ (model->rowCount (QModelIndex ()), 2); + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, QModelIndex ()), Qt::DisplayRole).toString ()), "INV2"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, QModelIndex ()), Qt::DisplayRole).toString ()), "RINGO"); + EXPECT_EQ (model->parent (model->index (0, 0, QModelIndex ())).isValid (), false); + EXPECT_EQ (model->parent (model->index (1, 0, QModelIndex ())).isValid (), false); + + QModelIndex ringoIndex = model->index (1, 0, QModelIndex ()); + QModelIndex inv2Index = model->index (0, 0, QModelIndex ()); + + EXPECT_EQ (model->hasChildren (inv2Index), true); + // 5 pins, 5 nets, 0 subcircuits, 4 devices + EXPECT_EQ (model->rowCount (inv2Index), 14); + // Pins + 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"); + // Nets + 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 (6, 0, inv2Index), Qt::DisplayRole).toString ()), "$2"); + EXPECT_EQ (tl::to_string (model->data (model->index (7, 0, inv2Index), Qt::DisplayRole).toString ()), "NOUT"); + 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 (9, 0, inv2Index), Qt::DisplayRole).toString ()), "$5"); + // No Subcircuits + // Devices + EXPECT_EQ (tl::to_string (model->data (model->index (10, 0, inv2Index), Qt::DisplayRole).toString ()), "$1"); + EXPECT_EQ (tl::to_string (model->data (model->index (11, 0, inv2Index), Qt::DisplayRole).toString ()), "$2"); + EXPECT_EQ (tl::to_string (model->data (model->index (12, 0, inv2Index), Qt::DisplayRole).toString ()), "$3"); + EXPECT_EQ (tl::to_string (model->data (model->index (13, 0, inv2Index), Qt::DisplayRole).toString ()), "$4"); + + EXPECT_EQ (model->hasChildren (ringoIndex), true); + // 0 pins, 12 nets, 10 subcircuits, 0 devices + EXPECT_EQ (model->rowCount (ringoIndex), 22); + // Pins + // Nets + EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoIndex), Qt::DisplayRole).toString ()), "FB"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, ringoIndex), Qt::DisplayRole).toString ()), "VSS"); + EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoIndex), Qt::DisplayRole).toString ()), "VDD"); + // Subcircuits + EXPECT_EQ (tl::to_string (model->data (model->index (12, 0, ringoIndex), Qt::DisplayRole).toString ()), "$1"); + EXPECT_EQ (tl::to_string (model->data (model->index (21, 0, ringoIndex), Qt::DisplayRole).toString ()), "$10"); + // Devices + + // OUT pin of INV2 has a single child node which is the "OUT" net + QModelIndex inv2PinOutIndex = model->index (2, 0, inv2Index); + 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->hasChildren (inv2PinOutIndexNet), false); + EXPECT_EQ (model->rowCount (inv2PinOutIndexNet), 0); + + // NOUT net has 1 pin, 2 devices + QModelIndex inv2NOutIndex = model->index (7, 0, inv2Index); + 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::DisplayRole).toString ()), "D"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2NOutIndex), Qt::DisplayRole).toString ()), "D"); + EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, inv2NOutIndex), Qt::DisplayRole).toString ()), "OUT"); + + // no children for pins on nets + QModelIndex inv2NOutPinOutIndex = model->index (2, 0, inv2NOutIndex); + EXPECT_EQ (model->hasChildren (inv2NOutPinOutIndex), false); + EXPECT_EQ (model->rowCount (inv2NOutPinOutIndex), 0); + + // a MOS3 transistor has three other terminals + QModelIndex inv2NOutDeviceIndex = model->index (0, 0, inv2NOutIndex); + EXPECT_EQ (model->hasChildren (inv2NOutDeviceIndex), true); + EXPECT_EQ (model->rowCount (inv2NOutDeviceIndex), 3); + + + +} + diff --git a/src/laybasic/unit_tests/unit_tests.pro b/src/laybasic/unit_tests/unit_tests.pro index 5fd39fc2f..d886cd865 100644 --- a/src/laybasic/unit_tests/unit_tests.pro +++ b/src/laybasic/unit_tests/unit_tests.pro @@ -14,10 +14,11 @@ SOURCES = \ layParsedLayerSource.cc \ layRenderer.cc \ laySnap.cc \ - layAbstractMenu.cc + layAbstractMenu.cc \ + layNetlistBrowserModelTests.cc -INCLUDEPATH += $$TL_INC $$LAYBASIC_INC $$DB_INC $$GSI_INC -DEPENDPATH += $$TL_INC $$LAYBASIC_INC $$DB_INC $$GSI_INC +INCLUDEPATH += $$TL_INC $$LAYBASIC_INC $$DB_INC $$GSI_INC $$OUT_PWD/../laybasic +DEPENDPATH += $$TL_INC $$LAYBASIC_INC $$DB_INC $$GSI_INC $$OUT_PWD/../laybasic LIBS += -L$$DESTDIR_UT -lklayout_laybasic -lklayout_db -lklayout_tl -lklayout_gsi diff --git a/src/tl/unit_tests/unit_tests.pro b/src/tl/unit_tests/unit_tests.pro index aa8106e22..97df6b507 100644 --- a/src/tl/unit_tests/unit_tests.pro +++ b/src/tl/unit_tests/unit_tests.pro @@ -35,9 +35,9 @@ SOURCES = \ tlHttpStream.cc \ tlInt128Support.cc \ tlLongInt.cc \ - tlUniqueIdTests.cc \ - tlListTests.cc \ - tlEquivalenceClustersTests.cc + tlUniqueIdTests.cc \ + tlListTests.cc \ + tlEquivalenceClustersTests.cc !equals(HAVE_QT, "0") { From 969d4e80cd602303aeeb784119884a62b8d1013e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 22 Apr 2019 09:28:26 +0200 Subject: [PATCH 007/229] WIP: netlist browser. --- .../laybasic/layNetlistBrowserPage.cc | 27 ++++++++-- .../unit_tests/layNetlistBrowserModelTests.cc | 53 ++++++++++++++++++- 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index 0b92c9741..fa6ecae54 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -466,7 +466,7 @@ NetlistBrowserModel::data (const QModelIndex &index, int role) const return tl::to_qstring (circuit->name ()); } - } else if (is_id_circuit_pin (id) || is_id_circuit_net_pin (id)) { + } else if (is_id_circuit_pin (id) || is_id_circuit_net_pin (id) || is_id_circuit_subcircuit_pin (id)) { db::Pin *pin = pin_from_id (id); if (pin) { @@ -491,6 +491,16 @@ NetlistBrowserModel::data (const QModelIndex &index, int role) const return tl::to_qstring (device->expanded_name ()); } + } else if (is_id_circuit_device_terminal (id)) { + + db::Device *device = device_from_id (id); + if (device && device->device_class ()) { + size_t terminal = circuit_device_terminal_index_from_id (id); + if (device->device_class ()->terminal_definitions ().size () > terminal) { + return tl::to_qstring (device->device_class ()->terminal_definitions () [terminal].name ()); + } + } + } else if (is_id_circuit_subcircuit (id)) { db::SubCircuit *subcircuit = subcircuit_from_id (id); @@ -515,7 +525,7 @@ NetlistBrowserModel::data (const QModelIndex &index, int role) const } else if (is_id_circuit_net_subcircuit_pin_others (id)) { const db::NetSubcircuitPinRef *ref = net_pinref_from_id (id); - size_t other_index = circuit_net_device_terminal_other_index_from_id (id); + size_t other_index = circuit_net_subcircuit_pin_other_index_from_id (id); if (ref && ref->pin () && ref->subcircuit () && ref->subcircuit ()->circuit_ref () && ref->subcircuit ()->circuit_ref ()->pin_by_id (other_index)) { @@ -930,8 +940,17 @@ NetlistBrowserModel::pin_from_id (void *id) const } else { - db::Circuit *circuit = circuit_from_id (id); - size_t index = circuit_pin_index_from_id (id); + db::Circuit *circuit; + size_t index; + + if (is_id_circuit_subcircuit_pin (id)) { + db::SubCircuit *subcircuit = subcircuit_from_id (id); + circuit = subcircuit->circuit_ref (); + index = circuit_subcircuit_pin_index_from_id (id); + } else { + circuit = circuit_from_id (id); + index = circuit_pin_index_from_id (id); + } std::map >::iterator cc = m_pin_by_circuit_and_index.find (circuit); if (cc == m_pin_by_circuit_and_index.end ()) { diff --git a/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc b/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc index b62d24ea9..bdb7c358d 100644 --- a/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc +++ b/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc @@ -86,7 +86,7 @@ TEST (1) EXPECT_EQ (model->hasChildren (inv2PinOutIndexNet), false); EXPECT_EQ (model->rowCount (inv2PinOutIndexNet), 0); - // NOUT net has 1 pin, 2 devices + // NOUT net has 1 pin, 2 devices, 0 subcircuits QModelIndex inv2NOutIndex = model->index (7, 0, inv2Index); EXPECT_EQ (model->hasChildren (inv2NOutIndex), true); EXPECT_EQ (model->rowCount (inv2NOutIndex), 3); @@ -105,7 +105,58 @@ TEST (1) EXPECT_EQ (model->hasChildren (inv2NOutDeviceIndex), true); EXPECT_EQ (model->rowCount (inv2NOutDeviceIndex), 3); + 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"); + QModelIndex inv2NOutDeviceGateIndex = model->index (1, 0, inv2NOutDeviceIndex); + EXPECT_EQ (model->hasChildren (inv2NOutDeviceGateIndex), false); + EXPECT_EQ (model->rowCount (inv2NOutDeviceGateIndex), 0); + // FB net has 0 pin, 0 devices, 2 subcircuits + QModelIndex ringoFbIndex = model->index (0, 0, ringoIndex); + 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::DisplayRole).toString ()), "$1"); + EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, ringoFbIndex), Qt::DisplayRole).toString ()), "IN"); + + QModelIndex ringoFbSubcircuit2Index = model->index (1, 0, ringoFbIndex); + EXPECT_EQ (model->hasChildren (ringoFbSubcircuit2Index), true); + EXPECT_EQ (model->rowCount (ringoFbSubcircuit2Index), 5); + + 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 (1, 0, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "$1"); + 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 (3, 0, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "$3"); + EXPECT_EQ (tl::to_string (model->data (model->index (4, 0, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "$4"); + + QModelIndex ringoFbSubcircuit2InPinIndex = model->index (1, 0, ringoFbSubcircuit2Index); + EXPECT_EQ (model->hasChildren (ringoFbSubcircuit2InPinIndex), false); + EXPECT_EQ (model->rowCount (ringoFbSubcircuit2InPinIndex), 0); + + // Subcircuit 1 of RINGO has 5 pins + + QModelIndex ringoSubcircuit1Index = model->index (12, 0, ringoIndex); + EXPECT_EQ (model->hasChildren (ringoSubcircuit1Index), true); + EXPECT_EQ (model->rowCount (ringoSubcircuit1Index), 5); + + EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoSubcircuit1Index), Qt::DisplayRole).toString ()), "OUT"); + + QModelIndex ringoSubcircuit1OutPinIndex = model->index (2, 0, ringoSubcircuit1Index); + EXPECT_EQ (model->hasChildren (ringoSubcircuit1OutPinIndex), false); + EXPECT_EQ (model->rowCount (ringoSubcircuit1OutPinIndex), 0); + + // Device 1 of INV2 has 3 pins + + QModelIndex inv2Device1Index = model->index (10, 0, inv2Index); + EXPECT_EQ (model->hasChildren (inv2Device1Index), true); + EXPECT_EQ (model->rowCount (inv2Device1Index), 3); + + EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Device1Index), Qt::DisplayRole).toString ()), "G"); + + QModelIndex inv2Device1GateIndex = model->index (1, 0, inv2Device1Index); + EXPECT_EQ (model->hasChildren (inv2Device1GateIndex), false); + EXPECT_EQ (model->rowCount (inv2Device1GateIndex), 0); } From 611cf9eb7bfc2b20e8ff02eda52452cf9f8bf86d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 22 Apr 2019 21:28:19 +0200 Subject: [PATCH 008/229] WIP: some refactoring --- .../laybasic/layNetlistBrowserPage.cc | 193 +++++------------- src/laybasic/laybasic/layNetlistBrowserPage.h | 7 +- 2 files changed, 53 insertions(+), 147 deletions(-) diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index fa6ecae54..881d03f22 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -466,7 +466,7 @@ NetlistBrowserModel::data (const QModelIndex &index, int role) const return tl::to_qstring (circuit->name ()); } - } else if (is_id_circuit_pin (id) || is_id_circuit_net_pin (id) || is_id_circuit_subcircuit_pin (id)) { + } else if (is_id_circuit_pin (id) || is_id_circuit_subcircuit_pin (id)) { db::Pin *pin = pin_from_id (id); if (pin) { @@ -515,20 +515,26 @@ NetlistBrowserModel::data (const QModelIndex &index, int role) const return tl::to_qstring (net->expanded_name ()); } + } else if (is_id_circuit_net_pin (id)) { + + const db::NetPinRef *ref = net_pinref_from_id (id); + if (ref && ref->pin ()) { + return tl::to_qstring (ref->pin ()->expanded_name ()); + } + } else if (is_id_circuit_net_subcircuit_pin (id)) { - const db::NetSubcircuitPinRef *ref = net_pinref_from_id (id); + const db::NetSubcircuitPinRef *ref = net_subcircuit_pinref_from_id (id); if (ref && ref->pin ()) { return tl::to_qstring (ref->pin ()->expanded_name ()); } } else if (is_id_circuit_net_subcircuit_pin_others (id)) { - const db::NetSubcircuitPinRef *ref = net_pinref_from_id (id); + const db::NetSubcircuitPinRef *ref = net_subcircuit_pinref_from_id (id); size_t other_index = circuit_net_subcircuit_pin_other_index_from_id (id); if (ref && ref->pin () && ref->subcircuit () && ref->subcircuit ()->circuit_ref () && ref->subcircuit ()->circuit_ref ()->pin_by_id (other_index)) { - const db::Pin *pin = ref->subcircuit ()->circuit_ref ()->pin_by_id (other_index); return tl::to_qstring (pin->expanded_name ()); } @@ -587,7 +593,7 @@ NetlistBrowserModel::hasChildren (const QModelIndex &parent) const db::Net *net = net_from_id (id); return net->pin_count () + net->subcircuit_pin_count () + net->terminal_count () > 0; } else if (is_id_circuit_net_subcircuit_pin (id)) { - const db::NetSubcircuitPinRef *ref = net_pinref_from_id (id); + const db::NetSubcircuitPinRef *ref = net_subcircuit_pinref_from_id (id); return ref->subcircuit ()->circuit_ref () && ref->subcircuit ()->circuit_ref ()->pin_count () > 0; } else if (is_id_circuit_net_device_terminal (id)) { const db::NetTerminalRef *ref = net_terminalref_from_id (id); @@ -802,24 +808,21 @@ NetlistBrowserModel::circuit_from_id (void *id) const return c->second; } -db::Net * -NetlistBrowserModel::net_from_id (void *id) const +template +static Attr *attr_by_object_and_index (Obj *obj, size_t index, const Iter &begin, const Iter &end, std::map > &cache) { - db::Circuit *circuit = circuit_from_id (id); - size_t index = circuit_net_index_from_id (id); - - std::map >::iterator cc = m_net_by_circuit_and_index.find (circuit); - if (cc == m_net_by_circuit_and_index.end ()) { - cc = m_net_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; + typename std::map >::iterator cc = cache.find (obj); + if (cc == cache.end ()) { + cc = cache.insert (std::make_pair (obj, std::map ())).first; } - std::map::iterator c = cc->second.find (index); + typename std::map::iterator c = cc->second.find (index); if (c == cc->second.end ()) { - c = cc->second.insert (std::make_pair (index, (db::Net *) 0)).first; - for (db::Circuit::net_iterator i = circuit->begin_nets (); i != circuit->end_nets (); ++i) { + c = cc->second.insert (std::make_pair (index, (Attr *) 0)).first; + for (Iter i = begin; i != end; ++i) { if (index-- == 0) { - c->second = i.operator-> (); + c->second = const_cast (i.operator-> ()); break; } } @@ -829,31 +832,31 @@ NetlistBrowserModel::net_from_id (void *id) const return c->second; } +db::Net * +NetlistBrowserModel::net_from_id (void *id) const +{ + db::Circuit *circuit = circuit_from_id (id); + size_t index = circuit_net_index_from_id (id); + + return attr_by_object_and_index (circuit, index, circuit->begin_nets (), circuit->end_nets (), m_net_by_circuit_and_index); +} + const db::NetSubcircuitPinRef * -NetlistBrowserModel::net_pinref_from_id (void *id) const +NetlistBrowserModel::net_subcircuit_pinref_from_id (void *id) const { db::Net *net = net_from_id (id); size_t index = circuit_net_subcircuit_pin_index_from_id (id); - std::map >::iterator cc = m_pinref_by_net_and_index.find (net); - if (cc == m_pinref_by_net_and_index.end ()) { - cc = m_pinref_by_net_and_index.insert (std::make_pair (net, std::map ())).first; - } + return attr_by_object_and_index (net, index, net->begin_subcircuit_pins (), net->end_subcircuit_pins (), m_subcircuit_pinref_by_net_and_index); +} - std::map::iterator c = cc->second.find (index); - if (c == cc->second.end ()) { +const db::NetPinRef * +NetlistBrowserModel::net_pinref_from_id (void *id) const +{ + db::Net *net = net_from_id (id); + size_t index = circuit_net_pin_index_from_id (id); - c = cc->second.insert (std::make_pair (index, (db::NetSubcircuitPinRef *) 0)).first; - for (db::Net::subcircuit_pin_iterator i = net->begin_subcircuit_pins (); i != net->end_subcircuit_pins (); ++i) { - if (index-- == 0) { - c->second = i.operator-> (); - break; - } - } - - } - - return c->second; + return attr_by_object_and_index (net, index, net->begin_pins (), net->end_pins (), m_pinref_by_net_and_index); } const db::NetTerminalRef * @@ -862,25 +865,7 @@ NetlistBrowserModel::net_terminalref_from_id (void *id) const db::Net *net = net_from_id (id); size_t index = circuit_net_device_terminal_index_from_id (id); - std::map >::iterator cc = m_terminalref_by_net_and_index.find (net); - if (cc == m_terminalref_by_net_and_index.end ()) { - cc = m_terminalref_by_net_and_index.insert (std::make_pair (net, std::map ())).first; - } - - std::map::iterator c = cc->second.find (index); - if (c == cc->second.end ()) { - - c = cc->second.insert (std::make_pair (index, (db::NetTerminalRef *) 0)).first; - for (db::Net::terminal_iterator i = net->begin_terminals (); i != net->end_terminals (); ++i) { - if (index-- == 0) { - c->second = i.operator-> (); - break; - } - } - - } - - return c->second; + return attr_by_object_and_index (net, index, net->begin_terminals (), net->end_terminals (), m_terminalref_by_net_and_index); } db::Device * @@ -889,88 +874,26 @@ NetlistBrowserModel::device_from_id (void *id) const db::Circuit *circuit = circuit_from_id (id); size_t index = circuit_device_index_from_id (id); - std::map >::iterator cc = m_device_by_circuit_and_index.find (circuit); - if (cc == m_device_by_circuit_and_index.end ()) { - cc = m_device_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; - } - - std::map::iterator c = cc->second.find (index); - if (c == cc->second.end ()) { - - c = cc->second.insert (std::make_pair (index, (db::Device *) 0)).first; - for (db::Circuit::device_iterator i = circuit->begin_devices (); i != circuit->end_devices (); ++i) { - if (index-- == 0) { - c->second = i.operator-> (); - break; - } - } - - } - - return c->second; + return attr_by_object_and_index (circuit, index, circuit->begin_devices (), circuit->end_devices (), m_device_by_circuit_and_index); } db::Pin * NetlistBrowserModel::pin_from_id (void *id) const { - if (is_id_circuit_net_pin (id)) { + if (is_id_circuit_subcircuit_pin (id)) { - db::Net *net = net_from_id (id); - size_t index = circuit_net_pin_index_from_id (id); + db::SubCircuit *subcircuit = subcircuit_from_id (id); + db::Circuit *circuit = subcircuit->circuit_ref (); + size_t index = circuit_subcircuit_pin_index_from_id (id); - std::map >::iterator cc = m_pin_by_net_and_index.find (net); - if (cc == m_pin_by_net_and_index.end ()) { - cc = m_pin_by_net_and_index.insert (std::make_pair (net, std::map ())).first; - } - - std::map::iterator c = cc->second.find (index); - if (c == cc->second.end ()) { - - c = cc->second.insert (std::make_pair (index, (db::Pin *) 0)).first; - for (db::Net::pin_iterator i = net->begin_pins (); i != net->end_pins (); ++i) { - if (index-- == 0) { - c->second = const_cast (i->pin ()); - break; - } - } - - } - - return c->second; + return attr_by_object_and_index (circuit, index, circuit->begin_pins (), circuit->end_pins (), m_pin_by_circuit_and_index); } else { - db::Circuit *circuit; - size_t index; + db::Circuit *circuit = circuit_from_id (id); + size_t index = circuit_pin_index_from_id (id); - if (is_id_circuit_subcircuit_pin (id)) { - db::SubCircuit *subcircuit = subcircuit_from_id (id); - circuit = subcircuit->circuit_ref (); - index = circuit_subcircuit_pin_index_from_id (id); - } else { - circuit = circuit_from_id (id); - index = circuit_pin_index_from_id (id); - } - - std::map >::iterator cc = m_pin_by_circuit_and_index.find (circuit); - if (cc == m_pin_by_circuit_and_index.end ()) { - cc = m_pin_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; - } - - std::map::iterator c = cc->second.find (index); - if (c == cc->second.end ()) { - - c = cc->second.insert (std::make_pair (index, (db::Pin *) 0)).first; - for (db::Circuit::pin_iterator i = circuit->begin_pins (); i != circuit->end_pins (); ++i) { - if (index-- == 0) { - c->second = i.operator-> (); - break; - } - } - - } - - return c->second; + return attr_by_object_and_index (circuit, index, circuit->begin_pins (), circuit->end_pins (), m_pin_by_circuit_and_index); } } @@ -981,25 +904,7 @@ NetlistBrowserModel::subcircuit_from_id (void *id) const db::Circuit *circuit = circuit_from_id (id); size_t index = circuit_subcircuit_index_from_id (id); - std::map >::iterator cc = m_subcircuit_by_circuit_and_index.find (circuit); - if (cc == m_subcircuit_by_circuit_and_index.end ()) { - cc = m_subcircuit_by_circuit_and_index.insert (std::make_pair (circuit, std::map ())).first; - } - - std::map::iterator c = cc->second.find (index); - if (c == cc->second.end ()) { - - c = cc->second.insert (std::make_pair (index, (db::SubCircuit *) 0)).first; - for (db::Circuit::subcircuit_iterator i = circuit->begin_subcircuits (); i != circuit->end_subcircuits (); ++i) { - if (index-- == 0) { - c->second = i.operator-> (); - break; - } - } - - } - - return c->second; + return attr_by_object_and_index (circuit, index, circuit->begin_subcircuits (), circuit->end_subcircuits (), m_subcircuit_by_circuit_and_index); } // ---------------------------------------------------------------------------------- diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.h b/src/laybasic/laybasic/layNetlistBrowserPage.h index 6a7fe39a1..bb4fe932d 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.h +++ b/src/laybasic/laybasic/layNetlistBrowserPage.h @@ -122,8 +122,9 @@ private: size_t circuit_net_device_terminal_other_index_from_id (void *id) const; db::Circuit *circuit_from_id (void *id) const; db::Net *net_from_id (void *id) const; - const db::NetSubcircuitPinRef *net_pinref_from_id (void *id) const; + const db::NetSubcircuitPinRef *net_subcircuit_pinref_from_id (void *id) const; const db::NetTerminalRef *net_terminalref_from_id (void *id) const; + const db::NetPinRef *net_pinref_from_id (void *id) const; db::Device *device_from_id (void *id) const; db::Pin *pin_from_id (void *id) const; db::SubCircuit *subcircuit_from_id (void *id) const; @@ -136,9 +137,9 @@ private: db::LayoutToNetlist *mp_l2ndb; mutable std::map m_circuit_by_index; mutable std::map > m_net_by_circuit_and_index; - mutable std::map > m_pinref_by_net_and_index; + mutable std::map > m_subcircuit_pinref_by_net_and_index; mutable std::map > m_terminalref_by_net_and_index; - mutable std::map > m_pin_by_net_and_index; + mutable std::map > m_pinref_by_net_and_index; mutable std::map > m_device_by_circuit_and_index; mutable std::map > m_pin_by_circuit_and_index; mutable std::map > m_subcircuit_by_circuit_and_index; From 0410ae765ea2d25c3c7bb44420c4a7b716b17a4d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 22 Apr 2019 21:53:53 +0200 Subject: [PATCH 009/229] WIP: netlist browser - some debugging --- .../laybasic/layNetlistBrowserPage.cc | 52 ++++++++++--------- .../unit_tests/layNetlistBrowserModelTests.cc | 13 +++++ 2 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index 881d03f22..6e7de5d9a 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -626,21 +626,22 @@ NetlistBrowserModel::index (int row, int column, const QModelIndex &parent) cons if (is_id_circuit (id)) { + int r = row; db::Circuit *circuit = circuit_from_id (id); - if (row < int (circuit->pin_count ())) { - new_id = make_id_circuit_pin (circuit_index_from_id (id), row); + if (r < int (circuit->pin_count ())) { + new_id = make_id_circuit_pin (circuit_index_from_id (id), size_t (r)); } else { - row -= int (circuit->pin_count ()); - if (row < int (circuit->net_count ())) { - new_id = make_id_circuit_net (circuit_index_from_id (id), row); + r -= int (circuit->pin_count ()); + if (r < int (circuit->net_count ())) { + new_id = make_id_circuit_net (circuit_index_from_id (id), size_t (r)); } else { - row -= int (circuit->net_count ()); - if (row < int (circuit->subcircuit_count ())) { - new_id = make_id_circuit_subcircuit (circuit_index_from_id (id), row); + r -= int (circuit->net_count ()); + if (r < int (circuit->subcircuit_count ())) { + new_id = make_id_circuit_subcircuit (circuit_index_from_id (id), size_t (r)); } else { - row -= int (circuit->subcircuit_count ()); - if (row < int (circuit->device_count ())) { - new_id = make_id_circuit_device (circuit_index_from_id (id), row); + r -= int (circuit->subcircuit_count ()); + if (r < int (circuit->device_count ())) { + new_id = make_id_circuit_device (circuit_index_from_id (id), size_t (r)); } } } @@ -648,40 +649,41 @@ NetlistBrowserModel::index (int row, int column, const QModelIndex &parent) cons } 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), row); + 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), row); + 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), row); + 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; db::Net *net = net_from_id (id); - if (row < int (net->terminal_count ())) { - new_id = make_id_circuit_net_device_terminal (circuit_index_from_id (id), circuit_net_index_from_id (id), row); + if (r < int (net->terminal_count ())) { + new_id = make_id_circuit_net_device_terminal (circuit_index_from_id (id), circuit_net_index_from_id (id), size_t (r)); } else { - row -= int (net->terminal_count ()); - if (row < int (net->pin_count ())) { - new_id = make_id_circuit_net_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), row); + r -= int (net->terminal_count ()); + if (r < int (net->pin_count ())) { + new_id = make_id_circuit_net_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), size_t (r)); } else { - row -= int (net->pin_count ()); - if (row < int (net->subcircuit_pin_count ())) { - new_id = make_id_circuit_net_subcircuit_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), row); + r -= int (net->pin_count ()); + if (r < int (net->subcircuit_pin_count ())) { + 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), row); + 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), row); + 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)); } @@ -727,7 +729,7 @@ NetlistBrowserModel::parent (const QModelIndex &index) const } else if (is_id_circuit_device_terminal (id)) { db::Circuit *circuit = circuit_from_id (id); - return createIndex (int (circuit->pin_count () + circuit->net_count () + circuit->subcircuit_count () + circuit_device_terminal_index_from_id (id)), column, make_id_circuit_device (circuit_index_from_id (id), circuit_device_index_from_id (id))); + return createIndex (int (circuit->pin_count () + circuit->net_count () + circuit->subcircuit_count () + 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)) { diff --git a/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc b/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc index bdb7c358d..59ab5cf22 100644 --- a/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc +++ b/src/laybasic/unit_tests/layNetlistBrowserModelTests.cc @@ -78,16 +78,19 @@ TEST (1) // OUT pin of INV2 has a single child node which is the "OUT" net QModelIndex inv2PinOutIndex = model->index (2, 0, inv2Index); + EXPECT_EQ (model->parent (inv2PinOutIndex) == 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); // NOUT net has 1 pin, 2 devices, 0 subcircuits QModelIndex inv2NOutIndex = model->index (7, 0, inv2Index); + EXPECT_EQ (model->parent (inv2NOutIndex) == inv2Index, true); EXPECT_EQ (model->hasChildren (inv2NOutIndex), true); EXPECT_EQ (model->rowCount (inv2NOutIndex), 3); @@ -97,11 +100,13 @@ TEST (1) // no children for pins on nets QModelIndex inv2NOutPinOutIndex = model->index (2, 0, inv2NOutIndex); + EXPECT_EQ (model->parent (inv2NOutPinOutIndex) == inv2NOutIndex, true); EXPECT_EQ (model->hasChildren (inv2NOutPinOutIndex), false); EXPECT_EQ (model->rowCount (inv2NOutPinOutIndex), 0); // a MOS3 transistor has three other terminals QModelIndex inv2NOutDeviceIndex = model->index (0, 0, inv2NOutIndex); + EXPECT_EQ (model->parent (inv2NOutDeviceIndex) == inv2NOutIndex, true); EXPECT_EQ (model->hasChildren (inv2NOutDeviceIndex), true); EXPECT_EQ (model->rowCount (inv2NOutDeviceIndex), 3); @@ -110,11 +115,13 @@ TEST (1) EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, inv2NOutDeviceIndex), Qt::DisplayRole).toString ()), "D"); 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); // FB net has 0 pin, 0 devices, 2 subcircuits QModelIndex ringoFbIndex = model->index (0, 0, ringoIndex); + EXPECT_EQ (model->parent (ringoFbIndex) == ringoIndex, true); EXPECT_EQ (model->hasChildren (ringoFbIndex), true); EXPECT_EQ (model->rowCount (ringoFbIndex), 2); @@ -122,6 +129,7 @@ TEST (1) EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, ringoFbIndex), Qt::DisplayRole).toString ()), "IN"); QModelIndex ringoFbSubcircuit2Index = model->index (1, 0, ringoFbIndex); + EXPECT_EQ (model->parent (ringoFbSubcircuit2Index) == ringoFbIndex, true); EXPECT_EQ (model->hasChildren (ringoFbSubcircuit2Index), true); EXPECT_EQ (model->rowCount (ringoFbSubcircuit2Index), 5); @@ -132,30 +140,35 @@ TEST (1) EXPECT_EQ (tl::to_string (model->data (model->index (4, 0, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "$4"); 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); // Subcircuit 1 of RINGO has 5 pins QModelIndex ringoSubcircuit1Index = model->index (12, 0, ringoIndex); + EXPECT_EQ (model->parent (ringoSubcircuit1Index) == ringoIndex, true); EXPECT_EQ (model->hasChildren (ringoSubcircuit1Index), true); EXPECT_EQ (model->rowCount (ringoSubcircuit1Index), 5); EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoSubcircuit1Index), Qt::DisplayRole).toString ()), "OUT"); QModelIndex ringoSubcircuit1OutPinIndex = model->index (2, 0, ringoSubcircuit1Index); + EXPECT_EQ (model->parent (ringoSubcircuit1OutPinIndex) == ringoSubcircuit1Index, true); EXPECT_EQ (model->hasChildren (ringoSubcircuit1OutPinIndex), false); EXPECT_EQ (model->rowCount (ringoSubcircuit1OutPinIndex), 0); // Device 1 of INV2 has 3 pins QModelIndex inv2Device1Index = model->index (10, 0, inv2Index); + EXPECT_EQ (model->parent (inv2Device1Index) == inv2Index, true); EXPECT_EQ (model->hasChildren (inv2Device1Index), true); EXPECT_EQ (model->rowCount (inv2Device1Index), 3); EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Device1Index), Qt::DisplayRole).toString ()), "G"); 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); } From 46b47ff0d9a6bc3f0c1bd62b4c27e807b8bdac95 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 22 Apr 2019 22:00:47 +0200 Subject: [PATCH 010/229] WIP: netlist browser - removed self test, is unit test now. --- .../laybasic/layNetlistBrowserPage.cc | 47 ------------------- src/laybasic/laybasic/layNetlistBrowserPage.h | 2 - 2 files changed, 49 deletions(-) diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index 6e7de5d9a..082155bb3 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -405,44 +405,6 @@ NetlistBrowserModel::circuit_net_device_terminal_other_index_from_id (void *id) return reinterpret_cast (id) - 1; } -void -NetlistBrowserModel::self_test (const QModelIndex &p) -{ - int rows = rowCount (p); - for (int r = 0; r != rows; ++r) { - - QModelIndex c, pp; - - c = index (r, 0, p); - if (c.column () != 0) { - tl_assert (false); - } - pp = parent (c); - if (pp.isValid () && pp.column () != 0) { - tl_assert (false); - } - if (pp.isValid () && pp.row () != r) { - tl_assert (false); - } - if (pp.isValid () && pp.internalId () != p.internalId ()) { - tl_assert (false); - } - - c = index (r, 1, p); - if (c.column () != 1) { - tl_assert (false); - } - pp = parent (c); - if (pp.isValid () && pp.column () != 1) { - tl_assert (false); - } - - self_test (c); - - } -} - - int NetlistBrowserModel::columnCount (const QModelIndex & /*parent*/) const { @@ -1061,15 +1023,6 @@ NetlistBrowserPage::set_l2ndb (db::LayoutToNetlist *database) QAbstractItemModel *tree_model = directory_tree->model (); NetlistBrowserModel *new_model = new NetlistBrowserModel (this, database); -#if !defined(NDEBUG) - try { - new_model->self_test (); // might throw an exception! - } catch (...) { - delete new_model; - mp_database.reset (0); - throw; - } -#endif directory_tree->setModel (new_model); // @@@ connect (directory_tree->selectionModel (), SIGNAL (selectionChanged (const QItemSelection &, const QItemSelection &)), this, SLOT (directory_selection_changed (const QItemSelection &, const QItemSelection &))); diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.h b/src/laybasic/laybasic/layNetlistBrowserPage.h index bb4fe932d..64e1d8dba 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.h +++ b/src/laybasic/laybasic/layNetlistBrowserPage.h @@ -78,8 +78,6 @@ public: virtual QModelIndex parent (const QModelIndex &index) const; virtual int rowCount (const QModelIndex &parent) const; - void self_test (const QModelIndex &index = QModelIndex ()); - private: void *make_id_circuit (size_t circuit_index) const; From 7f9da5e8de14e3b40db33fa9a957312be6d63005 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 23 Apr 2019 19:44:07 +0200 Subject: [PATCH 011/229] Introduced concept of device class templates This concept allows to persist at least the standard (built-in) device classes into L2N DB files. This way device classes are persisted. --- src/db/db/dbDeviceClass.cc | 26 +++++++++ src/db/db/dbDeviceClass.h | 68 ++++++++++++++++++++++++ src/db/db/dbLayoutToNetlistFormatDefs.cc | 2 + src/db/db/dbLayoutToNetlistFormatDefs.h | 4 +- src/db/db/dbLayoutToNetlistReader.cc | 28 +++++++--- src/db/db/dbLayoutToNetlistWriter.cc | 10 ++++ src/db/db/dbNetlistDeviceClasses.cc | 11 ++++ src/db/unit_tests/dbNetlistTests.cc | 17 ++++++ testdata/algo/l2n_writer_au.txt | 4 ++ testdata/algo/l2n_writer_au_2.txt | 4 ++ 10 files changed, 167 insertions(+), 7 deletions(-) diff --git a/src/db/db/dbDeviceClass.cc b/src/db/db/dbDeviceClass.cc index b42ddfcd0..322885071 100644 --- a/src/db/db/dbDeviceClass.cc +++ b/src/db/db/dbDeviceClass.cc @@ -22,6 +22,7 @@ #include "dbDeviceClass.h" #include "dbDevice.h" +#include "tlClassRegistry.h" namespace db { @@ -273,4 +274,29 @@ bool DeviceClass::equal (const db::Device &a, const db::Device &b) } } +// -------------------------------------------------------------------------------- +// DeviceClassTemplateBase class implementation + +DeviceClassTemplateBase * +DeviceClassTemplateBase::template_by_name (const std::string &name) +{ + for (tl::Registrar::iterator i = tl::Registrar::begin (); i != tl::Registrar::end (); ++i) { + if (i->name () == name) { + return i.operator-> (); + } + } + return 0; +} + +DeviceClassTemplateBase * +DeviceClassTemplateBase::is_a (const db::DeviceClass *dc) +{ + for (tl::Registrar::iterator i = tl::Registrar::begin (); i != tl::Registrar::end (); ++i) { + if (i->is_of (dc)) { + return i.operator-> (); + } + } + return 0; +} + } diff --git a/src/db/db/dbDeviceClass.h b/src/db/db/dbDeviceClass.h index 6b0388a79..9e5706e65 100644 --- a/src/db/db/dbDeviceClass.h +++ b/src/db/db/dbDeviceClass.h @@ -536,6 +536,74 @@ private: } }; +/** + * @brief A device class template + * + * This is a registered class which provides a device class template. + * The built-in classes serve as templates and registering a template + * allows regenerating the class from an abstract description (template + * name). + * + * NOTE: device classes derived from one of the built-in classes + * cannot be distinguished from pure built-in classes. Entirely + * customized classes are treated as "non-template based" (i.e. + * "is_a" returns 0). + */ +class DB_PUBLIC DeviceClassTemplateBase +{ +public: + DeviceClassTemplateBase (const std::string &name) + : m_name (name) + { + // .. nothing yet .. + } + + virtual ~DeviceClassTemplateBase () { } + + const std::string &name () const + { + return m_name; + } + + virtual bool is_of (const db::DeviceClass *) const = 0; + virtual DeviceClass *create () const = 0; + + static DeviceClassTemplateBase *template_by_name (const std::string &name); + static DeviceClassTemplateBase *is_a (const db::DeviceClass *dc); + +private: + std::string m_name; + + DeviceClassTemplateBase (const DeviceClassTemplateBase &); + DeviceClassTemplateBase &operator= (const DeviceClassTemplateBase &); +}; + +template +class DB_PUBLIC_TEMPLATE device_class_template + : public DeviceClassTemplateBase +{ +public: + device_class_template (const std::string &name) + : DeviceClassTemplateBase (name) + { + // .. nothing yet .. + } + + virtual bool is_of (const db::DeviceClass *dc) const + { + return dynamic_cast (dc) != 0; + } + + virtual DeviceClass *create () const + { + return new T (); + } + +private: + device_class_template (const device_class_template &); + device_class_template &operator= (const device_class_template &); +}; + } #endif diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.cc b/src/db/db/dbLayoutToNetlistFormatDefs.cc index 3a00f45e0..8b781f315 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.cc +++ b/src/db/db/dbLayoutToNetlistFormatDefs.cc @@ -32,6 +32,7 @@ namespace l2n_std_format template<> DB_PUBLIC const std::string keys::top_key ("top"); template<> DB_PUBLIC const std::string keys::unit_key ("unit"); template<> DB_PUBLIC const std::string keys::layer_key ("layer"); + template<> DB_PUBLIC const std::string keys::class_key ("class"); template<> DB_PUBLIC const std::string keys::connect_key ("connect"); template<> DB_PUBLIC const std::string keys::global_key ("global"); template<> DB_PUBLIC const std::string keys::circuit_key ("circuit"); @@ -54,6 +55,7 @@ namespace l2n_std_format template<> DB_PUBLIC const std::string keys::top_key ("W"); template<> DB_PUBLIC const std::string keys::unit_key ("U"); template<> DB_PUBLIC const std::string keys::layer_key ("L"); + template<> DB_PUBLIC const std::string keys::class_key ("K"); template<> DB_PUBLIC const std::string keys::connect_key ("C"); template<> DB_PUBLIC const std::string keys::global_key ("G"); template<> DB_PUBLIC const std::string keys::circuit_key ("X"); diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.h b/src/db/db/dbLayoutToNetlistFormatDefs.h index 8bb38dbec..abb314ec7 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.h +++ b/src/db/db/dbLayoutToNetlistFormatDefs.h @@ -58,6 +58,7 @@ namespace db * - connects the shapes of the layer with the given global * nets [short key: G] * circuit( [circuit-def]) - circuit (cell) [short key: X] + * class(