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)
This commit is contained in:
Matthias Koefferlein 2019-07-27 20:21:13 +02:00
parent 2e034c2172
commit 2993a6411a
5 changed files with 244 additions and 22 deletions

View File

@ -2411,6 +2411,42 @@ struct KeySize
}
};
struct DeviceConnectionDistance
{
typedef std::pair<std::vector<std::pair<size_t, size_t> >, std::pair<const db::Device *, size_t> > value_type;
double operator() (const value_type &a, const value_type &b) const
{
int d = 0.0;
for (std::vector<std::pair<size_t, size_t> >::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<size_t>::max () || j->second == std::numeric_limits<size_t>::max ()) {
++d;
}
}
return double (d);
}
};
struct DeviceParametersCompare
{
typedef std::pair<std::vector<std::pair<size_t, size_t> >, std::pair<const db::Device *, size_t> > 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 <class Iter, class Distance>
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<std::pair<const Net *, const Net *> > &net_identity, bool &pin_mismatch, std::map<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const db::Circuit *, CircuitMapper> &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<std::pair<const Net *, const Net *> > &net_identity,
bool &pin_mismatch,
std::map<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping,
std::map<const db::Circuit *, CircuitMapper> &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<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const db::Circuit *, CircuitMapper> &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::vector<std::pair<size_t, size_t> >, std::pair<const db::Device *, size_t> > device_map;
typedef std::vector<std::pair<std::vector<std::pair<size_t, size_t> >, std::pair<const db::Device *, size_t> > > 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<std::pair<size_t, size_t> > k = compute_device_key (*d, g1);
bool mapped = true;
for (std::vector<std::pair<size_t, size_t> >::iterator i = k.begin (); i != k.end () && mapped; ++i) {
for (std::vector<std::pair<size_t, size_t> >::iterator i = k.begin (); i != k.end (); ++i) {
if (! g1.begin () [i->second].has_other ()) {
i->second = std::numeric_limits<size_t>::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<std::pair<size_t, size_t> >::iterator i = k.begin (); i != k.end (); ++i) {
if (! g2.begin () [i->second].has_other ()) {
i->second = std::numeric_limits<size_t>::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::vector<std::pair<size_t, size_t> >, std::pair<const db::Device *, size_t> >::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<const Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const Circuit *, CircuitMapper> &c22_circuit_and_pin_mapping, bool &good) const
{
// Report subcircuit assignment
std::multimap<std::vector<std::pair<size_t, size_t> >, std::pair<const db::SubCircuit *, size_t> > subcircuit_map;
@ -3055,8 +3195,6 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
}
}
return good;
}
}

View File

@ -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<std::pair<const Net *, const Net *> > &net_identity, bool &pin_mismatch, std::map<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const db::Circuit *, CircuitMapper> &c22_circuit_and_pin_mapping) const;
bool all_subcircuits_verified (const db::Circuit *c, const std::set<const db::Circuit *> &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<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const db::Circuit *, CircuitMapper> &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<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const db::Circuit *, CircuitMapper> &c22_circuit_and_pin_mapping, bool &good) const;
mutable NetlistCompareLogger *mp_logger;
std::map<std::pair<const db::Circuit *, const db::Circuit *>, std::vector<std::pair<const Net *, const Net *> > > m_same_nets;

View File

@ -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 <class Obj>
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<DevicePairData, by_name_value_compare<db::Device> > ());
std::stable_sort (mp_per_circuit_data->devices.begin (), mp_per_circuit_data->devices.end (), pair_data_compare<DevicePairData, ByDeviceClassNameCompare> ());
std::stable_sort (mp_per_circuit_data->subcircuits.begin (), mp_per_circuit_data->subcircuits.end (), pair_data_compare<SubCircuitPairData, ByRefCircuitNameCompare> ());
std::stable_sort (mp_per_circuit_data->pins.begin (), mp_per_circuit_data->pins.end (), pair_data_compare<PinPairData, by_name_value_compare<db::Pin> > ());
std::stable_sort (mp_per_circuit_data->subcircuits.begin (), mp_per_circuit_data->subcircuits.end (), pair_data_compare<SubCircuitPairData, by_name_value_compare<db::SubCircuit> > ());
std::stable_sort (mp_per_circuit_data->nets.begin (), mp_per_circuit_data->nets.end (), pair_data_compare<NetPairData, by_name_value_compare<db::Net> > ());
m_current_circuits = std::make_pair((const db::Circuit *)0, (const db::Circuit *)0);

View File

@ -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<db::DeviceParameterDefinition> &pd = device->device_class ()->parameter_definitions ();
for (std::vector<db::DeviceParameterDefinition>::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<const db::Device *, const db::Device *> &devices, bool is_single)
std::string devices_string (const std::pair<const db::Device *, const db::Device *> &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<const db::DeviceClass *, const db::DeviceClass *> device_classes = device_classes_from_devices (devices);
size_t terminal = circuit_device_terminal_index_from_id (id);
std::pair<const db::DeviceTerminalDefinition *, const db::DeviceTerminalDefinition *> 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<const db::DeviceClass *, const db::DeviceClass *> device_classes = device_classes_from_devices (devices);
std::pair<const db::DeviceTerminalDefinition *, const db::DeviceTerminalDefinition *> 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;
}
}

View File

@ -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"