From 2993a6411a6ab3e8f2673984375c38e22582cbc4 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 27 Jul 2019 20:21:13 +0200 Subject: [PATCH] WIP: some enhancements to cross reference and browser Devices: try to pair unmatching ones similar to subcircuits Don't sort devices by the device name but by class name Show the device parameters for netlist devices (same as for netlist browser) --- src/db/db/dbNetlistCompare.cc | 156 +++++++++++++++++- src/db/db/dbNetlistCompare.h | 5 + src/db/db/dbNetlistCrossReference.cc | 35 +++- .../laybasic/layNetlistBrowserModel.cc | 65 ++++++-- .../laybasic/layNetlistCrossReferenceModel.cc | 5 + 5 files changed, 244 insertions(+), 22 deletions(-) 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"