diff --git a/Changelog b/Changelog
index 10bfc476b..25b2e9280 100644
--- a/Changelog
+++ b/Changelog
@@ -11,6 +11,11 @@
The algorithm was improved to provide better reproducibility. The
detection of matching paths in the presence of ambiguities was
improved.
+ In addition, the netlist compare now favours net names for resolving
+ ambiguities. So if nets are named the same in the layout and the
+ schematic, ambiguities are resolved based on these names. This is
+ usually more efficient. A new function is available to turn this
+ feature off: "consider_net_names(false)".
0.26.6 (2020-06-05):
diff --git a/Jenkinsfile b/Jenkinsfile
index 1b3f64cff..f0c65c2ee 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -14,6 +14,7 @@ node("master") {
stage("Checkout sources") {
checkout scm
+ checkout_private()
}
diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc
index ac592823d..c9103b7c7 100644
--- a/src/db/db/dbNetlistCompare.cc
+++ b/src/db/db/dbNetlistCompare.cc
@@ -616,7 +616,7 @@ class NetGraph;
struct CompareData
{
CompareData ()
- : other (0), max_depth (0), max_n_branch (0), depth_first (true), dont_consider_net_names (false), logger (0),
+ : other (0), max_depth (0), max_n_branch (0), depth_first (true), dont_consider_net_names (false), with_ambiguous (false), logger (0),
circuit_pin_mapper (0), subcircuit_equivalence (0), device_equivalence (0), progress (0)
{ }
@@ -625,6 +625,7 @@ struct CompareData
size_t max_n_branch;
bool depth_first;
bool dont_consider_net_names;
+ bool with_ambiguous;
NetlistCompareLogger *logger;
CircuitPinMapper *circuit_pin_mapper;
SubCircuitEquivalenceTracker *subcircuit_equivalence;
@@ -967,6 +968,9 @@ struct CompareNodePtr
};
class TentativeNodeMapping;
+struct NodeRange;
+class DeviceMapperForTargetNode;
+class SubCircuitMapperForTargetNode;
std::string indent (size_t depth)
{
@@ -1112,20 +1116,16 @@ public:
*
* If "tentative" is non-null, assignments will be recorded in the TentativeMapping
* audit object and can be undone afterwards when backtracking recursion happens.
- *
- * If "with_ambiguous" is true, ambiguous matches are considered. This will happen
- * in a second pass to give exact and unique matches priority over ambiguous matches.
*/
- size_t derive_node_identities (size_t net_index, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, bool with_ambiguous, CompareData *data);
+ size_t derive_node_identities (size_t net_index, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, CompareData *data);
/**
* @brief The backtracking driver
*
* This method will analyze the given nodes and call "derive_node_identities" for all nodes
- * with a proposed identity. With "with_ambiguous", amiguities are resolved by trying
- * different combinations in tentative mode and deciding for one combination if possible.
+ * with a proposed identity.
*/
- size_t derive_node_identities_from_node_set (std::vector > &nodes, std::vector > &other_nodes, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, bool with_ambiguous, CompareData *data);
+ size_t derive_node_identities_from_node_set (std::vector > &nodes, std::vector > &other_nodes, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, CompareData *data);
private:
std::vector m_nodes;
@@ -1133,7 +1133,9 @@ private:
std::map m_net_index;
const db::Circuit *mp_circuit;
- size_t 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 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, CompareData *data);
+ size_t derive_node_identities_from_ambiguity_group (const NodeRange &nr, DeviceMapperForTargetNode &dm, DeviceMapperForTargetNode &dm_other, SubCircuitMapperForTargetNode &scm, SubCircuitMapperForTargetNode &scm_other, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, CompareData *data);
+ size_t derive_node_identities_from_singular_match (const NetGraphNode *n, const NetGraphNode::edge_iterator &e, const NetGraphNode *n_other, const NetGraphNode::edge_iterator &e_other, DeviceMapperForTargetNode &dm, DeviceMapperForTargetNode &dm_other, SubCircuitMapperForTargetNode &scm, SubCircuitMapperForTargetNode &scm_other, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, CompareData *data, bool consider_net_names);
};
// --------------------------------------------------------------------------------------------------------------------
@@ -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)
+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, CompareData *data)
{
// NOTE: we can skip edges to known nodes because we did a pre-analysis making sure those are compatible
@@ -2029,7 +2031,7 @@ NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGr
// 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);
+ size_t bt_count = derive_node_identities_from_node_set (nodes, other_nodes, depth, n_branch, tentative, data);
if (bt_count == failed_match) {
if (tentative) {
@@ -2064,7 +2066,7 @@ static bool has_subcircuits (db::NetGraphNode::edge_iterator e, db::NetGraphNode
}
size_t
-NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, bool with_ambiguous, CompareData *data)
+NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, CompareData *data)
{
NetGraphNode *n = & node (net_index);
@@ -2221,7 +2223,7 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc
++ee_other;
}
- size_t bt_count = derive_node_identities_for_edges (e, ee, e_other, ee_other, net_index, other_net_index, depth, n_branch, tentative, with_ambiguous, data);
+ size_t bt_count = derive_node_identities_for_edges (e, ee, e_other, ee_other, net_index, other_net_index, depth, n_branch, tentative, data);
if (bt_count == failed_match) {
if (options ()->debug_netcompare) {
tl::info << indent(depth) << "=> rejected pair.";
@@ -2260,7 +2262,7 @@ namespace {
}
-static void sort_node_range_by_best_match (NodeRange &nr)
+static void sort_node_range_by_best_match (const NodeRange &nr)
{
std::stable_sort (nr.n1, nr.nn1, SortNodeByNet ());
std::stable_sort (nr.n2, nr.nn2, SortNodeByNet ());
@@ -2319,9 +2321,20 @@ static bool net_names_are_different (const db::Net *a, const db::Net *b)
}
}
-size_t
-NetGraph::derive_node_identities_from_node_set (std::vector > &nodes, std::vector > &other_nodes, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, bool with_ambiguous, CompareData *data)
+static bool net_names_are_equal (const db::Net *a, const db::Net *b)
{
+ if (! a || ! b || a->name ().empty () || b->name ().empty ()) {
+ return false;
+ } else {
+ return name_compare (a->name (), b->name ()) == 0;
+ }
+}
+
+size_t
+NetGraph::derive_node_identities_from_ambiguity_group (const NodeRange &nr, DeviceMapperForTargetNode &dm, DeviceMapperForTargetNode &dm_other, SubCircuitMapperForTargetNode &scm, SubCircuitMapperForTargetNode &scm_other, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, CompareData *data)
+{
+ tl::AbsoluteProgress progress (tl::to_string (tr ("Deriving match for ambiguous net group")));
+
std::string indent_s;
if (options ()->debug_netcompare) {
indent_s = indent (depth);
@@ -2329,6 +2342,294 @@ NetGraph::derive_node_identities_from_node_set (std::vector > pairs;
+ tl::equivalence_clusters equivalent_other_nodes;
+
+ sort_node_range_by_best_match (nr);
+
+ {
+
+ // marks the nodes from the ambiguity group as unknown so we don't revisit them (causing deep recursion)
+ TentativeNodeMapping tn2unknown;
+
+ // collect and mark the ambiguity combinations to consider
+ std::vector >::const_iterator> iters1, iters2;
+
+ for (std::vector >::const_iterator i1 = nr.n1; i1 != nr.nn1; ++i1) {
+ if (! i1->first->has_any_other ()) {
+ iters1.push_back (i1);
+ size_t ni = node_index_for_net (i1->first->net ());
+ TentativeNodeMapping::map_to_unknown (&tn2unknown, this, ni);
+ }
+ }
+
+ for (std::vector >::const_iterator i2 = nr.n2; i2 != nr.nn2; ++i2) {
+ if (! i2->first->has_any_other ()) {
+ iters2.push_back (i2);
+ size_t other_ni = data->other->node_index_for_net (i2->first->net ());
+ TentativeNodeMapping::map_to_unknown (&tn2unknown, data->other, other_ni);
+ }
+ }
+
+ for (std::vector >::const_iterator>::const_iterator ii1 = iters1.begin (); ii1 != iters1.end (); ++ii1) {
+
+ std::vector >::const_iterator i1 = *ii1;
+
+ bool any = false;
+ std::vector >::const_iterator>::iterator to_remove = iters2.end ();
+
+ for (std::vector >::const_iterator>::iterator ii2 = iters2.begin (); ii2 != iters2.end (); ++ii2) {
+
+ ++progress;
+
+ std::vector >::const_iterator i2 = *ii2;
+
+ // try this candidate in tentative mode
+ if (options ()->debug_netcompare) {
+ tl::info << indent_s << "trying in tentative mode: " << i1->first->net ()->expanded_name () << " vs. " << i2->first->net ()->expanded_name ();
+ }
+
+ if (! edges_are_compatible (*i1->second, *i2->second, *data->device_equivalence, *data->subcircuit_equivalence)) {
+ if (options ()->debug_netcompare) {
+ tl::info << indent_s << "=> rejected because edges are incompatible with already established device or subcircuit equivalences";
+ }
+ continue;
+ }
+
+ if (! data->dont_consider_net_names && net_names_are_equal (i1->first->net (), i2->first->net ())) {
+
+ if (options ()->debug_netcompare) {
+ tl::info << indent_s << "=> accepted for identical names";
+ }
+
+ // utilize net names to propose a match
+ new_nodes += 1;
+ pairs.push_back (std::make_pair (i1->first, i2->first));
+ to_remove = ii2;
+ any = true;
+ break;
+
+ } else {
+
+ size_t ni = node_index_for_net (i1->first->net ());
+ size_t other_ni = data->other->node_index_for_net (i2->first->net ());
+
+ TentativeNodeMapping tn;
+ TentativeNodeMapping::map_pair_from_unknown (&tn, this, ni, data->other, other_ni, dm, dm_other, *data->device_equivalence, scm, scm_other, *data->subcircuit_equivalence, depth);
+
+ size_t bt_count = derive_node_identities (ni, depth + 1, complexity * n_branch, &tn, data);
+
+ if (bt_count != failed_match) {
+
+ if (options ()->debug_netcompare) {
+ tl::info << indent_s << "match found";
+ }
+ // we have a match ...
+
+ if (any) {
+
+ // there is already a known pair, so we can mark *i2 and the previous *i2 as equivalent
+ // (makes them ambiguous)
+ equivalent_other_nodes.same (i2->first, pairs.back ().second);
+ // we know enough now ...
+ break;
+
+ } else {
+
+ // identified a new pair
+ new_nodes += bt_count + 1;
+ pairs.push_back (std::make_pair (i1->first, i2->first));
+ to_remove = ii2;
+ any = true;
+
+ // no ambiguity analysis in tentative mode - we can stop now
+ if (tentative) {
+ break;
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ if (to_remove != iters2.end ()) {
+ iters2.erase (to_remove);
+ }
+
+ if (! any && tentative) {
+ if (options ()->debug_netcompare) {
+ tl::info << indent_s << "mismatch.";
+ }
+ // a mismatch - stop here.
+ return failed_match;
+ }
+
+ }
+
+ }
+
+ if (! tentative) {
+
+ // issue the matching pairs
+
+ for (std::vector >::const_iterator p = pairs.begin (); p != pairs.end (); ++p) {
+
+ size_t ni = node_index_for_net (p->first->net ());
+ size_t other_ni = data->other->node_index_for_net (p->second->net ());
+
+ TentativeNodeMapping::map_pair (0, this, ni, data->other, other_ni, dm, dm_other, *data->device_equivalence, scm, scm_other, *data->subcircuit_equivalence, depth);
+
+ if (options ()->debug_netcompare) {
+ if (equivalent_other_nodes.has_attribute (p->second)) {
+ tl::info << indent_s << "deduced ambiguous match: " << p->first->net ()->expanded_name () << " vs. " << p->second->net ()->expanded_name ();
+ } else {
+ 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) {
+ data->logger->match_ambiguous_nets (p->first->net (), p->second->net ());
+ } else {
+ data->logger->match_nets (p->first->net (), p->second->net ());
+ }
+ }
+
+ ++*data->progress;
+
+ }
+
+ // And seek further from these pairs
+
+ for (std::vector >::const_iterator p = pairs.begin (); p != pairs.end (); ++p) {
+
+ size_t ni = node_index_for_net (p->first->net ());
+
+ size_t bt_count = derive_node_identities (ni, depth + 1, complexity * n_branch, tentative, data);
+ tl_assert (bt_count != failed_match);
+
+ }
+
+ } else {
+
+ for (std::vector >::const_iterator p = pairs.begin (); p != pairs.end (); ++p) {
+
+ size_t ni = node_index_for_net (p->first->net ());
+ size_t other_ni = data->other->node_index_for_net (p->second->net ());
+
+ TentativeNodeMapping::map_pair (tentative, this, ni, data->other, other_ni, dm, dm_other, *data->device_equivalence, scm, scm_other, *data->subcircuit_equivalence, depth);
+
+ }
+
+ }
+
+ return new_nodes;
+}
+
+size_t
+NetGraph::derive_node_identities_from_singular_match (const NetGraphNode *n, const NetGraphNode::edge_iterator &e, const NetGraphNode *n_other, const NetGraphNode::edge_iterator &e_other, DeviceMapperForTargetNode &dm, DeviceMapperForTargetNode &dm_other, SubCircuitMapperForTargetNode &scm, SubCircuitMapperForTargetNode &scm_other, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, CompareData *data, bool consider_net_names)
+{
+ std::string indent_s;
+ if (options ()->debug_netcompare) {
+ indent_s = indent (depth);
+ indent_s += "*" + tl::to_string (n_branch) + " ";
+ }
+
+ if (! edges_are_compatible (*e, *e_other, *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 (! n->has_any_other () && ! n_other->has_any_other ()) {
+
+ // in tentative mode, reject this choice if both nets are named and
+ // their names differ -> this favors net matching by name
+
+ if (tentative && consider_net_names && net_names_are_different (n->net (), n_other->net ())) {
+ if (options ()->debug_netcompare) {
+ tl::info << indent_s << "rejecting pair as names are not identical: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name ();
+ }
+ return failed_match;
+ }
+
+ // A single candiate: just take this one -> this may render
+ // inexact matches, but further propagates net pairing
+
+ size_t ni = node_index_for_net (n->net ());
+ size_t other_ni = data->other->node_index_for_net (n_other->net ());
+
+ TentativeNodeMapping::map_pair (tentative, this, ni, data->other, other_ni, dm, dm_other, *data->device_equivalence, scm, scm_other, *data->subcircuit_equivalence, depth);
+
+ if (options ()->debug_netcompare) {
+ tl::info << indent_s << "deduced match (singular): " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name ();
+ }
+ 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 (n->net (), n_other->net ());
+ } else {
+ data->logger->match_nets (n->net (), n_other->net ());
+ }
+ }
+ }
+
+ size_t new_nodes = 1;
+
+ if (data->depth_first || tentative) {
+ size_t bt_count = derive_node_identities (ni, depth + 1, n_branch, tentative, data);
+ if (bt_count == failed_match) {
+ if (tentative) {
+ return failed_match;
+ }
+ } else {
+ new_nodes += bt_count;
+ }
+ }
+
+ return new_nodes;
+
+ } else if (n->has_unknown_other ()) {
+
+ // accept any other net
+ return 0;
+
+ } else if (n->has_other ()) {
+
+ // this decision leads to a contradiction
+ if (data->other->node_index_for_net (n_other->net ()) != n->other_net_index ()) {
+ return failed_match;
+ } else {
+ return 0;
+ }
+
+ } else {
+
+ // mismatch of assignment state
+ return failed_match;
+
+ }
+}
+
+size_t
+NetGraph::derive_node_identities_from_node_set (std::vector > &nodes, std::vector > &other_nodes, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, CompareData *data)
+{
+ std::string indent_s;
+ if (options ()->debug_netcompare) {
+ indent_s = indent (depth);
+ indent_s += "*" + tl::to_string (n_branch) + " ";
+ }
if (depth > data->max_depth) {
if (options ()->debug_netcompare) {
@@ -2353,81 +2654,15 @@ NetGraph::derive_node_identities_from_node_set (std::vectordevice_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 (! n->has_any_other () && ! n_other->has_any_other ()) {
-
- // a single candiate: just take this one -> this may render
- // inexact matches, but further propagates net pairing
-
- size_t ni = node_index_for_net (n->net ());
- size_t other_ni = data->other->node_index_for_net (n_other->net ());
-
- TentativeNodeMapping::map_pair (tentative, this, ni, data->other, other_ni, dm, dm_other, *data->device_equivalence, scm, scm_other, *data->subcircuit_equivalence, depth);
-
- if (options ()->debug_netcompare) {
- tl::info << indent_s << "deduced match (singular): " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name ();
- }
- 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 ());
- }
- }
- }
-
- 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 (n->has_unknown_other ()) {
-
- // accept this solution as the pairing is possible
-
- } else if (n->has_other ()) {
-
- // this decision leads to a contradiction
- if (data->other->node_index_for_net (n_other->net ()) != n->other_net_index ()) {
- return failed_match;
- }
-
- } else {
-
- // mismatch of assignment state
- return failed_match;
-
- }
-
- return new_nodes;
+ return derive_node_identities_from_singular_match (nodes.front ().first, nodes.front ().second, other_nodes.front ().first, other_nodes.front ().second,
+ dm, dm_other, scm, scm_other, depth, n_branch, tentative, data, false /*don't consider net names*/);
}
// Determine the range of nodes with same identity
std::vector node_ranges;
+ size_t new_nodes = 0;
std::vector >::iterator n1 = nodes.begin ();
std::vector >::iterator n2 = other_nodes.begin ();
@@ -2469,13 +2704,13 @@ NetGraph::derive_node_identities_from_node_set (std::vectorwith_ambiguous) {
node_ranges.push_back (NodeRange (num, n1, nn1, n2, nn2));
}
// in tentative mode ambiguous nodes don't make a match without
// with_ambiguous
- if (num > 1 && tentative && ! with_ambiguous) {
+ if (num > 1 && tentative && ! data->with_ambiguous) {
return failed_match;
}
@@ -2484,7 +2719,7 @@ NetGraph::derive_node_identities_from_node_set (std::vectorwith_ambiguous) {
std::stable_sort (node_ranges.begin (), node_ranges.end ());
}
@@ -2523,79 +2758,13 @@ NetGraph::derive_node_identities_from_node_set (std::vectornum == 1) {
- 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
-
- if (tentative && ! data->dont_consider_net_names && net_names_are_different (nr->n1->first->net (), nr->n2->first->net ())) {
- if (options ()->debug_netcompare) {
- tl::info << indent_s << "rejecting pair as names are not identical: " << nr->n1->first->net ()->expanded_name () << " vs. " << nr->n2->first->net ()->expanded_name ();
- }
- return failed_match;
- }
-
- // A single candiate: just take this one -> this may render
- // inexact matches, but further propagates net pairing
-
- size_t ni = node_index_for_net (nr->n1->first->net ());
- size_t other_ni = data->other->node_index_for_net (nr->n2->first->net ());
-
- TentativeNodeMapping::map_pair (tentative, this, ni, data->other, other_ni, dm, dm_other, *data->device_equivalence, scm, scm_other, *data->subcircuit_equivalence, depth);
-
- 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 (! 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 ());
- }
- }
- }
-
- 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
-
- } else if (nr->n1->first->has_other ()) {
-
- // this decision leads to a contradiction
- if (data->other->node_index_for_net (nr->n2->first->net ()) != nr->n1->first->other_net_index ()) {
- return failed_match;
- }
-
- } else {
-
- // mismatch of assignment state
+ size_t n = derive_node_identities_from_singular_match (nr->n1->first, nr->n1->second, nr->n2->first, nr->n2->second, dm, dm_other, scm, scm_other, depth, n_branch, tentative, data, ! data->dont_consider_net_names);
+ if (n == failed_match) {
return failed_match;
-
}
+ new_nodes += n;
+
} else if (nr->num * n_branch > data->max_n_branch) {
if (options ()->debug_netcompare) {
@@ -2609,168 +2778,12 @@ NetGraph::derive_node_identities_from_node_set (std::vectornum << " members";
}
- // sort the ambiguity group such that net names match best
-
- std::vector > pairs;
- tl::equivalence_clusters equivalent_other_nodes;
- std::set seen;
-
- if (! data->dont_consider_net_names) {
- sort_node_range_by_best_match (*nr);
+ size_t n = derive_node_identities_from_ambiguity_group (*nr, dm, dm_other, scm, scm_other, depth, n_branch, tentative, data);
+ if (n == failed_match) {
+ return failed_match;
}
- {
-
- // marks the nodes from the ambiguity group as unknown so we don't revisit them (causing deep recursion)
- TentativeNodeMapping tn2unknown;
-
- // collect and mark the ambiguity combinations to consider
- std::vector >::const_iterator> iters1, iters2;
-
- for (std::vector >::const_iterator i1 = nr->n1; i1 != nr->nn1; ++i1) {
- if (! i1->first->has_any_other ()) {
- iters1.push_back (i1);
- size_t ni = node_index_for_net (i1->first->net ());
- TentativeNodeMapping::map_to_unknown (&tn2unknown, this, ni);
- }
- }
-
- for (std::vector >::const_iterator i2 = nr->n2; i2 != nr->nn2; ++i2) {
- if (! i2->first->has_any_other ()) {
- iters2.push_back (i2);
- size_t other_ni = data->other->node_index_for_net (i2->first->net ());
- TentativeNodeMapping::map_to_unknown (&tn2unknown, data->other, other_ni);
- }
- }
-
- for (std::vector >::const_iterator>::const_iterator ii1 = iters1.begin (); ii1 != iters1.end (); ++ii1) {
-
- std::vector >::const_iterator i1 = *ii1;
-
- bool any = false;
-
- for (std::vector >::const_iterator>::const_iterator ii2 = iters2.begin (); ii2 != iters2.end (); ++ii2) {
-
- std::vector >::const_iterator i2 = *ii2;
-
- if (seen.find (i2->first) != seen.end ()) {
- continue;
- }
-
- // try this candidate in tentative mode
- if (options ()->debug_netcompare) {
- tl::info << indent_s << "trying in tentative mode: " << i1->first->net ()->expanded_name () << " vs. " << i2->first->net ()->expanded_name ();
- }
-
- if (! edges_are_compatible (*i1->second, *i2->second, *data->device_equivalence, *data->subcircuit_equivalence)) {
- if (options ()->debug_netcompare) {
- tl::info << indent_s << "=> rejected because edges are incompatible with already established device or subcircuit equivalences";
- }
- continue;
- }
-
- size_t ni = node_index_for_net (i1->first->net ());
- size_t other_ni = data->other->node_index_for_net (i2->first->net ());
-
- TentativeNodeMapping tn;
- TentativeNodeMapping::map_pair_from_unknown (&tn, this, ni, data->other, other_ni, dm, dm_other, *data->device_equivalence, scm, scm_other, *data->subcircuit_equivalence, depth);
-
- size_t bt_count = derive_node_identities (ni, depth + 1, nr->num * n_branch, &tn, with_ambiguous, data);
-
- if (bt_count != failed_match) {
-
- if (options ()->debug_netcompare) {
- tl::info << indent_s << "match found";
- }
- // we have a match ...
-
- if (any) {
-
- // there is already a known pair, so we can mark *i2 and the previous *i2 as equivalent
- // (makes them ambiguous)
- equivalent_other_nodes.same (i2->first, pairs.back ().second);
-
- } else {
-
- // identified a new pair
- new_nodes += bt_count + 1;
- pairs.push_back (std::make_pair (i1->first, i2->first));
- seen.insert (i2->first);
- any = true;
-
- }
-
- }
-
- }
-
- if (! any && tentative) {
- if (options ()->debug_netcompare) {
- tl::info << indent_s << "mismatch.";
- }
- // a mismatch - stop here.
- return failed_match;
- }
-
- }
-
- }
-
- if (! tentative) {
-
- // issue the matching pairs
-
- for (std::vector >::const_iterator p = pairs.begin (); p != pairs.end (); ++p) {
-
- size_t ni = node_index_for_net (p->first->net ());
- size_t other_ni = data->other->node_index_for_net (p->second->net ());
-
- TentativeNodeMapping::map_pair (0, this, ni, data->other, other_ni, dm, dm_other, *data->device_equivalence, scm, scm_other, *data->subcircuit_equivalence, depth);
-
- if (options ()->debug_netcompare) {
- if (equivalent_other_nodes.has_attribute (p->second)) {
- tl::info << indent_s << "deduced ambiguous match: " << p->first->net ()->expanded_name () << " vs. " << p->second->net ()->expanded_name ();
- } else {
- 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) {
- data->logger->match_ambiguous_nets (p->first->net (), p->second->net ());
- } else {
- data->logger->match_nets (p->first->net (), p->second->net ());
- }
- }
-
- ++*data->progress;
-
- }
-
- // And seek further from these pairs
-
- for (std::vector >::const_iterator p = pairs.begin (); p != pairs.end (); ++p) {
-
- size_t ni = node_index_for_net (p->first->net ());
-
- size_t bt_count = derive_node_identities (ni, depth + 1, nr->num * n_branch, tentative, with_ambiguous, data);
- tl_assert (bt_count != failed_match);
-
- }
-
- } else {
-
- for (std::vector >::const_iterator p = pairs.begin (); p != pairs.end (); ++p) {
-
- size_t ni = node_index_for_net (p->first->net ());
- size_t other_ni = data->other->node_index_for_net (p->second->net ());
-
- TentativeNodeMapping::map_pair (tentative, this, ni, data->other, other_ni, dm, dm_other, *data->device_equivalence, scm, scm_other, *data->subcircuit_equivalence, depth);
-
- }
-
- }
+ new_nodes += n;
if (options ()->debug_netcompare) {
tl::info << indent_s << "finished analysis of ambiguity group with " << nr->num << " members";
@@ -3471,13 +3484,14 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
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.with_ambiguous = (pass > 0);
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);
+ size_t ni = g1.derive_node_identities (i1 - g1.begin (), 0, 1, 0 /*not tentative*/, &data);
if (ni > 0 && ni != failed_match) {
new_identities += ni;
if (options ()->debug_netcompare) {
@@ -3537,13 +3551,14 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
data.max_depth = m_max_depth;
data.max_n_branch = m_max_n_branch;
data.dont_consider_net_names = m_dont_consider_net_names;
+ data.with_ambiguous = (pass > 0);
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_from_node_set (nodes, other_nodes, 0, 1, 0 /*not tentatively*/, pass > 0 /*with ambiguities*/, &data);
+ size_t ni = g1.derive_node_identities_from_node_set (nodes, other_nodes, 0, 1, 0 /*not tentatively*/, &data);
if (ni > 0 && ni != failed_match) {
new_identities += ni;
if (options ()->debug_netcompare) {
diff --git a/src/db/db/gsiDeclDbNetlistCompare.cc b/src/db/db/gsiDeclDbNetlistCompare.cc
index df91db260..46c1b8725 100644
--- a/src/db/db/gsiDeclDbNetlistCompare.cc
+++ b/src/db/db/gsiDeclDbNetlistCompare.cc
@@ -538,6 +538,18 @@ Class decl_dbNetlistComparer ("db", "NetlistComparer",
"@brief Gets the maximum branch complexity\n"
"See \\max_branch_complexity= for details."
) +
+ gsi::method ("dont_consider_net_names=", &db::NetlistComparer::set_dont_consider_net_names, gsi::arg ("f"),
+ "@brief Sets a value indicating whether net names shall not be considered\n"
+ "If this value is set to true, net names will not be considered when resolving ambiguities.\n"
+ "Not considering net names usually is more expensive. The default is 'false' indicating that\n"
+ "net names will be considered for ambiguity resolution.\n"
+ "\n"
+ "This property has been introduced in version 0.26.7.\n"
+ ) +
+ gsi::method ("dont_consider_net_names", &db::NetlistComparer::dont_consider_net_names,
+ "@brief Gets a value indicating whether net names shall not be considered\n"
+ "See \\dont_consider_net_names= for details."
+ ) +
gsi::method_ext ("unmatched_circuits_a", &unmatched_circuits_a, gsi::arg ("a"), gsi::arg ("b"),
"@brief Returns a list of circuits in A for which there is not corresponding circuit in B\n"
"This list can be used to flatten these circuits so they do not participate in the compare process.\n"
diff --git a/src/db/unit_tests/dbNetlistCompareTests.cc b/src/db/unit_tests/dbNetlistCompareTests.cc
index 718d85ffd..f967da605 100644
--- a/src/db/unit_tests/dbNetlistCompareTests.cc
+++ b/src/db/unit_tests/dbNetlistCompareTests.cc
@@ -449,6 +449,7 @@ TEST(1_SimpleInverter)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@@ -470,6 +471,7 @@ TEST(1_SimpleInverter)
db::NetlistCrossReference xref;
db::NetlistComparer comp_xref (&xref);
+ comp.set_dont_consider_net_names (true);
good = comp_xref.compare (&nl1, &nl2);
@@ -519,6 +521,7 @@ TEST(1_SimpleInverterMatchedDeviceClasses)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
comp.same_device_classes (nl1.device_class_by_name ("PMOS"), nl2.device_class_by_name ("PMOSB"));
bool good = comp.compare (&nl1, &nl2);
@@ -571,6 +574,7 @@ TEST(1_SimpleInverterSkippedDevices)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@@ -594,6 +598,7 @@ TEST(1_SimpleInverterSkippedDevices)
db::NetlistCrossReference xref;
db::NetlistComparer comp_xref (&xref);
+ comp.set_dont_consider_net_names (true);
good = comp_xref.compare (&nl1, &nl2);
@@ -751,6 +756,8 @@ TEST(2_SimpleInverterWithForcedNetAssignment)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
+
const db::Circuit *ca = nl1.circuit_by_name ("INV");
const db::Circuit *cb = nl2.circuit_by_name ("INV");
comp.same_nets (ca->net_by_name ("VDD"), cb->net_by_name ("VDD"));
@@ -797,6 +804,7 @@ TEST(3_Buffer)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@@ -852,6 +860,7 @@ TEST(4_BufferTwoPaths)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@@ -912,6 +921,7 @@ TEST(5_BufferTwoPathsDifferentParameters)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
// Forcing the power nets into equality makes the parameter error harder to detect
const db::Circuit *ca = nl1.circuit_by_name ("BUF");
@@ -1134,6 +1144,7 @@ TEST(5_BufferTwoPathsDifferentDeviceClasses)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
// NOTE: adding this power hint makes the device class error harder to detect
const db::Circuit *ca = nl1.circuit_by_name ("BUF");
@@ -1199,6 +1210,7 @@ TEST(6_BufferTwoPathsAdditionalResistor)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
// Forcing the power nets into equality makes the resistor error harder to detect
const db::Circuit *ca = nl1.circuit_by_name ("BUF");
@@ -1293,6 +1305,7 @@ TEST(6_BufferTwoPathsAdditionalDevices)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@@ -1345,6 +1358,7 @@ TEST(7_Resistors)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@@ -1386,6 +1400,7 @@ TEST(7_ResistorsParameterMismatch)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@@ -1428,6 +1443,7 @@ TEST(7_ResistorsPlusOneDevice)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@@ -1470,6 +1486,7 @@ TEST(8_Diodes)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@@ -1511,6 +1528,7 @@ TEST(8_DiodesDontMatchOnSwappedPins)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@@ -1558,6 +1576,7 @@ TEST(10_SimpleSubCircuits)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@@ -1620,6 +1639,7 @@ TEST(10_SimpleSubCircuitsMatchedNames)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
EXPECT_EQ (good, false);
@@ -1788,22 +1808,22 @@ TEST(11_MismatchingSubcircuits)
// nets are now ambiguous
EXPECT_EQ (xref2s (xref),
"TOP:TOP [Match]:\n"
- " pin $0:$0 [Match]\n"
- " pin $1:$1 [Match]\n"
- " pin $2:$2 [Match]\n"
+ " pin $0:$2 [Match]\n"
+ " pin $1:$0 [Match]\n"
+ " pin $2:$1 [Match]\n"
" pin $3:$3 [Match]\n"
- " net IN:OUT [MatchWithWarning]\n"
- " pin $0:$0\n"
- " subcircuit_pin (null):$1[$3]\n"
+ " net IN:IN [MatchWithWarning]\n"
+ " pin $0:$2\n"
+ " subcircuit_pin (null):$2[$1]\n"
" subcircuit_pin $1[$0]:(null)\n"
- " net OUT:VDD [MatchWithWarning]\n"
- " pin $1:$1\n"
+ " net OUT:OUT [MatchWithWarning]\n"
+ " pin $1:$0\n"
+ " subcircuit_pin (null):$1[$3]\n"
+ " subcircuit_pin $2[$1]:(null)\n"
+ " net VDD:VDD [MatchWithWarning]\n"
+ " pin $2:$1\n"
" subcircuit_pin (null):$1[$0]\n"
" subcircuit_pin (null):$2[$0]\n"
- " subcircuit_pin $2[$1]:(null)\n"
- " net VDD:IN [MatchWithWarning]\n"
- " pin $2:$2\n"
- " subcircuit_pin (null):$2[$1]\n"
" subcircuit_pin $1[$2]:(null)\n"
" subcircuit_pin $2[$2]:(null)\n"
" net VSS:VSS [MatchWithWarning]\n"
@@ -1845,6 +1865,7 @@ TEST(12_MismatchingSubcircuitsDuplicates)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@@ -1912,6 +1933,7 @@ TEST(13_MismatchingSubcircuitsAdditionalHierarchy)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@@ -1979,6 +2001,7 @@ TEST(14_Subcircuit2Nand)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
comp.equivalent_pins (nl2.circuit_by_name ("NAND"), 0, 1);
bool good = comp.compare (&nl1, &nl2);
@@ -2053,6 +2076,7 @@ TEST(14_Subcircuit2NandMismatchNoSwap)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
// intentionally missing: comp.equivalent_pins (nl2.circuit_by_name ("NAND"), 0, 1);
bool good = comp.compare (&nl1, &nl2);
@@ -2204,6 +2228,7 @@ TEST(14_Subcircuit2MatchWithSwap)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
comp.equivalent_pins (nl2.circuit_by_name ("NAND"), 0, 1);
bool good = comp.compare (&nl1, &nl2);
@@ -2283,6 +2308,7 @@ TEST(15_EmptySubCircuitTest)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@@ -2358,6 +2384,7 @@ TEST(15_EmptySubCircuitWithoutPinNames)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@@ -2440,6 +2467,7 @@ TEST(16_UniqueSubCircuitMatching)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@@ -2813,6 +2841,7 @@ TEST(18_ClockTree)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (false);
bool good = comp.compare (&nl1, &nl2);
@@ -2822,6 +2851,68 @@ TEST(18_ClockTree)
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_nets SX SX\n"
+ "match_nets SX SX\n"
+ "match_nets SXX SXX\n"
+ "match_nets SXX SXX\n"
+ "match_nets SXXX SXXX\n"
+ "match_nets SXXX SXXX\n"
+ "match_nets SXXX SXXX\n"
+ "match_nets SXXX SXXX\n"
+ "match_nets SXX SXX\n"
+ "match_nets SXX SXX\n"
+ "match_nets SXXX SXXX\n"
+ "match_nets SXXX SXXX\n"
+ "match_nets SXXX SXXX\n"
+ "match_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);
+
+ logger.clear ();
+
+ comp.set_dont_consider_net_names (true);
+ 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"
@@ -3042,6 +3133,7 @@ TEST(19_SymmetricCircuit)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@@ -3061,8 +3153,8 @@ TEST(19_SymmetricCircuit)
"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 nn2 NN2\n"
+ "match_ambiguous_nets nn2_ NN2_\n"
"match_ambiguous_nets q0 Q0\n"
"match_ambiguous_nets q1 Q1\n"
"match_nets $11 CS0\n"
@@ -3160,8 +3252,8 @@ TEST(19_SymmetricCircuit)
"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 nn2 NN2\n"
+ "match_ambiguous_nets nn2_ NN2_\n"
"match_ambiguous_nets q0 Q0\n"
"match_ambiguous_nets q1 Q1\n"
"match_nets $11 CS0\n"
@@ -3298,6 +3390,7 @@ TEST(20_BusLikeConnections)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@@ -3442,6 +3535,153 @@ TEST(20_BusLikeConnections)
"end_circuit TOP TOP MATCH"
);
EXPECT_EQ (good, true);
+
+ logger.clear ();
+
+ comp.set_dont_consider_net_names (false);
+ good = comp.compare (&nl1, &nl2);
+
+ txt = logger.text ();
+
+ 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 INV8 INV8\n"
+ "match_nets VSS VSS\n"
+ "match_nets VDD VDD\n"
+ "match_ambiguous_nets IN1 A1\n"
+ "match_ambiguous_nets IN2 A2\n"
+ "match_ambiguous_nets IN3 A3\n"
+ "match_ambiguous_nets IN4 A4\n"
+ "match_ambiguous_nets IN5 A5\n"
+ "match_ambiguous_nets IN6 A6\n"
+ "match_ambiguous_nets IN7 A7\n"
+ "match_ambiguous_nets IN8 A8\n"
+ "match_nets OUT1 Q1\n"
+ "match_nets OUT2 Q2\n"
+ "match_nets OUT3 Q3\n"
+ "match_nets OUT4 Q4\n"
+ "match_nets OUT5 Q5\n"
+ "match_nets OUT6 Q6\n"
+ "match_nets OUT7 Q7\n"
+ "match_nets OUT8 Q8\n"
+ "match_pins IN1 A1\n"
+ "match_pins OUT1 Q1\n"
+ "match_pins IN2 A2\n"
+ "match_pins OUT2 Q2\n"
+ "match_pins IN3 A3\n"
+ "match_pins OUT3 Q3\n"
+ "match_pins IN4 A4\n"
+ "match_pins OUT4 Q4\n"
+ "match_pins IN5 A5\n"
+ "match_pins OUT5 Q5\n"
+ "match_pins IN6 A6\n"
+ "match_pins OUT6 Q6\n"
+ "match_pins IN7 A7\n"
+ "match_pins OUT7 Q7\n"
+ "match_pins IN8 A8\n"
+ "match_pins OUT8 Q8\n"
+ "match_pins VDD VDD\n"
+ "match_pins VSS VSS\n"
+ "match_subcircuits I1 I1\n"
+ "match_subcircuits I8 I8\n"
+ "match_subcircuits I3 I3\n"
+ "match_subcircuits I7 I7\n"
+ "match_subcircuits I4 I4\n"
+ "match_subcircuits I2 I2\n"
+ "match_subcircuits I6 I6\n"
+ "match_subcircuits I5 I5\n"
+ "end_circuit INV8 INV8 MATCH\n"
+ "begin_circuit INV8_WRAP INV8_WRAP\n"
+ "match_nets VSS VSS\n"
+ "match_nets VDD VDD\n"
+ "match_nets IN8 A8\n"
+ "match_nets OUT8 Q8\n"
+ "match_nets IN7 A7\n"
+ "match_nets OUT7 Q7\n"
+ "match_nets IN6 A6\n"
+ "match_nets OUT6 Q6\n"
+ "match_nets IN5 A5\n"
+ "match_nets OUT5 Q5\n"
+ "match_nets IN4 A4\n"
+ "match_nets OUT4 Q4\n"
+ "match_nets IN3 A3\n"
+ "match_nets OUT3 Q3\n"
+ "match_nets IN2 A2\n"
+ "match_nets OUT2 Q2\n"
+ "match_nets IN1 A1\n"
+ "match_nets OUT1 Q1\n"
+ "match_pins IN1 A1\n"
+ "match_pins OUT1 Q1\n"
+ "match_pins IN2 A2\n"
+ "match_pins OUT2 Q2\n"
+ "match_pins IN3 A3\n"
+ "match_pins OUT3 Q3\n"
+ "match_pins IN4 A4\n"
+ "match_pins OUT4 Q4\n"
+ "match_pins IN5 A5\n"
+ "match_pins OUT5 Q5\n"
+ "match_pins IN6 A6\n"
+ "match_pins OUT6 Q6\n"
+ "match_pins IN7 A7\n"
+ "match_pins OUT7 Q7\n"
+ "match_pins IN8 A8\n"
+ "match_pins OUT8 Q8\n"
+ "match_pins VDD VDD\n"
+ "match_pins VSS VSS\n"
+ "match_subcircuits INV8 INV8\n"
+ "end_circuit INV8_WRAP INV8_WRAP MATCH\n"
+ "begin_circuit TOP TOP\n"
+ "match_nets VSS VSS\n"
+ "match_nets VDD VDD\n"
+ "match_nets IN8 A8\n"
+ "match_nets OUT8 Q8\n"
+ "match_nets IN7 A7\n"
+ "match_nets OUT7 Q7\n"
+ "match_nets IN6 A6\n"
+ "match_nets OUT6 Q6\n"
+ "match_nets IN5 A5\n"
+ "match_nets OUT5 Q5\n"
+ "match_nets IN4 A4\n"
+ "match_nets OUT4 Q4\n"
+ "match_nets IN3 A3\n"
+ "match_nets OUT3 Q3\n"
+ "match_nets IN2 A2\n"
+ "match_nets OUT2 Q2\n"
+ "match_nets IN1 A1\n"
+ "match_nets OUT1 Q1\n"
+ "match_pins IN1 A1\n"
+ "match_pins OUT1 Q1\n"
+ "match_pins IN2 A2\n"
+ "match_pins OUT2 Q2\n"
+ "match_pins IN3 A3\n"
+ "match_pins OUT3 Q3\n"
+ "match_pins IN4 A4\n"
+ "match_pins OUT4 Q4\n"
+ "match_pins IN5 A5\n"
+ "match_pins OUT5 Q5\n"
+ "match_pins IN6 A6\n"
+ "match_pins OUT6 Q6\n"
+ "match_pins IN7 A7\n"
+ "match_pins OUT7 Q7\n"
+ "match_pins IN8 A8\n"
+ "match_pins OUT8 Q8\n"
+ "match_pins VDD VDD\n"
+ "match_pins VSS VSS\n"
+ "match_subcircuits INV8 INV8\n"
+ "end_circuit TOP TOP MATCH"
+ );
+ EXPECT_EQ (good, true);
}
TEST(21_BusLikeAmbiguousConnections)
@@ -3478,6 +3718,7 @@ TEST(21_BusLikeAmbiguousConnections)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@@ -3650,6 +3891,7 @@ TEST(22_NodesRemoved)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@@ -3770,6 +4012,7 @@ TEST(23_NodesRemovedWithError)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@@ -3869,6 +4112,7 @@ TEST(24_NodesRemovedButConnectedInOther)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
+ comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@@ -3960,6 +4204,7 @@ TEST(25_JoinSymmetricNets)
db::NetlistComparer comp;
comp.join_symmetric_nets (nl.circuit_by_name ("NAND2"));
+ comp.set_dont_consider_net_names (true);
// NOTE $1 and $2 are joined because they are symmetric
EXPECT_EQ (nl.to_string (),
@@ -3998,6 +4243,7 @@ TEST(25b_JoinSymmetricNetsMultiple)
db::NetlistComparer comp;
comp.join_symmetric_nets (nl.circuit_by_name ("NAND3"));
+ comp.set_dont_consider_net_names (true);
nl.combine_devices ();
@@ -4037,6 +4283,7 @@ TEST(25c_JoinSymmetricNetsMultipleMessedUp)
db::NetlistComparer comp;
comp.join_symmetric_nets (nl.circuit_by_name ("NOR3"));
+ comp.set_dont_consider_net_names (true);
nl.combine_devices ();
@@ -4076,6 +4323,7 @@ TEST(26_JoinSymmetricNets)
db::NetlistComparer comp;
comp.join_symmetric_nets (nl.circuit_by_name ("RESCUBE"));
+ comp.set_dont_consider_net_names (true);
EXPECT_EQ (nl.to_string (),
"circuit RESCUBE (A=A,B=B);\n"
@@ -4120,6 +4368,7 @@ TEST(27_DontJoinSymmetricNetsWithPins)
db::NetlistComparer comp;
comp.join_symmetric_nets (nl.circuit_by_name ("NAND2"));
+ comp.set_dont_consider_net_names (true);
// NOTE $1 and $2 are NOT joined because they have pins
EXPECT_EQ (nl.to_string (),
@@ -4152,6 +4401,8 @@ TEST(28_NoSymmetryDetectionCases)
prep_nl (nl, nls);
db::NetlistComparer comp;
+ comp.set_dont_consider_net_names (true);
+
std::string sref = nl.to_string ();
comp.join_symmetric_nets (nl.circuit_by_name ("NAND2"));
@@ -4174,6 +4425,8 @@ TEST(28_NoSymmetryDetectionCases)
prep_nl (nl, nls);
db::NetlistComparer comp;
+ comp.set_dont_consider_net_names (true);
+
std::string sref = nl.to_string ();
comp.join_symmetric_nets (nl.circuit_by_name ("NAND2"));
@@ -4203,6 +4456,7 @@ TEST(28_JoinSymmetricNets)
prep_nl (nl, nls);
db::NetlistComparer comp;
+ comp.set_dont_consider_net_names (true);
comp.join_symmetric_nets (nl.circuit_by_name ("INV2LOAD"));
// NOTE $1 and $2 are joined because they are symmetric
diff --git a/src/lay/lay/doc/about/lvs_ref_global.xml b/src/lay/lay/doc/about/lvs_ref_global.xml
index c1afc715e..f854e06e6 100644
--- a/src/lay/lay/doc/about/lvs_ref_global.xml
+++ b/src/lay/lay/doc/about/lvs_ref_global.xml
@@ -37,6 +37,15 @@ See Netter#align for a description
See Netter#compare for a description of that function.
+"consider_net_names" - Indicates whether the netlist comparer shall use net names
+
+Usage:
+
+
+See Netter#consider_net_names for a description of that function.
+
"equivalent_pins" - Marks pins as equivalent
Usage:
diff --git a/src/lay/lay/doc/about/lvs_ref_netter.xml b/src/lay/lay/doc/about/lvs_ref_netter.xml
index 1d39215a6..e73991d46 100644
--- a/src/lay/lay/doc/about/lvs_ref_netter.xml
+++ b/src/lay/lay/doc/about/lvs_ref_netter.xml
@@ -85,6 +85,18 @@ corresponding circuits: the unpaired circuit will be flattened then.
This method will return true, if the netlists are equivalent and false
otherwise.
+"consider_net_names" - Indicates whether the netlist comparer shall use net names
+
+Usage:
+
+
+If this value is set to true (the default), the netlist comparer
+will employ net names to resolve ambiguities. If set to false,
+ambiguities will be resolved based on the topology alone. Topology
+resolution is more expensive.
+
"equivalent_pins" - Marks pins as equivalent
Usage:
diff --git a/src/lvs/lvs/built-in-macros/_lvs_engine.rb b/src/lvs/lvs/built-in-macros/_lvs_engine.rb
index e1179f3a7..f53bfcc72 100644
--- a/src/lvs/lvs/built-in-macros/_lvs_engine.rb
+++ b/src/lvs/lvs/built-in-macros/_lvs_engine.rb
@@ -155,6 +155,12 @@ module LVS
# @synopsis max_depth(n)
# See \Netter#max_depth for a description of that function.
+ # %LVS%
+ # @name consider_net_names
+ # @brief Indicates whether the netlist comparer shall use net names
+ # @synopsis consider_net_names(f)
+ # See \Netter#consider_net_names for a description of that function.
+
# %LVS%
# @name tolerance
# @brief Specifies compare tolerances for certain device parameters
@@ -162,7 +168,7 @@ module LVS
# @synopsis tolerance(device_class_name, parameter_name [, :absolute => absolute_tolerance] [, :relative => relative_tolerance])
# See \Netter#tolerance for a description of that function.
- %w(schematic compare join_symmetric_nets tolerance align same_nets same_circuits same_device_classes equivalent_pins min_caps max_res max_depth max_branch_complexity).each do |f|
+ %w(schematic compare join_symmetric_nets tolerance align same_nets same_circuits same_device_classes equivalent_pins min_caps max_res max_depth max_branch_complexity consider_net_names).each do |f|
eval <<"CODE"
def #{f}(*args)
_netter.#{f}(*args)
diff --git a/src/lvs/lvs/built-in-macros/_lvs_netter.rb b/src/lvs/lvs/built-in-macros/_lvs_netter.rb
index 28d2ae487..2f4219f69 100644
--- a/src/lvs/lvs/built-in-macros/_lvs_netter.rb
+++ b/src/lvs/lvs/built-in-macros/_lvs_netter.rb
@@ -631,6 +631,20 @@ module LVS
@comparer_config << lambda { |comparer| comparer.max_branch_complexity = v }
end
+ # %LVS%
+ # @name consider_net_names
+ # @brief Indicates whether the netlist comparer shall use net names
+ # @synopsis consider_net_names(f)
+ # If this value is set to true (the default), the netlist comparer
+ # will employ net names to resolve ambiguities. If set to false,
+ # ambiguities will be resolved based on the topology alone. Topology
+ # resolution is more expensive.
+
+ def consider_net_names(value)
+ v = ! value
+ @comparer_config << lambda { |comparer| comparer.dont_consider_net_names = v }
+ end
+
end
end
diff --git a/testdata/lvs/double_height.lvsdb b/testdata/lvs/double_height.lvsdb
index 0d2517e42..7a1634dd0 100644
--- a/testdata/lvs/double_height.lvsdb
+++ b/testdata/lvs/double_height.lvsdb
@@ -295,8 +295,8 @@ Z(
Z(
N(2 3 1)
N(3 5 1)
- N(4 4 W)
- N(5 6 W)
+ N(4 4 1)
+ N(5 6 1)
N(1 1 1)
N(6 2 1)
P(1 2 1)
diff --git a/testdata/lvs/double_height2.lvs b/testdata/lvs/double_height2.lvs
index 23edbf991..cac92ec75 100644
--- a/testdata/lvs/double_height2.lvs
+++ b/testdata/lvs/double_height2.lvs
@@ -131,5 +131,7 @@ connect_implicit("DOESNOTEXIST", "DOESNOTEXIST")
netlist.simplify
align
+consider_net_names(false)
+
compare
diff --git a/testdata/lvs/floating.lvs b/testdata/lvs/floating.lvs
index 2bdc842f1..8a3c6417e 100644
--- a/testdata/lvs/floating.lvs
+++ b/testdata/lvs/floating.lvs
@@ -71,5 +71,7 @@ connect_global(ptie, "SUBSTRATE")
netlist.simplify
align
+consider_net_names(false)
+
compare
diff --git a/testdata/lvs/invchain_cheat.lvs b/testdata/lvs/invchain_cheat.lvs
index d0fd20237..93c6206e7 100644
--- a/testdata/lvs/invchain_cheat.lvs
+++ b/testdata/lvs/invchain_cheat.lvs
@@ -126,5 +126,7 @@ connect_global(bulk, "SUBSTRATE")
netlist.simplify
align
+consider_net_names(false)
+
compare
diff --git a/testdata/lvs/ringo_simple_blackboxing.lvs b/testdata/lvs/ringo_simple_blackboxing.lvs
index 475262be3..2fe02fd83 100644
--- a/testdata/lvs/ringo_simple_blackboxing.lvs
+++ b/testdata/lvs/ringo_simple_blackboxing.lvs
@@ -83,5 +83,7 @@ netlist.purge
netlist.combine_devices
netlist.purge_nets
+consider_net_names(false)
+
compare