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