From ab70c42c681dcb1651ca3394459749db2a943ef2 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 28 Jun 2021 22:33:46 +0200 Subject: [PATCH] Some enhancements for strong matching of nets * same_nets! method for strong matching * same_nets and same_nets! except glob pattern to circuits and nets * both observe case sensitivity * helper functions for case sensitivity Netlist#is_case_sensitive?, Netlist#case_sensitive= * Netlist#nets_by_name to get nets from pattern --- src/db/db/dbNetlistCompare.cc | 65 +++++-- src/db/db/dbNetlistCompare.h | 16 +- src/db/db/gsiDeclDbNetlist.cc | 30 +++ src/db/db/gsiDeclDbNetlistCompare.cc | 23 ++- src/lay/lay/doc/about/lvs_ref_netter.xml | 30 ++- src/lvs/lvs/built-in-macros/_lvs_engine.rb | 13 +- src/lvs/lvs/built-in-macros/_lvs_netter.rb | 138 ++++++++++---- ...simple_net_and_circuit_equivalence.lvsdb.1 | 1 + ...simple_net_and_circuit_equivalence.lvsdb.2 | 1 + testdata/ruby/dbNetlist.rb | 22 +++ testdata/ruby/dbNetlistCompare.rb | 174 +++++++++++++++++- 11 files changed, 455 insertions(+), 58 deletions(-) diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index cfd4db9c2..1d146713d 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -1013,6 +1013,14 @@ public: return j->second; } + /** + * @brief Gets a value indicating whether there is a node for the given net + */ + bool has_node_index_for_net (const db::Net *net) const + { + return m_net_index.find (net) != m_net_index.end (); + } + /** * @brief Gets the node for a given node index */ @@ -2880,9 +2888,16 @@ NetlistComparer::exclude_resistors (double threshold) } void -NetlistComparer::same_nets (const db::Net *na, const db::Net *nb) +NetlistComparer::same_nets (const db::Net *na, const db::Net *nb, bool must_match) { - m_same_nets [std::make_pair (na->circuit (), nb->circuit ())].push_back (std::make_pair (na, nb)); + tl_assert (na && na); + m_same_nets [std::make_pair (na->circuit (), nb->circuit ())].push_back (std::make_pair (std::make_pair (na, nb), must_match)); +} + +void +NetlistComparer::same_nets (const db::Circuit *ca, const db::Circuit *cb, const db::Net *na, const db::Net *nb, bool must_match) +{ + m_same_nets [std::make_pair (ca, cb)].push_back (std::make_pair (std::make_pair (na, nb), must_match)); } void @@ -3114,9 +3129,9 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const tl_assert (i->second.second.size () == size_t (1)); const db::Circuit *cb = i->second.second.front (); - std::vector > empty; - const std::vector > *net_identity = ∅ - std::map, std::vector > >::const_iterator sn = m_same_nets.find (std::make_pair (ca, cb)); + std::vector, bool> > empty; + const std::vector, bool> > *net_identity = ∅ + std::map, std::vector, bool> > >::const_iterator sn = m_same_nets.find (std::make_pair (ca, cb)); if (sn != m_same_nets.end ()) { net_identity = &sn->second; } @@ -3525,7 +3540,7 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, db::DeviceCategorizer &device_categorizer, db::CircuitCategorizer &circuit_categorizer, db::CircuitPinMapper &circuit_pin_mapper, - const std::vector > &net_identity, + const std::vector, bool> > &net_identity, bool &pin_mismatch, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping) const @@ -3551,11 +3566,39 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, g1.identify (0, 0); g2.identify (0, 0); - for (std::vector >::const_iterator p = net_identity.begin (); p != net_identity.end (); ++p) { - size_t ni1 = g1.node_index_for_net (p->first); - size_t ni2 = g2.node_index_for_net (p->second); - g1.identify (ni1, ni2); - g2.identify (ni2, ni1); + for (std::vector, bool> >::const_iterator p = net_identity.begin (); p != net_identity.end (); ++p) { + + // NOTE: nets may vanish, hence there + if (g1.has_node_index_for_net (p->first.first) && g2.has_node_index_for_net (p->first.second)) { + + size_t ni1 = g1.node_index_for_net (p->first.first); + size_t ni2 = g2.node_index_for_net (p->first.second); + g1.identify (ni1, ni2); + g2.identify (ni2, ni1); + + // in must_match mode, check if the nets are identical + if (p->second && ! (g1.node(ni1) == g2.node(ni2))) { + mp_logger->net_mismatch (p->first.first, p->first.second); + } else { + mp_logger->match_nets (p->first.first, p->first.second); + } + + } else if (p->second && g1.has_node_index_for_net (p->first.first)) { + + mp_logger->net_mismatch (p->first.first, 0); + + size_t ni1 = g1.node_index_for_net (p->first.first); + g1.identify (ni1, 0); + + } else if (p->second && g2.has_node_index_for_net (p->first.second)) { + + mp_logger->net_mismatch (0, p->first.second); + + size_t ni2 = g2.node_index_for_net (p->first.second); + g2.identify (ni2, 0); + + } + } int iter = 0; diff --git a/src/db/db/dbNetlistCompare.h b/src/db/db/dbNetlistCompare.h index 2d4e81506..197d5ef6c 100644 --- a/src/db/db/dbNetlistCompare.h +++ b/src/db/db/dbNetlistCompare.h @@ -181,7 +181,17 @@ public: * net nb in netlist b. * By default nets are not identical expect through their topology. */ - void same_nets (const db::Net *na, const db::Net *nb); + void same_nets (const db::Net *na, const db::Net *nb, bool must_match = false); + + /** + * @brief Mark two nets as identical + * + * This makes a net na in netlist a identical to the corresponding + * net nb in netlist b. + * By default nets are not identical expect through their topology. + * This version allows mapping one net to a null net because the circuits are explicitly specified. + */ + void same_nets (const db::Circuit *ca, const db::Circuit *cb, const db::Net *na, const db::Net *nb, bool must_match); /** * @brief Mark two pins as equivalent (i.e. can be swapped) @@ -344,7 +354,7 @@ private: NetlistComparer &operator= (const NetlistComparer &); protected: - bool compare_circuits (const db::Circuit *c1, const db::Circuit *c2, db::DeviceCategorizer &device_categorizer, db::CircuitCategorizer &circuit_categorizer, db::CircuitPinMapper &circuit_pin_mapper, const std::vector > &net_identity, bool &pin_mismatch, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping) const; + bool compare_circuits (const db::Circuit *c1, const db::Circuit *c2, db::DeviceCategorizer &device_categorizer, db::CircuitCategorizer &circuit_categorizer, db::CircuitPinMapper &circuit_pin_mapper, const std::vector, bool> > &net_identity, bool &pin_mismatch, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping) const; bool all_subcircuits_verified (const db::Circuit *c, const std::set &verified_circuits) const; std::string generate_subcircuits_not_verified_warning (const db::Circuit *ca, const std::set &verified_circuits_a, const db::Circuit *cb, const std::set &verified_circuits_b) const; static void derive_pin_equivalence (const db::Circuit *ca, const db::Circuit *cb, CircuitPinMapper *circuit_pin_mapper); @@ -354,7 +364,7 @@ protected: bool handle_pin_mismatch (const NetGraph &g1, const db::Circuit *c1, const db::Pin *pin1, const NetGraph &g2, const db::Circuit *c2, const db::Pin *p2) const; mutable NetlistCompareLogger *mp_logger; - std::map, std::vector > > m_same_nets; + std::map, std::vector, bool> > > m_same_nets; std::unique_ptr mp_circuit_pin_mapper; std::unique_ptr mp_device_categorizer; std::unique_ptr mp_circuit_categorizer; diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index 4461534e1..19bfd3a5e 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -1238,8 +1238,14 @@ static std::vector nets_by_name (db::Circuit *circuit, const std::string &name_pattern) { std::vector res; + if (! circuit) { + return res; + } tl::GlobPattern glob (name_pattern); + if (circuit->netlist ()) { + glob.set_case_sensitive (circuit->netlist ()->is_case_sensitive ()); + } for (db::Circuit::net_iterator n = circuit->begin_nets (); n != circuit->end_nets (); ++n) { db::Net *net = n.operator-> (); if (glob.match (net->name ())) { @@ -1254,8 +1260,14 @@ static std::vector nets_by_name_const (const db::Circuit *circuit, const std::string &name_pattern) { std::vector res; + if (! circuit) { + return res; + } tl::GlobPattern glob (name_pattern); + if (circuit->netlist ()) { + glob.set_case_sensitive (circuit->netlist ()->is_case_sensitive ()); + } for (db::Circuit::const_net_iterator n = circuit->begin_nets (); n != circuit->end_nets (); ++n) { const db::Net *net = n.operator-> (); if (glob.match (net->name ())) { @@ -1681,8 +1693,13 @@ static std::vector circuits_by_name (db::Netlist *netlist, const std::string &name_pattern) { std::vector res; + if (! netlist) { + return res; + } tl::GlobPattern glob (name_pattern); + glob.set_case_sensitive (netlist->is_case_sensitive ()); + for (db::Netlist::circuit_iterator c = netlist->begin_circuits (); c != netlist->end_circuits (); ++c) { db::Circuit *circuit = c.operator-> (); if (glob.match (circuit->name ())) { @@ -1697,8 +1714,13 @@ static std::vector circuits_by_name_const (const db::Netlist *netlist, const std::string &name_pattern) { std::vector res; + if (! netlist) { + return res; + } tl::GlobPattern glob (name_pattern); + glob.set_case_sensitive (netlist->is_case_sensitive ()); + for (db::Netlist::const_circuit_iterator c = netlist->begin_circuits (); c != netlist->end_circuits (); ++c) { const db::Circuit *circuit = c.operator-> (); if (glob.match (circuit->name ())) { @@ -1710,6 +1732,14 @@ circuits_by_name_const (const db::Netlist *netlist, const std::string &name_patt } Class decl_dbNetlist ("db", "Netlist", + gsi::method ("is_case_sensitive?", &db::Netlist::is_case_sensitive, + "@brief Returns a value indicating whether the netlist names are case sensitive\n" + "This method has been added in version 0.27.3.\n" + ) + + gsi::method ("case_sensitive=", &db::Netlist::set_case_sensitive, gsi::arg ("cs"), + "@brief Sets a value indicating whether the netlist names are case sensitive\n" + "This method has been added in version 0.27.3.\n" + ) + gsi::method_ext ("add", &gsi::add_circuit, gsi::arg ("circuit"), "@brief Adds the circuit to the netlist\n" "This method will add the given circuit object to the netlist. " diff --git a/src/db/db/gsiDeclDbNetlistCompare.cc b/src/db/db/gsiDeclDbNetlistCompare.cc index 815790559..5a0696ee6 100644 --- a/src/db/db/gsiDeclDbNetlistCompare.cc +++ b/src/db/db/gsiDeclDbNetlistCompare.cc @@ -476,13 +476,32 @@ Class decl_dbNetlistComparer ("db", "NetlistComparer", "The logger is a delegate or event receiver which the comparer will send compare events to. " "See the class description for more details." ) + - gsi::method ("same_nets", &db::NetlistComparer::same_nets, gsi::arg ("net_a"), gsi::arg ("net_b"), + gsi::method ("same_nets", (void (db::NetlistComparer::*) (const db::Net *, const db::Net *, bool)) &db::NetlistComparer::same_nets, gsi::arg ("net_a"), gsi::arg ("net_b"), gsi::arg ("must_match", false), "@brief Marks two nets as identical.\n" "This makes a net net_a in netlist a identical to the corresponding\n" "net net_b in netlist b (see \\compare).\n" "Otherwise, the algorithm will try to identify nets according to their topology. " "This method can be used to supply hints to the compare algorithm. It will use " - "these hints to derive further identities." + "these hints to derive further identities.\n" + "\n" + "If 'must_match' is true, the nets are required to match. If they don't, an error is reported.\n" + "\n" + "The 'must_match' optional argument has been added in version 0.27.3.\n" + ) + + gsi::method ("same_nets", (void (db::NetlistComparer::*) (const db::Circuit *, const db::Circuit *, const db::Net *, const db::Net *, bool)) &db::NetlistComparer::same_nets, gsi::arg ("circuit_a"), gsi::arg ("circuit_b"), gsi::arg ("net_a"), gsi::arg ("net_b"), gsi::arg ("must_match", false), + "@brief Marks two nets as identical.\n" + "This makes a net net_a in netlist a identical to the corresponding\n" + "net net_b in netlist b (see \\compare).\n" + "Otherwise, the algorithm will try to identify nets according to their topology. " + "This method can be used to supply hints to the compare algorithm. It will use " + "these hints to derive further identities.\n" + "\n" + "If 'must_match' is true, the nets are required to match. If they don't, an error is reported.\n" + "\n" + "This variant allows specifying nil for the nets indicating the nets are mismatched by definition. " + "with 'must_match' this will render a net mismatch error.\n" + "\n" + "This variant has been added in version 0.27.3.\n" ) + gsi::method ("equivalent_pins", (void (db::NetlistComparer::*) (const db::Circuit *, size_t, size_t)) &db::NetlistComparer::equivalent_pins, gsi::arg ("circuit_b"), gsi::arg ("pin_id1"), gsi::arg ("pin_id2"), "@brief Marks two pins of the given circuit as equivalent (i.e. they can be swapped).\n" diff --git a/src/lay/lay/doc/about/lvs_ref_netter.xml b/src/lay/lay/doc/about/lvs_ref_netter.xml index d68a49a96..4b33f3fe5 100644 --- a/src/lay/lay/doc/about/lvs_ref_netter.xml +++ b/src/lay/lay/doc/about/lvs_ref_netter.xml @@ -81,7 +81,7 @@ The filter is a glob expression. This has the following effects: