From b91e2324d0ed026595f7cfcebeadcd7f7c0fe2fa Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 26 Jun 2020 17:01:03 +0200 Subject: [PATCH] Netlist compare enhancement This enhancement targets towards a better resolution of ambiguities. The enhancement is to utilize knowledge about device and subcircuit equivalences to avoid stale branches of the ambiguity resolution tree. So far following these branches could lead to a contradictions which render an ambiguitiy resolution choice useless. One effect of this change is enhanced reproducibility of the matching log because some pointers are not involved anymore. --- src/db/db/dbNetlistCompare.cc | 1287 +++++++++++++++----- src/db/db/dbNetlistCompare.h | 27 +- src/db/unit_tests/dbNetlistCompareTests.cc | 278 ++++- testdata/lvs/double_height2.lvsdb | 2 +- testdata/lvs/ringo_simple_dmos.lvsdb.1 | 2 +- testdata/lvs/ringo_simple_dmos.lvsdb.2 | 912 -------------- 6 files changed, 1245 insertions(+), 1263 deletions(-) delete mode 100644 testdata/lvs/ringo_simple_dmos.lvsdb.2 diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 39be51719..7844e4f1b 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -333,6 +333,63 @@ private: double m_cap_threshold, m_res_threshold; }; +// -------------------------------------------------------------------------------------------------------------------- +// A generic equivalence mapper + +template +class generic_equivalence_tracker +{ +public: + generic_equivalence_tracker () + { + // .. nothing yet .. + } + + bool map (const Obj *a, const Obj *b) + { + std::pair::iterator, bool> inserted1 = m_eq.insert (std::make_pair (a, b)); + tl_assert (inserted1.first->second == b); + std::pair::iterator, bool> inserted2 = m_eq.insert (std::make_pair (b, a)); + tl_assert (inserted2.first->second == a); + return inserted1.second; + } + + void unmap (const Obj *a, const Obj *b) + { + m_eq.erase (a); + m_eq.erase (b); + } + + const Obj *other (const Obj *o) const + { + typename std::map::const_iterator i = m_eq.find (o); + return i == m_eq.end () ? 0 : i->second; + } + +public: + std::map m_eq; +}; + +// -------------------------------------------------------------------------------------------------------------------- +// A class describing the equivalence between subcircuits we established so far + +class SubCircuitEquivalenceTracker + : public generic_equivalence_tracker +{ +public: + SubCircuitEquivalenceTracker () : generic_equivalence_tracker () { } +}; + +// -------------------------------------------------------------------------------------------------------------------- +// A class describing the equivalence between devices we established so far + +class DeviceEquivalenceTracker + : public generic_equivalence_tracker +{ +public: + DeviceEquivalenceTracker () : generic_equivalence_tracker () { } +}; + // -------------------------------------------------------------------------------------------------------------------- // generic_categorizer definition and implementation @@ -559,15 +616,20 @@ class NetGraph; struct CompareData { CompareData () - : other (0), max_depth (0), max_n_branch (0), dont_consider_net_names (false), logger (0), circuit_pin_mapper (0) + : other (0), max_depth (0), max_n_branch (0), depth_first (true), dont_consider_net_names (false), logger (0), + circuit_pin_mapper (0), subcircuit_equivalence (0), device_equivalence (0), progress (0) { } NetGraph *other; size_t max_depth; size_t max_n_branch; + bool depth_first; bool dont_consider_net_names; NetlistCompareLogger *logger; CircuitPinMapper *circuit_pin_mapper; + SubCircuitEquivalenceTracker *subcircuit_equivalence; + DeviceEquivalenceTracker *device_equivalence; + tl::RelativeProgress *progress; }; // -------------------------------------------------------------------------------------------------------------------- @@ -619,6 +681,16 @@ public: m_id2 = pin2_id; } + size_t id1 () const + { + return m_id1; + } + + size_t id2 () const + { + return m_id2; + } + bool operator< (const Transition &other) const { if (is_for_subcircuit () != other.is_for_subcircuit ()) { @@ -888,9 +960,9 @@ namespace db struct CompareNodePtr { - bool operator() (const NetGraphNode *a, const NetGraphNode *b) const + bool operator() (const std::pair &a, const std::pair &b) const { - return *a < *b; + return *a.first < *b.first; } }; @@ -1053,7 +1125,7 @@ public: * with a proposed identity. With "with_ambiguous", amiguities are resolved by trying * different combinations in tentative mode and deciding for one combination if possible. */ - 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, bool with_ambiguous, CompareData *data); private: std::vector m_nodes; @@ -1426,7 +1498,8 @@ NetGraphNode::edge_equal (const db::Net *a, const db::Net *b) */ struct NodeRange { - NodeRange (size_t _num, std::vector::iterator _n1, std::vector::iterator _nn1, std::vector::iterator _n2, std::vector::iterator _nn2) + NodeRange (size_t _num, std::vector >::iterator _n1, std::vector >::iterator _nn1, + std::vector >::iterator _n2, std::vector >::iterator _nn2) : num (_num), n1 (_n1), nn1 (_nn1), n2 (_n2), nn2 (_nn2) { // .. nothing yet .. @@ -1438,11 +1511,163 @@ struct NodeRange } size_t num; - std::vector::iterator n1, nn1, n2, nn2; + std::vector >::iterator n1, nn1, n2, nn2; }; // -------------------------------------------------------------------------------------------------------------------- +struct CatAndIds +{ +public: + CatAndIds (size_t _cat, size_t _id1, size_t _id2) + : cat (_cat), id1 (_id1), id2 (_id2) + { } + + bool operator== (const CatAndIds &other) const + { + return cat == other.cat && id1 == other.id1 && id2 == other.id2; + } + + bool operator< (const CatAndIds &other) const + { + if (cat != other.cat) { + return cat < other.cat; + } + if (id1 != other.id1) { + return id1 < other.id1; + } + if (id2 != other.id2) { + return id2 < other.id2; + } + return false; + } + + size_t cat, id1, id2; +}; + +template +class generic_mapper_for_target_node +{ +public: + generic_mapper_for_target_node () + { + // .. nothing yet .. + } + + static void derive_mapping (const generic_mapper_for_target_node &m1, const generic_mapper_for_target_node &m2, size_t n1, size_t n2, std::vector > &mapped) + { + if (m1.empty () || m2.empty ()) { + return; + } + + const std::set > &s1 = m1.for_node (n1); + const std::set > &s2 = m2.for_node (n2); + + typename std::set >::const_iterator i1 = s1.begin (), i2 = s2.begin (); + + while (i1 != s1.end () && i2 != s2.end ()) { + + if (i1->first < i2->first) { + ++i1; + } else if (i2->first < i1->first) { + ++i2; + } else { + typename std::set >::const_iterator i10 = i1, i20 = i2; + size_t n1 = 0, n2 = 0; + while (i1 != s1.end () && i1->first == i10->first) { + ++i1; + ++n1; + } + while (i2 != s2.end () && i2->first == i20->first) { + ++i2; + ++n2; + } + if (n1 == 1 && n2 == 1) { + // unique mapping - one device of one category + mapped.push_back (std::make_pair (i10->second, i20->second)); + } + } + + } + + } + +protected: + const std::set > &for_node (size_t ni) const + { + typename std::map > >::const_iterator d = m_per_target_node.find (ni); + tl_assert (d != m_per_target_node.end ()); + return d->second; + } + + std::set > &for_node_nc (size_t ni) + { + return m_per_target_node [ni]; + } + + bool empty () const + { + return m_per_target_node.empty (); + } + +private: + std::map > > m_per_target_node; +}; + +class DeviceMapperForTargetNode + : public generic_mapper_for_target_node +{ +public: + DeviceMapperForTargetNode () + : generic_mapper_for_target_node () + { + // .. nothing yet .. + } + + void insert (const NetGraphNode::edge_type &e) + { + if (e.first.empty ()) { + // happens initially + return; + } + + size_t ni = e.second.first; + std::set > &dev = for_node_nc (ni); + for (std::vector::const_iterator j = e.first.begin (); j != e.first.end (); ++j) { + if (! j->is_for_subcircuit ()) { + dev.insert (std::make_pair (CatAndIds (j->device_pair ().second, j->id1 (), j->id2 ()), j->device_pair ().first)); + } + } + } +}; + +class SubCircuitMapperForTargetNode + : public generic_mapper_for_target_node +{ +public: + SubCircuitMapperForTargetNode () + : generic_mapper_for_target_node () + { + // .. nothing yet .. + } + + void insert (const NetGraphNode::edge_type &e) + { + if (e.first.empty ()) { + // happens initially + return; + } + + size_t ni = e.second.first; + std::set > &sc = for_node_nc (ni); + for (std::vector::const_iterator j = e.first.begin (); j != e.first.end (); ++j) { + if (j->is_for_subcircuit ()) { + sc.insert (std::make_pair (CatAndIds (j->subcircuit_pair ().second, j->id1 (), j->id2 ()), j->subcircuit_pair ().first)); + } + } + } +}; + /** * @brief An audit object which allows reverting tentative node assignments */ @@ -1460,26 +1685,46 @@ public: for (std::vector >::const_iterator i = m_to_undo_to_unknown.begin (); i != m_to_undo_to_unknown.end (); ++i) { i->first->identify (i->second, unknown_id); } + for (std::vector > >::const_iterator i = m_to_undo_devices.begin (); i != m_to_undo_devices.end (); ++i) { + i->first->unmap (i->second.first, i->second.second); + } + for (std::vector > >::const_iterator i = m_to_undo_subcircuits.begin (); i != m_to_undo_subcircuits.end (); ++i) { + i->first->unmap (i->second.first, i->second.second); + } } - static void map_pair (TentativeNodeMapping *nm, NetGraph *g1, size_t n1, NetGraph *g2, size_t n2) + static void map_pair (TentativeNodeMapping *nm, NetGraph *g1, size_t n1, NetGraph *g2, size_t n2, + const DeviceMapperForTargetNode &dm1, const DeviceMapperForTargetNode &dm2, DeviceEquivalenceTracker &device_eq, + const SubCircuitMapperForTargetNode &scm1, const SubCircuitMapperForTargetNode &scm2, SubCircuitEquivalenceTracker &subcircuit_eq, + size_t depth) { g1->identify (n1, n2); g2->identify (n2, n1); + if (nm) { nm->keep (g1, n1); nm->keep (g2, n2); } + + derive_device_equivalence (nm, n1, n2, dm1, dm2, device_eq, depth); + derive_subcircuit_equivalence (nm, n1, n2, scm1, scm2, subcircuit_eq, depth); } - static void map_pair_from_unknown (TentativeNodeMapping *nm, NetGraph *g1, size_t n1, NetGraph *g2, size_t n2) + static void map_pair_from_unknown (TentativeNodeMapping *nm, NetGraph *g1, size_t n1, NetGraph *g2, size_t n2, + const DeviceMapperForTargetNode &dm1, const DeviceMapperForTargetNode &dm2, DeviceEquivalenceTracker &device_eq, + const SubCircuitMapperForTargetNode &scm1, const SubCircuitMapperForTargetNode &scm2, SubCircuitEquivalenceTracker &subcircuit_eq, + size_t depth) { g1->identify (n1, n2); g2->identify (n2, n1); + if (nm) { nm->keep_for_unknown (g1, n1); nm->keep_for_unknown (g2, n2); } + + derive_device_equivalence (nm, n1, n2, dm1, dm2, device_eq, depth); + derive_subcircuit_equivalence (nm, n1, n2, scm1, scm2, subcircuit_eq, depth); } static void map_to_unknown (TentativeNodeMapping *nm, NetGraph *g1, size_t n1) @@ -1490,8 +1735,48 @@ public: } } + static void derive_device_equivalence (TentativeNodeMapping *nm, size_t n1, size_t n2, + const DeviceMapperForTargetNode &dm1, const DeviceMapperForTargetNode &dm2, DeviceEquivalenceTracker &device_eq, size_t depth) + { + std::vector > device_map; + DeviceMapperForTargetNode::derive_mapping (dm1, dm2, n1, n2, device_map); + + for (std::vector >::const_iterator dd = device_map.begin (); dd != device_map.end (); ++dd) { + if (device_eq.map (dd->first, dd->second)) { + if (nm) { + nm->keep (&device_eq, dd->first, dd->second); + } else { + if (options ()->debug_netcompare) { + tl::info << indent(depth) << "enforcing device equivalence: " << dd->first->expanded_name () << " vs. " << dd->second->expanded_name (); + } + } + } + } + } + + static void derive_subcircuit_equivalence (TentativeNodeMapping *nm, size_t n1, size_t n2, + const SubCircuitMapperForTargetNode &scm1, const SubCircuitMapperForTargetNode &scm2, SubCircuitEquivalenceTracker &subcircuit_eq, size_t depth) + { + std::vector > subcircuit_map; + SubCircuitMapperForTargetNode::derive_mapping (scm1, scm2, n1, n2, subcircuit_map); + + for (std::vector >::const_iterator cc = subcircuit_map.begin (); cc != subcircuit_map.end (); ++cc) { + if (subcircuit_eq.map (cc->first, cc->second)) { + if (nm) { + nm->keep (&subcircuit_eq, cc->first, cc->second); + } else { + if (options ()->debug_netcompare) { + tl::info << indent(depth) << "enforcing subcircuit equivalence: " << cc->first->expanded_name () << " vs. " << cc->second->expanded_name (); + } + } + } + } + } + private: std::vector > m_to_undo, m_to_undo_to_unknown; + std::vector > > m_to_undo_devices; + std::vector > > m_to_undo_subcircuits; void keep (NetGraph *g1, size_t n1) { @@ -1502,6 +1787,16 @@ private: { m_to_undo_to_unknown.push_back (std::make_pair (g1, n1)); } + + void keep (DeviceEquivalenceTracker *dt, const db::Device *a, const db::Device *b) + { + m_to_undo_devices.push_back (std::make_pair (dt, std::make_pair (a, b))); + } + + void keep (SubCircuitEquivalenceTracker *dt, const db::SubCircuit *a, const db::SubCircuit *b) + { + m_to_undo_subcircuits.push_back (std::make_pair (dt, std::make_pair (a, b))); + } }; // -------------------------------------------------------------------------------------------------------------------- @@ -1533,8 +1828,6 @@ NetGraph::build (const db::Circuit *c, DeviceCategorizer &device_categorizer, Ci } } - std::sort (m_nodes.begin (), m_nodes.end ()); - for (std::vector::const_iterator i = m_nodes.begin (); i != m_nodes.end (); ++i) { m_net_index.insert (std::make_pair (i->net (), i - m_nodes.begin ())); } @@ -1579,110 +1872,174 @@ NetGraph::build (const db::Circuit *c, DeviceCategorizer &device_categorizer, Ci } } +/** + * @brief Returns true if the edges (given by transition iterators) are compatible with already established device or subcircuit equivalences. + */ +static bool edges_are_compatible (const NetGraphNode::edge_type &e, const NetGraphNode::edge_type &e_other, const DeviceEquivalenceTracker &device_eq, const SubCircuitEquivalenceTracker &sc_eq) +{ + std::vector::const_iterator t1 = e.first.begin (), tt1 = e.first.end (); + std::vector::const_iterator t2 = e_other.first.begin (), tt2 = e_other.first.end (); + + std::vector p1, p2; + + while (t1 != tt1 && t2 != tt2) { + + std::vector::const_iterator t10 = t1, t20 = t2; + + p1.clear (); + while (t1 != tt1 && *t1 == *t10) { + if (t1->is_for_subcircuit ()) { + p1.push_back ((void *) sc_eq.other (t1->subcircuit_pair ().first)); + } else { + p1.push_back ((void *) device_eq.other (t1->device_pair ().first)); + } + ++t1; + } + + p2.clear (); + while (t2 != tt2 && *t2 == *t20) { + if (t2->is_for_subcircuit ()) { + p2.push_back ((void *) (sc_eq.other (t2->subcircuit_pair ().first) ? t2->subcircuit_pair ().first : 0)); + } else { + p2.push_back ((void *) (device_eq.other (t2->device_pair ().first) ? t2->device_pair ().first : 0)); + } + ++t2; + } + + std::sort (p1.begin (), p1.end ()); + std::sort (p2.begin (), p2.end ()); + + if (p1 != p2) { + return false; + } + + } + + tl_assert (t1 == tt1 && t2 == tt2); + return true; +} + size_t NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGraphNode::edge_iterator ee, NetGraphNode::edge_iterator e_other, NetGraphNode::edge_iterator ee_other, size_t net_index, size_t other_net_index, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, bool with_ambiguous, CompareData *data) { - size_t new_nodes = 0; + // NOTE: we can skip edges to known nodes because we did a pre-analysis making sure those are compatible - std::vector nodes; + std::vector > nodes; nodes.reserve (ee - e); - std::vector other_nodes; + std::vector > other_nodes; other_nodes.reserve (ee - e); - if (options ()->debug_netcompare) { - tl::info << indent(depth) << "considering transitions:"; - } - bool first = true; + tl_assert (e->first == e_other->first); for (NetGraphNode::edge_iterator i = e; i != ee; ++i) { if (i->second.first != net_index) { const NetGraphNode *nn = &node (i->second.first); - if (options ()->debug_netcompare) { - if (first) { - tl::info << indent (depth) << " here: " << (node (net_index).net () ? node (net_index).net ()->expanded_name ().c_str () : "(null)") << " ->"; - first = false; - } - tl::info << indent (depth) << " " << (nn->net () ? nn->net ()->expanded_name ().c_str() : "(null)") << " via: " << tl::noendl; - for (std::vector::const_iterator t = i->first.begin (); t != i->first.end(); ++t) { - tl::info << (t != i->first.begin () ? "; " : "") << t->to_string() << tl::noendl; - } - tl::info << ""; + if (! nn->has_other ()) { + nodes.push_back (std::make_pair (nn, i)); } - nodes.push_back (nn); } } if (! nodes.empty ()) { // if non-ambiguous, non-assigned - first = true; - for (NetGraphNode::edge_iterator i = e_other; i != ee_other; ++i) { if (i->second.first != other_net_index) { const NetGraphNode *nn = &data->other->node (i->second.first); - if (options ()->debug_netcompare) { - if (first) { - tl::info << indent (depth) << " there: " << (data->other->node (other_net_index).net () ? data->other->node (other_net_index).net ()->expanded_name ().c_str () : "(null)") << " ->"; - first = false; - } - tl::info << indent(depth) << " " << (nn->net() ? nn->net()->expanded_name().c_str() : "(null)") << " via: " << tl::noendl; - for (std::vector::const_iterator t = i->first.begin (); t != i->first.end(); ++t) { - tl::info << (t != i->first.begin () ? "; " : "") << t->to_string() << tl::noendl; - } - tl::info << ""; + if (! nn->has_other ()) { + other_nodes.push_back (std::make_pair (nn, i)); } - other_nodes.push_back (nn); } } } - if (! nodes.empty () || ! other_nodes.empty ()) { + if (nodes.empty () || other_nodes.empty ()) { + return 0; + } - std::sort (nodes.begin (), nodes.end (), CompareNodePtr ()); - std::sort (other_nodes.begin (), other_nodes.end (), CompareNodePtr ()); + std::sort (nodes.begin (), nodes.end (), CompareNodePtr ()); + std::sort (other_nodes.begin (), other_nodes.end (), CompareNodePtr ()); - // for the purpose of match evaluation we require an exact match of the node structure + size_t new_nodes = 0; - if (tentative) { + if (options ()->debug_netcompare) { - if (nodes.size () != other_nodes.size ()) { - if (options ()->debug_netcompare) { - tl::info << indent(depth) << "=> rejected branch."; - } - return failed_match; + // print transitions if requested + + tl::info << indent(depth) << "considering transitions:"; + + bool first = true; + + for (std::vector >::const_iterator i = nodes.begin (); i != nodes.end (); ++i) { + const NetGraphNode *nn = i->first; + if (first) { + tl::info << indent (depth) << " here: " << (node (net_index).net () ? node (net_index).net ()->expanded_name ().c_str () : "(null)") << " ->"; + first = false; } + tl::info << indent (depth) << " " << (nn->net () ? nn->net ()->expanded_name ().c_str() : "(null)") << " via: " << tl::noendl; + for (std::vector::const_iterator t = i->second->first.begin (); t != i->second->first.end(); ++t) { + tl::info << (t != i->second->first.begin () ? "; " : "") << t->to_string() << tl::noendl; + } + tl::info << ""; + } - // 1:1 pairing is less strict - if (nodes.size () > 1 || other_nodes.size () > 1) { - for (size_t i = 0; i < nodes.size (); ++i) { - if (! (*nodes[i] == *other_nodes[i])) { - if (options ()->debug_netcompare) { - tl::info << indent(depth) << "=> rejected branch."; - } - return failed_match; + first = true; + + for (std::vector >::const_iterator i = other_nodes.begin (); i != other_nodes.end (); ++i) { + const NetGraphNode *nn = i->first; + if (first) { + tl::info << indent (depth) << " there: " << (data->other->node (other_net_index).net () ? data->other->node (other_net_index).net ()->expanded_name ().c_str () : "(null)") << " ->"; + first = false; + } + tl::info << indent(depth) << " " << (nn->net() ? nn->net()->expanded_name().c_str() : "(null)") << " via: " << tl::noendl; + for (std::vector::const_iterator t = i->second->first.begin (); t != i->second->first.end(); ++t) { + tl::info << (t != i->second->first.begin () ? "; " : "") << t->to_string() << tl::noendl; + } + tl::info << ""; + } + + } + + // for the purpose of match evaluation we require an exact match of the node structure + + if (tentative) { + + if (nodes.size () != other_nodes.size ()) { + if (options ()->debug_netcompare) { + tl::info << indent(depth) << "=> rejected branch."; + } + return failed_match; + } + + // 1:1 pairing is less strict + if (nodes.size () > 1 || other_nodes.size () > 1) { + for (size_t i = 0; i < nodes.size (); ++i) { + if (! (*nodes[i].first == *other_nodes[i].first)) { + if (options ()->debug_netcompare) { + tl::info << indent(depth) << "=> rejected branch."; } + return failed_match; } } - } - // propagate pairing in picky mode: this means we only accept exact a match if the node set - // is exactly identical and no ambiguous nodes are present when ambiguous nodes are forbidden + } - size_t bt_count = derive_node_identities_from_node_set (nodes, other_nodes, depth, n_branch, tentative, with_ambiguous, data); + // propagate pairing in picky mode: this means we only accept exact a match if the node set + // is exactly identical and no ambiguous nodes are present when ambiguous nodes are forbidden - if (bt_count == failed_match) { - if (tentative) { - if (options ()->debug_netcompare) { - tl::info << indent(depth) << "=> rejected branch."; - } - return bt_count; + size_t bt_count = derive_node_identities_from_node_set (nodes, other_nodes, depth, n_branch, tentative, with_ambiguous, data); + + if (bt_count == failed_match) { + if (tentative) { + if (options ()->debug_netcompare) { + tl::info << indent(depth) << "=> rejected branch."; } - } else { - new_nodes += bt_count; + return bt_count; } - + } else { + new_nodes += bt_count; } if (options ()->debug_netcompare) { @@ -1714,16 +2071,6 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc size_t other_net_index = n->other_net_index (); NetGraphNode *n_other = & data->other->node (other_net_index); - if (options ()->debug_netcompare) { - if (! tentative) { - tl::info << indent(depth) << "deducing from pair: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name (); - } else { - tl::info << indent(depth) << "tentatively deducing from pair: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name (); - } - } - - size_t new_nodes = 0; - NetGraphNode nn, nn_other; // If there are subcircuits on the graph we temporarily create edges from our node to the other nodes of @@ -1741,6 +2088,117 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc } + // do a pre-analysis filtering out all nodes with fully satisfied edges or which provide a contradiction + + bool analysis_required = false; + + for (NetGraphNode::edge_iterator e = n->begin (); e != n->end (); ) { + + NetGraphNode::edge_iterator ee = e; + ++ee; + + while (ee != n->end () && ee->first == e->first) { + ++ee; + } + + NetGraphNode::edge_iterator e_other = n_other->find_edge (e->first); + if (e_other != n_other->end ()) { + + NetGraphNode::edge_iterator ee_other = e_other; + ++ee_other; + + while (ee_other != n_other->end () && ee_other->first == e_other->first) { + ++ee_other; + } + + std::vector nodes; + nodes.reserve (ee - e); + + std::vector other_nodes_translated; + other_nodes_translated.reserve (ee - e); + + tl_assert (e->first == e_other->first); + + for (NetGraphNode::edge_iterator i = e; i != ee; ++i) { + if (i->second.first != net_index) { + const NetGraphNode *nn = &node (i->second.first); + if (nn->has_other ()) { + nodes.push_back (nn); + } else { + analysis_required = true; + } + } + } + + for (NetGraphNode::edge_iterator i = e_other; i != ee_other; ++i) { + if (i->second.first != other_net_index) { + const NetGraphNode *nn = &data->other->node (i->second.first); + if (nn->has_other ()) { + other_nodes_translated.push_back (&node (nn->other_net_index ())); + } else { + analysis_required = true; + } + } + } + + std::sort (nodes.begin (), nodes.end ()); + std::sort (other_nodes_translated.begin (), other_nodes_translated.end ()); + + // No fit, we can shortcut + if (nodes != other_nodes_translated) { + return tentative ? failed_match : 0; + } + + } else if (tentative) { + // in tentative mode an exact match is required: no having the same edges for a node disqualifies the node + // as matching. + return failed_match; + } + + e = ee; + + } + + if (tentative) { + + // in tentative mode, again an exact match is required + + for (NetGraphNode::edge_iterator e_other = n_other->begin (); e_other != n_other->end (); ) { + + NetGraphNode::edge_iterator ee_other = e_other; + ++ee_other; + + while (ee_other != n_other->end () && ee_other->first == e_other->first) { + ++ee_other; + } + + NetGraphNode::edge_iterator e = n->find_edge (e_other->first); + if (e == n->end ()) { + return failed_match; + } + + e_other = ee_other; + + } + + } + + if (! analysis_required) { + return 0; + } + + // do a detailed analysis + + size_t new_nodes = 0; + + if (options ()->debug_netcompare) { + if (! tentative) { + tl::info << indent(depth) << "deducing from pair: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name (); + } else { + tl::info << indent(depth) << "tentatively deducing from pair: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name (); + } + } + // non-ambiguous paths to non-assigned nodes create a node identity on the // end of this path @@ -1773,46 +2231,12 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc new_nodes += bt_count; } - } else if (tentative) { - // in tentative mode an exact match is required: no having the same edges for a node disqualifies the node - // as matching. - if (options ()->debug_netcompare) { - tl::info << indent(depth) << "=> rejected pair for missing edge."; - } - return failed_match; } e = ee; } - if (tentative) { - - // in tentative mode, again an exact match is required - - for (NetGraphNode::edge_iterator e_other = n_other->begin (); e_other != n_other->end (); ) { - - NetGraphNode::edge_iterator ee_other = e_other; - ++ee_other; - - while (ee_other != n_other->end () && ee_other->first == e_other->first) { - ++ee_other; - } - - NetGraphNode::edge_iterator e = n->find_edge (e_other->first); - if (e == n->end ()) { - if (options ()->debug_netcompare) { - tl::info << indent(depth) << "=> rejected pair for missing edge."; - } - return failed_match; - } - - e_other = ee_other; - - } - - } - if (options ()->debug_netcompare) { if (! tentative && new_nodes > 0) { tl::info << indent(depth) << "=> finished pair deduction: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name () << " with " << new_nodes << " new pairs"; @@ -1827,10 +2251,10 @@ namespace { struct SortNodeByNet { public: - bool operator() (const NetGraphNode *a, const NetGraphNode *b) const + bool operator() (const std::pair &a, const std::pairb) const { - tl_assert (a->net () && b->net ()); - return name_compare (a->net ()->name (), b->net ()->name ()) < 0; + tl_assert (a.first->net () && b.first->net ()); + return name_compare (a.first->net ()->name (), b.first->net ()->name ()) < 0; } }; @@ -1841,12 +2265,12 @@ static void sort_node_range_by_best_match (NodeRange &nr) std::stable_sort (nr.n1, nr.nn1, SortNodeByNet ()); std::stable_sort (nr.n2, nr.nn2, SortNodeByNet ()); - std::vector nomatch1, nomatch2; + std::vector > nomatch1, nomatch2; nomatch1.reserve (nr.nn1 - nr.n1); nomatch2.reserve (nr.nn2 - nr.n2); - std::vector::const_iterator i = nr.n1, j = nr.n2; - std::vector::iterator iw = nr.n1, jw = nr.n2; + std::vector >::const_iterator i = nr.n1, j = nr.n2; + std::vector >::iterator iw = nr.n1, jw = nr.n2; SortNodeByNet compare; @@ -1896,7 +2320,7 @@ 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) +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) { std::string indent_s; if (options ()->debug_netcompare) { @@ -1913,49 +2337,80 @@ NetGraph::derive_node_identities_from_node_set (std::vector >::const_iterator i = nodes.begin (); i != nodes.end (); ++i) { + dm.insert (*i->second); + scm.insert (*i->second); + } + + DeviceMapperForTargetNode dm_other; + SubCircuitMapperForTargetNode scm_other; + for (std::vector >::const_iterator i = other_nodes.begin (); i != other_nodes.end (); ++i) { + dm_other.insert (*i->second); + scm_other.insert (*i->second); + } + if (nodes.size () == 1 && other_nodes.size () == 1) { - if (! nodes.front ()->has_any_other () && ! other_nodes.front ()->has_any_other ()) { + 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 (nodes.front ()->net ()); - size_t other_ni = data->other->node_index_for_net (other_nodes.front ()->net ()); + 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); + 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): " << nodes.front ()->net ()->expanded_name () << " vs. " << other_nodes.front ()->net ()->expanded_name (); + tl::info << indent_s << "deduced match (singular): " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name (); } - if (data->logger && ! tentative) { - if (! (node (ni) == data->other->node (other_ni))) { - // this is a mismatch but we continue, because that is the only candidate - data->logger->net_mismatch (nodes.front ()->net (), other_nodes.front ()->net ()); - } else { - data->logger->match_nets (nodes.front ()->net (), other_nodes.front ()->net ()); + if (! tentative) { + ++*data->progress; + if (data->logger) { + if (! (node (ni) == data->other->node (other_ni))) { + // this is a mismatch but we continue, because that is the only candidate + data->logger->net_mismatch (n->net (), n_other->net ()); + } else { + data->logger->match_nets (n->net (), n_other->net ()); + } } } - // continue here. - size_t bt_count = derive_node_identities (ni, depth + 1, n_branch, tentative, with_ambiguous, data); - - if (bt_count != failed_match) { - new_nodes += bt_count; - } else if (tentative) { - return bt_count; + if (data->depth_first || tentative) { + size_t bt_count = derive_node_identities (ni, depth + 1, n_branch, tentative, with_ambiguous, data); + if (bt_count == failed_match) { + if (tentative) { + return failed_match; + } + } else { + new_nodes += bt_count; + } } new_nodes += 1; - } else if (nodes.front ()->has_unknown_other ()) { + } else if (n->has_unknown_other ()) { // accept this solution as the pairing is possible - } else if (nodes.front ()->has_other ()) { + } else if (n->has_other ()) { // this decision leads to a contradiction - if (data->other->node_index_for_net (other_nodes.front ()->net ()) != nodes.front ()->other_net_index ()) { + if (data->other->node_index_for_net (n_other->net ()) != n->other_net_index ()) { return failed_match; } @@ -1974,38 +2429,38 @@ NetGraph::derive_node_identities_from_node_set (std::vector node_ranges; - std::vector::iterator n1 = nodes.begin (); - std::vector::iterator n2 = other_nodes.begin (); + std::vector >::iterator n1 = nodes.begin (); + std::vector >::iterator n2 = other_nodes.begin (); while (n1 != nodes.end () && n2 != other_nodes.end ()) { - if ((*n1)->has_any_other ()) { + if (n1->first->has_other ()) { ++n1; continue; - } else if ((*n2)->has_any_other ()) { + } else if (n2->first->has_other ()) { ++n2; continue; } - if (**n1 < **n2) { + if (*n1->first < *n2->first) { ++n1; continue; - } else if (**n2 < **n1) { + } else if (*n2->first < *n1->first) { ++n2; continue; } - std::vector::iterator nn1 = n1, nn2 = n2; + std::vector >::iterator nn1 = n1, nn2 = n2; size_t num = 1; ++nn1; ++nn2; while (nn1 != nodes.end () && nn2 != other_nodes.end ()) { - if ((*nn1)->has_any_other ()) { + if (nn1->first->has_other ()) { ++nn1; - } else if ((*nn2)->has_any_other ()) { + } else if (nn2->first->has_other ()) { ++nn2; - } else if (! (**nn1 == **n1) || ! (**nn2 == **n2)) { + } else if (! (*nn1->first == *n1->first) || ! (*nn2->first == *n2->first)) { break; } else { ++num; @@ -2038,9 +2493,9 @@ NetGraph::derive_node_identities_from_node_set (std::vectorn1 != nr->nn1 && nr->n2 != nr->nn2) { - if ((*nr->n1)->has_any_other ()) { + if (nr->n1->first->has_other ()) { ++nr->n1; - } else if ((*nr->n2)->has_any_other ()) { + } else if (nr->n2->first->has_other ()) { ++nr->n2; } else { break; @@ -2048,12 +2503,12 @@ NetGraph::derive_node_identities_from_node_set (std::vectornum = 0; - std::vector::const_iterator i1 = nr->n1, i2 = nr->n2; + std::vector >::const_iterator i1 = nr->n1, i2 = nr->n2; while (i1 != nr->nn1 && i2 != nr->nn2) { - if ((*i1)->has_any_other ()) { + if (i1->first->has_other ()) { ++i1; - } else if ((*i2)->has_any_other ()) { + } else if (i2->first->has_other ()) { ++i2; } else { ++nr->num; @@ -2068,14 +2523,21 @@ NetGraph::derive_node_identities_from_node_set (std::vectornum == 1) { - if (! (*nr->n1)->has_any_other () && ! (*nr->n2)->has_any_other ()) { + if (! edges_are_compatible (*nr->n1->second, *nr->n2->second, *data->device_equivalence, *data->subcircuit_equivalence)) { + + if (options ()->debug_netcompare) { + tl::info << indent(depth) << "=> rejected because edges are incompatible with already established device or subcircuit equivalences"; + } + return tentative ? failed_match : 0; + + } else if (! nr->n1->first->has_any_other () && ! nr->n2->first->has_any_other ()) { // in tentative mode, reject this choice if both nets are named and // their names differ -> this favors net matching by name - if (tentative && ! data->dont_consider_net_names && net_names_are_different ((*nr->n1)->net (), (*nr->n2)->net ())) { + 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)->net ()->expanded_name () << " vs. " << (*nr->n2)->net ()->expanded_name (); + 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; } @@ -2083,41 +2545,47 @@ NetGraph::derive_node_identities_from_node_set (std::vector this may render // inexact matches, but further propagates net pairing - size_t ni = node_index_for_net ((*nr->n1)->net ()); - size_t other_ni = data->other->node_index_for_net ((*nr->n2)->net ()); + 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); + 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)->net ()->expanded_name () << " vs. " << (*nr->n2)->net ()->expanded_name (); + tl::info << indent_s << "deduced match (singular): " << nr->n1->first->net ()->expanded_name () << " vs. " << nr->n2->first->net ()->expanded_name (); } - if (data->logger && ! tentative) { - if (! (node (ni) == data->other->node (other_ni))) { - // this is a mismatch, but we continue with this - data->logger->net_mismatch ((*nr->n1)->net (), (*nr->n2)->net ()); - } else { - data->logger->match_nets ((*nr->n1)->net (), (*nr->n2)->net ()); + if (! tentative) { + ++*data->progress; + if (data->logger) { + if (! (node (ni) == data->other->node (other_ni))) { + // this is a mismatch, but we continue with this + data->logger->net_mismatch (nr->n1->first->net (), nr->n2->first->net ()); + } else { + data->logger->match_nets (nr->n1->first->net (), nr->n2->first->net ()); + } } } - // continue here. - size_t bt_count = derive_node_identities (ni, depth + 1, n_branch, tentative, with_ambiguous, data); - - if (bt_count != failed_match) { - new_nodes += bt_count; - new_nodes += 1; - } else if (tentative) { - new_nodes = bt_count; + if (data->depth_first || tentative) { + size_t bt_count = derive_node_identities (ni, depth + 1, n_branch, tentative, with_ambiguous, data); + if (bt_count == failed_match) { + if (tentative) { + return failed_match; + } + } else { + new_nodes += bt_count; + } } - } else if ((*nr->n1)->has_unknown_other ()) { + new_nodes += 1; + + } else if (nr->n1->first->has_unknown_other ()) { // accept any other net - } else if ((*nr->n1)->has_other ()) { + } else if (nr->n1->first->has_other ()) { // this decision leads to a contradiction - if (data->other->node_index_for_net ((*nr->n2)->net ()) != (*nr->n1)->other_net_index ()) { + if (data->other->node_index_for_net (nr->n2->first->net ()) != nr->n1->first->other_net_index ()) { return failed_match; } @@ -2157,48 +2625,56 @@ NetGraph::derive_node_identities_from_node_set (std::vector::const_iterator> iters1, iters2; + std::vector >::const_iterator> iters1, iters2; - for (std::vector::const_iterator i1 = nr->n1; i1 != nr->nn1; ++i1) { - if (! (*i1)->has_any_other ()) { + 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)->net ()); + 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)->has_any_other ()) { + 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)->net ()); + 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) { + for (std::vector >::const_iterator>::const_iterator ii1 = iters1.begin (); ii1 != iters1.end (); ++ii1) { - std::vector::const_iterator i1 = *ii1; + std::vector >::const_iterator i1 = *ii1; bool any = false; - for (std::vector::const_iterator>::const_iterator ii2 = iters2.begin (); ii2 != iters2.end (); ++ii2) { + for (std::vector >::const_iterator>::const_iterator ii2 = iters2.begin (); ii2 != iters2.end (); ++ii2) { - std::vector::const_iterator i2 = *ii2; + std::vector >::const_iterator i2 = *ii2; - if (seen.find (*i2) != seen.end ()) { + if (seen.find (i2->first) != seen.end ()) { continue; } - size_t ni = node_index_for_net ((*i1)->net ()); - size_t other_ni = data->other->node_index_for_net ((*i2)->net ()); - - TentativeNodeMapping tn; - TentativeNodeMapping::map_pair_from_unknown (&tn, this, ni, data->other, other_ni); - // try this candidate in tentative mode if (options ()->debug_netcompare) { - tl::info << indent_s << "trying in tentative mode: " << (*i1)->net ()->expanded_name () << " vs. " << (*i2)->net ()->expanded_name (); + 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) { @@ -2212,14 +2688,14 @@ NetGraph::derive_node_identities_from_node_set (std::vectorfirst, pairs.back ().second); } else { // identified a new pair new_nodes += bt_count + 1; - pairs.push_back (std::make_pair (*i1, *i2)); - seen.insert (*i2); + pairs.push_back (std::make_pair (i1->first, i2->first)); + seen.insert (i2->first); any = true; } @@ -2249,7 +2725,7 @@ NetGraph::derive_node_identities_from_node_set (std::vectorfirst->net ()); size_t other_ni = data->other->node_index_for_net (p->second->net ()); - TentativeNodeMapping::map_pair (tentative, this, ni, data->other, other_ni); + 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)) { @@ -2258,6 +2734,7 @@ NetGraph::derive_node_identities_from_node_set (std::vectorfirst->net ()->expanded_name () << " vs. " << p->second->net ()->expanded_name (); } } + if (data->logger) { bool ambiguous = equivalent_other_nodes.has_attribute (p->second); if (ambiguous) { @@ -2267,6 +2744,8 @@ NetGraph::derive_node_identities_from_node_set (std::vectorprogress; + } // And seek further from these pairs @@ -2287,7 +2766,7 @@ NetGraph::derive_node_identities_from_node_set (std::vectorfirst->net ()); size_t other_ni = data->other->node_index_for_net (p->second->net ()); - TentativeNodeMapping::map_pair (tentative, this, ni, data->other, other_ni); + TentativeNodeMapping::map_pair (tentative, this, ni, data->other, other_ni, dm, dm_other, *data->device_equivalence, scm, scm_other, *data->subcircuit_equivalence, depth); } @@ -2320,6 +2799,7 @@ NetlistComparer::NetlistComparer (NetlistCompareLogger *logger) m_max_depth = 50; m_max_n_branch = 500; + m_depth_first = true; m_dont_consider_net_names = false; } @@ -2531,6 +3011,8 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const std::map c12_pin_mapping, c22_pin_mapping; + tl::RelativeProgress progress (tl::to_string (tr ("Comparing netlists")), a->circuit_count (), 1); + for (db::Netlist::const_bottom_up_circuit_iterator c = a->begin_bottom_up (); c != a->end_bottom_up (); ++c) { const db::Circuit *ca = c.operator-> (); @@ -2561,6 +3043,7 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const if (all_subcircuits_verified (ca, verified_circuits_a) && all_subcircuits_verified (cb, verified_circuits_b)) { if (options ()->debug_netcompare) { + tl::info << "----------------------------------------------------------------------"; tl::info << "treating circuit: " << ca->name () << " vs. " << cb->name (); } if (mp_logger) { @@ -2593,6 +3076,8 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const } + ++progress; + } if (mp_logger) { @@ -2663,8 +3148,42 @@ compute_device_key (const db::Device &device, const db::NetGraph &g, bool strict k.push_back (std::make_pair (terminal_id, net_id)); } - std::sort (k.begin (), k.end ()); + return k; +} +static std::vector > +compute_device_key_for_this (const db::Device &device, const db::NetGraph &g, bool strict, bool &mapped) +{ + std::vector > k = compute_device_key (device, g, strict); + + mapped = true; + for (std::vector >::iterator i = k.begin (); i != k.end (); ++i) { + if (! g.begin () [i->second].has_other ()) { + i->second = invalid_id; // normalization + mapped = false; + } + } + + std::sort (k.begin (), k.end ()); + return k; +} + +static std::vector > +compute_device_key_for_other (const db::Device &device, const db::NetGraph &g, bool strict, bool &mapped) +{ + std::vector > k = compute_device_key (device, g, strict); + + mapped = true; + for (std::vector >::iterator i = k.begin (); i != k.end (); ++i) { + if (! g.begin () [i->second].has_other ()) { + i->second = invalid_id; // normalization + mapped = false; + } else { + i->second = g.begin () [i->second].other_net_index (); + } + } + + std::sort (k.begin (), k.end ()); return k; } @@ -2699,11 +3218,51 @@ compute_subcircuit_key (const db::SubCircuit &subcircuit, const db::NetGraph &g, } - std::sort (k.begin (), k.end ()); - return true; } +static std::vector > +compute_subcircuit_key_for_this (const db::SubCircuit &subcircuit, const db::NetGraph &g, const std::map *circuit_map, const CircuitPinMapper *pin_map, bool &mapped, bool &valid) +{ + valid = true; + std::vector > k; + if (! compute_subcircuit_key (subcircuit, g, circuit_map, pin_map, k)) { + valid = false; + } + + mapped = true; + for (std::vector >::iterator i = k.begin (); i != k.end () && mapped; ++i) { + if (! g.begin () [i->second].has_other ()) { + mapped = false; + } + } + + std::sort (k.begin (), k.end ()); + return k; +} + +static std::vector > +compute_subcircuit_key_for_other (const db::SubCircuit &subcircuit, const db::NetGraph &g, const std::map *circuit_map, const CircuitPinMapper *pin_map, bool &mapped, bool &valid) +{ + valid = true; + std::vector > k; + if (! compute_subcircuit_key (subcircuit, g, circuit_map, pin_map, k)) { + valid = false; + } + + mapped = true; + for (std::vector >::iterator i = k.begin (); i != k.end (); ++i) { + if (! g.begin () [i->second].has_other ()) { + mapped = false; + } else { + i->second = g.begin () [i->second].other_net_index (); + } + } + + std::sort (k.begin (), k.end ()); + return k; +} + namespace { inline double size_dist (size_t a, size_t b) @@ -2860,6 +3419,8 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, std::map &c22_circuit_and_pin_mapping) const { db::DeviceFilter device_filter (m_cap_threshold, m_res_threshold); + SubCircuitEquivalenceTracker subcircuit_equivalence; + DeviceEquivalenceTracker device_equivalence; db::NetGraph g1, g2; @@ -2881,11 +3442,13 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, int iter = 0; + tl::RelativeProgress progress (tl::to_string (tr ("Comparing circuits ")) + c1->name () + "/" + c2->name (), std::max (g1.end () - g1.begin (), g2.end () - g2.begin ()), 1); + // two passes: one without ambiguities, the second one with - bool good; + bool good = false; - for (int pass = 0; pass < 2; ++pass) { + for (int pass = 0; pass < 2 && ! good; ++pass) { if (options ()->debug_netcompare) { if (pass > 0) { @@ -2912,9 +3475,13 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, data.other = &g2; data.max_depth = m_max_depth; data.max_n_branch = m_max_n_branch; + data.depth_first = m_depth_first; data.dont_consider_net_names = m_dont_consider_net_names; data.circuit_pin_mapper = &circuit_pin_mapper; + data.subcircuit_equivalence = &subcircuit_equivalence; + data.device_equivalence = &device_equivalence; data.logger = mp_logger; + data.progress = &progress; size_t ni = g1.derive_node_identities (i1 - g1.begin (), 0, 1, 0 /*not tentative*/, pass > 0 /*with ambiguities*/, &data); if (ni > 0 && ni != failed_match) { @@ -2934,29 +3501,35 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, // derive new identities through topology: first collect all nets with the same topological signature - std::vector nodes, other_nodes; + std::vector > nodes, other_nodes; + + std::vector no_edges; + no_edges.push_back (NetGraphNode::edge_type ()); nodes.reserve (g1.end () - g1.begin ()); for (db::NetGraph::node_iterator i1 = g1.begin (); i1 != g1.end (); ++i1) { if (! i1->has_other () && i1->net ()) { - nodes.push_back (i1.operator-> ()); + nodes.push_back (std::make_pair (i1.operator-> (), no_edges.begin ())); } } other_nodes.reserve (g2.end () - g2.begin ()); for (db::NetGraph::node_iterator i2 = g2.begin (); i2 != g2.end (); ++i2) { if (! i2->has_other () && i2->net ()) { - other_nodes.push_back (i2.operator-> ()); + other_nodes.push_back (std::make_pair (i2.operator-> (), no_edges.begin ())); } } if (nodes.empty () || other_nodes.empty ()) { // active mismatched nodes give an error - for (std::vector::const_iterator n = nodes.begin (); n != nodes.end () && good; ++n) { - good = is_passive_net ((*n)->net (), c12_circuit_and_pin_mapping); + for (std::vector >::const_iterator n = nodes.begin (); n != nodes.end () && good; ++n) { + good = is_passive_net (n->first->net (), c12_circuit_and_pin_mapping); } - for (std::vector::const_iterator n = other_nodes.begin (); n != other_nodes.end () && good; ++n) { - good = is_passive_net ((*n)->net (), c22_circuit_and_pin_mapping); + for (std::vector >::const_iterator n = other_nodes.begin (); n != other_nodes.end () && good; ++n) { + good = is_passive_net (n->first->net (), c22_circuit_and_pin_mapping); + } + if (options ()->debug_netcompare) { + tl::info << "Stopped with " << nodes.size () << "/" << other_nodes.size () << " nodes left unresolved " << (good ? "(accepted)" : "(not accepted)"); } // this assumes that we don't gain anything here. Stop now. break; @@ -2971,9 +3544,12 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, data.max_n_branch = m_max_n_branch; data.dont_consider_net_names = m_dont_consider_net_names; data.circuit_pin_mapper = &circuit_pin_mapper; + data.subcircuit_equivalence = &subcircuit_equivalence; + data.device_equivalence = &device_equivalence; data.logger = mp_logger; + data.progress = &progress; - size_t ni = g1.derive_node_identities_from_node_set (nodes, other_nodes, 0, 1, 0 /*not tentative*/, pass > 0 /*with ambiguities*/, &data); + size_t ni = g1.derive_node_identities_from_node_set (nodes, other_nodes, 0, 1, 0 /*not tentatively*/, pass > 0 /*with ambiguities*/, &data); if (ni > 0 && ni != failed_match) { new_identities += ni; if (options ()->debug_netcompare) { @@ -2982,6 +3558,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, } if (new_identities == 0) { + if (options ()->debug_netcompare) { + tl::info << "Stopped with " << nodes.size () << "/" << other_nodes.size () << " nodes left unresolved."; + } good = false; break; } @@ -2994,6 +3573,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, for (db::NetGraph::node_iterator i = g1.begin (); i != g1.end (); ++i) { if (! i->has_other ()) { + if (options ()->debug_netcompare) { + tl::info << "Unresolved net from left: " << i->net ()->expanded_name () << " " << (good ? "(accepted)" : "(not accepted)"); + } if (mp_logger) { if (good) { mp_logger->match_nets (i->net (), 0); @@ -3010,6 +3592,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, for (db::NetGraph::node_iterator i = g2.begin (); i != g2.end (); ++i) { if (! i->has_other ()) { + if (options ()->debug_netcompare) { + tl::info << "Unresolved net from right: " << i->net ()->expanded_name () << " " << (good ? "(accepted)" : "(not accepted)"); + } if (mp_logger) { if (good) { mp_logger->match_nets (0, i->net ()); @@ -3025,8 +3610,8 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, } do_pin_assignment (c1, g1, c2, g2, c12_circuit_and_pin_mapping, c22_circuit_and_pin_mapping, pin_mismatch, good); - do_device_assignment (c1, g1, c2, g2, device_filter, device_categorizer, good); - do_subcircuit_assignment (c1, g1, c2, g2, circuit_categorizer, circuit_pin_mapper, c12_circuit_and_pin_mapping, c22_circuit_and_pin_mapping, good); + do_device_assignment (c1, g1, c2, g2, device_filter, device_categorizer, device_equivalence, good); + do_subcircuit_assignment (c1, g1, c2, g2, circuit_categorizer, circuit_pin_mapper, c12_circuit_and_pin_mapping, c22_circuit_and_pin_mapping, subcircuit_equivalence, good); return good; } @@ -3241,7 +3826,7 @@ NetlistComparer::do_pin_assignment (const db::Circuit *c1, const db::NetGraph &g } void -NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, const db::DeviceFilter &device_filter, db::DeviceCategorizer &device_categorizer, bool &good) const +NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, const db::DeviceFilter &device_filter, db::DeviceCategorizer &device_categorizer, DeviceEquivalenceTracker &device_eq, bool &good) const { // Report device assignment @@ -3250,27 +3835,26 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph typedef std::vector >, std::pair > > unmatched_list; unmatched_list unmatched_a, unmatched_b; + // check mapping of devices whose equivalence is established topologically + for (db::Circuit::const_device_iterator d = c1->begin_devices (); d != c1->end_devices (); ++d) { if (! device_filter.filter (d.operator-> ())) { continue; } + if (device_eq.other (d.operator-> ())) { + continue; + } + size_t device_cat = device_categorizer.cat_for_device (d.operator-> ()); if (! device_cat) { // device is ignored continue; } - std::vector > k = compute_device_key (*d, g1, device_categorizer.is_strict_device_category (device_cat)); - bool mapped = true; - for (std::vector >::iterator i = k.begin (); i != k.end (); ++i) { - if (! g1.begin () [i->second].has_other ()) { - i->second = invalid_id; // normalization - mapped = false; - } - } + std::vector > k = compute_device_key_for_this (*d, g1, device_categorizer.is_strict_device_category (device_cat), mapped); if (! mapped) { if (mp_logger) { @@ -3296,53 +3880,84 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph continue; } - std::vector > k = compute_device_key (*d, g2, device_categorizer.is_strict_device_category (device_cat)); + const db::Device *c1_device = 0; + size_t c1_device_cat = 0; + + const db::Device *d_this = device_eq.other (d.operator-> ()); + if (d_this) { + + size_t device_cat_this = device_categorizer.cat_for_device (d_this); + if (! device_cat_this) { + // device is ignored + continue; + } + + bool mapped1 = true, mapped2 = true; + std::vector > k_this = compute_device_key_for_this (*d_this, g1, device_categorizer.is_strict_device_category (device_cat_this), mapped1); + std::vector > k = compute_device_key_for_other (*d, g2, device_categorizer.is_strict_device_category (device_cat), mapped2); + + if (! mapped1 || ! mapped2 || k != k_this) { + + // topological mismatch + if (mp_logger) { + mp_logger->device_mismatch (d_this, d.operator-> ()); + } + good = false; - bool mapped = true; - for (std::vector >::iterator i = k.begin (); i != k.end (); ++i) { - if (! g2.begin () [i->second].has_other ()) { - i->second = invalid_id; // normalization - mapped = false; } else { - i->second = g2.begin () [i->second].other_net_index (); + + c1_device = d_this; + c1_device_cat = device_cat_this; + } - } - - std::sort (k.begin (), k.end ()); - - std::multimap >, std::pair >::iterator dm = device_map.find (k); - - if (! mapped || dm == device_map.end () || dm->first != k) { - - if (mp_logger) { - unmatched_b.push_back (std::make_pair (k, std::make_pair (d.operator-> (), device_cat))); - } - good = false; } else { + bool mapped = true; + std::vector > k = compute_device_key_for_other (*d, g2, device_categorizer.is_strict_device_category (device_cat), mapped); + + std::multimap >, std::pair >::iterator dm = device_map.find (k); + + if (! mapped || dm == device_map.end () || dm->first != k) { + + if (mp_logger) { + unmatched_b.push_back (std::make_pair (k, std::make_pair (d.operator-> (), device_cat))); + } + good = false; + + } else { + + c1_device = dm->second.first; + c1_device_cat = dm->second.second; + + device_map.erase (dm); + + } + + } + + if (c1_device) { + db::DeviceCompare dc; - if (! dc.equals (dm->second, std::make_pair (d.operator-> (), device_cat))) { - if (dm->second.second != device_cat) { + if (! dc.equals (std::make_pair (c1_device, c1_device_cat), std::make_pair (d.operator-> (), device_cat))) { + if (c1_device_cat != device_cat) { if (mp_logger) { - mp_logger->match_devices_with_different_device_classes (dm->second.first, d.operator-> ()); + mp_logger->match_devices_with_different_device_classes (c1_device, d.operator-> ()); } good = false; } else { if (mp_logger) { - mp_logger->match_devices_with_different_parameters (dm->second.first, d.operator-> ()); + mp_logger->match_devices_with_different_parameters (c1_device, d.operator-> ()); } good = false; } } else { if (mp_logger) { - mp_logger->match_devices (dm->second.first, d.operator-> ()); + mp_logger->match_devices (c1_device, d.operator-> ()); } } - device_map.erase (dm); - } } @@ -3426,7 +4041,7 @@ NetlistComparer::do_device_assignment (const db::Circuit *c1, const db::NetGraph } void -NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, CircuitCategorizer &circuit_categorizer, const CircuitPinMapper &circuit_pin_mapper, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping, bool &good) const +NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, CircuitCategorizer &circuit_categorizer, const CircuitPinMapper &circuit_pin_mapper, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping, SubCircuitEquivalenceTracker &subcircuit_eq, bool &good) const { // Report subcircuit assignment @@ -3440,16 +4055,13 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG continue; } - std::vector > k; - bool valid = compute_subcircuit_key (*sc, g1, &c12_circuit_and_pin_mapping, &circuit_pin_mapper, k); - - bool mapped = true; - for (std::vector >::iterator i = k.begin (); i != k.end () && mapped; ++i) { - if (! g1.begin () [i->second].has_other ()) { - mapped = false; - } + if (subcircuit_eq.other (sc.operator-> ())) { + continue; } + bool mapped = true, valid = true; + std::vector > k = compute_subcircuit_key_for_this (*sc, g1, &c12_circuit_and_pin_mapping, &circuit_pin_mapper, mapped, valid); + if (! mapped) { if (mp_logger) { mp_logger->subcircuit_mismatch (sc.operator-> (), 0); @@ -3473,75 +4085,93 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG continue; } - std::vector > k; - compute_subcircuit_key (*sc, g2, &c22_circuit_and_pin_mapping, &circuit_pin_mapper, k); + const db::SubCircuit *sc_this = subcircuit_eq.other (sc.operator-> ()); + if (sc_this) { - bool mapped = true; - for (std::vector >::iterator i = k.begin (); i != k.end (); ++i) { - if (! g2.begin () [i->second].has_other ()) { - mapped = false; + size_t sc_cat_this = circuit_categorizer.cat_for_subcircuit (sc_this); + if (! sc_cat_this) { + // subcircuit is ignored + continue; + } + + bool mapped1 = true, mapped2 = true; + bool valid1 = true, valid2 = true; + std::vector > k_this = compute_subcircuit_key_for_this (*sc_this, g1, &c12_circuit_and_pin_mapping, &circuit_pin_mapper, mapped1, valid1); + std::vector > k = compute_subcircuit_key_for_other (*sc, g2, &c22_circuit_and_pin_mapping, &circuit_pin_mapper, mapped2, valid2); + + if (! valid1 || ! valid2 || ! mapped1 || ! mapped2 || k_this != k || sc_cat != sc_cat_this) { + if (mp_logger) { + mp_logger->subcircuit_mismatch (sc_this, sc.operator-> ()); + } + good = false; } else { - i->second = g2.begin () [i->second].other_net_index (); + if (mp_logger) { + mp_logger->match_subcircuits (sc_this, sc.operator-> ()); + } } - } - - std::sort (k.begin (), k.end ()); - - std::multimap >, std::pair >::iterator scm = subcircuit_map.find (k); - - if (! mapped || scm == subcircuit_map.end ()) { - - if (mp_logger) { - unmatched_b.push_back (std::make_pair (k, sc.operator-> ())); - } - good = false; } else { - db::SubCircuitCompare scc; + bool mapped = true, valid = true; + std::vector > k = compute_subcircuit_key_for_other (*sc, g2, &c22_circuit_and_pin_mapping, &circuit_pin_mapper, mapped, valid); - std::multimap >, std::pair >::iterator scm_start = scm; + std::multimap >, std::pair >::iterator scm = subcircuit_map.find (k); - bool found = false; - size_t nscm = 0; - while (! found && scm != subcircuit_map.end () && scm->first == k) { - ++nscm; - if (scc.equals (scm->second, std::make_pair (sc.operator-> (), sc_cat))) { - found = true; + if (! mapped || scm == subcircuit_map.end () || scm->first != k) { + + if (mp_logger) { + unmatched_b.push_back (std::make_pair (k, sc.operator-> ())); } - } - - if (! found) { - - if (nscm == 1) { - - // unique match, but doesn't fit: report this one as paired, but mismatching: - if (mp_logger) { - mp_logger->subcircuit_mismatch (scm_start->second.first, sc.operator-> ()); - } - - // no longer look for this one - subcircuit_map.erase (scm_start); - - } else { - - // no unqiue match - if (mp_logger) { - mp_logger->subcircuit_mismatch (0, sc.operator-> ()); - } - - } - good = false; } else { - if (mp_logger) { - mp_logger->match_subcircuits (scm->second.first, sc.operator-> ()); + db::SubCircuitCompare scc; + + std::multimap >, std::pair >::iterator scm_start = scm; + + bool found = false; + size_t nscm = 0; + while (! found && scm != subcircuit_map.end () && scm->first == k) { + ++nscm; + if (scc.equals (scm->second, std::make_pair (sc.operator-> (), sc_cat))) { + found = true; + } } - // no longer look for this one - subcircuit_map.erase (scm); + if (! found) { + + if (nscm == 1) { + + // unique match, but doesn't fit: report this one as paired, but mismatching: + if (mp_logger) { + mp_logger->subcircuit_mismatch (scm_start->second.first, sc.operator-> ()); + } + + // no longer look for this one + subcircuit_map.erase (scm_start); + + } else { + + // no unqiue match + if (mp_logger) { + mp_logger->subcircuit_mismatch (0, sc.operator-> ()); + } + + } + + good = false; + + } else { + + if (mp_logger) { + mp_logger->match_subcircuits (scm->second.first, sc.operator-> ()); + } + + // no longer look for this one + subcircuit_map.erase (scm); + + } } @@ -3731,12 +4361,15 @@ NetlistComparer::join_symmetric_nets (db::Circuit *circuit) // nodes are identical if the attached devices and circuits are of the same kind and with the same parameters // and connect to other nodes in identical configurations. - std::vector nodes; + std::vector > nodes; + + std::vector no_edges; + no_edges.push_back (NetGraphNode::edge_type ()); nodes.reserve (graph.end () - graph.begin ()); for (db::NetGraph::node_iterator i = graph.begin (); i != graph.end (); ++i) { if (! i->has_other () && i->net ()) { - nodes.push_back (i.operator-> ()); + nodes.push_back (std::make_pair (i.operator-> (), no_edges.begin ())); } } @@ -3746,18 +4379,18 @@ NetlistComparer::join_symmetric_nets (db::Circuit *circuit) tl::equivalence_clusters identical_nodes; - for (std::vector::const_iterator np = nodes.begin (); np + 1 != nodes.end (); ++np) { - if (*np[0] == *np[1]) { - identical_nodes.same (np[0], np[1]); + for (std::vector >::const_iterator np = nodes.begin (); np + 1 != nodes.end (); ++np) { + if (*np[0].first == *np[1].first) { + identical_nodes.same (np[0].first, np[1].first); } } std::vector > symmetry_groups; std::set visited; - for (std::vector::const_iterator np = nodes.begin (); np != nodes.end (); ++np) { + for (std::vector >::const_iterator np = nodes.begin (); np != nodes.end (); ++np) { - size_t node_id = graph.node_index_for_net (np[0]->net ()); + size_t node_id = graph.node_index_for_net (np[0].first->net ()); if (visited.find (node_id) != visited.end ()) { continue; } diff --git a/src/db/db/dbNetlistCompare.h b/src/db/db/dbNetlistCompare.h index d639ed12f..2edd6062c 100644 --- a/src/db/db/dbNetlistCompare.h +++ b/src/db/db/dbNetlistCompare.h @@ -38,6 +38,8 @@ class DeviceCategorizer; class CircuitCategorizer; class CircuitMapper; class NetGraph; +class SubCircuitEquivalenceTracker; +class DeviceEquivalenceTracker; /** * @brief A receiver for netlist compare events @@ -285,6 +287,26 @@ public: return m_max_n_branch; } + /** + * @brief Sets a value indicating depth-first traversal + * + * With depth first (the default), the algorithm looks for further identities before moving to another + * node. With breadth first (false), the algorithm will work in "waves" rather than digging deerly + * into the direction of a node. + */ + void set_depth_first (bool df) + { + m_depth_first = df; + } + + /** + * @brief Gets a value indicating depth-first traversal + */ + bool depth_first () const + { + return m_depth_first; + } + /** * @brief Gets the list of circuits without matching circuit in the other netlist * The result can be used to flatten these circuits prior to compare. @@ -326,8 +348,8 @@ protected: bool all_subcircuits_verified (const db::Circuit *c, const std::set &verified_circuits) const; static void derive_pin_equivalence (const db::Circuit *ca, const db::Circuit *cb, CircuitPinMapper *circuit_pin_mapper); void do_pin_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping, bool &pin_mismatch, bool &good) const; - void do_device_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, const db::DeviceFilter &device_filter, DeviceCategorizer &device_categorizer, bool &good) const; - void do_subcircuit_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, CircuitCategorizer &circuit_categorizer, const db::CircuitPinMapper &circuit_pin_mapper, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping, bool &good) const; + void do_device_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, const db::DeviceFilter &device_filter, DeviceCategorizer &device_categorizer, db::DeviceEquivalenceTracker &device_eq, bool &good) const; + void do_subcircuit_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, CircuitCategorizer &circuit_categorizer, const db::CircuitPinMapper &circuit_pin_mapper, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping, db::SubCircuitEquivalenceTracker &subcircuit_eq, bool &good) const; bool handle_pin_mismatch (const NetGraph &g1, const db::Circuit *c1, const db::Pin *pin1, const NetGraph &g2, const db::Circuit *c2, const db::Pin *p2) const; mutable NetlistCompareLogger *mp_logger; @@ -339,6 +361,7 @@ protected: double m_res_threshold; size_t m_max_n_branch; size_t m_max_depth; + bool m_depth_first; bool m_dont_consider_net_names; }; diff --git a/src/db/unit_tests/dbNetlistCompareTests.cc b/src/db/unit_tests/dbNetlistCompareTests.cc index c0d190f6d..718d85ffd 100644 --- a/src/db/unit_tests/dbNetlistCompareTests.cc +++ b/src/db/unit_tests/dbNetlistCompareTests.cc @@ -1147,8 +1147,8 @@ TEST(5_BufferTwoPathsDifferentDeviceClasses) "begin_circuit BUF BUF\n" "match_nets INT $10\n" "match_nets IN IN\n" - "net_mismatch OUT OUT\n" "net_mismatch INT2 $11\n" + "net_mismatch OUT OUT\n" "match_pins $0 $1\n" "match_pins $1 $3\n" "match_pins $2 $0\n" @@ -1212,8 +1212,35 @@ TEST(6_BufferTwoPathsAdditionalResistor) "begin_circuit BUF BUF\n" "net_mismatch INT $10\n" "match_nets IN IN\n" + "net_mismatch INT2 $11\n" + "match_nets OUT OUT\n" + "match_pins $0 $1\n" + "match_pins $1 $3\n" + "match_pins $2 $0\n" + "match_pins $3 $2\n" + "match_devices $1 $1\n" + "match_devices $3 $2\n" + "match_devices $5 $3\n" + "match_devices $7 $4\n" + "match_devices $2 $5\n" + "match_devices $4 $6\n" + "match_devices $6 $7\n" + "match_devices $8 $8\n" + "device_mismatch (null) $9\n" + "end_circuit BUF BUF NOMATCH" + ); + EXPECT_EQ (good, false); + + comp.set_depth_first (false); + logger.clear (); + good = comp.compare (&nl1, &nl2); + + EXPECT_EQ (logger.text (), + "begin_circuit BUF BUF\n" + "net_mismatch INT $10\n" "match_nets OUT OUT\n" "net_mismatch INT2 $11\n" + "match_nets IN IN\n" "match_pins $0 $1\n" "match_pins $1 $3\n" "match_pins $2 $0\n" @@ -1274,9 +1301,9 @@ TEST(6_BufferTwoPathsAdditionalDevices) "match_nets INT $11\n" "net_mismatch VDD VDD\n" "match_nets IN IN\n" + "net_mismatch INT2 $10\n" "net_mismatch VSS VSS\n" "net_mismatch OUT OUT\n" - "net_mismatch INT2 $10\n" "match_pins $0 $1\n" "match_pins $1 $3\n" "match_pins $2 $0\n" @@ -2552,8 +2579,8 @@ TEST(17_InherentlyAmbiguousDecoder) "match_ambiguous_nets NQ1 NQ1\n" "match_ambiguous_nets NQ2 NQ2\n" "match_nets NQ3 NQ3\n" - "match_ambiguous_nets NA NA\n" - "match_ambiguous_nets NB NB\n" + "match_nets NA NA\n" + "match_nets NB NB\n" "match_nets B B\n" "match_nets A A\n" "match_pins $0 $1\n" @@ -2657,10 +2684,61 @@ TEST(17_InherentlyAmbiguousDecoder) "match_nets B B\n" "match_nets NB NB\n" "match_nets NA NA\n" - "match_nets NQ0 NQ0\n" - "match_nets NQ2 NQ2\n" "match_nets NQ1 NQ1\n" "match_nets NQ3 NQ3\n" + "match_nets NQ2 NQ2\n" + "match_nets NQ0 NQ0\n" + "match_pins $0 $1\n" + "match_pins $1 $0\n" + "match_pins $2 $2\n" + "match_pins $3 $3\n" + "match_pins $4 $4\n" + "match_pins $5 $5\n" + "match_pins $6 $6\n" + "match_pins $7 $7\n" + "match_subcircuits $1 $1\n" + "match_subcircuits $2 $2\n" + "match_subcircuits $4 $3\n" + "match_subcircuits $6 $4\n" + "match_subcircuits $3 $5\n" + "match_subcircuits $5 $6\n" + "end_circuit DECODER DECODER MATCH" + ); + + EXPECT_EQ (good, true); + + comp.set_depth_first (false); + logger.clear (); + good = comp.compare (&nl1, &nl2); + + EXPECT_EQ (logger.text (), + "begin_circuit NAND NAND\n" + "match_nets VSS VSS\n" + "match_nets INT INT\n" + "match_nets OUT OUT\n" + "match_nets VDD VDD\n" + "match_nets B B\n" + "match_nets A A\n" + "match_pins $0 $0\n" + "match_pins $1 $1\n" + "match_pins $2 $2\n" + "match_pins $3 $3\n" + "match_pins $4 $4\n" + "match_devices $1 $1\n" + "match_devices $2 $2\n" + "match_devices $3 $3\n" + "match_devices $4 $4\n" + "end_circuit NAND NAND MATCH\n" + "begin_circuit DECODER DECODER\n" + "match_nets VSS VSS\n" + "match_nets VDD VDD\n" + "match_nets NA NA\n" + "match_nets NB NB\n" + "match_nets B B\n" + "match_nets NQ1 NQ1\n" + "match_nets NQ3 NQ3\n" + "match_nets NQ2 NQ2\n" + "match_nets NQ0 NQ0\n" "match_pins $0 $1\n" "match_pins $1 $0\n" "match_pins $2 $2\n" @@ -2794,6 +2872,67 @@ TEST(18_ClockTree) "end_circuit TXEE TXEE MATCH" ); EXPECT_EQ (good, true); + + comp.set_depth_first (false); + logger.clear (); + good = comp.compare (&nl1, &nl2); + + txt = logger.text (); + // because L/R matching is ambiguous, we need to do this to + // establish reproducability on different platforms: + txt = tl::replaced (txt, "L", "X"); + txt = tl::replaced (txt, "R", "X"); + + EXPECT_EQ (txt, + "begin_circuit INV INV\n" + "match_nets VDD VDD\n" + "match_nets OUT OUT\n" + "match_nets IN IN\n" + "match_nets VSS VSS\n" + "match_pins IN IN\n" + "match_pins OUT OUT\n" + "match_pins VDD VDD\n" + "match_pins VSS VSS\n" + "match_devices $1 $1\n" + "match_devices $2 $2\n" + "end_circuit INV INV MATCH\n" + "begin_circuit TXEE TXEE\n" + "match_nets IN IN\n" + "match_nets VSS VSS\n" + "match_nets VDD VDD\n" + "match_nets S S\n" + "match_ambiguous_nets SX SX\n" + "match_ambiguous_nets SX SX\n" + "match_ambiguous_nets SXX SXX\n" + "match_ambiguous_nets SXX SXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_ambiguous_nets SXX SXX\n" + "match_ambiguous_nets SXX SXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_ambiguous_nets SXXX SXXX\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits TX TX\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits TXX TXX\n" + "match_subcircuits TXX TXX\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits T T\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits TX TX\n" + "match_subcircuits TXX TXX\n" + "match_subcircuits TXXX TXXX\n" + "match_subcircuits TXX TXX\n" + "end_circuit TXEE TXEE MATCH" + ); + EXPECT_EQ (good, true); } TEST(19_SymmetricCircuit) @@ -2922,24 +3061,123 @@ TEST(19_SymmetricCircuit) "match_nets g1 G1\n" "match_nets $44 YI\n" "match_nets $14 WELL\n" - "match_nets $8 NET215\n" - "match_nets $9 NET175\n" - "match_nets $6 NET181\n" - "match_nets $4 NET200\n" - "match_nets nn1 NN1\n" - "match_nets $11 CS0\n" - "match_nets $13 CS1\n" "match_nets nn2 NN2\n" "match_nets nn2_ NN2_\n" - "match_nets q0 Q0\n" - "match_nets q1 Q1\n" + "match_ambiguous_nets q0 Q0\n" + "match_ambiguous_nets q1 Q1\n" + "match_nets $11 CS0\n" "match_nets q0_ Q0_\n" + "match_nets $6 NET181\n" + "match_nets nn1 NN1\n" + "match_nets $8 NET215\n" + "match_nets $13 CS1\n" "match_nets q1_ Q1_\n" - "match_nets a0_ A0_\n" - "match_nets $34 HNET48\n" - "match_nets nn1_ NN1_\n" "match_nets a0 A0\n" "match_nets $35 HNET44\n" + "match_nets nn1_ NN1_\n" + "match_nets $9 NET175\n" + "match_nets $4 NET200\n" + "match_nets a0_ A0_\n" + "match_nets $34 HNET48\n" + "match_pins VDD VDD\n" + "match_pins nn1_ NN1_\n" + "match_pins nn1 NN1\n" + "match_pins q0 Q0\n" + "match_pins q0_ Q0_\n" + "match_pins q1_ Q1_\n" + "match_pins q1 Q1\n" + "match_pins nn2 NN2\n" + "match_pins nn2_ NN2_\n" + "match_pins a0 A0\n" + "match_pins a0_ A0_\n" + "match_pins g1 G1\n" + "match_pins g0 G0\n" + "match_pins gtp NN3\n" + "match_pins VSS VSS\n" + "match_pins WELL WELL\n" + "match_devices $30 0\n" + "match_devices $29 1\n" + "match_devices $9 10\n" + "match_devices $10 11\n" + "match_devices $36 12\n" + "match_devices $35 13\n" + "match_devices $34 14\n" + "match_devices $38 15\n" + "match_devices $37 16\n" + "match_devices $33 17\n" + "match_devices $27 18\n" + "match_devices $28 19\n" + "match_devices $17 2\n" + "match_devices $31 20\n" + "match_devices $32 21\n" + "match_devices $22 22\n" + "match_devices $26 23\n" + "match_devices $23 24\n" + "match_devices $43 25\n" + "match_devices $20 26\n" + "match_devices $25 27\n" + "match_devices $15 28\n" + "match_devices $14 29\n" + "match_devices $16 3\n" + "match_devices $18 30\n" + "match_devices $21 31\n" + "match_devices $13 32\n" + "match_devices $19 33\n" + "match_devices $7 34\n" + "match_devices $8 35\n" + "match_devices $24 36\n" + "match_devices $3 37\n" + "match_devices $6 38\n" + "match_devices $4 39\n" + "match_devices $39 4\n" + "match_devices $5 40\n" + "match_devices $2 41\n" + "match_devices $1 42\n" + "match_devices $40 5\n" + "match_devices $11 6\n" + "match_devices $12 7\n" + "match_devices $41 8\n" + "match_devices $42 9\n" + "end_circuit DECODE DECODE MATCH" + ); + EXPECT_EQ (good, true); + + comp.set_depth_first (false); + logger.clear (); + good = comp.compare (&nl1, &nl2); + + EXPECT_EQ (logger.text (), + "begin_circuit DECODE DECODE\n" + "match_nets $41 WL1_EN_\n" + "match_nets VDD VDD\n" + "match_nets $39 NET194\n" + "match_nets g0 G0\n" + "match_nets $40 HNET52\n" + "match_nets VSS VSS\n" + "match_nets $42 NET189\n" + "match_nets gtp NN3\n" + "match_nets $37 NET193\n" + "match_nets g1 G1\n" + "match_nets $44 YI\n" + "match_nets $14 WELL\n" + "match_nets nn2 NN2\n" + "match_nets nn2_ NN2_\n" + "match_ambiguous_nets q0 Q0\n" + "match_ambiguous_nets q1 Q1\n" + "match_nets $11 CS0\n" + "match_nets q0_ Q0_\n" + "match_nets $4 NET200\n" + "match_nets $13 CS1\n" + "match_nets q1_ Q1_\n" + "match_nets $9 NET175\n" + "match_nets a0 A0\n" + "match_nets a0_ A0_\n" + "match_nets $35 HNET44\n" + "match_nets $34 HNET48\n" + "match_nets $6 NET181\n" + "match_nets $8 NET215\n" + "match_nets nn1 NN1\n" + "match_nets nn1_ NN1_\n" "match_pins VDD VDD\n" "match_pins nn1_ NN1_\n" "match_pins nn1 NN1\n" @@ -3805,11 +4043,11 @@ TEST(25c_JoinSymmetricNetsMultipleMessedUp) // NOTE $1 and $2 are joined because they are symmetric EXPECT_EQ (nl.to_string (), "circuit NOR3 (A=A,C=C,B=B,OUT=OUT,VSS=VSS,VDD=VDD);\n" - " device PMOS $1 (S=$5,G=B,D=$3) (L=0.27,W=3.3,AS=0,AD=0,PS=0,PD=0);\n" + " device PMOS $1 (S=$6,G=B,D=$3) (L=0.27,W=3.3,AS=0,AD=0,PS=0,PD=0);\n" " device NMOS $2 (S=OUT,G=A,D=VSS) (L=0.23,W=2.05,AS=0,AD=0,PS=0,PD=0);\n" " device PMOS $3 (S=$3,G=A,D=OUT) (L=0.27,W=3.3,AS=0,AD=0,PS=0,PD=0);\n" " device NMOS $4 (S=OUT,G=B,D=VSS) (L=0.23,W=2.05,AS=0,AD=0,PS=0,PD=0);\n" - " device PMOS $8 (S=VDD,G=C,D=$5) (L=0.27,W=3.3,AS=0,AD=0,PS=0,PD=0);\n" + " device PMOS $8 (S=VDD,G=C,D=$6) (L=0.27,W=3.3,AS=0,AD=0,PS=0,PD=0);\n" " device NMOS $12 (S=VSS,G=C,D=OUT) (L=0.23,W=2.05,AS=0,AD=0,PS=0,PD=0);\n" "end;\n" ) diff --git a/testdata/lvs/double_height2.lvsdb b/testdata/lvs/double_height2.lvsdb index f9d933d9c..b75ed63bc 100644 --- a/testdata/lvs/double_height2.lvsdb +++ b/testdata/lvs/double_height2.lvsdb @@ -314,8 +314,8 @@ Z( N(5 2 1) N(4 1 1) N(2 4 1) - P(2 () 1) P(0 () 1) + P(2 () 1) P(4 () 1) P(3 () 1) P(1 () 1) diff --git a/testdata/lvs/ringo_simple_dmos.lvsdb.1 b/testdata/lvs/ringo_simple_dmos.lvsdb.1 index 47ac96fa8..f68490049 100644 --- a/testdata/lvs/ringo_simple_dmos.lvsdb.1 +++ b/testdata/lvs/ringo_simple_dmos.lvsdb.1 @@ -867,8 +867,8 @@ xref( pin(6 6 match) pin(0 0 match) pin(2 2 match) - device(4 4 match) device(3 3 mismatch) + device(4 4 match) device(2 2 match) device(1 1 mismatch) ) diff --git a/testdata/lvs/ringo_simple_dmos.lvsdb.2 b/testdata/lvs/ringo_simple_dmos.lvsdb.2 deleted file mode 100644 index 45fc263a5..000000000 --- a/testdata/lvs/ringo_simple_dmos.lvsdb.2 +++ /dev/null @@ -1,912 +0,0 @@ -#%lvsdb-klayout - -# Layout -layout( - top(RINGO) - unit(0.001) - - # Layer section - # This section lists the mask layers (drawing or derived) and their connections. - - # Mask layers - layer(l4 '1/0') - layer(l5 '5/0') - layer(l10 '8/0') - layer(l13 '9/0') - layer(l14 '10/0') - layer(l15 '11/0') - layer(l9) - layer(l3) - layer(l1) - layer(l11) - layer(l8) - layer(l6) - layer(l12) - - # Mask layer connectivity - connect(l4 l4 l11) - connect(l5 l5 l10) - connect(l10 l5 l10 l13 l3 l1 l11 l8 l6 l12) - connect(l13 l10 l13 l14) - connect(l14 l13 l14 l15) - connect(l15 l14 l15) - connect(l9 l9) - connect(l3 l10 l3) - connect(l1 l10 l1) - connect(l11 l4 l10 l11) - connect(l8 l10 l8) - connect(l6 l10 l6) - connect(l12 l10 l12) - - # Global nets and connectivity - global(l9 SUBSTRATE) - global(l12 SUBSTRATE) - - # Device class section - class(PMOS MOS4) - class(NMOS MOS4) - - # Device abstracts section - # Device abstracts list the pin shapes of the devices. - device(D$PMOS PMOS - terminal(S - rect(l3 (125 -750) (450 1500)) - ) - terminal(G - rect(l5 (-125 -750) (250 1500)) - ) - terminal(D - rect(l1 (-550 -750) (425 1500)) - ) - terminal(B - rect(l4 (-125 -750) (250 1500)) - ) - ) - device(D$PMOS$1 PMOS - terminal(S - rect(l3 (-575 -750) (450 1500)) - ) - terminal(G - rect(l5 (-125 -750) (250 1500)) - ) - terminal(D - rect(l1 (125 -750) (425 1500)) - ) - terminal(B - rect(l4 (-125 -750) (250 1500)) - ) - ) - device(D$PMOS$2 PMOS - terminal(S - rect(l3 (-550 -750) (425 1500)) - ) - terminal(G - rect(l5 (-125 -750) (250 1500)) - ) - terminal(D - rect(l1 (125 -750) (425 1500)) - ) - terminal(B - rect(l4 (-125 -750) (250 1500)) - ) - ) - device(D$NMOS NMOS - terminal(S - rect(l8 (125 -475) (450 950)) - ) - terminal(G - rect(l5 (-125 -475) (250 950)) - ) - terminal(D - rect(l6 (-550 -475) (425 950)) - ) - terminal(B - rect(l9 (-125 -475) (250 950)) - ) - ) - device(D$NMOS$1 NMOS - terminal(S - rect(l8 (-575 -475) (450 950)) - ) - terminal(G - rect(l5 (-125 -475) (250 950)) - ) - terminal(D - rect(l6 (125 -475) (425 950)) - ) - terminal(B - rect(l9 (-125 -475) (250 950)) - ) - ) - device(D$NMOS$2 NMOS - terminal(S - rect(l8 (-550 -475) (425 950)) - ) - terminal(G - rect(l5 (-125 -475) (250 950)) - ) - terminal(D - rect(l6 (125 -475) (425 950)) - ) - terminal(B - rect(l9 (-125 -475) (250 950)) - ) - ) - - # Circuit section - # Circuits are the hierarchical building blocks of the netlist. - circuit(ND2X1 - - # Circuit boundary - rect((-100 400) (2600 7600)) - - # Nets with their geometries - net(1 name(VDD) - rect(l10 (1110 5160) (180 180)) - rect(l10 (-180 920) (180 180)) - rect(l10 (-180 -730) (180 180)) - rect(l13 (-240 -790) (300 1700)) - rect(l13 (-1350 0) (2400 800)) - rect(l13 (-1151 -401) (2 2)) - rect(l3 (-251 -2151) (425 1500)) - rect(l3 (-450 -1500) (425 1500)) - ) - net(2 name(OUT) - rect(l10 (1810 1770) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l10 (-1580 3760) (180 180)) - rect(l10 (-180 -730) (180 180)) - rect(l10 (-180 -730) (180 180)) - rect(l10 (1220 920) (180 180)) - rect(l10 (-180 -1280) (180 180)) - rect(l10 (-180 370) (180 180)) - polygon(l13 (-240 -4180) (0 1390) (490 0) (0 -300) (-190 0) (0 -1090)) - rect(l13 (-110 1390) (300 1400)) - polygon(l13 (-1890 0) (0 600) (300 0) (0 -300) (1590 0) (0 -300)) - rect(l13 (-141 -501) (2 2)) - rect(l13 (-1751 1099) (300 1400)) - rect(l13 (1100 -1700) (300 300)) - rect(l13 (-300 0) (300 1400)) - rect(l1 (-1750 -1450) (425 1500)) - rect(l1 (950 -1500) (425 1500)) - rect(l6 (-425 -4890) (425 950)) - ) - net(3 name(VSS) - rect(l10 (410 1770) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l13 (-240 -1300) (300 1360)) - rect(l13 (-650 -2160) (2400 800)) - rect(l13 (-1151 -401) (2 2)) - rect(l6 (-951 859) (425 950)) - ) - net(4 - rect(l8 (1000 1660) (425 950)) - rect(l8 (-450 -950) (425 950)) - ) - net(5 - rect(l4 (-100 4500) (2600 3500)) - ) - net(6 name(B) - rect(l5 (1425 2860) (250 1940)) - rect(l5 (-345 -950) (300 300)) - rect(l5 (-205 650) (250 2000)) - rect(l5 (-250 -2000) (250 2000)) - rect(l5 (-250 -5390) (250 1450)) - rect(l10 (-285 1050) (180 180)) - rect(l13 (-71 -91) (2 2)) - rect(l13 (-171 -151) (300 300)) - ) - net(7 name(A) - rect(l5 (725 2860) (250 1940)) - rect(l5 (-325 -1850) (300 300)) - rect(l5 (-225 1550) (250 2000)) - rect(l5 (-250 -2000) (250 2000)) - rect(l5 (-250 -5390) (250 1450)) - rect(l10 (-265 150) (180 180)) - rect(l13 (-91 -91) (2 2)) - rect(l13 (-151 -151) (300 300)) - ) - net(8 name(SUBSTRATE)) - - # Outgoing pins and their connections to nets - pin(1 name(VDD)) - pin(2 name(OUT)) - pin(3 name(VSS)) - pin(5) - pin(6 name(B)) - pin(7 name(A)) - pin(8 name(SUBSTRATE)) - - # Devices and their connections - device(1 D$PMOS - location(850 5800) - param(L 0.25) - param(W 1.5) - param(AS 0.3375) - param(AD 0.6375) - param(PS 1.95) - param(PD 3.85) - terminal(S 1) - terminal(G 7) - terminal(D 2) - terminal(B 5) - ) - device(2 D$PMOS$1 - location(1550 5800) - param(L 0.25) - param(W 1.5) - param(AS 0.3375) - param(AD 0.6375) - param(PS 1.95) - param(PD 3.85) - terminal(S 1) - terminal(G 6) - terminal(D 2) - terminal(B 5) - ) - device(3 D$NMOS - location(850 2135) - param(L 0.25) - param(W 0.95) - param(AS 0.21375) - param(AD 0.40375) - param(PS 1.4) - param(PD 2.75) - terminal(S 4) - terminal(G 7) - terminal(D 3) - terminal(B 8) - ) - device(4 D$NMOS$1 - location(1550 2135) - param(L 0.25) - param(W 0.95) - param(AS 0.21375) - param(AD 0.40375) - param(PS 1.4) - param(PD 2.75) - terminal(S 4) - terminal(G 6) - terminal(D 2) - terminal(B 8) - ) - - ) - circuit(INVX1 - - # Circuit boundary - rect((-100 400) (2000 7600)) - - # Nets with their geometries - net(1 name(VDD) - rect(l10 (410 6260) (180 180)) - rect(l10 (-180 -730) (180 180)) - rect(l10 (-180 -730) (180 180)) - rect(l13 (-240 -240) (300 1400)) - rect(l13 (-650 300) (1800 800)) - rect(l13 (-1450 -1100) (300 300)) - rect(l13 (299 399) (2 2)) - rect(l3 (-651 -2151) (425 1500)) - ) - net(2 name(OUT) - rect(l10 (1110 5160) (180 180)) - rect(l10 (-180 920) (180 180)) - rect(l10 (-180 -730) (180 180)) - rect(l10 (-180 -4120) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l13 (-240 -790) (300 4790)) - rect(l13 (-151 -2501) (2 2)) - rect(l1 (-226 1049) (425 1500)) - rect(l6 (-425 -4890) (425 950)) - ) - net(3 name(VSS) - rect(l10 (410 1770) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l13 (-240 -1300) (300 1360)) - rect(l13 (-650 -2160) (1800 800)) - rect(l13 (-851 -401) (2 2)) - rect(l8 (-651 859) (425 950)) - ) - net(4 - rect(l4 (-100 4500) (2000 3500)) - ) - net(5 name(IN) - rect(l5 (725 2860) (250 1940)) - rect(l5 (-525 -1850) (300 300)) - rect(l5 (-25 1550) (250 2000)) - rect(l5 (-250 -2000) (250 2000)) - rect(l5 (-250 -5390) (250 1450)) - rect(l10 (-465 150) (180 180)) - rect(l13 (-91 -91) (2 2)) - rect(l13 (-151 -151) (300 300)) - ) - net(6 name(SUBSTRATE)) - - # Outgoing pins and their connections to nets - pin(1 name(VDD)) - pin(2 name(OUT)) - pin(3 name(VSS)) - pin(4) - pin(5 name(IN)) - pin(6 name(SUBSTRATE)) - - # Devices and their connections - device(1 D$PMOS$2 - location(850 5800) - param(L 0.25) - param(W 1.5) - param(AS 0.6375) - param(AD 0.6375) - param(PS 3.85) - param(PD 3.85) - terminal(S 1) - terminal(G 5) - terminal(D 2) - terminal(B 4) - ) - device(2 D$NMOS$2 - location(850 2135) - param(L 0.25) - param(W 0.95) - param(AS 0.40375) - param(AD 0.40375) - param(PS 2.75) - param(PD 2.75) - terminal(S 3) - terminal(G 5) - terminal(D 2) - terminal(B 6) - ) - - ) - circuit(RINGO - - # Circuit boundary - rect((0 350) (25800 7650)) - - # Nets with their geometries - net(1 - rect(l13 (4040 2950) (610 300)) - ) - net(2 - rect(l13 (5550 2950) (900 300)) - ) - net(3 - rect(l13 (7350 2950) (900 300)) - ) - net(4 - rect(l13 (9150 2950) (900 300)) - ) - net(5 - rect(l13 (10950 2950) (900 300)) - ) - net(6 - rect(l13 (12750 2950) (900 300)) - ) - net(7 - rect(l13 (14550 2950) (900 300)) - ) - net(8 - rect(l13 (16350 2950) (900 300)) - ) - net(9 - rect(l13 (18150 2950) (900 300)) - ) - net(10 - rect(l13 (19950 2950) (900 300)) - ) - net(11 name(FB) - rect(l13 (21750 2950) (900 300)) - rect(l13 (-19530 590) (320 320)) - rect(l13 (17820 -320) (320 320)) - rect(l14 (-18400 -260) (200 200)) - rect(l14 (17940 -200) (200 200)) - rect(l15 (-18040 -300) (17740 400)) - rect(l15 (-17921 -201) (2 2)) - rect(l15 (-221 -201) (400 400)) - rect(l15 (17740 -400) (400 400)) - ) - net(12 name(VDD) - rect(l4 (500 4500) (1400 3500)) - rect(l4 (-1900 -3500) (600 3500)) - rect(l4 (23300 -3500) (1400 3500)) - rect(l4 (-100 -3500) (600 3500)) - rect(l10 (-24690 -1240) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l10 (-180 -1280) (180 180)) - rect(l10 (23220 370) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l10 (-180 -1280) (180 180)) - rect(l13 (-21741 859) (2 2)) - rect(l13 (-2351 -451) (1200 800)) - rect(l13 (-750 -1450) (300 1400)) - rect(l13 (-101 -351) (2 2)) - rect(l13 (-1251 -401) (600 800)) - rect(l13 (23400 -800) (1200 800)) - rect(l13 (-750 -1450) (300 1400)) - rect(l13 (-101 -351) (2 2)) - rect(l13 (549 -401) (600 800)) - rect(l11 (-24850 -1500) (500 1500)) - rect(l11 (22900 -1500) (500 1500)) - ) - net(13 name(OUT) - rect(l13 (23440 3840) (320 320)) - rect(l14 (-260 -260) (200 200)) - rect(l15 (-101 -101) (2 2)) - rect(l15 (-201 -201) (400 400)) - ) - net(14 name(ENABLE) - rect(l13 (2440 2940) (320 320)) - rect(l14 (-260 -260) (200 200)) - rect(l15 (-101 -101) (2 2)) - rect(l15 (-201 -201) (400 400)) - ) - net(15 name(VSS) - rect(l10 (1110 1610) (180 180)) - rect(l10 (-180 -1280) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l10 (23220 370) (180 180)) - rect(l10 (-180 -1280) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l13 (-21741 -391) (2 2)) - rect(l13 (-1901 -401) (300 1400)) - rect(l13 (-750 -1450) (1200 800)) - rect(l13 (-551 -401) (2 2)) - rect(l13 (-1251 -401) (600 800)) - rect(l13 (23850 -750) (300 1400)) - rect(l13 (-750 -1450) (1200 800)) - rect(l13 (-551 -401) (2 2)) - rect(l13 (549 -401) (600 800)) - rect(l12 (-24850 -800) (500 1500)) - rect(l12 (22900 -1500) (500 1500)) - ) - - # Outgoing pins and their connections to nets - pin(11 name(FB)) - pin(12 name(VDD)) - pin(13 name(OUT)) - pin(14 name(ENABLE)) - pin(15 name(VSS)) - - # Subcircuits and their connections - circuit(1 ND2X1 location(1800 0) - pin(0 12) - pin(1 1) - pin(2 15) - pin(3 12) - pin(4 11) - pin(5 14) - pin(6 15) - ) - circuit(2 INVX1 location(4200 0) - pin(0 12) - pin(1 2) - pin(2 15) - pin(3 12) - pin(4 1) - pin(5 15) - ) - circuit(3 INVX1 location(6000 0) - pin(0 12) - pin(1 3) - pin(2 15) - pin(3 12) - pin(4 2) - pin(5 15) - ) - circuit(4 INVX1 location(7800 0) - pin(0 12) - pin(1 4) - pin(2 15) - pin(3 12) - pin(4 3) - pin(5 15) - ) - circuit(5 INVX1 location(9600 0) - pin(0 12) - pin(1 5) - pin(2 15) - pin(3 12) - pin(4 4) - pin(5 15) - ) - circuit(6 INVX1 location(11400 0) - pin(0 12) - pin(1 6) - pin(2 15) - pin(3 12) - pin(4 5) - pin(5 15) - ) - circuit(7 INVX1 location(13200 0) - pin(0 12) - pin(1 7) - pin(2 15) - pin(3 12) - pin(4 6) - pin(5 15) - ) - circuit(8 INVX1 location(15000 0) - pin(0 12) - pin(1 8) - pin(2 15) - pin(3 12) - pin(4 7) - pin(5 15) - ) - circuit(9 INVX1 location(16800 0) - pin(0 12) - pin(1 9) - pin(2 15) - pin(3 12) - pin(4 8) - pin(5 15) - ) - circuit(10 INVX1 location(18600 0) - pin(0 12) - pin(1 10) - pin(2 15) - pin(3 12) - pin(4 9) - pin(5 15) - ) - circuit(11 INVX1 location(20400 0) - pin(0 12) - pin(1 11) - pin(2 15) - pin(3 12) - pin(4 10) - pin(5 15) - ) - circuit(12 INVX1 location(22200 0) - pin(0 12) - pin(1 13) - pin(2 15) - pin(3 12) - pin(4 11) - pin(5 15) - ) - - ) -) - -# Reference netlist -reference( - - # Device class section - class(PMOS MOS4) - class(NMOS MOS4) - - # Circuit section - # Circuits are the hierarchical building blocks of the netlist. - circuit(ND2X1 - - # Nets - net(1 name(VDD)) - net(2 name(OUT)) - net(3 name(VSS)) - net(4 name(NWELL)) - net(5 name(B)) - net(6 name(A)) - net(7 name(BULK)) - net(8 name('1')) - - # Outgoing pins and their connections to nets - pin(1 name(VDD)) - pin(2 name(OUT)) - pin(3 name(VSS)) - pin(4 name(NWELL)) - pin(5 name(B)) - pin(6 name(A)) - pin(7 name(BULK)) - - # Devices and their connections - device(1 PMOS - name($1) - param(L 0.25) - param(W 1.5) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 2) - terminal(G 6) - terminal(D 1) - terminal(B 4) - ) - device(2 PMOS - name($2) - param(L 0.25) - param(W 1.5) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 1) - terminal(G 5) - terminal(D 2) - terminal(B 4) - ) - device(3 NMOS - name($3) - param(L 0.25) - param(W 0.95) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 3) - terminal(G 6) - terminal(D 8) - terminal(B 7) - ) - device(4 NMOS - name($4) - param(L 0.25) - param(W 0.95) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 8) - terminal(G 5) - terminal(D 2) - terminal(B 7) - ) - - ) - circuit(INVX1 - - # Nets - net(1 name(VDD)) - net(2 name(OUT)) - net(3 name(VSS)) - net(4 name(NWELL)) - net(5 name(IN)) - net(6 name(BULK)) - - # Outgoing pins and their connections to nets - pin(1 name(VDD)) - pin(2 name(OUT)) - pin(3 name(VSS)) - pin(4 name(NWELL)) - pin(5 name(IN)) - pin(6 name(BULK)) - - # Devices and their connections - device(1 PMOS - name($1) - param(L 0.25) - param(W 1.5) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 1) - terminal(G 5) - terminal(D 2) - terminal(B 4) - ) - device(2 NMOS - name($2) - param(L 0.25) - param(W 0.95) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 3) - terminal(G 5) - terminal(D 2) - terminal(B 6) - ) - - ) - circuit(RINGO - - # Nets - net(1 name(VSS)) - net(2 name(VDD)) - net(3 name(FB)) - net(4 name(ENABLE)) - net(5 name(OUT)) - net(6 name('1')) - net(7 name('2')) - net(8 name('3')) - net(9 name('4')) - net(10 name('5')) - net(11 name('6')) - net(12 name('7')) - net(13 name('8')) - net(14 name('9')) - net(15 name('10')) - - # Outgoing pins and their connections to nets - pin(1 name(VSS)) - pin(2 name(VDD)) - pin(3 name(FB)) - pin(4 name(ENABLE)) - pin(5 name(OUT)) - - # Subcircuits and their connections - circuit(1 ND2X1 name($1) - pin(0 2) - pin(1 6) - pin(2 1) - pin(3 2) - pin(4 3) - pin(5 4) - pin(6 1) - ) - circuit(2 INVX1 name($2) - pin(0 2) - pin(1 7) - pin(2 1) - pin(3 2) - pin(4 6) - pin(5 1) - ) - circuit(3 INVX1 name($3) - pin(0 2) - pin(1 8) - pin(2 1) - pin(3 2) - pin(4 7) - pin(5 1) - ) - circuit(4 INVX1 name($4) - pin(0 2) - pin(1 9) - pin(2 1) - pin(3 2) - pin(4 8) - pin(5 1) - ) - circuit(5 INVX1 name($5) - pin(0 2) - pin(1 10) - pin(2 1) - pin(3 2) - pin(4 9) - pin(5 1) - ) - circuit(6 INVX1 name($6) - pin(0 2) - pin(1 11) - pin(2 1) - pin(3 2) - pin(4 10) - pin(5 1) - ) - circuit(7 INVX1 name($7) - pin(0 2) - pin(1 12) - pin(2 1) - pin(3 2) - pin(4 11) - pin(5 1) - ) - circuit(8 INVX1 name($8) - pin(0 2) - pin(1 13) - pin(2 1) - pin(3 2) - pin(4 12) - pin(5 1) - ) - circuit(9 INVX1 name($9) - pin(0 2) - pin(1 14) - pin(2 1) - pin(3 2) - pin(4 13) - pin(5 1) - ) - circuit(10 INVX1 name($10) - pin(0 2) - pin(1 15) - pin(2 1) - pin(3 2) - pin(4 14) - pin(5 1) - ) - circuit(11 INVX1 name($11) - pin(0 2) - pin(1 3) - pin(2 1) - pin(3 2) - pin(4 15) - pin(5 1) - ) - circuit(12 INVX1 name($12) - pin(0 2) - pin(1 5) - pin(2 1) - pin(3 2) - pin(4 3) - pin(5 1) - ) - - ) -) - -# Cross reference -xref( - circuit(INVX1 INVX1 match - xref( - net(4 4 match) - net(5 5 match) - net(2 2 match) - net(6 6 match) - net(1 1 match) - net(3 3 match) - pin(3 3 match) - pin(4 4 match) - pin(1 1 match) - pin(5 5 match) - pin(0 0 match) - pin(2 2 match) - device(2 2 match) - device(1 1 match) - ) - ) - circuit(ND2X1 ND2X1 nomatch - xref( - net(4 8 mismatch) - net(5 4 mismatch) - net(7 6 match) - net(6 5 match) - net(2 2 mismatch) - net(8 7 mismatch) - net(1 1 mismatch) - net(3 3 mismatch) - pin(3 3 match) - pin(5 5 match) - pin(4 4 match) - pin(1 1 match) - pin(6 6 match) - pin(0 0 match) - pin(2 2 match) - device(4 4 match) - device(3 3 mismatch) - device(2 2 match) - device(1 1 mismatch) - ) - ) - circuit(RINGO RINGO match - xref( - net(1 6 match) - net(10 15 match) - net(2 7 match) - net(3 8 match) - net(4 9 match) - net(5 10 match) - net(6 11 match) - net(7 12 match) - net(8 13 match) - net(9 14 match) - net(14 4 match) - net(11 3 match) - net(13 5 match) - net(12 2 match) - net(15 1 match) - pin(3 3 match) - pin(0 2 match) - pin(2 4 match) - pin(1 1 match) - pin(4 0 match) - circuit(2 2 match) - circuit(3 3 match) - circuit(4 4 match) - circuit(5 5 match) - circuit(6 6 match) - circuit(7 7 match) - circuit(8 8 match) - circuit(9 9 match) - circuit(10 10 match) - circuit(11 11 match) - circuit(12 12 match) - circuit(1 1 match) - ) - ) -)