diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 8e9d81ea1..c1ee28855 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -2411,6 +2411,42 @@ struct KeySize } }; +struct DeviceConnectionDistance +{ + typedef std::pair >, std::pair > value_type; + + double operator() (const value_type &a, const value_type &b) const + { + int d = 0.0; + for (std::vector >::const_iterator i = a.first.begin (), j = b.first.begin (); i != a.first.end () && j != b.first.end (); ++i, ++j) { + if (i->second != j->second || i->second == std::numeric_limits::max () || j->second == std::numeric_limits::max ()) { + ++d; + } + } + return double (d); + } +}; + +struct DeviceParametersCompare +{ + typedef std::pair >, std::pair > value_type; + + bool operator() (const value_type &a, const value_type &b) const + { + // category and parameters + return m_dc (a.second, b.second); + } + + bool equals (const value_type &a, const value_type &b) const + { + // category and parameters + return m_dc.equals (a.second, b.second); + } + +private: + db::DeviceCompare m_dc; +}; + template void align (Iter i1, Iter i2, Iter j1, Iter j2, Distance distance) { @@ -2446,12 +2482,12 @@ void align (Iter i1, Iter i2, Iter j1, Iter j2, Distance distance) any_swapped = false; - for (size_t m = n + 1; m < vj.size () - 1; ++m) { + for (size_t m = n + 1; m < vj.size (); ++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]); + std::swap (*vj [n], *vj [m]); any_swapped = true; } } @@ -2462,7 +2498,14 @@ void align (Iter i1, Iter i2, Iter j1, Iter j2, Distance distance) } 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 +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 { db::DeviceFilter device_filter (m_cap_threshold, m_res_threshold); @@ -2605,7 +2648,16 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, } } + do_pin_assignment (c1, g1, c2, g2, c12_circuit_and_pin_mapping, c22_circuit_and_pin_mapping, pin_mismatch, good); + do_device_assignment (c1, g1, c2, g2, device_filter, device_categorizer, good); + do_subcircuit_assignment (c1, g1, c2, g2, circuit_categorizer, circuit_pin_mapper, c12_circuit_and_pin_mapping, c22_circuit_and_pin_mapping, good); + return good; +} + +void +NetlistComparer::do_pin_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping, bool &pin_mismatch, bool &good) const +{ // Report pin assignment // This step also does the pin identity mapping. @@ -2785,10 +2837,18 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, } +} + +void +NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, const db::DeviceFilter &device_filter, db::DeviceCategorizer &device_categorizer, bool &good) const +{ // Report device assignment std::multimap >, std::pair > device_map; + typedef std::vector >, std::pair > > unmatched_list; + unmatched_list unmatched_a, unmatched_b; + for (db::Circuit::const_device_iterator d = c1->begin_devices (); d != c1->end_devices (); ++d) { if (! device_filter.filter (d.operator-> ())) { @@ -2804,15 +2864,16 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, std::vector > k = compute_device_key (*d, g1); bool mapped = true; - for (std::vector >::iterator i = k.begin (); i != k.end () && mapped; ++i) { + for (std::vector >::iterator i = k.begin (); i != k.end (); ++i) { if (! g1.begin () [i->second].has_other ()) { + i->second = std::numeric_limits::max (); // normalization mapped = false; } } if (! mapped) { if (mp_logger) { - mp_logger->device_mismatch (d.operator-> (), 0); + unmatched_a.push_back (std::make_pair (k, std::make_pair (d.operator-> (), device_cat))); } good = false; } else { @@ -2839,6 +2900,7 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, bool mapped = true; for (std::vector >::iterator i = k.begin (); i != k.end (); ++i) { if (! g2.begin () [i->second].has_other ()) { + i->second = std::numeric_limits::max (); // normalization mapped = false; } else { i->second = g2.begin () [i->second].other_net_index (); @@ -2852,7 +2914,7 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, if (! mapped || dm == device_map.end () || dm->first != k) { if (mp_logger) { - mp_logger->device_mismatch (0, d.operator-> ()); + unmatched_b.push_back (std::make_pair (k, std::make_pair (d.operator-> (), device_cat))); } good = false; @@ -2886,12 +2948,90 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, for (std::multimap >, std::pair >::const_iterator dm = device_map.begin (); dm != device_map.end (); ++dm) { if (mp_logger) { - mp_logger->device_mismatch (dm->second.first, 0); + unmatched_a.push_back (*dm); } good = false; } + // try to do some better mapping of unmatched devices - they will still be reported as mismatching, but their pairing gives some hint + // what to fix. + 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->device_mismatch (i->second.first, 0); + } + for (unmatched_list::const_iterator i = unmatched_b.begin (); i != unmatched_b.end (); ++i) { + mp_logger->device_mismatch (0, i->second.first); + } + + } else { + + DeviceParametersCompare cmp; + + std::sort (unmatched_a.begin (), unmatched_a.end (), cmp); + std::sort (unmatched_b.begin (), unmatched_b.end (), cmp); + + 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 () || !cmp.equals (*j, *i))) { + mp_logger->device_mismatch (0, j->second.first); + ++j; + } + + while (i != unmatched_a.end () && (j == unmatched_b.end () || !cmp.equals (*i, *j))) { + mp_logger->device_mismatch (i->second.first, 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 () && cmp.equals (*i, *ii)) { + ++i; + } + + while (j != unmatched_b.end () && cmp.equals (*j, *jj)) { + ++j; + } + + if (i - ii == size_t(2)) { + printf("@@@1\n"); fflush(stdout); + } + align (ii, i, jj, j, DeviceConnectionDistance ()); + + for ( ; ii != i && jj != j; ++ii, ++jj) { + mp_logger->device_mismatch (ii->second.first, jj->second.first); + } + + for ( ; jj != j; ++jj) { + mp_logger->device_mismatch (0, jj->second.first); + } + + for ( ; ii != i; ++ii) { + mp_logger->device_mismatch (ii->second.first, 0); + } + + } + + } + + } +} + +void +NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, CircuitCategorizer &circuit_categorizer, const CircuitPinMapper &circuit_pin_mapper, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping, bool &good) const +{ // Report subcircuit assignment std::multimap >, std::pair > subcircuit_map; @@ -3055,8 +3195,6 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, } } - - return good; } } diff --git a/src/db/db/dbNetlistCompare.h b/src/db/db/dbNetlistCompare.h index d35dd0770..774936442 100644 --- a/src/db/db/dbNetlistCompare.h +++ b/src/db/db/dbNetlistCompare.h @@ -33,9 +33,11 @@ namespace db { class CircuitPinMapper; +class DeviceFilter; class DeviceCategorizer; class CircuitCategorizer; class CircuitMapper; +class NetGraph; /** * @brief A receiver for netlist compare events @@ -292,6 +294,9 @@ 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 all_subcircuits_verified (const db::Circuit *c, const std::set &verified_circuits) const; static void derive_pin_equivalence (const db::Circuit *ca, const db::Circuit *cb, CircuitPinMapper *circuit_pin_mapper); + void do_pin_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping, bool &pin_mismatch, bool &good) const; + 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, 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::CircuitPinMapper &circuit_pin_mapper, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping, bool &good) const; mutable NetlistCompareLogger *mp_logger; std::map, std::vector > > m_same_nets; diff --git a/src/db/db/dbNetlistCrossReference.cc b/src/db/db/dbNetlistCrossReference.cc index 5b6ad9ee7..d278075d4 100644 --- a/src/db/db/dbNetlistCrossReference.cc +++ b/src/db/db/dbNetlistCrossReference.cc @@ -141,6 +141,36 @@ struct by_expanded_name_value_compare } }; +struct ByDeviceClassNameCompare +{ + int operator() (const db::Device &a, const db::Device &b) const + { + if ((a.device_class () == 0) != (b.device_class () == 0)) { + return a.device_class () == 0 ? -1 : 1; + } + if (a.device_class () == 0) { + return 0; + } else { + return string_value_compare (a.device_class ()->name (), b.device_class ()->name ()); + } + } +}; + +struct ByRefCircuitNameCompare +{ + int operator() (const db::SubCircuit &a, const db::SubCircuit &b) const + { + if ((a.circuit_ref () == 0) != (b.circuit_ref () == 0)) { + return a.circuit_ref () == 0 ? -1 : 1; + } + if (a.circuit_ref () == 0) { + return 0; + } else { + return string_value_compare (a.circuit_ref ()->name (), b.circuit_ref ()->name ()); + } + } +}; + template struct net_object_compare; @@ -328,9 +358,10 @@ NetlistCrossReference::gen_end_circuit (const db::Circuit *, const db::Circuit * { mp_per_circuit_data->status = status; - std::stable_sort (mp_per_circuit_data->devices.begin (), mp_per_circuit_data->devices.end (), pair_data_compare > ()); + std::stable_sort (mp_per_circuit_data->devices.begin (), mp_per_circuit_data->devices.end (), pair_data_compare ()); + std::stable_sort (mp_per_circuit_data->subcircuits.begin (), mp_per_circuit_data->subcircuits.end (), pair_data_compare ()); + std::stable_sort (mp_per_circuit_data->pins.begin (), mp_per_circuit_data->pins.end (), pair_data_compare > ()); - std::stable_sort (mp_per_circuit_data->subcircuits.begin (), mp_per_circuit_data->subcircuits.end (), pair_data_compare > ()); std::stable_sort (mp_per_circuit_data->nets.begin (), mp_per_circuit_data->nets.end (), pair_data_compare > ()); m_current_circuits = std::make_pair((const db::Circuit *)0, (const db::Circuit *)0); diff --git a/src/laybasic/laybasic/layNetlistBrowserModel.cc b/src/laybasic/laybasic/layNetlistBrowserModel.cc index fcf200244..6c7741aef 100644 --- a/src/laybasic/laybasic/layNetlistBrowserModel.cc +++ b/src/laybasic/laybasic/layNetlistBrowserModel.cc @@ -821,13 +821,10 @@ std::string formatted_value (double v) } static -std::string device_string (const db::Device *device) +std::string device_parameter_string (const db::Device *device) { - if (! device || ! device->device_class ()) { - return std::string (); - } + std::string s; - std::string s = device->device_class ()->name (); bool first = true; const std::vector &pd = device->device_class ()->parameter_definitions (); for (std::vector::const_iterator p = pd.begin (); p != pd.end (); ++p) { @@ -849,6 +846,16 @@ std::string device_string (const db::Device *device) return s; } +static +std::string device_string (const db::Device *device) +{ + if (! device || ! device->device_class ()) { + return std::string (); + } + + return device->device_class ()->name () + device_parameter_string (device); +} + static std::string device_class_string (const db::Device *device, bool dash_for_empty = false) { @@ -862,13 +869,20 @@ std::string device_class_string (const db::Device *device, bool dash_for_empty = } static -std::string devices_string (const std::pair &devices, bool is_single) +std::string devices_string (const std::pair &devices, bool is_single, bool with_parameters) { if (devices.first || devices.second) { - std::string s = device_class_string (devices.first, ! is_single); + std::string s; + s = device_class_string (devices.first, ! is_single); + if (with_parameters) { + s += device_parameter_string (devices.first); + } if (! is_single) { std::string t = device_class_string (devices.second, ! is_single); + if (with_parameters) { + t += device_parameter_string (devices.second); + } if (t != s) { s += var_sep; s += t; @@ -1212,7 +1226,7 @@ NetlistBrowserModel::text (const QModelIndex &index) const } else { if (index.column () == m_object_column) { - return escaped (devices_string (devices, mp_indexer->is_single ())); + return escaped (devices_string (devices, mp_indexer->is_single (), false /*without parameters*/)); } else if (index.column () == m_first_column) { return escaped (str_from_expanded_name (devices.first) + field_sep + device_string (devices.first)); } else if (index.column () == m_second_column) { @@ -1332,7 +1346,7 @@ NetlistBrowserModel::text (const QModelIndex &index) const if (mp_indexer->is_single ()) { return escaped (str_from_name (termdefs.first) + field_sep + device_string (devices.first)); } else { - return escaped (str_from_names (termdefs, mp_indexer->is_single ()) + field_sep + devices_string (devices, mp_indexer->is_single ())); + return escaped (str_from_names (termdefs, mp_indexer->is_single ()) + field_sep + devices_string (devices, mp_indexer->is_single (), true /*with parameters*/)); } } else if (index.column () == m_first_column || index.column () == m_second_column) { @@ -1439,6 +1453,20 @@ NetlistBrowserModel::status (const QModelIndex &index) const size_t index = circuit_device_index_from_id (id); return mp_indexer->device_from_index (circuits, index).second; + } else if (is_id_circuit_device_terminal (id)) { + + IndexedNetlistModel::device_pair devices = devices_from_id (id); + std::pair device_classes = device_classes_from_devices (devices); + size_t terminal = circuit_device_terminal_index_from_id (id); + + std::pair termdefs = terminal_defs_from_device_classes (device_classes, terminal); + + if (! is_valid_net_pair (nets_from_device_terminals (devices, termdefs))) { + // This indicates a wrong connection: the nets are associated in a way which is a not + // corresponding to a mapped net pair. Report Mismatch here. + return db::NetlistCrossReference::NoMatch; + } + } else if (is_id_circuit_subcircuit (id)) { IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); @@ -1460,7 +1488,7 @@ NetlistBrowserModel::status (const QModelIndex &index) const if (! is_valid_net_pair (nets_from_subcircuit_pins (subcircuits, pins))) { // This indicates a wrong connection: the nets are associated in a way which is a not // corresponding to a mapped net pair. Report Mismatch here. - return db::NetlistCrossReference::MatchWithWarning; + return db::NetlistCrossReference::NoMatch; } } else if (is_id_circuit_net (id)) { @@ -1477,6 +1505,21 @@ NetlistBrowserModel::status (const QModelIndex &index) const return mp_indexer->device_from_index (circuits, mp_indexer->device_index (devices)).second; + } else if (is_id_circuit_net_device_terminal_others (id)) { + + IndexedNetlistModel::net_terminal_pair termrefs = net_terminalrefs_from_id (id); + size_t other_index = circuit_net_device_terminal_other_index_from_id (id); + + IndexedNetlistModel::device_pair devices = devices_from_termrefs (termrefs); + std::pair device_classes = device_classes_from_devices (devices); + std::pair termdefs = terminal_defs_from_device_classes (device_classes, other_index); + + if (! is_valid_net_pair (nets_from_device_terminals (devices, termdefs))) { + // This indicates a wrong connection: the nets are associated in a way which is a not + // corresponding to a mapped net pair. Report Mismatch here. + return db::NetlistCrossReference::NoMatch; + } + } else if (is_id_circuit_net_subcircuit_pin (id)) { IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id); @@ -1497,7 +1540,7 @@ NetlistBrowserModel::status (const QModelIndex &index) const if (! is_valid_net_pair (nets_from_subcircuit_pins (subcircuits, pins))) { // This indicates a wrong connection: the nets are associated in a way which is a not // corresponding to a mapped net pair. Report Mismatch here. - return db::NetlistCrossReference::MatchWithWarning; + return db::NetlistCrossReference::NoMatch; } } diff --git a/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc b/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc index 6532afed4..0c28f51e3 100644 --- a/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc +++ b/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc @@ -532,6 +532,11 @@ std::string NetlistCrossReferenceModel::device_status_hint (const circuit_pair & "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 { + return tl::to_string (tr ("Devices don't match topologically.\n" + "Check the terminal connections to identify the terminals not being connected to\n" + "corresponding nets. Either the devices are not connected correctly or the nets\n" + "need to be fixed before 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\n"