From 2452c72d2de487043964ae49ce5825e244b29c54 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 30 Mar 2019 23:04:57 +0100 Subject: [PATCH] WIP: netlist compare deployed for netlist extractors Some enhancements were required: * Clusters left over from joined clusters must not be turned into nets: this leads to dummy nets. * null Nets can happen as targets of edges. Don't assert in this case but treat null nets as identical for both netlists. * Don't resolve ambiguous nets if there are options to do this non-ambiguously. * logger can be null * Added compare_netlists to dbTestSupport --- src/db/db/dbHierNetworkProcessor.cc | 7 + src/db/db/dbHierNetworkProcessor.h | 5 + src/db/db/dbNetlistCompare.cc | 133 +++++++++++----- src/db/db/dbNetlistExtractor.cc | 9 +- src/db/db/dbTestSupport.cc | 150 +++++++++++++++++++ src/db/db/dbTestSupport.h | 6 + src/db/unit_tests/dbNetlistCompareTests.cc | 75 +++++++++- src/db/unit_tests/dbNetlistExtractorTests.cc | 17 ++- 8 files changed, 355 insertions(+), 47 deletions(-) diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 45c2623e0..a1016b750 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -267,6 +267,13 @@ local_cluster::clear () m_global_nets.clear (); } +template +bool +local_cluster::empty () const +{ + return m_global_nets.empty () && m_shapes.empty (); +} + template void local_cluster::set_global_nets (const global_nets &gn) diff --git a/src/db/db/dbHierNetworkProcessor.h b/src/db/db/dbHierNetworkProcessor.h index 6fef35daa..94fb0ec28 100644 --- a/src/db/db/dbHierNetworkProcessor.h +++ b/src/db/db/dbHierNetworkProcessor.h @@ -218,6 +218,11 @@ public: */ void clear (); + /** + * @brief Returns true if the cluster is empty + */ + bool empty () const; + /** * @brief Adds a shape with the given layer to the cluster */ diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 200062bf5..3905c97f5 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -415,6 +415,10 @@ public: NetDeviceGraphNode (const db::Net *net, DeviceCategorizer &device_categorizer, CircuitCategorizer &circuit_categorizer, const std::map *circuit_map, const CircuitPinMapper *pin_map) : mp_net (net), m_other_net_index (std::numeric_limits::max ()) { + if (! net) { + return; + } + std::map n2entry; for (db::Net::const_subcircuit_pin_iterator i = net->begin_subcircuit_pins (); i != net->end_subcircuit_pins (); ++i) { @@ -648,6 +652,9 @@ public: m_nodes.clear (); m_net_index.clear (); + // create a dummy node for a null net + m_nodes.push_back (NetDeviceGraphNode (0, device_categorizer, circuit_categorizer, circuit_and_pin_mapping, circuit_pin_mapper)); + size_t nets = 0; for (db::Circuit::const_net_iterator n = c->begin_nets (); n != c->end_nets (); ++n) { ++nets; @@ -1025,6 +1032,10 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, g1.build (c1, device_categorizer, circuit_categorizer, &circuit_and_pin_mapping, mp_circuit_pin_mapper.get ()); g2.build (c2, device_categorizer, circuit_categorizer, 0, mp_circuit_pin_mapper.get ()); + // Match dummy nodes for null nets + g1.identify (0, 0); + g2.identify (0, 0); + for (std::vector >::const_iterator p = net_identity.begin (); p != net_identity.end (); ++p) { size_t ni1 = g1.node_index_for_net (p->first); size_t ni2 = g2.node_index_for_net (p->second); @@ -1069,31 +1080,45 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, #if defined(PRINT_DEBUG_NETCOMPARE) tl::log << "checking topological identity ..."; #endif - // derive new identities through topology - db::NetDeviceGraph::node_iterator i1 = g1.begin (), i2 = g2.begin (); - for ( ; i1 != g1.end () && i2 != g2.end (); ) { + // first pass: without ambiguities, second pass: match ambiguous nets + for (int pass = 0; pass < 2 && new_identities == 0; ++pass) { - if (i1->has_other ()) { - ++i1; - } else if (i2->has_other ()) { - ++i2; - } else if (*i1 < *i2) { - ++i1; - } else if (*i2 < *i1) { - ++i2; - } else { + // derive new identities through topology - db::NetDeviceGraph::node_iterator ii1 = i1, ii2 = i2; + bool same_as_prev = false; - ++i1; - ++i2; + db::NetDeviceGraph::node_iterator i1 = g1.begin (), i2 = g2.begin (); + for ( ; i1 != g1.end () && i2 != g2.end (); ) { - bool ambiguous = (i1 != g1.end () && *i1 == *ii1) || (i2 != g2.end () && *i2 == *ii2); + bool same_as_next = false; - // found a candidate - a single node with the same edges - db::NetDeviceGraph::confirm_identity (g1, ii1, g2, ii2, mp_logger, ambiguous); - ++new_identities; + if (i1->has_other ()) { + ++i1; + } else if (i2->has_other ()) { + ++i2; + } else if (*i1 < *i2) { + ++i1; + } else if (*i2 < *i1) { + ++i2; + } else { + + db::NetDeviceGraph::node_iterator ii1 = i1, ii2 = i2; + + ++i1; + ++i2; + + same_as_next = (i1 != g1.end () && *i1 == *ii1) || (i2 != g2.end () && *i2 == *ii2); + + // found a candidate - a single node with the same edges + if (! (same_as_next || same_as_prev) || pass) { + db::NetDeviceGraph::confirm_identity (g1, ii1, g2, ii2, mp_logger, same_as_next || same_as_prev); + ++new_identities; + } + + } + + same_as_prev = same_as_next; } @@ -1111,13 +1136,13 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, // Report missing net assignment for (db::NetDeviceGraph::node_iterator i = g1.begin (); i != g1.end (); ++i) { - if (! i->has_other ()) { + if (! i->has_other () && mp_logger) { mp_logger->net_mismatch (i->net (), 0); } } for (db::NetDeviceGraph::node_iterator i = g2.begin (); i != g2.end (); ++i) { - if (! i->has_other ()) { + if (! i->has_other () && mp_logger) { mp_logger->net_mismatch (0, i->net ()); } } @@ -1138,15 +1163,15 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, for (db::NetDeviceGraph::node_iterator i = g1.begin (); i != g1.end (); ++i) { const db::Net *net = i->net (); - tl_assert (net != 0); - - if (net->pin_count () == 0) { + if (! net || net->pin_count () == 0) { continue; } if (! i->has_other ()) { for (db::Net::const_pin_iterator pi = net->begin_pins (); pi != net->end_pins (); ++pi) { - mp_logger->pin_mismatch (pi->pin (), 0); + if (mp_logger) { + mp_logger->pin_mismatch (pi->pin (), 0); + } pin_mismatch = true; good = false; } @@ -1160,7 +1185,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, if (np != net2pin.end () && np->first == other_net) { - mp_logger->match_pins (pi->pin (), np->second); + if (mp_logger) { + mp_logger->match_pins (pi->pin (), np->second); + } pin_mapping.map_pin (pi->pin ()->id (), np->second->id ()); std::multimap::iterator np_delete = np; @@ -1168,9 +1195,13 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, net2pin.erase (np_delete); } else { - mp_logger->pin_mismatch (pi->pin (), 0); + + if (mp_logger) { + mp_logger->pin_mismatch (pi->pin (), 0); + } pin_mismatch = true; good = false; + } } @@ -1178,7 +1209,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, } for (std::multimap::iterator np = net2pin.begin (); np != net2pin.end (); ++np) { - mp_logger->pin_mismatch (0, np->second); + if (mp_logger) { + mp_logger->pin_mismatch (0, np->second); + } pin_mismatch = true; good = false; } @@ -1200,7 +1233,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, } if (! mapped) { - mp_logger->device_mismatch (d.operator-> (), 0); + if (mp_logger) { + mp_logger->device_mismatch (d.operator-> (), 0); + } good = false; } else { // TODO: report devices which cannot be distiguished topologically? @@ -1228,7 +1263,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, if (! mapped || dm == device_map.end () || dm->first != k) { - mp_logger->device_mismatch (0, d.operator-> ()); + if (mp_logger) { + mp_logger->device_mismatch (0, d.operator-> ()); + } good = false; } else { @@ -1239,14 +1276,20 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, if (! dc.equals (dm->second, std::make_pair (d.operator-> (), device_cat))) { if (dm->second.second != device_cat) { - mp_logger->match_devices_with_different_device_classes (dm->second.first, d.operator-> ()); + if (mp_logger) { + mp_logger->match_devices_with_different_device_classes (dm->second.first, d.operator-> ()); + } good = false; } else { - mp_logger->match_devices_with_different_parameters (dm->second.first, d.operator-> ()); + if (mp_logger) { + mp_logger->match_devices_with_different_parameters (dm->second.first, d.operator-> ()); + } good = false; } } else { - mp_logger->match_devices (dm->second.first, d.operator-> ()); + if (mp_logger) { + mp_logger->match_devices (dm->second.first, d.operator-> ()); + } } device_map.erase (dm); @@ -1256,7 +1299,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, } for (std::multimap >, std::pair >::const_iterator dm = device_map.begin (); dm != device_map.end (); ++dm) { - mp_logger->device_mismatch (dm->second.first, 0); + if (mp_logger) { + mp_logger->device_mismatch (dm->second.first, 0); + } good = false; } @@ -1277,7 +1322,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, } if (! mapped) { - mp_logger->subcircuit_mismatch (sc.operator-> (), 0); + if (mp_logger) { + mp_logger->subcircuit_mismatch (sc.operator-> (), 0); + } good = false; } else if (! k.empty ()) { // TODO: report devices which cannot be distiguished topologically? @@ -1305,7 +1352,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, if (! mapped || scm == subcircuit_map.end ()) { - mp_logger->subcircuit_mismatch (0, sc.operator-> ()); + if (mp_logger) { + mp_logger->subcircuit_mismatch (0, sc.operator-> ()); + } good = false; } else { @@ -1314,10 +1363,14 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, size_t sc_cat = circuit_categorizer.cat_for_subcircuit (sc.operator-> ()); if (! scc.equals (scm->second, std::make_pair (sc.operator-> (), sc_cat))) { - mp_logger->subcircuit_mismatch (scm->second.first, sc.operator-> ()); + if (mp_logger) { + mp_logger->subcircuit_mismatch (scm->second.first, sc.operator-> ()); + } good = false; } else { - mp_logger->match_subcircuits (scm->second.first, sc.operator-> ()); + if (mp_logger) { + mp_logger->match_subcircuits (scm->second.first, sc.operator-> ()); + } } subcircuit_map.erase (scm); @@ -1327,7 +1380,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, } for (std::multimap >, std::pair >::const_iterator scm = subcircuit_map.begin (); scm != subcircuit_map.end (); ++scm) { - mp_logger->subcircuit_mismatch (scm->second.first, 0); + if (mp_logger) { + mp_logger->subcircuit_mismatch (scm->second.first, 0); + } good = false; } diff --git a/src/db/db/dbNetlistExtractor.cc b/src/db/db/dbNetlistExtractor.cc index e8ba2bade..40cd6439f 100644 --- a/src/db/db/dbNetlistExtractor.cc +++ b/src/db/db/dbNetlistExtractor.cc @@ -127,11 +127,18 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo for (connected_clusters_type::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) { + const db::local_cluster &lc = clusters.cluster_by_id (*c); + if (clusters.connections_for_cluster (*c).empty () && lc.empty ()) { + // this is an entirely empty cluster so we skip it. + // Such clusters are left over when joining clusters. + continue; + } + db::Net *net = new db::Net (); net->set_cluster_id (*c); circuit->add_net (net); - const db::local_cluster::global_nets &gn = clusters.cluster_by_id (*c).get_global_nets (); + const db::local_cluster::global_nets &gn = lc.get_global_nets (); for (db::local_cluster::global_nets::const_iterator g = gn.begin (); g != gn.end (); ++g) { assign_net_name (conn.global_net_name (*g), net); } diff --git a/src/db/db/dbTestSupport.cc b/src/db/db/dbTestSupport.cc index b8b1af7d5..70c24b7fc 100644 --- a/src/db/db/dbTestSupport.cc +++ b/src/db/db/dbTestSupport.cc @@ -28,6 +28,8 @@ #include "dbCell.h" #include "dbCellInst.h" #include "dbLayoutDiff.h" +#include "dbNetlist.h" +#include "dbNetlistCompare.h" #include "tlUnitTest.h" #include "tlFileUtils.h" @@ -152,4 +154,152 @@ void compare_layouts (tl::TestBase *_this, const db::Layout &layout, const std:: } } +class CompareLogger + : public db::NetlistCompareLogger +{ +public: + CompareLogger () + : m_new_circuit (true) { } + + void out (const std::string &text) + { + if (m_new_circuit) { + tl::log << m_circuit; + m_new_circuit = false; + } + tl::log << text; + } + + virtual void begin_netlist () + { + tl::log << "Comparing netlists:"; + } + + virtual void end_netlist () + { + tl::log << "End of difference log."; + } + + virtual void begin_circuit (const db::Circuit *a, const db::Circuit *b) + { + m_new_circuit = true; + m_circuit = circuit2str (a) + " vs. " + circuit2str (b); + } + + virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b) + { + out ("circuit_skipped " + circuit2str (a) + " " + circuit2str (b)); + } + + virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b) + { + out ("circuit_mismatch " + circuit2str (a) + " " + circuit2str (b)); + } + + virtual void match_nets (const db::Net *a, const db::Net *b) + { + out ("match_nets " + net2str (a) + " " + net2str (b)); + } + + virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b) + { + out ("match_ambiguous_nets " + net2str (a) + " " + net2str (b)); + } + + virtual void net_mismatch (const db::Net *a, const db::Net *b) + { + out ("net_mismatch " + net2str (a) + " " + net2str (b)); + } + + virtual void match_devices (const db::Device *a, const db::Device *b) + { + out ("match_devices " + device2str (a) + " " + device2str (b)); + } + + virtual void device_mismatch (const db::Device *a, const db::Device *b) + { + out ("device_mismatch " + device2str (a) + " " + device2str (b)); + } + + virtual void match_devices_with_different_parameters (const db::Device *a, const db::Device *b) + { + out ("match_devices_with_different_parameters " + device2str (a) + " " + device2str (b)); + } + + virtual void match_devices_with_different_device_classes (const db::Device *a, const db::Device *b) + { + out ("match_devices_with_different_device_classes " + device2str (a) + " " + device2str (b)); + } + + virtual void match_pins (const db::Pin *a, const db::Pin *b) + { + out ("match_pins " + pin2str (a) + " " + pin2str (b)); + } + + virtual void pin_mismatch (const db::Pin *a, const db::Pin *b) + { + out ("pin_mismatch " + pin2str (a) + " " + pin2str (b)); + } + + virtual void match_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b) + { + out ("match_subcircuits " + subcircuit2str (a) + " " + subcircuit2str (b)); + } + + virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b) + { + out ("subcircuit_mismatch " + subcircuit2str (a) + " " + subcircuit2str (b)); + } + +private: + bool m_new_circuit; + std::string m_circuit; + + std::string circuit2str (const db::Circuit *x) const + { + return x ? x->name () : "(null)"; + } + + std::string device2str (const db::Device *x) const + { + return x ? x->expanded_name () : "(null)"; + } + + std::string net2str (const db::Net *x) const + { + return x ? x->expanded_name () : "(null)"; + } + + std::string pin2str (const db::Pin *x) const + { + return x ? x->expanded_name () : "(null)"; + } + + std::string subcircuit2str (const db::SubCircuit *x) const + { + return x ? x->expanded_name () : "(null)"; + } +}; + +void DB_PUBLIC compare_netlist (tl::TestBase *_this, const db::Netlist &netlist, const std::string &au_nl_string) +{ + db::NetlistComparer comp (0); + + db::Netlist au_nl; + for (db::Netlist::const_device_class_iterator d = netlist.begin_device_classes (); d != netlist.end_device_classes (); ++d) { + au_nl.add_device_class (d->clone ()); + } + + au_nl.from_string (au_nl_string); + + if (! comp.compare (&netlist, &au_nl)) { + _this->raise ("Compare failed - see log for details.\n\nActual:\n" + netlist.to_string () + "\nGolden:\n" + au_nl_string); + // Compare once again - this time with logger + CompareLogger logger; + db::NetlistComparer comp (&logger); + comp.compare (&netlist, &au_nl); + } +} + + } diff --git a/src/db/db/dbTestSupport.h b/src/db/db/dbTestSupport.h index 00fb38432..6e4e34917 100644 --- a/src/db/db/dbTestSupport.h +++ b/src/db/db/dbTestSupport.h @@ -39,6 +39,7 @@ namespace db class Layout; class Cell; class LayerMap; +class Netlist; /** * @brief Specifies the normalization mode for compare_layouts @@ -73,6 +74,11 @@ void DB_PUBLIC compare_layouts (tl::TestBase *_this, const db::Layout &layout, c */ void DB_PUBLIC compare_layouts (tl::TestBase *_this, const db::Layout &layout, const std::string &au_file, const db::LayerMap &lmap, bool read_all_others, NormalizationMode norm = WriteGDS2, db::Coord tolerance = 0); +/** + * @brief Compares a netlist against a string + */ +void DB_PUBLIC compare_netlist (tl::TestBase *_this, const db::Netlist &netlist, const std::string &au_nl_string); + } #endif diff --git a/src/db/unit_tests/dbNetlistCompareTests.cc b/src/db/unit_tests/dbNetlistCompareTests.cc index e4521bf0c..0def3a631 100644 --- a/src/db/unit_tests/dbNetlistCompareTests.cc +++ b/src/db/unit_tests/dbNetlistCompareTests.cc @@ -412,11 +412,11 @@ TEST(4_BufferTwoPaths) EXPECT_EQ (logger.text (), "begin_circuit BUF BUF\n" "match_nets OUT OUT\n" - "match_ambiguous_nets INT $10\n" - "match_nets INT2 $11\n" "match_nets VDD VDD\n" "match_nets IN IN\n" "match_nets VSS VSS\n" + "match_ambiguous_nets INT $10\n" + "match_ambiguous_nets INT2 $11\n" "match_pins $1 $3\n" "match_pins $2 $0\n" "match_pins $0 $1\n" @@ -1312,3 +1312,74 @@ TEST(14_Subcircuit2MatchWithSwap) EXPECT_EQ (good, true); } + +TEST(15_EmptySubCircuitTest) +{ + const char *nls1 = + "circuit RINGO ();\n" + " subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $3 (IN=$I19,$2=$I39,OUT=$I1,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $4 (IN=$I1,$2=$I40,OUT=$I2,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $5 (IN=$I2,$2=$I41,OUT=$I3,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $6 (IN=$I3,$2=$I42,OUT=$I4,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $7 (IN=$I4,$2=$I43,OUT=$I5,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $8 (IN=$I5,$2=$I44,OUT=$I6,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $9 (IN=$I6,$2=$I45,OUT=$I7,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $10 (IN=$I7,$2=$I46,OUT=$I8,$4=VSS,$5=VDD);\n" + "end;\n" + "circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n" + " device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + " device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" + " device NMOS $3 (S=$2,G=IN,D=$4) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + " device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" + " subcircuit TRANS $1 (S=$2,G=$4,D=IN);\n" + " subcircuit TRANS $2 (S=$2,G=$5,D=IN);\n" + " subcircuit TRANS $3 (S=$5,G=OUT,D=$2);\n" + " subcircuit TRANS $4 (S=$4,G=OUT,D=$2);\n" + "end;\n" + "circuit TRANS (S=$1,G=$2,D=$3);\n" + "end;\n"; + + const char *nls2 = + "circuit RINGO ();\n" + " subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $3 (IN=$I19,$2=$I39,OUT=$I1,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $4 (IN=$I2,$2=$I41,OUT=$I3,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $5 (IN=$I3,$2=$I42,OUT=$I4,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $6 (IN=$I1,$2=$I40,OUT=$I2,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $7 (IN=$I4,$2=$I43,OUT=$I5,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $8 (IN=$I5,$2=$I44,OUT=$I6,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $9 (IN=$I6,$2=$I45,OUT=$I7,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $10 (IN=$I7,$2=$I46,OUT=$I8,$4=VSS,$5=VDD);\n" + "end;\n" + "circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n" + " device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + " device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" + " device NMOS $3 (S=$2,G=IN,D=$4) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + " device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" + " subcircuit TRANS $1 (G=$4,S=$2,D=IN);\n" + " subcircuit TRANS $2 (G=$5,S=$2,D=IN);\n" + " subcircuit TRANS $3 (G=OUT,S=$5,D=$2);\n" + " subcircuit TRANS $4 (G=OUT,S=$4,D=$2);\n" + "end;\n" + // This circuit is an abstract and it's pins are defined by the pin names + "circuit TRANS (G=$1,S=$2,D=$3);\n" + "end;\n"; + + db::Netlist nl1, nl2; + prep_nl (nl1, nls1); + prep_nl (nl2, nls2); + + NetlistCompareTestLogger logger; + db::NetlistComparer comp (&logger); + + bool good = comp.compare (&nl1, &nl2); + + EXPECT_EQ (logger.text (), + "..." + ); + + EXPECT_EQ (good, true); +} diff --git a/src/db/unit_tests/dbNetlistExtractorTests.cc b/src/db/unit_tests/dbNetlistExtractorTests.cc index 52c2a5961..3fd08616c 100644 --- a/src/db/unit_tests/dbNetlistExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistExtractorTests.cc @@ -35,6 +35,7 @@ #include "dbCommonReader.h" #include "dbTestSupport.h" #include "dbCellMapping.h" +#include "dbTestSupport.h" #include "tlUnitTest.h" #include "tlString.h" @@ -280,7 +281,8 @@ TEST(1_DeviceAndNetExtraction) dump_nets_to_layout (nl, cl, ly, dump_map, cm); // compare netlist as string - EXPECT_EQ (nl.to_string (), + CHECKPOINT (); + db::compare_netlist (_this, nl, "circuit RINGO ();\n" " subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n" " subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD);\n" @@ -321,9 +323,11 @@ TEST(1_DeviceAndNetExtraction) // make pins for named nets of top-level circuits - this way they are not purged nl.make_top_level_pins (); nl.purge (); + nl.purge_nets (); // compare netlist as string - EXPECT_EQ (nl.to_string (), + CHECKPOINT (); + db::compare_netlist (_this, nl, "circuit RINGO (FB=FB,OSC=OSC,VSS=VSS,VDD=VDD);\n" " subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n" " subcircuit INV2 $2 (IN=FB,$2=(null),OUT=$I19,$4=VSS,$5=VDD);\n" @@ -508,7 +512,8 @@ TEST(2_DeviceAndNetExtractionFlat) // compare netlist as string // NOTE: some of the nets are called IN,OUT but are different ones. They // happen to be the same because they share the same label. - EXPECT_EQ (nl.to_string (), + CHECKPOINT (); + db::compare_netlist (_this, nl, "circuit RINGO ();\n" " device PMOS $1 (S=$16,G='IN,OUT',D=VDD) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" " device PMOS $2 (S=VDD,G=$16,D='IN,OUT') (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" @@ -742,7 +747,8 @@ TEST(3_DeviceAndNetExtractionWithImplicitConnections) dump_nets_to_layout (nl, cl, ly, dump_map, cm); // compare netlist as string - EXPECT_EQ (nl.to_string (), + CHECKPOINT (); + db::compare_netlist (_this, nl, "circuit RINGO ();\n" " subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4='VSSZ,VSS',$5='VDDZ,VDD');\n" " subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4='VSSZ,VSS',$5='VDDZ,VDD');\n" @@ -777,7 +783,8 @@ TEST(3_DeviceAndNetExtractionWithImplicitConnections) nl.purge (); // compare netlist as string - EXPECT_EQ (nl.to_string (), + CHECKPOINT (); + db::compare_netlist (_this, nl, "circuit RINGO (FB=FB,OSC=OSC,NEXT=NEXT,'VSSZ,VSS'='VSSZ,VSS','VDDZ,VDD'='VDDZ,VDD');\n" " subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4='VSSZ,VSS',$5='VDDZ,VDD');\n" " subcircuit INV2 $2 (IN=FB,$2=(null),OUT=$I19,$4='VSSZ,VSS',$5='VDDZ,VDD');\n"