diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 6040ba4a8..038fb9e7c 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -86,14 +86,17 @@ NetlistComparer::exclude_resistors (double threshold) void NetlistComparer::same_nets (const db::Net *na, const db::Net *nb, bool must_match) { - 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)); + if (na || nb) { + 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)); + if (na || nb) { + m_same_nets [std::make_pair (ca, cb)].push_back (std::make_pair (std::make_pair (na, nb), must_match)); + } } void @@ -207,6 +210,49 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const return res; } +/** + * @brief Returns a consolidated list of identical nets for a circuit pair (aka "same_nets") + * + * The list is reduced by duplicates of the first net such, that the + * last "same_nets" entry wins. + * + * The return value is a list of net pairs and a flag indicating "must_match" mode. + * The second net can be null if "must_match" is true, indicating that no schematic + * net with the same name was found - hence a mismatch exists. + */ +std::vector, bool> > +NetlistComparer::get_net_identity (const db::Circuit *ca, const db::Circuit *cb) 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 ()) { + + const std::vector, bool> > &ni = sn->second; + + // take last definition for a given first net + net_identity.reserve (ni.size ()); + std::set seen; + for (auto i = ni.end (); i != ni.begin (); ) { + --i; + const Net *main_net = i->first.first ? i->first.first : i->first.second; + const Net *other_net = i->first.first ? i->first.second : i->first.first; + if (seen.find (main_net) == seen.end () && (! other_net || seen.find (other_net) == seen.end ())) { + net_identity.push_back (*i); + seen.insert (main_net); + if (other_net) { + seen.insert (other_net); + } + } + } + + std::reverse (net_identity.begin (), net_identity.end ()); + + } + + return net_identity; +} + bool NetlistComparer::compare_impl (const db::Netlist *a, const db::Netlist *b) const { @@ -344,13 +390,6 @@ NetlistComparer::compare_impl (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, 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; - } - if (all_subcircuits_verified (ca, verified_circuits_a) && all_subcircuits_verified (cb, verified_circuits_b)) { if (db::NetlistCompareGlobalOptions::options ()->debug_netcompare) { @@ -362,7 +401,7 @@ NetlistComparer::compare_impl (const db::Netlist *a, const db::Netlist *b) const } bool pin_mismatch = false; - bool g = compare_circuits (ca, cb, device_categorizer, circuit_categorizer, circuit_pin_mapper, *net_identity, pin_mismatch, c12_pin_mapping, c22_pin_mapping); + bool g = compare_circuits (ca, cb, device_categorizer, circuit_categorizer, circuit_pin_mapper, get_net_identity (ca, cb), pin_mismatch, c12_pin_mapping, c22_pin_mapping); if (! g) { good = false; } diff --git a/src/db/db/dbNetlistCompare.h b/src/db/db/dbNetlistCompare.h index 0dff2e059..18ff5288d 100644 --- a/src/db/db/dbNetlistCompare.h +++ b/src/db/db/dbNetlistCompare.h @@ -387,6 +387,7 @@ protected: void do_device_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, const db::DeviceFilter &device_filter, DeviceCategorizer &device_categorizer, db::DeviceEquivalenceTracker &device_eq, bool &good) const; void do_subcircuit_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, CircuitCategorizer &circuit_categorizer, const db::CircuitPinCategorizer &circuit_pin_mapper, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping, db::SubCircuitEquivalenceTracker &subcircuit_eq, bool &good) const; 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; + std::vector, bool> > get_net_identity (const db::Circuit *ca, const db::Circuit *cb) const; mutable NetlistCompareLogger *mp_logger; bool m_with_log; diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index a1163ae29..f84294c9f 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -1451,7 +1451,7 @@ nets_by_name_const (const db::Circuit *circuit, const std::string &name_pattern) } 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 ())) { + if (!net->name ().empty () && glob.match (net->name ())) { res.push_back (net); } } @@ -1480,7 +1480,7 @@ nets_by_name_const_from_netlist (const db::Netlist *netlist, const std::string & for (auto n = c->begin_nets (); n != c->end_nets (); ++n) { const db::Net *net = n.operator-> (); // NOTE: we only pick root nets (pin_count == 0 or in top cell) - if ((is_top || net->pin_count () == 0) && glob.match (net->name ())) { + if ((is_top || net->pin_count () == 0) && !net->name ().empty () && glob.match (net->name ())) { res.push_back (net); } } diff --git a/src/lvs/lvs/built-in-macros/_lvs_netter.rb b/src/lvs/lvs/built-in-macros/_lvs_netter.rb index 9eb5b5541..4b3a44f7c 100644 --- a/src/lvs/lvs/built-in-macros/_lvs_netter.rb +++ b/src/lvs/lvs/built-in-macros/_lvs_netter.rb @@ -552,6 +552,9 @@ CODE # same_nets("INV*", "A*") # @/code # + # A plain "*" for the net pattern forces all (named) nets to be equivalent between layout and schematic. + # Unnamed nets from the extracted netlist are not considered - i.e. nets without a label. + # # After using this function, the compare algorithm will consider these nets equivalent. # Use this method to provide hints for the comparer in cases which are difficult to # resolve otherwise. @@ -560,6 +563,16 @@ CODE # Names are case sensitive for layout-derived netlists and case-insensitive for SPICE schematic netlists. # # Use this method andwhere in the script before the \compare call. + # + # Multiple calls of "same_nets" can be used. The calls are effective in the order + # the are given. For example, the following sequence specifies equivalence of all + # equally named nets, with the exception of "A" and "B" which are equivalent to each other + # inside cell "ND2", despite their different name: + # + # @code + # same_nets("*", "*") + # same_nets("ND2", "A", "B") + # @/code def same_nets(*args) _same_nets_impl(false, *args) @@ -573,6 +586,22 @@ CODE # @synopsis same_nets!(circuit_a, net_a, circuit_b, net_b) # This method is equivalent to \same_nets, but requires identity of the given nets. # If the specified nets do not match, an error is reported. + # + # For example, this global specification requires all named nets from the + # layout to have an equivalent net in the schematic and those nets need to be + # identical for all circuits: + # + # @code + # same_nets!("*", "*") + # @/code + # + # The following specification requires "A" and "B" to be identical in + # circuit "ND2". It is not an error if either "A" does not exist in the + # layout or "B" does not exist in the schematic: + # + # @code + # same_nets!("ND2", "A", "B") + # @/code def same_nets!(*args) _same_nets_impl(true, *args) @@ -655,7 +684,7 @@ CODE nets = [] n2n.keys.sort.each do |n| - if force || (n2n[n][0] && n2n[n][1]) + if n2n[n][0] && (force || n2n[n][1]) nets << n2n[n] end end