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:

+
    +
  • consider_net_names(f)
  • +
+

+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:

+
    +
  • 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. +

"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