Netlist compare: Ambiguity resolution through name matching now default (can be turned off) (#594)

* WIP: some refactoring

* WIP: some refactoring

* Netlist compare: introducing ambiguity resolution by net names

By default now net names are used for resolving ambiguities.
If net names match, they will be used to associate nets if the
choice is ambiguous. This is usually much faster and more reliable
than trying to resolve ambiguities through topology analysis.

This feature can be disabled using "consider_net_names(false)" in
the LVS script.

* Some refactoring, Jenkinsfile modified for better test coverage
This commit is contained in:
Matthias Köfferlein 2020-06-29 20:47:57 +02:00 committed by GitHub
parent e744eb32d1
commit b413cb9d74
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 672 additions and 339 deletions

1
Jenkinsfile vendored
View File

@ -16,6 +16,7 @@ node("master") {
stage("Checkout sources") {
checkout scm
checkout_private()
}

View File

@ -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<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> > &nodes, std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> > &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<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> > &nodes, std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> > &other_nodes, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, CompareData *data);
private:
std::vector<NetGraphNode> m_nodes;
@ -1133,7 +1133,9 @@ private:
std::map<const db::Net *, size_t> 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<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> > &nodes, std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> > &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<std::pair<const NetG
}
size_t new_nodes = 0;
size_t complexity = nr.num;
// sort the ambiguity group such that net names match best
std::vector<std::pair<const NetGraphNode *, const NetGraphNode *> > pairs;
tl::equivalence_clusters<const NetGraphNode *> 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<std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::const_iterator> iters1, iters2;
for (std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::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<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::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<std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::const_iterator>::const_iterator ii1 = iters1.begin (); ii1 != iters1.end (); ++ii1) {
std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::const_iterator i1 = *ii1;
bool any = false;
std::vector<std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::const_iterator>::iterator to_remove = iters2.end ();
for (std::vector<std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::const_iterator>::iterator ii2 = iters2.begin (); ii2 != iters2.end (); ++ii2) {
++progress;
std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::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<std::pair<const NetGraphNode *, const NetGraphNode *> >::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<std::pair<const NetGraphNode *, const NetGraphNode *> >::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<std::pair<const NetGraphNode *, const NetGraphNode *> >::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<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> > &nodes, std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> > &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::vector<std::pair<const NetG
if (nodes.size () == 1 && other_nodes.size () == 1) {
const NetGraphNode *n = nodes.front ().first;
const NetGraphNode *n_other = other_nodes.front ().first;
// reject the transition if the edges provide a contradiction to already established equivalences
if (! edges_are_compatible (*nodes.front ().second, *other_nodes.front ().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 (! 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<NodeRange> node_ranges;
size_t new_nodes = 0;
std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::iterator n1 = nodes.begin ();
std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::iterator n2 = other_nodes.begin ();
@ -2469,13 +2704,13 @@ NetGraph::derive_node_identities_from_node_set (std::vector<std::pair<const NetG
}
}
if (num == 1 || with_ambiguous) {
if (num == 1 || data->with_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::vector<std::pair<const NetG
}
if (with_ambiguous) {
if (data->with_ambiguous) {
std::stable_sort (node_ranges.begin (), node_ranges.end ());
}
@ -2523,79 +2758,13 @@ NetGraph::derive_node_identities_from_node_set (std::vector<std::pair<const NetG
} else if (nr->num == 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::vector<std::pair<const NetG
tl::info << indent_s << "analyzing ambiguity group with " << nr->num << " members";
}
// sort the ambiguity group such that net names match best
std::vector<std::pair<const NetGraphNode *, const NetGraphNode *> > pairs;
tl::equivalence_clusters<const NetGraphNode *> equivalent_other_nodes;
std::set<const NetGraphNode *> 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<std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::const_iterator> iters1, iters2;
for (std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::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<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::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<std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::const_iterator>::const_iterator ii1 = iters1.begin (); ii1 != iters1.end (); ++ii1) {
std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::const_iterator i1 = *ii1;
bool any = false;
for (std::vector<std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::const_iterator>::const_iterator ii2 = iters2.begin (); ii2 != iters2.end (); ++ii2) {
std::vector<std::pair<const NetGraphNode *, NetGraphNode::edge_iterator> >::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<std::pair<const NetGraphNode *, const NetGraphNode *> >::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<std::pair<const NetGraphNode *, const NetGraphNode *> >::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<std::pair<const NetGraphNode *, const NetGraphNode *> >::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) {

View File

@ -538,6 +538,18 @@ Class<db::NetlistComparer> 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"

View File

@ -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"
@ -3103,6 +3194,7 @@ TEST(19_SymmetricCircuit)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@ -3122,8 +3214,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"
@ -3221,8 +3313,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"
@ -3359,6 +3451,7 @@ TEST(20_BusLikeConnections)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@ -3503,6 +3596,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)
@ -3539,6 +3779,7 @@ TEST(21_BusLikeAmbiguousConnections)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@ -3711,6 +3952,7 @@ TEST(22_NodesRemoved)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@ -3831,6 +4073,7 @@ TEST(23_NodesRemovedWithError)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@ -3930,6 +4173,7 @@ TEST(24_NodesRemovedButConnectedInOther)
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
comp.set_dont_consider_net_names (true);
bool good = comp.compare (&nl1, &nl2);
@ -4021,6 +4265,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 (),
@ -4059,6 +4304,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 ();
@ -4098,6 +4344,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 ();
@ -4137,6 +4384,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"
@ -4181,6 +4429,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 (),
@ -4213,6 +4462,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"));
@ -4235,6 +4486,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"));
@ -4264,6 +4517,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

View File

@ -37,6 +37,15 @@ See <a href="/about/lvs_ref_netter.xml#align">Netter#align</a> for a description
<p>
See <a href="/about/lvs_ref_netter.xml#compare">Netter#compare</a> for a description of that function.
</p>
<a name="consider_net_names"/><h2>"consider_net_names" - Indicates whether the netlist comparer shall use net names</h2>
<keyword name="consider_net_names"/>
<p>Usage:</p>
<ul>
<li><tt>consider_net_names(f)</tt></li>
</ul>
<p>
See <a href="/about/lvs_ref_netter.xml#consider_net_names">Netter#consider_net_names</a> for a description of that function.
</p>
<a name="equivalent_pins"/><h2>"equivalent_pins" - Marks pins as equivalent</h2>
<keyword name="equivalent_pins"/>
<p>Usage:</p>

View File

@ -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.
</p>
<a name="consider_net_names"/><h2>"consider_net_names" - Indicates whether the netlist comparer shall use net names</h2>
<keyword name="consider_net_names"/>
<p>Usage:</p>
<ul>
<li><tt>consider_net_names(f)</tt></li>
</ul>
<p>
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.
</p>
<a name="equivalent_pins"/><h2>"equivalent_pins" - Marks pins as equivalent</h2>
<keyword name="equivalent_pins"/>
<p>Usage:</p>

View File

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

View File

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

View File

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

View File

@ -131,5 +131,7 @@ connect_implicit("DOESNOTEXIST", "DOESNOTEXIST")
netlist.simplify
align
consider_net_names(false)
compare

View File

@ -131,5 +131,7 @@ connect_implicit("DOESNOTEXIST", "DOESNOTEXIST")
netlist.simplify
align
consider_net_names(false)
compare

View File

@ -71,5 +71,7 @@ connect_global(ptie, "SUBSTRATE")
netlist.simplify
align
consider_net_names(false)
compare

View File

@ -126,5 +126,7 @@ connect_global(bulk, "SUBSTRATE")
netlist.simplify
align
consider_net_names(false)
compare

View File

@ -83,5 +83,7 @@ netlist.purge
netlist.combine_devices
netlist.purge_nets
consider_net_names(false)
compare