diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 5b6927c6d..5d94ea580 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -1942,6 +1942,89 @@ compute_subcircuit_key (const db::SubCircuit &subcircuit, const db::NetGraph &g, return k; } +namespace { + +inline double size_dist (size_t a, size_t b) +{ + double d = a - b; + return d * d; +} + +struct KeyDistance +{ + typedef std::pair >, const db::SubCircuit *> value_type; + + double operator() (const value_type &a, const value_type &b) const + { + tl_assert (a.first.size () == b.first.size ()); + double d = 0.0; + for (std::vector >::const_iterator i = a.first.begin (), j = b.first.begin (); i != a.first.end (); ++i, ++j) { + d += size_dist (i->first, j->first) + size_dist (i->second, j->second); + } + return d; + } +}; + +struct KeySize +{ + typedef std::pair >, const db::SubCircuit *> value_type; + + bool operator() (const value_type &a, const value_type &b) const + { + return (a.first.size () < b.first.size ()); + } +}; + +template +void align (Iter i1, Iter i2, Iter j1, Iter j2, Distance distance) +{ + // TODO: this can probably be done more efficiently + + std::vector vi, vj; + vi.reserve (std::max (i2 - i1, j2 - j1)); + vj.reserve (std::max (i2 - i1, j2 - j1)); + + for (Iter i = i1; i != i2; ++i) { + vi.push_back (i); + } + + for (Iter j = j1; j != j2; ++j) { + vj.push_back (j); + } + + while (vi.size () < vj.size ()) { + vi.push_back (Iter ()); + } + + while (vj.size () < vi.size ()) { + vj.push_back (Iter ()); + } + + if (vi.size () <= 1) { + return; + } + + // Caution: this is an O(2) algorithm ... + bool any_swapped = true; + for (size_t n = 0; n < vi.size () - 1 && any_swapped; ++n) { + + any_swapped = false; + + for (size_t m = n + 1; m < vj.size () - 1; ++m) { + if (vi [n] == Iter () || vi [m] == Iter () || vj [n] == Iter () || vj [m] == Iter ()) { + continue; + } else if (distance (*vi [n], *vj [m]) + distance (*vi [m], *vj [n]) < distance (*vi [n], *vj [n]) + distance (*vi [m], *vj [m])) { + // this will reduce the overall distance: + std::swap (vj [n], vj [m]); + any_swapped = true; + } + } + + } +} + +} + bool 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, bool &pin_mismatch, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping) const { @@ -2325,6 +2408,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, } + typedef std::vector >, const db::SubCircuit *> > unmatched_list; + unmatched_list unmatched_a, unmatched_b; + for (db::Circuit::const_subcircuit_iterator sc = c2->begin_subcircuits (); sc != c2->end_subcircuits (); ++sc) { std::vector > k = compute_subcircuit_key (*sc, g2, &c22_circuit_and_pin_mapping, &circuit_pin_mapper); @@ -2345,7 +2431,7 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, if (! mapped || scm == subcircuit_map.end ()) { if (mp_logger) { - mp_logger->subcircuit_mismatch (0, sc.operator-> ()); + unmatched_b.push_back (std::make_pair (k, sc.operator-> ())); } good = false; @@ -2373,11 +2459,81 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, for (std::multimap >, std::pair >::const_iterator scm = subcircuit_map.begin (); scm != subcircuit_map.end (); ++scm) { if (mp_logger) { - mp_logger->subcircuit_mismatch (scm->second.first, 0); + unmatched_a.push_back (std::make_pair (scm->first, scm->second.first)); } good = false; } + // try to do some pairing between the mismatching subcircuits - even though we will still report them as + // mismatches it will give some better hint about what needs to be fixed + + if (mp_logger) { + + size_t max_analysis_set = 1000; + if (unmatched_a.size () + unmatched_b.size () > max_analysis_set) { + + // don't try too much analysis - this may be a waste of time + for (unmatched_list::const_iterator i = unmatched_a.begin (); i != unmatched_a.end (); ++i) { + mp_logger->subcircuit_mismatch (i->second, 0); + } + for (unmatched_list::const_iterator i = unmatched_b.begin (); i != unmatched_b.end (); ++i) { + mp_logger->subcircuit_mismatch (0, i->second); + } + + } else { + + std::sort (unmatched_a.begin (), unmatched_a.end (), KeySize ()); + std::sort (unmatched_b.begin (), unmatched_b.end (), KeySize ()); + + for (unmatched_list::iterator i = unmatched_a.begin (), j = unmatched_b.begin (); i != unmatched_a.end () || j != unmatched_b.end (); ) { + + while (j != unmatched_b.end () && (i == unmatched_a.end () || j->first.size () < i->first.size ())) { + mp_logger->subcircuit_mismatch (0, j->second); + ++j; + } + + while (i != unmatched_a.end () && (j == unmatched_b.end () || i->first.size () < j->first.size ())) { + mp_logger->subcircuit_mismatch (i->second, 0); + ++i; + } + + if (i == unmatched_a.end () && j == unmatched_b.end ()) { + break; + } + + unmatched_list::iterator ii = i, jj = j; + ++i, ++j; + size_t n = ii->first.size (); + tl_assert (n == jj->first.size ()); + + while (i != unmatched_a.end () && i->first.size () == n) { + ++i; + } + + while (j != unmatched_b.end () && j->first.size () == n) { + ++j; + } + + align (ii, i, jj, j, KeyDistance ()); + + for ( ; ii != i && jj != j; ++ii, ++jj) { + mp_logger->subcircuit_mismatch (ii->second, jj->second); + } + + for ( ; jj != j; ++jj) { + mp_logger->subcircuit_mismatch (0, jj->second); + } + + for ( ; ii != i; ++ii) { + mp_logger->subcircuit_mismatch (ii->second, 0); + } + + } + + } + + } + return good; } diff --git a/src/laybasic/laybasic/layNetlistBrowserModel.cc b/src/laybasic/laybasic/layNetlistBrowserModel.cc index 70ea45411..048e683a1 100644 --- a/src/laybasic/laybasic/layNetlistBrowserModel.cc +++ b/src/laybasic/laybasic/layNetlistBrowserModel.cc @@ -830,6 +830,11 @@ std::string devices_string (const std::pairpin_status_hint (circuit_refs, mp_indexer->pin_index (pins, circuit_refs)); + if (hint.empty ()) { + + // Another test here is to check whether the pins may be attached to an invalid net pair + if (! is_valid_net_pair (nets_from_subcircuit_pins (subcircuits, pins))) { + hint = rewire_subcircuit_pins_status_hint (); + } + + } } else if (is_id_circuit_net (id)) { @@ -1435,6 +1512,21 @@ NetlistBrowserModel::tooltip (const QModelIndex &index) const hint = mp_indexer->subcircuit_status_hint (circuits, mp_indexer->subcircuit_index (subcircuits)); + } else if (is_id_circuit_net_subcircuit_pin_others (id)) { + + IndexedNetlistModel::net_subcircuit_pin_pair pinrefs = net_subcircuit_pinrefs_from_id (id); + IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_pinrefs (pinrefs); + size_t other_index = circuit_net_subcircuit_pin_other_index_from_id (id); + + IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits); + IndexedNetlistModel::pin_pair pins = mp_indexer->pin_from_index (circuit_refs, other_index).first; + + if (! is_valid_net_pair (nets_from_subcircuit_pins (subcircuits, pins))) { + // This indicates a wrong connection: the nets are associated in a way which is a not + // corresponding to a mapped net pair. Report Mismatch here. + hint = rewire_subcircuit_pins_status_hint (); + } + } if (hint.empty ()) { @@ -1773,7 +1865,7 @@ NetlistBrowserModel::icon (const QModelIndex &index) const } else if (is_id_circuit_subcircuit (id)) { return icon_for_circuit (); - } else if (is_id_circuit_subcircuit_pin (id) || is_id_circuit_net_pin (id) || is_id_circuit_net_subcircuit_pin_others (id)) { + } else if (is_id_circuit_subcircuit_pin (id) || is_id_circuit_net_pin (id)) { return icon_for_pin (); } else if (is_id_circuit_net_subcircuit_pin (id)) { return icon_for_circuit (); diff --git a/src/laybasic/laybasic/layNetlistBrowserModel.h b/src/laybasic/laybasic/layNetlistBrowserModel.h index 1a8deb05a..5c9039c32 100644 --- a/src/laybasic/laybasic/layNetlistBrowserModel.h +++ b/src/laybasic/laybasic/layNetlistBrowserModel.h @@ -219,6 +219,8 @@ private: return std::pair (mp_l2ndb->netlist (), (const db::Netlist *)0); } + bool is_valid_net_pair (const std::pair &net) const; + QIcon icon_for_nets (const std::pair &net) const; QIcon icon_for_connection (const std::pair &net) const; diff --git a/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc b/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc index 518183179..1e7eda47d 100644 --- a/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc +++ b/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc @@ -238,10 +238,14 @@ static IndexedNetlistModel::circuit_pair get_parent_of (const Pair &pair, const } i = cache.find (pair); - tl_assert (i != cache.end ()); } - return i->second; + + if (i == cache.end ()) { + return IndexedNetlistModel::circuit_pair ((const db::Circuit *) 0, (const db::Circuit *) 0); + } else { + return i->second; + } } IndexedNetlistModel::circuit_pair NetlistCrossReferenceModel::parent_of (const IndexedNetlistModel::net_pair &net_pair) const @@ -436,19 +440,19 @@ std::string NetlistCrossReferenceModel::circuit_pair_status_hint (const std::pai if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) { if (! cps.first.first || ! cps.first.second) { return tl::to_string (tr ("No matching circuit found in the other netlist.\n" - "By default, circuits are identified by their name. " + "By default, circuits are identified by their name.\n" "A missing circuit probably means there is no circuit in the other netlist with this name.\n" - "If circuits with different names need to be associated, use 'same_circuits' in the " + "If circuits with different names need to be associated, use 'same_circuits' in the\n" "LVS script to establish such an association.")); } else { return tl::to_string (tr ("Circuits could be paired, but there is a mismatch inside.\n" "Browse the circuit's component list to identify the mismatching elements.")); } } else if (cps.second == db::NetlistCrossReference::Skipped) { - return tl::to_string (tr ("Circuits can only be matched if their child circuits have a known counterpart and a pin-to-pin " - "correspondence could be established for each child circuit.\n" + return tl::to_string (tr ("Circuits can only be matched if their child circuits have a known counterpart and a\n" + "pin-to-pin correspondence could be established for each child circuit.\n" "This is not the case here. Browse the child circuits to identify the blockers.\n" - "Potential blockers are subcircuits without a corresponding other circuit or circuits " + "Potential blockers are subcircuits without a corresponding other circuit or circuits\n" "where some pins could not be mapped to pins from the corresponding other circuit.")); } return std::string (); @@ -469,15 +473,15 @@ std::string NetlistCrossReferenceModel::child_circuit_status_hint (const circuit std::pair cps = child_circuit_from_index (circuits, index); if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) { if (!cps.first.first || !cps.first.second) { - return tl::to_string (tr ("No matching subcircuit was found in the other netlist - this is likely because pin assignment " - "could not be derived from the nets connected to the pins.\n" - "Check, if the pins are attached properly. If pins need to be swappable, consider using 'equivalent_pins' " - "in the LVS script.")); + return tl::to_string (tr ("No matching subcircuit was found in the other netlist - this is likely because pin\n" + "assignment could not be derived from the nets connected to the pins.\n" + "Check, if the pins are attached properly. If pins need to be swappable, consider using\n" + "'equivalent_pins' in the LVS script.")); } else { - return tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not " + return tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not\n" "originating from equivalent circuits.\n" - "If the circuits behind the subcircuits are identical, using 'same_circuits' in the LVS script " - "helps to associate them.")); + "If the circuits behind the subcircuits are identical, using 'same_circuits'\n" + "in the LVS script will associate them.")); } } return std::string (); @@ -487,9 +491,9 @@ std::string NetlistCrossReferenceModel::net_status_hint (const circuit_pair &cir { std::pair cps = net_from_index (circuits, index); if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) { - return tl::to_string (tr ("Nets don't match. Nets match, if connected subcircuit pins and device terminals match to a counterpart in " - "the other netlist (component-wise and pin/terminal-wise).\n" - "If there already is a net candidate from the other netlist, scan the net members for " + return tl::to_string (tr ("Nets don't match. Nets match, if connected subcircuit pins and device terminals match to a\n" + "counterpart in the other netlist (component-wise and pin/terminal-wise).\n" + "If there already is a net candidate from the other netlist, scan the net members for\n" "mismatching items (with errors or warnings) and fix these issues.\n" "Otherwise, look for the corresponding other net.\n" "Net items not found in the reference netlist indicate additional connections.\n" @@ -504,15 +508,15 @@ std::string NetlistCrossReferenceModel::device_status_hint (const circuit_pair & if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) { if (!cps.first.first || !cps.first.second) { return tl::to_string (tr ("No matching device was found in the other netlist.\n" - "Devices are identified by the nets they are attached to. Unmatched devices mean that " + "Devices are identified by the nets they are attached to. Unmatched devices mean that\n" "at least one terminal net isn't matched with a corresponding net from the other netlist.\n" "Make all terminal nets match and the devices will match too.")); } } else if (cps.second == db::NetlistCrossReference::MatchWithWarning) { - return tl::to_string (tr ("Topologically matching devices are found here but either the parameters or the " + return tl::to_string (tr ("Topologically matching devices are found here but either the parameters or the\n" "device classes don't match.\n" - "If the device class is different but should be considered the same, " - "using 'same_device_class' in the LVS script will solve this issue.")); + "If the device class is different but should be considered the same, using\n" + "'same_device_classed' in the LVS script will solve this issue.")); } return std::string (); } @@ -523,8 +527,8 @@ std::string NetlistCrossReferenceModel::pin_status_hint (const circuit_pair &cir if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) { if (!cps.first.first || !cps.first.second) { return tl::to_string (tr ("No matching pin was found in the other netlist.\n" - "Pins are identified by the nets they are attached to - pins on equivalent nets are also equivalent.\n" - "Making the nets match will make the pins match too.")); + "Pins are identified by the nets they are attached to - pins on equivalent nets are also\n" + "equivalent. Making the nets match will make the pins match too.")); } } return std::string (); @@ -535,15 +539,15 @@ std::string NetlistCrossReferenceModel::subcircuit_status_hint (const circuit_pa std::pair cps = subcircuit_from_index (circuits, index); if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) { if (!cps.first.first || !cps.first.second) { - return tl::to_string (tr ("No matching subcircuit was found in the other netlist - this is likely because pin assignment " + return tl::to_string (tr ("No matching subcircuit was found in the other netlist - this is likely because pin assignment\n" "could not be derived from the nets connected to the pins.\n" - "Check, if the pins are attached properly. If pins need to be swappable, consider using 'equivalent_pins' " - "in the LVS script.")); + "Check, if the pins are attached properly. If pins need to be swappable, consider using\n" + "'equivalent_pins' in the LVS script.")); } else { - return tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not " - "originating from equivalent circuits.\n" - "If the circuits behind the subcircuits are identical, using 'same_circuits' in the LVS script " - "helps to associate them.")); + return tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not originating from\n" + "equivalent circuits.\n" + "If the circuits behind the subcircuits are identical, using 'same_circuits' in the LVS script\n" + "will associate them.")); } } return std::string ();