Merge remote-tracking branch 'origin/netlist-compare-hardening' into macos-fixes

This commit is contained in:
Matthias 2020-06-26 08:00:13 -07:00
commit 91eca19b3a
4 changed files with 674 additions and 207 deletions

View File

@ -616,18 +616,20 @@ class NetGraph;
struct CompareData
{
CompareData ()
: other (0), max_depth (0), max_n_branch (0), dont_consider_net_names (false), logger (0),
circuit_pin_mapper (0), subcircuit_equivalence (0), device_equivalence (0)
: other (0), max_depth (0), max_n_branch (0), depth_first (true), dont_consider_net_names (false), logger (0),
circuit_pin_mapper (0), subcircuit_equivalence (0), device_equivalence (0), progress (0)
{ }
NetGraph *other;
size_t max_depth;
size_t max_n_branch;
bool depth_first;
bool dont_consider_net_names;
NetlistCompareLogger *logger;
CircuitPinMapper *circuit_pin_mapper;
SubCircuitEquivalenceTracker *subcircuit_equivalence;
DeviceEquivalenceTracker *device_equivalence;
tl::RelativeProgress *progress;
};
// --------------------------------------------------------------------------------------------------------------------
@ -1920,7 +1922,7 @@ static bool edges_are_compatible (const NetGraphNode::edge_type &e, const NetGra
size_t
NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGraphNode::edge_iterator ee, NetGraphNode::edge_iterator e_other, NetGraphNode::edge_iterator ee_other, size_t net_index, size_t other_net_index, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, bool with_ambiguous, CompareData *data)
{
size_t new_nodes = 0;
// NOTE: we can skip edges to known nodes because we did a pre-analysis making sure those are compatible
std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> > nodes;
nodes.reserve (ee - e);
@ -1930,100 +1932,114 @@ NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGr
tl_assert (e->first == e_other->first);
if (options ()->debug_netcompare) {
tl::info << indent(depth) << "considering transitions:";
}
bool first = true;
for (NetGraphNode::edge_iterator i = e; i != ee; ++i) {
if (i->second.first != net_index) {
const NetGraphNode *nn = &node (i->second.first);
if (options ()->debug_netcompare) {
if (first) {
tl::info << indent (depth) << " here: " << (node (net_index).net () ? node (net_index).net ()->expanded_name ().c_str () : "(null)") << " ->";
first = false;
}
tl::info << indent (depth) << " " << (nn->net () ? nn->net ()->expanded_name ().c_str() : "(null)") << " via: " << tl::noendl;
for (std::vector<NetGraphNode::Transition>::const_iterator t = i->first.begin (); t != i->first.end(); ++t) {
tl::info << (t != i->first.begin () ? "; " : "") << t->to_string() << tl::noendl;
}
tl::info << "";
if (! nn->has_other ()) {
nodes.push_back (std::make_pair (nn, i));
}
nodes.push_back (std::make_pair (nn, i));
}
}
if (! nodes.empty ()) { // if non-ambiguous, non-assigned
first = true;
for (NetGraphNode::edge_iterator i = e_other; i != ee_other; ++i) {
if (i->second.first != other_net_index) {
const NetGraphNode *nn = &data->other->node (i->second.first);
if (options ()->debug_netcompare) {
if (first) {
tl::info << indent (depth) << " there: " << (data->other->node (other_net_index).net () ? data->other->node (other_net_index).net ()->expanded_name ().c_str () : "(null)") << " ->";
first = false;
}
tl::info << indent(depth) << " " << (nn->net() ? nn->net()->expanded_name().c_str() : "(null)") << " via: " << tl::noendl;
for (std::vector<NetGraphNode::Transition>::const_iterator t = i->first.begin (); t != i->first.end(); ++t) {
tl::info << (t != i->first.begin () ? "; " : "") << t->to_string() << tl::noendl;
}
tl::info << "";
if (! nn->has_other ()) {
other_nodes.push_back (std::make_pair (nn, i));
}
other_nodes.push_back (std::make_pair (nn, i));
}
}
}
if (! nodes.empty () || ! other_nodes.empty ()) {
if (nodes.empty () || other_nodes.empty ()) {
return 0;
}
std::sort (nodes.begin (), nodes.end (), CompareNodePtr ());
std::sort (other_nodes.begin (), other_nodes.end (), CompareNodePtr ());
std::sort (nodes.begin (), nodes.end (), CompareNodePtr ());
std::sort (other_nodes.begin (), other_nodes.end (), CompareNodePtr ());
// for the purpose of match evaluation we require an exact match of the node structure
size_t new_nodes = 0;
if (tentative) {
if (options ()->debug_netcompare) {
if (nodes.size () != other_nodes.size ()) {
if (options ()->debug_netcompare) {
tl::info << indent(depth) << "=> rejected branch.";
}
return failed_match;
// print transitions if requested
tl::info << indent(depth) << "considering transitions:";
bool first = true;
for (std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::const_iterator i = nodes.begin (); i != nodes.end (); ++i) {
const NetGraphNode *nn = i->first;
if (first) {
tl::info << indent (depth) << " here: " << (node (net_index).net () ? node (net_index).net ()->expanded_name ().c_str () : "(null)") << " ->";
first = false;
}
tl::info << indent (depth) << " " << (nn->net () ? nn->net ()->expanded_name ().c_str() : "(null)") << " via: " << tl::noendl;
for (std::vector<NetGraphNode::Transition>::const_iterator t = i->second->first.begin (); t != i->second->first.end(); ++t) {
tl::info << (t != i->second->first.begin () ? "; " : "") << t->to_string() << tl::noendl;
}
tl::info << "";
}
// 1:1 pairing is less strict
if (nodes.size () > 1 || other_nodes.size () > 1) {
for (size_t i = 0; i < nodes.size (); ++i) {
if (! (*nodes[i].first == *other_nodes[i].first)) {
if (options ()->debug_netcompare) {
tl::info << indent(depth) << "=> rejected branch.";
}
return failed_match;
first = true;
for (std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::const_iterator i = other_nodes.begin (); i != other_nodes.end (); ++i) {
const NetGraphNode *nn = i->first;
if (first) {
tl::info << indent (depth) << " there: " << (data->other->node (other_net_index).net () ? data->other->node (other_net_index).net ()->expanded_name ().c_str () : "(null)") << " ->";
first = false;
}
tl::info << indent(depth) << " " << (nn->net() ? nn->net()->expanded_name().c_str() : "(null)") << " via: " << tl::noendl;
for (std::vector<NetGraphNode::Transition>::const_iterator t = i->second->first.begin (); t != i->second->first.end(); ++t) {
tl::info << (t != i->second->first.begin () ? "; " : "") << t->to_string() << tl::noendl;
}
tl::info << "";
}
}
// for the purpose of match evaluation we require an exact match of the node structure
if (tentative) {
if (nodes.size () != other_nodes.size ()) {
if (options ()->debug_netcompare) {
tl::info << indent(depth) << "=> rejected branch.";
}
return failed_match;
}
// 1:1 pairing is less strict
if (nodes.size () > 1 || other_nodes.size () > 1) {
for (size_t i = 0; i < nodes.size (); ++i) {
if (! (*nodes[i].first == *other_nodes[i].first)) {
if (options ()->debug_netcompare) {
tl::info << indent(depth) << "=> rejected branch.";
}
return failed_match;
}
}
}
// propagate pairing in picky mode: this means we only accept exact a match if the node set
// is exactly identical and no ambiguous nodes are present when ambiguous nodes are forbidden
}
size_t bt_count = derive_node_identities_from_node_set (nodes, other_nodes, depth, n_branch, tentative, with_ambiguous, data);
// propagate pairing in picky mode: this means we only accept exact a match if the node set
// is exactly identical and no ambiguous nodes are present when ambiguous nodes are forbidden
if (bt_count == failed_match) {
if (tentative) {
if (options ()->debug_netcompare) {
tl::info << indent(depth) << "=> rejected branch.";
}
return bt_count;
size_t bt_count = derive_node_identities_from_node_set (nodes, other_nodes, depth, n_branch, tentative, with_ambiguous, data);
if (bt_count == failed_match) {
if (tentative) {
if (options ()->debug_netcompare) {
tl::info << indent(depth) << "=> rejected branch.";
}
} else {
new_nodes += bt_count;
return bt_count;
}
} else {
new_nodes += bt_count;
}
if (options ()->debug_netcompare) {
@ -2055,16 +2071,6 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc
size_t other_net_index = n->other_net_index ();
NetGraphNode *n_other = & data->other->node (other_net_index);
if (options ()->debug_netcompare) {
if (! tentative) {
tl::info << indent(depth) << "deducing from pair: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name ();
} else {
tl::info << indent(depth) << "tentatively deducing from pair: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name ();
}
}
size_t new_nodes = 0;
NetGraphNode nn, nn_other;
// If there are subcircuits on the graph we temporarily create edges from our node to the other nodes of
@ -2082,6 +2088,117 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc
}
// do a pre-analysis filtering out all nodes with fully satisfied edges or which provide a contradiction
bool analysis_required = false;
for (NetGraphNode::edge_iterator e = n->begin (); e != n->end (); ) {
NetGraphNode::edge_iterator ee = e;
++ee;
while (ee != n->end () && ee->first == e->first) {
++ee;
}
NetGraphNode::edge_iterator e_other = n_other->find_edge (e->first);
if (e_other != n_other->end ()) {
NetGraphNode::edge_iterator ee_other = e_other;
++ee_other;
while (ee_other != n_other->end () && ee_other->first == e_other->first) {
++ee_other;
}
std::vector<const NetGraphNode *> nodes;
nodes.reserve (ee - e);
std::vector<const NetGraphNode *> other_nodes_translated;
other_nodes_translated.reserve (ee - e);
tl_assert (e->first == e_other->first);
for (NetGraphNode::edge_iterator i = e; i != ee; ++i) {
if (i->second.first != net_index) {
const NetGraphNode *nn = &node (i->second.first);
if (nn->has_other ()) {
nodes.push_back (nn);
} else {
analysis_required = true;
}
}
}
for (NetGraphNode::edge_iterator i = e_other; i != ee_other; ++i) {
if (i->second.first != other_net_index) {
const NetGraphNode *nn = &data->other->node (i->second.first);
if (nn->has_other ()) {
other_nodes_translated.push_back (&node (nn->other_net_index ()));
} else {
analysis_required = true;
}
}
}
std::sort (nodes.begin (), nodes.end ());
std::sort (other_nodes_translated.begin (), other_nodes_translated.end ());
// No fit, we can shortcut
if (nodes != other_nodes_translated) {
return tentative ? failed_match : 0;
}
} else if (tentative) {
// in tentative mode an exact match is required: no having the same edges for a node disqualifies the node
// as matching.
return failed_match;
}
e = ee;
}
if (tentative) {
// in tentative mode, again an exact match is required
for (NetGraphNode::edge_iterator e_other = n_other->begin (); e_other != n_other->end (); ) {
NetGraphNode::edge_iterator ee_other = e_other;
++ee_other;
while (ee_other != n_other->end () && ee_other->first == e_other->first) {
++ee_other;
}
NetGraphNode::edge_iterator e = n->find_edge (e_other->first);
if (e == n->end ()) {
return failed_match;
}
e_other = ee_other;
}
}
if (! analysis_required) {
return 0;
}
// do a detailed analysis
size_t new_nodes = 0;
if (options ()->debug_netcompare) {
if (! tentative) {
tl::info << indent(depth) << "deducing from pair: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name ();
} else {
tl::info << indent(depth) << "tentatively deducing from pair: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name ();
}
}
// non-ambiguous paths to non-assigned nodes create a node identity on the
// end of this path
@ -2114,46 +2231,12 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc
new_nodes += bt_count;
}
} else if (tentative) {
// in tentative mode an exact match is required: no having the same edges for a node disqualifies the node
// as matching.
if (options ()->debug_netcompare) {
tl::info << indent(depth) << "=> rejected pair for missing edge.";
}
return failed_match;
}
e = ee;
}
if (tentative) {
// in tentative mode, again an exact match is required
for (NetGraphNode::edge_iterator e_other = n_other->begin (); e_other != n_other->end (); ) {
NetGraphNode::edge_iterator ee_other = e_other;
++ee_other;
while (ee_other != n_other->end () && ee_other->first == e_other->first) {
++ee_other;
}
NetGraphNode::edge_iterator e = n->find_edge (e_other->first);
if (e == n->end ()) {
if (options ()->debug_netcompare) {
tl::info << indent(depth) << "=> rejected pair for missing edge.";
}
return failed_match;
}
e_other = ee_other;
}
}
if (options ()->debug_netcompare) {
if (! tentative && new_nodes > 0) {
tl::info << indent(depth) << "=> finished pair deduction: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name () << " with " << new_nodes << " new pairs";
@ -2295,22 +2378,27 @@ NetGraph::derive_node_identities_from_node_set (std::vector<std::pair<const NetG
if (options ()->debug_netcompare) {
tl::info << indent_s << "deduced match (singular): " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name ();
}
if (data->logger && ! tentative) {
if (! (node (ni) == data->other->node (other_ni))) {
// this is a mismatch but we continue, because that is the only candidate
data->logger->net_mismatch (n->net (), n_other->net ());
} else {
data->logger->match_nets (n->net (), n_other->net ());
if (! tentative) {
++*data->progress;
if (data->logger) {
if (! (node (ni) == data->other->node (other_ni))) {
// this is a mismatch but we continue, because that is the only candidate
data->logger->net_mismatch (n->net (), n_other->net ());
} else {
data->logger->match_nets (n->net (), n_other->net ());
}
}
}
// continue here.
size_t bt_count = derive_node_identities (ni, depth + 1, n_branch, tentative, with_ambiguous, data);
if (bt_count != failed_match) {
new_nodes += bt_count;
} else if (tentative) {
return bt_count;
if (data->depth_first || tentative) {
size_t bt_count = derive_node_identities (ni, depth + 1, n_branch, tentative, with_ambiguous, data);
if (bt_count == failed_match) {
if (tentative) {
return failed_match;
}
} else {
new_nodes += bt_count;
}
}
new_nodes += 1;
@ -2346,10 +2434,10 @@ NetGraph::derive_node_identities_from_node_set (std::vector<std::pair<const NetG
while (n1 != nodes.end () && n2 != other_nodes.end ()) {
if (n1->first->has_any_other ()) {
if (n1->first->has_other ()) {
++n1;
continue;
} else if (n2->first->has_any_other ()) {
} else if (n2->first->has_other ()) {
++n2;
continue;
}
@ -2368,9 +2456,9 @@ NetGraph::derive_node_identities_from_node_set (std::vector<std::pair<const NetG
++nn1;
++nn2;
while (nn1 != nodes.end () && nn2 != other_nodes.end ()) {
if (nn1->first->has_any_other ()) {
if (nn1->first->has_other ()) {
++nn1;
} else if (nn2->first->has_any_other ()) {
} else if (nn2->first->has_other ()) {
++nn2;
} else if (! (*nn1->first == *n1->first) || ! (*nn2->first == *n2->first)) {
break;
@ -2405,9 +2493,9 @@ NetGraph::derive_node_identities_from_node_set (std::vector<std::pair<const NetG
// node ranges might have changed - adjust to real count and skip leading pairs assigned already
while (nr->n1 != nr->nn1 && nr->n2 != nr->nn2) {
if (nr->n1->first->has_any_other ()) {
if (nr->n1->first->has_other ()) {
++nr->n1;
} else if (nr->n2->first->has_any_other ()) {
} else if (nr->n2->first->has_other ()) {
++nr->n2;
} else {
break;
@ -2418,9 +2506,9 @@ NetGraph::derive_node_identities_from_node_set (std::vector<std::pair<const NetG
std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::const_iterator i1 = nr->n1, i2 = nr->n2;
while (i1 != nr->nn1 && i2 != nr->nn2) {
if (i1->first->has_any_other ()) {
if (i1->first->has_other ()) {
++i1;
} else if (i2->first->has_any_other ()) {
} else if (i2->first->has_other ()) {
++i2;
} else {
++nr->num;
@ -2435,7 +2523,14 @@ NetGraph::derive_node_identities_from_node_set (std::vector<std::pair<const NetG
} else if (nr->num == 1) {
if (! nr->n1->first->has_any_other () && ! nr->n2->first->has_any_other ()) {
if (! edges_are_compatible (*nr->n1->second, *nr->n2->second, *data->device_equivalence, *data->subcircuit_equivalence)) {
if (options ()->debug_netcompare) {
tl::info << indent(depth) << "=> rejected because edges are incompatible with already established device or subcircuit equivalences";
}
return tentative ? failed_match : 0;
} else if (! nr->n1->first->has_any_other () && ! nr->n2->first->has_any_other ()) {
// in tentative mode, reject this choice if both nets are named and
// their names differ -> this favors net matching by name
@ -2458,25 +2553,31 @@ NetGraph::derive_node_identities_from_node_set (std::vector<std::pair<const NetG
if (options ()->debug_netcompare) {
tl::info << indent_s << "deduced match (singular): " << nr->n1->first->net ()->expanded_name () << " vs. " << nr->n2->first->net ()->expanded_name ();
}
if (data->logger && ! tentative) {
if (! (node (ni) == data->other->node (other_ni))) {
// this is a mismatch, but we continue with this
data->logger->net_mismatch (nr->n1->first->net (), nr->n2->first->net ());
} else {
data->logger->match_nets (nr->n1->first->net (), nr->n2->first->net ());
if (! tentative) {
++*data->progress;
if (data->logger) {
if (! (node (ni) == data->other->node (other_ni))) {
// this is a mismatch, but we continue with this
data->logger->net_mismatch (nr->n1->first->net (), nr->n2->first->net ());
} else {
data->logger->match_nets (nr->n1->first->net (), nr->n2->first->net ());
}
}
}
// continue here.
size_t bt_count = derive_node_identities (ni, depth + 1, n_branch, tentative, with_ambiguous, data);
if (bt_count != failed_match) {
new_nodes += bt_count;
new_nodes += 1;
} else if (tentative) {
new_nodes = bt_count;
if (data->depth_first || tentative) {
size_t bt_count = derive_node_identities (ni, depth + 1, n_branch, tentative, with_ambiguous, data);
if (bt_count == failed_match) {
if (tentative) {
return failed_match;
}
} else {
new_nodes += bt_count;
}
}
new_nodes += 1;
} else if (nr->n1->first->has_unknown_other ()) {
// accept any other net
@ -2633,6 +2734,7 @@ NetGraph::derive_node_identities_from_node_set (std::vector<std::pair<const NetG
tl::info << indent_s << "deduced match: " << p->first->net ()->expanded_name () << " vs. " << p->second->net ()->expanded_name ();
}
}
if (data->logger) {
bool ambiguous = equivalent_other_nodes.has_attribute (p->second);
if (ambiguous) {
@ -2642,6 +2744,8 @@ NetGraph::derive_node_identities_from_node_set (std::vector<std::pair<const NetG
}
}
++*data->progress;
}
// And seek further from these pairs
@ -2695,6 +2799,7 @@ NetlistComparer::NetlistComparer (NetlistCompareLogger *logger)
m_max_depth = 50;
m_max_n_branch = 500;
m_depth_first = true;
m_dont_consider_net_names = false;
}
@ -2906,6 +3011,8 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const
std::map<const db::Circuit *, CircuitMapper> c12_pin_mapping, c22_pin_mapping;
tl::RelativeProgress progress (tl::to_string (tr ("Comparing netlists")), a->circuit_count (), 1);
for (db::Netlist::const_bottom_up_circuit_iterator c = a->begin_bottom_up (); c != a->end_bottom_up (); ++c) {
const db::Circuit *ca = c.operator-> ();
@ -2936,6 +3043,7 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const
if (all_subcircuits_verified (ca, verified_circuits_a) && all_subcircuits_verified (cb, verified_circuits_b)) {
if (options ()->debug_netcompare) {
tl::info << "----------------------------------------------------------------------";
tl::info << "treating circuit: " << ca->name () << " vs. " << cb->name ();
}
if (mp_logger) {
@ -2968,6 +3076,8 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const
}
++progress;
}
if (mp_logger) {
@ -3038,8 +3148,42 @@ compute_device_key (const db::Device &device, const db::NetGraph &g, bool strict
k.push_back (std::make_pair (terminal_id, net_id));
}
std::sort (k.begin (), k.end ());
return k;
}
static std::vector<std::pair<size_t, size_t> >
compute_device_key_for_this (const db::Device &device, const db::NetGraph &g, bool strict, bool &mapped)
{
std::vector<std::pair<size_t, size_t> > k = compute_device_key (device, g, strict);
mapped = true;
for (std::vector<std::pair<size_t, size_t> >::iterator i = k.begin (); i != k.end (); ++i) {
if (! g.begin () [i->second].has_other ()) {
i->second = invalid_id; // normalization
mapped = false;
}
}
std::sort (k.begin (), k.end ());
return k;
}
static std::vector<std::pair<size_t, size_t> >
compute_device_key_for_other (const db::Device &device, const db::NetGraph &g, bool strict, bool &mapped)
{
std::vector<std::pair<size_t, size_t> > k = compute_device_key (device, g, strict);
mapped = true;
for (std::vector<std::pair<size_t, size_t> >::iterator i = k.begin (); i != k.end (); ++i) {
if (! g.begin () [i->second].has_other ()) {
i->second = invalid_id; // normalization
mapped = false;
} else {
i->second = g.begin () [i->second].other_net_index ();
}
}
std::sort (k.begin (), k.end ());
return k;
}
@ -3074,11 +3218,51 @@ compute_subcircuit_key (const db::SubCircuit &subcircuit, const db::NetGraph &g,
}
std::sort (k.begin (), k.end ());
return true;
}
static std::vector<std::pair<size_t, size_t> >
compute_subcircuit_key_for_this (const db::SubCircuit &subcircuit, const db::NetGraph &g, const std::map<const db::Circuit *, CircuitMapper> *circuit_map, const CircuitPinMapper *pin_map, bool &mapped, bool &valid)
{
valid = true;
std::vector<std::pair<size_t, size_t> > k;
if (! compute_subcircuit_key (subcircuit, g, circuit_map, pin_map, k)) {
valid = false;
}
mapped = true;
for (std::vector<std::pair<size_t, size_t> >::iterator i = k.begin (); i != k.end () && mapped; ++i) {
if (! g.begin () [i->second].has_other ()) {
mapped = false;
}
}
std::sort (k.begin (), k.end ());
return k;
}
static std::vector<std::pair<size_t, size_t> >
compute_subcircuit_key_for_other (const db::SubCircuit &subcircuit, const db::NetGraph &g, const std::map<const db::Circuit *, CircuitMapper> *circuit_map, const CircuitPinMapper *pin_map, bool &mapped, bool &valid)
{
valid = true;
std::vector<std::pair<size_t, size_t> > k;
if (! compute_subcircuit_key (subcircuit, g, circuit_map, pin_map, k)) {
valid = false;
}
mapped = true;
for (std::vector<std::pair<size_t, size_t> >::iterator i = k.begin (); i != k.end (); ++i) {
if (! g.begin () [i->second].has_other ()) {
mapped = false;
} else {
i->second = g.begin () [i->second].other_net_index ();
}
}
std::sort (k.begin (), k.end ());
return k;
}
namespace {
inline double size_dist (size_t a, size_t b)
@ -3252,11 +3436,13 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
int iter = 0;
tl::RelativeProgress progress (tl::to_string (tr ("Comparing circuits ")) + c1->name () + "/" + c2->name (), std::max (g1.end () - g1.begin (), g2.end () - g2.begin ()), 1);
// two passes: one without ambiguities, the second one with
bool good;
bool good = false;
for (int pass = 0; pass < 2; ++pass) {
for (int pass = 0; pass < 2 && ! good; ++pass) {
if (options ()->debug_netcompare) {
if (pass > 0) {
@ -3283,11 +3469,13 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
data.other = &g2;
data.max_depth = m_max_depth;
data.max_n_branch = m_max_n_branch;
data.depth_first = m_depth_first;
data.dont_consider_net_names = m_dont_consider_net_names;
data.circuit_pin_mapper = &circuit_pin_mapper;
data.subcircuit_equivalence = &subcircuit_equivalence;
data.device_equivalence = &device_equivalence;
data.logger = mp_logger;
data.progress = &progress;
size_t ni = g1.derive_node_identities (i1 - g1.begin (), 0, 1, 0 /*not tentative*/, pass > 0 /*with ambiguities*/, &data);
if (ni > 0 && ni != failed_match) {
@ -3334,6 +3522,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
for (std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::const_iterator n = other_nodes.begin (); n != other_nodes.end () && good; ++n) {
good = is_passive_net (n->first->net (), c22_circuit_and_pin_mapping);
}
if (options ()->debug_netcompare) {
tl::info << "Stopped with " << nodes.size () << "/" << other_nodes.size () << " nodes left unresolved " << (good ? "(accepted)" : "(not accepted)");
}
// this assumes that we don't gain anything here. Stop now.
break;
}
@ -3350,6 +3541,7 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
data.subcircuit_equivalence = &subcircuit_equivalence;
data.device_equivalence = &device_equivalence;
data.logger = mp_logger;
data.progress = &progress;
size_t ni = g1.derive_node_identities_from_node_set (nodes, other_nodes, 0, 1, 0 /*not tentatively*/, pass > 0 /*with ambiguities*/, &data);
if (ni > 0 && ni != failed_match) {
@ -3360,6 +3552,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
}
if (new_identities == 0) {
if (options ()->debug_netcompare) {
tl::info << "Stopped with " << nodes.size () << "/" << other_nodes.size () << " nodes left unresolved.";
}
good = false;
break;
}
@ -3372,6 +3567,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
for (db::NetGraph::node_iterator i = g1.begin (); i != g1.end (); ++i) {
if (! i->has_other ()) {
if (options ()->debug_netcompare) {
tl::info << "Unresolved net from left: " << i->net ()->expanded_name () << " " << (good ? "(accepted)" : "(not accepted)");
}
if (mp_logger) {
if (good) {
mp_logger->match_nets (i->net (), 0);
@ -3388,6 +3586,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
for (db::NetGraph::node_iterator i = g2.begin (); i != g2.end (); ++i) {
if (! i->has_other ()) {
if (options ()->debug_netcompare) {
tl::info << "Unresolved net from right: " << i->net ()->expanded_name () << " " << (good ? "(accepted)" : "(not accepted)");
}
if (mp_logger) {
if (good) {
mp_logger->match_nets (0, i->net ());
@ -3628,6 +3829,8 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph
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;
// check mapping of devices whose equivalence is established topologically
for (db::Circuit::const_device_iterator d = c1->begin_devices (); d != c1->end_devices (); ++d) {
if (! device_filter.filter (d.operator-> ())) {
@ -3644,15 +3847,8 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph
continue;
}
std::vector<std::pair<size_t, size_t> > k = compute_device_key (*d, g1, device_categorizer.is_strict_device_category (device_cat));
bool mapped = true;
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 = invalid_id; // normalization
mapped = false;
}
}
std::vector<std::pair<size_t, size_t> > k = compute_device_key_for_this (*d, g1, device_categorizer.is_strict_device_category (device_cat), mapped);
if (! mapped) {
if (mp_logger) {
@ -3678,28 +3874,41 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph
continue;
}
const db::Device *c1_device = device_eq.other (d.operator-> ());
const db::Device *c1_device = 0;
size_t c1_device_cat = 0;
if (c1_device) {
const db::Device *d_this = device_eq.other (d.operator-> ());
if (d_this) {
c1_device_cat = device_categorizer.cat_for_device (c1_device);
size_t device_cat_this = device_categorizer.cat_for_device (d_this);
if (! device_cat_this) {
// device is ignored
continue;
}
bool mapped1 = true, mapped2 = true;
std::vector<std::pair<size_t, size_t> > k_this = compute_device_key_for_this (*d_this, g1, device_categorizer.is_strict_device_category (device_cat_this), mapped1);
std::vector<std::pair<size_t, size_t> > k = compute_device_key_for_other (*d, g2, device_categorizer.is_strict_device_category (device_cat), mapped2);
if (! mapped1 || ! mapped2 || k != k_this) {
// topological mismatch
if (mp_logger) {
mp_logger->device_mismatch (d_this, d.operator-> ());
}
good = false;
} else {
c1_device = d_this;
c1_device_cat = device_cat_this;
}
} else {
std::vector<std::pair<size_t, size_t> > k = compute_device_key (*d, g2, device_categorizer.is_strict_device_category (device_cat));
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 = invalid_id; // normalization
mapped = false;
} else {
i->second = g2.begin () [i->second].other_net_index ();
}
}
std::sort (k.begin (), k.end ());
std::vector<std::pair<size_t, size_t> > k = compute_device_key_for_other (*d, g2, device_categorizer.is_strict_device_category (device_cat), mapped);
std::multimap<std::vector<std::pair<size_t, size_t> >, std::pair<const db::Device *, size_t> >::iterator dm = device_map.find (k);
@ -3844,15 +4053,8 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG
continue;
}
std::vector<std::pair<size_t, size_t> > k;
bool valid = compute_subcircuit_key (*sc, g1, &c12_circuit_and_pin_mapping, &circuit_pin_mapper, k);
bool mapped = true;
for (std::vector<std::pair<size_t, size_t> >::iterator i = k.begin (); i != k.end () && mapped; ++i) {
if (! g1.begin () [i->second].has_other ()) {
mapped = false;
}
}
bool mapped = true, valid = true;
std::vector<std::pair<size_t, size_t> > k = compute_subcircuit_key_for_this (*sc, g1, &c12_circuit_and_pin_mapping, &circuit_pin_mapper, mapped, valid);
if (! mapped) {
if (mp_logger) {
@ -3877,33 +4079,39 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG
continue;
}
const db::SubCircuit *c1_subcircuit = subcircuit_eq.other (sc.operator-> ());
const db::SubCircuit *sc_this = subcircuit_eq.other (sc.operator-> ());
if (sc_this) {
if (c1_subcircuit) {
size_t sc_cat_this = circuit_categorizer.cat_for_subcircuit (sc_this);
if (! sc_cat_this) {
// subcircuit is ignored
continue;
}
if (mp_logger) {
mp_logger->match_subcircuits (c1_subcircuit, sc.operator-> ());
bool mapped1 = true, mapped2 = true;
bool valid1 = true, valid2 = true;
std::vector<std::pair<size_t, size_t> > k_this = compute_subcircuit_key_for_this (*sc_this, g1, &c12_circuit_and_pin_mapping, &circuit_pin_mapper, mapped1, valid1);
std::vector<std::pair<size_t, size_t> > k = compute_subcircuit_key_for_other (*sc, g2, &c22_circuit_and_pin_mapping, &circuit_pin_mapper, mapped2, valid2);
if (! valid1 || ! valid2 || ! mapped1 || ! mapped2 || k_this != k || sc_cat != sc_cat_this) {
if (mp_logger) {
mp_logger->subcircuit_mismatch (sc_this, sc.operator-> ());
}
good = false;
} else {
if (mp_logger) {
mp_logger->match_subcircuits (sc_this, sc.operator-> ());
}
}
} else {
std::vector<std::pair<size_t, size_t> > k;
compute_subcircuit_key (*sc, g2, &c22_circuit_and_pin_mapping, &circuit_pin_mapper, k);
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 ()) {
mapped = false;
} else {
i->second = g2.begin () [i->second].other_net_index ();
}
}
std::sort (k.begin (), k.end ());
bool mapped = true, valid = true;
std::vector<std::pair<size_t, size_t> > k = compute_subcircuit_key_for_other (*sc, g2, &c22_circuit_and_pin_mapping, &circuit_pin_mapper, mapped, valid);
std::multimap<std::vector<std::pair<size_t, size_t> >, std::pair<const db::SubCircuit *, size_t> >::iterator scm = subcircuit_map.find (k);
if (! mapped || scm == subcircuit_map.end ()) {
if (! mapped || scm == subcircuit_map.end () || scm->first != k) {
if (mp_logger) {
unmatched_b.push_back (std::make_pair (k, sc.operator-> ()));

View File

@ -287,6 +287,26 @@ public:
return m_max_n_branch;
}
/**
* @brief Sets a value indicating depth-first traversal
*
* With depth first (the default), the algorithm looks for further identities before moving to another
* node. With breadth first (false), the algorithm will work in "waves" rather than digging deerly
* into the direction of a node.
*/
void set_depth_first (bool df)
{
m_depth_first = df;
}
/**
* @brief Gets a value indicating depth-first traversal
*/
bool depth_first () const
{
return m_depth_first;
}
/**
* @brief Gets the list of circuits without matching circuit in the other netlist
* The result can be used to flatten these circuits prior to compare.
@ -341,6 +361,7 @@ protected:
double m_res_threshold;
size_t m_max_n_branch;
size_t m_max_depth;
bool m_depth_first;
bool m_dont_consider_net_names;
};

View File

@ -1147,8 +1147,8 @@ TEST(5_BufferTwoPathsDifferentDeviceClasses)
"begin_circuit BUF BUF\n"
"match_nets INT $10\n"
"match_nets IN IN\n"
"net_mismatch OUT OUT\n"
"net_mismatch INT2 $11\n"
"net_mismatch OUT OUT\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
@ -1212,8 +1212,35 @@ TEST(6_BufferTwoPathsAdditionalResistor)
"begin_circuit BUF BUF\n"
"net_mismatch INT $10\n"
"match_nets IN IN\n"
"net_mismatch INT2 $11\n"
"match_nets OUT OUT\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
"match_pins $3 $2\n"
"match_devices $1 $1\n"
"match_devices $3 $2\n"
"match_devices $5 $3\n"
"match_devices $7 $4\n"
"match_devices $2 $5\n"
"match_devices $4 $6\n"
"match_devices $6 $7\n"
"match_devices $8 $8\n"
"device_mismatch (null) $9\n"
"end_circuit BUF BUF NOMATCH"
);
EXPECT_EQ (good, false);
comp.set_depth_first (false);
logger.clear ();
good = comp.compare (&nl1, &nl2);
EXPECT_EQ (logger.text (),
"begin_circuit BUF BUF\n"
"net_mismatch INT $10\n"
"match_nets OUT OUT\n"
"net_mismatch INT2 $11\n"
"match_nets IN IN\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
@ -1274,9 +1301,9 @@ TEST(6_BufferTwoPathsAdditionalDevices)
"match_nets INT $11\n"
"net_mismatch VDD VDD\n"
"match_nets IN IN\n"
"net_mismatch INT2 $10\n"
"net_mismatch VSS VSS\n"
"net_mismatch OUT OUT\n"
"net_mismatch INT2 $10\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
@ -2679,6 +2706,57 @@ TEST(17_InherentlyAmbiguousDecoder)
);
EXPECT_EQ (good, true);
comp.set_depth_first (false);
logger.clear ();
good = comp.compare (&nl1, &nl2);
EXPECT_EQ (logger.text (),
"begin_circuit NAND NAND\n"
"match_nets VSS VSS\n"
"match_nets INT INT\n"
"match_nets OUT OUT\n"
"match_nets VDD VDD\n"
"match_nets B B\n"
"match_nets A A\n"
"match_pins $0 $0\n"
"match_pins $1 $1\n"
"match_pins $2 $2\n"
"match_pins $3 $3\n"
"match_pins $4 $4\n"
"match_devices $1 $1\n"
"match_devices $2 $2\n"
"match_devices $3 $3\n"
"match_devices $4 $4\n"
"end_circuit NAND NAND MATCH\n"
"begin_circuit DECODER DECODER\n"
"match_nets VSS VSS\n"
"match_nets VDD VDD\n"
"match_nets NA NA\n"
"match_nets NB NB\n"
"match_nets B B\n"
"match_nets NQ1 NQ1\n"
"match_nets NQ3 NQ3\n"
"match_nets NQ2 NQ2\n"
"match_nets NQ0 NQ0\n"
"match_pins $0 $1\n"
"match_pins $1 $0\n"
"match_pins $2 $2\n"
"match_pins $3 $3\n"
"match_pins $4 $4\n"
"match_pins $5 $5\n"
"match_pins $6 $6\n"
"match_pins $7 $7\n"
"match_subcircuits $1 $1\n"
"match_subcircuits $2 $2\n"
"match_subcircuits $4 $3\n"
"match_subcircuits $6 $4\n"
"match_subcircuits $3 $5\n"
"match_subcircuits $5 $6\n"
"end_circuit DECODER DECODER MATCH"
);
EXPECT_EQ (good, true);
}
TEST(18_ClockTree)
@ -2794,6 +2872,67 @@ TEST(18_ClockTree)
"end_circuit TXEE TXEE MATCH"
);
EXPECT_EQ (good, true);
comp.set_depth_first (false);
logger.clear ();
good = comp.compare (&nl1, &nl2);
txt = logger.text ();
// because L/R matching is ambiguous, we need to do this to
// establish reproducability on different platforms:
txt = tl::replaced (txt, "L", "X");
txt = tl::replaced (txt, "R", "X");
EXPECT_EQ (txt,
"begin_circuit INV INV\n"
"match_nets VDD VDD\n"
"match_nets OUT OUT\n"
"match_nets IN IN\n"
"match_nets VSS VSS\n"
"match_pins IN IN\n"
"match_pins OUT OUT\n"
"match_pins VDD VDD\n"
"match_pins VSS VSS\n"
"match_devices $1 $1\n"
"match_devices $2 $2\n"
"end_circuit INV INV MATCH\n"
"begin_circuit TXEE TXEE\n"
"match_nets IN IN\n"
"match_nets VSS VSS\n"
"match_nets VDD VDD\n"
"match_nets S S\n"
"match_ambiguous_nets SX SX\n"
"match_ambiguous_nets SX SX\n"
"match_ambiguous_nets SXX SXX\n"
"match_ambiguous_nets SXX SXX\n"
"match_ambiguous_nets SXXX SXXX\n"
"match_ambiguous_nets SXXX SXXX\n"
"match_ambiguous_nets SXXX SXXX\n"
"match_ambiguous_nets SXXX SXXX\n"
"match_ambiguous_nets SXX SXX\n"
"match_ambiguous_nets SXX SXX\n"
"match_ambiguous_nets SXXX SXXX\n"
"match_ambiguous_nets SXXX SXXX\n"
"match_ambiguous_nets SXXX SXXX\n"
"match_ambiguous_nets SXXX SXXX\n"
"match_subcircuits TXXX TXXX\n"
"match_subcircuits TX TX\n"
"match_subcircuits TXXX TXXX\n"
"match_subcircuits TXXX TXXX\n"
"match_subcircuits TXX TXX\n"
"match_subcircuits TXX TXX\n"
"match_subcircuits TXXX TXXX\n"
"match_subcircuits TXXX TXXX\n"
"match_subcircuits TXXX TXXX\n"
"match_subcircuits T T\n"
"match_subcircuits TXXX TXXX\n"
"match_subcircuits TX TX\n"
"match_subcircuits TXX TXX\n"
"match_subcircuits TXXX TXXX\n"
"match_subcircuits TXX TXX\n"
"end_circuit TXEE TXEE MATCH"
);
EXPECT_EQ (good, true);
}
TEST(19_SymmetricCircuit)
@ -2924,8 +3063,8 @@ TEST(19_SymmetricCircuit)
"match_nets $14 WELL\n"
"match_nets nn2 NN2\n"
"match_nets nn2_ NN2_\n"
"match_nets q0 Q0\n"
"match_nets q1 Q1\n"
"match_ambiguous_nets q0 Q0\n"
"match_ambiguous_nets q1 Q1\n"
"match_nets $11 CS0\n"
"match_nets q0_ Q0_\n"
"match_nets $6 NET181\n"
@ -3002,6 +3141,105 @@ TEST(19_SymmetricCircuit)
"end_circuit DECODE DECODE MATCH"
);
EXPECT_EQ (good, true);
comp.set_depth_first (false);
logger.clear ();
good = comp.compare (&nl1, &nl2);
EXPECT_EQ (logger.text (),
"begin_circuit DECODE DECODE\n"
"match_nets $41 WL1_EN_\n"
"match_nets VDD VDD\n"
"match_nets $39 NET194\n"
"match_nets g0 G0\n"
"match_nets $40 HNET52\n"
"match_nets VSS VSS\n"
"match_nets $42 NET189\n"
"match_nets gtp NN3\n"
"match_nets $37 NET193\n"
"match_nets g1 G1\n"
"match_nets $44 YI\n"
"match_nets $14 WELL\n"
"match_nets nn2 NN2\n"
"match_nets nn2_ NN2_\n"
"match_ambiguous_nets q0 Q0\n"
"match_ambiguous_nets q1 Q1\n"
"match_nets $11 CS0\n"
"match_nets q0_ Q0_\n"
"match_nets $4 NET200\n"
"match_nets $13 CS1\n"
"match_nets q1_ Q1_\n"
"match_nets $9 NET175\n"
"match_nets a0 A0\n"
"match_nets a0_ A0_\n"
"match_nets $35 HNET44\n"
"match_nets $34 HNET48\n"
"match_nets $6 NET181\n"
"match_nets $8 NET215\n"
"match_nets nn1 NN1\n"
"match_nets nn1_ NN1_\n"
"match_pins VDD VDD\n"
"match_pins nn1_ NN1_\n"
"match_pins nn1 NN1\n"
"match_pins q0 Q0\n"
"match_pins q0_ Q0_\n"
"match_pins q1_ Q1_\n"
"match_pins q1 Q1\n"
"match_pins nn2 NN2\n"
"match_pins nn2_ NN2_\n"
"match_pins a0 A0\n"
"match_pins a0_ A0_\n"
"match_pins g1 G1\n"
"match_pins g0 G0\n"
"match_pins gtp NN3\n"
"match_pins VSS VSS\n"
"match_pins WELL WELL\n"
"match_devices $30 0\n"
"match_devices $29 1\n"
"match_devices $9 10\n"
"match_devices $10 11\n"
"match_devices $36 12\n"
"match_devices $35 13\n"
"match_devices $34 14\n"
"match_devices $38 15\n"
"match_devices $37 16\n"
"match_devices $33 17\n"
"match_devices $27 18\n"
"match_devices $28 19\n"
"match_devices $17 2\n"
"match_devices $31 20\n"
"match_devices $32 21\n"
"match_devices $22 22\n"
"match_devices $26 23\n"
"match_devices $23 24\n"
"match_devices $43 25\n"
"match_devices $20 26\n"
"match_devices $25 27\n"
"match_devices $15 28\n"
"match_devices $14 29\n"
"match_devices $16 3\n"
"match_devices $18 30\n"
"match_devices $21 31\n"
"match_devices $13 32\n"
"match_devices $19 33\n"
"match_devices $7 34\n"
"match_devices $8 35\n"
"match_devices $24 36\n"
"match_devices $3 37\n"
"match_devices $6 38\n"
"match_devices $4 39\n"
"match_devices $39 4\n"
"match_devices $5 40\n"
"match_devices $2 41\n"
"match_devices $1 42\n"
"match_devices $40 5\n"
"match_devices $11 6\n"
"match_devices $12 7\n"
"match_devices $41 8\n"
"match_devices $42 9\n"
"end_circuit DECODE DECODE MATCH"
);
EXPECT_EQ (good, true);
}
TEST(20_BusLikeConnections)
@ -3576,7 +3814,7 @@ TEST(23_NodesRemovedWithError)
"pin_mismatch (null) BULK\n"
"pin_mismatch (null) $6\n"
"match_subcircuits $1 $1\n"
"match_subcircuits $2 $2\n"
"subcircuit_mismatch $2 $2\n"
"end_circuit INV2PAIR INV2PAIR NOMATCH\n"
"circuit_skipped RINGO RINGO"
);

View File

@ -850,7 +850,7 @@ xref(
device(1 1 match)
)
)
circuit(ND2X1 ND2X1 match
circuit(ND2X1 ND2X1 nomatch
xref(
net(4 8 mismatch)
net(5 4 mismatch)
@ -867,10 +867,10 @@ xref(
pin(6 6 match)
pin(0 0 match)
pin(2 2 match)
device(3 3 match)
device(3 3 mismatch)
device(4 4 match)
device(1 1 match)
device(2 2 match)
device(1 1 mismatch)
)
)
circuit(RINGO RINGO match