diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index c2b43d015..3dbd96430 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -25,6 +25,7 @@ #include "dbHash.h" #include "tlProgress.h" #include "tlTimer.h" +#include "tlEquivalenceClusters.h" namespace db { @@ -98,7 +99,7 @@ public: void map_pins (const db::Circuit *circuit, size_t pin1_id, size_t pin2_id) { - m_pin_map [circuit].insert (std::make_pair (pin1_id, pin2_id)); + m_pin_map [circuit].same (pin1_id, pin2_id); } void map_pins (const db::Circuit *circuit, const std::vector &pin_ids) @@ -107,26 +108,26 @@ public: return; } - std::map &pm = m_pin_map [circuit]; + tl::equivalence_clusters &pm = m_pin_map [circuit]; for (size_t i = 1; i < pin_ids.size (); ++i) { - pm.insert (std::make_pair (pin_ids [i], pin_ids [0])); + pm.same (pin_ids [0], pin_ids [i]); } } size_t normalize_pin_id (const db::Circuit *circuit, size_t pin_id) const { - std::map >::const_iterator pm = m_pin_map.find (circuit); + std::map >::const_iterator pm = m_pin_map.find (circuit); if (pm != m_pin_map.end ()) { - std::map::const_iterator ipm = pm->second.find (pin_id); - if (ipm != pm->second.end ()) { - return ipm->second; + size_t cluster_id = pm->second.cluster_id (pin_id); + if (cluster_id > 0) { + return (*pm->second.begin_cluster (cluster_id))->first; } } return pin_id; } private: - std::map > m_pin_map; + std::map > m_pin_map; }; // -------------------------------------------------------------------------------------------------------------------- @@ -450,6 +451,7 @@ public: size_t pin_id = i->pin ()->id (); const db::Circuit *cr = sc->circuit_ref (); + size_t this_pin_id = pin_id; pin_id = pin_map->normalize_pin_id (cr, pin_id); std::map::const_iterator icm = circuit_map->find (cr); @@ -476,7 +478,6 @@ public: // we cannot afford creating edges from all to all other pins, so we just create edges to the previous and next // pin. This may take more iterations to solve, but should be equivalent. - std::vector pids; size_t pin_count = cr->pin_count (); // take a number if additional pins as edges: this allows identifying a pin as dependent @@ -484,6 +485,12 @@ public: // 5 additional pins should be sufficient to capture one additional non-power pin. size_t take_additional_pins = 5; + + std::vector pids; + pids.reserve (take_additional_pins + 1); + // this symmetrizes the pin list with respect to the before-normalization pin id: + pids.push_back (pin_id); + for (size_t n = 0; n < take_additional_pins; ++n) { size_t add_pin_id = (pin_id + n + 1) % pin_count; if (add_pin_id == pin_id) { @@ -500,12 +507,17 @@ public: for (std::vector::const_iterator i = pids.begin (); i != pids.end (); ++i) { size_t pin2_id = *i; + size_t this_pin2_id = cm->this_pin_from_other_pin (pin2_id); + + if (this_pin2_id == this_pin_id) { + // we should not go back to our original, non-normalized pin + continue; + } // NOTE: if a pin mapping is given, EdgeDesc::pin1_id and EdgeDesc::pin2_id are given // as pin ID's of the other circuit. EdgeDesc ed (sc, circuit_categorizer.cat_for_subcircuit (sc), pin_id, pin_map->normalize_pin_id (cr, pin2_id)); - size_t this_pin2_id = cm->this_pin_from_other_pin (pin2_id); const db::Net *net2 = sc->net_for_pin (this_pin2_id); std::map::const_iterator in = n2entry.find (net2); @@ -660,8 +672,7 @@ private: /** * @brief Compares edges as "less" - * Edge comparison is based on the pins attached (name of the first pin) or net - * name if no pins are attached on both nets. + * Edge comparison is based on the pins attached (name of the first pin). */ static bool edge_less (const db::Net *a, const db::Net *b) { @@ -679,7 +690,7 @@ private: return pna < pnb; } } - return a->name () < b->name (); + return false; } else { return false; } @@ -705,7 +716,7 @@ private: return pna == pnb; } } - return a->name () == b->name (); + return true; } else { return true; } @@ -1205,9 +1216,35 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, 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); + + bool ambiguous = (same_as_next || same_as_prev); + if (! ambiguous || pass) { + + // For ambiguous nets make the pins exchangable + + if (same_as_next) { + + if (ii1->net () && i1->net ()) { + for (db::Net::const_pin_iterator pp = ii1->net ()->begin_pins (); pp != ii1->net ()->end_pins (); ++pp) { + for (db::Net::const_pin_iterator p = i1->net ()->begin_pins (); p != i1->net ()->end_pins (); ++p) { + mp_circuit_pin_mapper->map_pins (c1, pp->pin_id (), p->pin_id ()); + } + } + } + + if (ii2->net () && i2->net ()) { + for (db::Net::const_pin_iterator pp = ii2->net ()->begin_pins (); pp != ii2->net ()->end_pins (); ++pp) { + for (db::Net::const_pin_iterator p = i2->net ()->begin_pins (); p != i2->net ()->end_pins (); ++p) { + mp_circuit_pin_mapper->map_pins (c2, pp->pin_id (), p->pin_id ()); + } + } + } + + } + + db::NetDeviceGraph::confirm_identity (g1, ii1, g2, ii2, mp_logger, ambiguous); ++new_identities; + } } diff --git a/src/db/db/dbTestSupport.cc b/src/db/db/dbTestSupport.cc index b9f48536f..6aa938e9d 100644 --- a/src/db/db/dbTestSupport.cc +++ b/src/db/db/dbTestSupport.cc @@ -283,8 +283,6 @@ private: 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 ()); @@ -292,6 +290,8 @@ void DB_PUBLIC compare_netlist (tl::TestBase *_this, const db::Netlist &netlist, au_nl.from_string (au_nl_string); + db::NetlistComparer comp (0); + 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 @@ -301,5 +301,18 @@ void DB_PUBLIC compare_netlist (tl::TestBase *_this, const db::Netlist &netlist, } } +void DB_PUBLIC compare_netlist (tl::TestBase *_this, const db::Netlist &netlist, const db::Netlist &netlist_au) +{ + db::NetlistComparer comp (0); + + if (! comp.compare (&netlist, &netlist_au)) { + _this->raise ("Compare failed - see log for details.\n\nActual:\n" + netlist.to_string () + "\nGolden:\n" + netlist_au.to_string ()); + // Compare once again - this time with logger + CompareLogger logger; + db::NetlistComparer comp (&logger); + comp.compare (&netlist, &netlist_au); + } +} + } diff --git a/src/db/db/dbTestSupport.h b/src/db/db/dbTestSupport.h index 6e4e34917..e079cf05b 100644 --- a/src/db/db/dbTestSupport.h +++ b/src/db/db/dbTestSupport.h @@ -79,6 +79,11 @@ void DB_PUBLIC compare_layouts (tl::TestBase *_this, const db::Layout &layout, c */ void DB_PUBLIC compare_netlist (tl::TestBase *_this, const db::Netlist &netlist, const std::string &au_nl_string); +/** + * @brief Compares a netlist against another netlist + */ +void DB_PUBLIC compare_netlist (tl::TestBase *_this, const db::Netlist &netlist, const db::Netlist &netlist_au); + } #endif diff --git a/src/db/unit_tests/dbNetlistCompareTests.cc b/src/db/unit_tests/dbNetlistCompareTests.cc index 7d21d100b..43f6b9eba 100644 --- a/src/db/unit_tests/dbNetlistCompareTests.cc +++ b/src/db/unit_tests/dbNetlistCompareTests.cc @@ -1273,11 +1273,11 @@ TEST(14_Subcircuit2Nand) "end_circuit NAND NAND MATCH\n" "begin_circuit TOP TOP\n" "match_nets OUT OUT\n" - "match_nets IN2 IN2\n" "match_nets VSS VSS\n" "match_nets VDD VDD\n" - "match_nets INT INT\n" "match_nets IN1 IN1\n" + "match_nets INT INT\n" + "match_nets IN2 IN2\n" "match_pins $0 $0\n" "match_pins $1 $1\n" "match_pins $2 $2\n" @@ -1425,11 +1425,11 @@ TEST(14_Subcircuit2MatchWithSwap) "end_circuit NAND NAND MATCH\n" "begin_circuit TOP TOP\n" "match_nets OUT OUT\n" - "match_nets IN2 IN2\n" "match_nets VSS VSS\n" "match_nets VDD VDD\n" - "match_nets INT INT\n" "match_nets IN1 IN1\n" + "match_nets INT INT\n" + "match_nets IN2 IN2\n" "match_pins $0 $0\n" "match_pins $1 $1\n" "match_pins $2 $2\n" @@ -1517,6 +1517,80 @@ TEST(15_EmptySubCircuitTest) EXPECT_EQ (good, true); } +TEST(15_EmptySubCircuitWithoutPinNames) +{ + const char *nls1 = + "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 ($1=$2,$2=$4,$3=IN);\n" + " subcircuit TRANS $2 ($1=$2,$2=$5,$3=IN);\n" + " subcircuit TRANS $3 ($1=$5,$2=OUT,$3=$2);\n" + " subcircuit TRANS $4 ($1=$4,$2=OUT,$3=$2);\n" + "end;\n" + "circuit TRANS ($1=$1,$2=$2,$3=$3);\n" + "end;\n"; + + const char *nls2 = + "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 NMOS $1 (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 PMOS $3 (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 $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 ($1=$4,$2=$2,$3=IN);\n" + " subcircuit TRANS $2 ($1=$5,$2=$2,$3=IN);\n" + " subcircuit TRANS $3 ($1=OUT,$2=$5,$3=$2);\n" + " subcircuit TRANS $4 ($1=OUT,$2=$4,$3=$2);\n" + "end;\n" + // This circuit is an abstract and it's pins are defined by the pin names + "circuit TRANS ($1=$1,$2=$2,$3=$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 (), + "begin_circuit TRANS TRANS\n" + "match_ambiguous_nets $1 $1\n" + "match_ambiguous_nets $2 $2\n" + "match_ambiguous_nets $3 $3\n" + "match_pins $0 $0\n" + "match_pins $1 $1\n" + "match_pins $2 $2\n" + "end_circuit TRANS TRANS MATCH\n" + "begin_circuit INV2 INV2\n" + "match_nets OUT OUT\n" + "match_nets IN IN\n" + "match_nets $4 $4\n" + "match_nets $2 $2\n" + "match_nets $5 $5\n" + "match_pins IN IN\n" + "match_pins $1 $1\n" + "match_pins OUT OUT\n" + "match_pins $3 $3\n" + "match_pins $4 $4\n" + "match_devices $1 $1\n" + "match_devices $3 $2\n" + "match_devices $2 $3\n" + "match_devices $4 $4\n" + "match_subcircuits $1 $1\n" + "match_subcircuits $2 $2\n" + "match_subcircuits $3 $3\n" + "match_subcircuits $4 $4\n" + "end_circuit INV2 INV2 MATCH" + ); + + EXPECT_EQ (good, true); +} + TEST(16_UniqueSubCircuitMatching) { const char *nls1 = diff --git a/src/drc/unit_tests/drcSimpleTests.cc b/src/drc/unit_tests/drcSimpleTests.cc index 885495d8c..6d27bd9ae 100644 --- a/src/drc/unit_tests/drcSimpleTests.cc +++ b/src/drc/unit_tests/drcSimpleTests.cc @@ -23,6 +23,8 @@ #include "tlUnitTest.h" #include "dbReader.h" #include "dbTestSupport.h" +#include "dbNetlist.h" +#include "dbNetlistSpiceReader.h" #include "lymMacro.h" #include "tlFileUtils.h" @@ -343,6 +345,25 @@ TEST(8_TextsAndPolygons) db::compare_layouts (_this, layout, au, db::NoNormalization); } +static void compare_netlists (tl::TestBase *_this, const std::string &cir, const std::string &cir_au) +{ + db::Netlist nl, nl_au; + + db::NetlistSpiceReader reader; + + { + tl::InputStream is (cir); + reader.read (is, nl); + } + + { + tl::InputStream is (cir_au); + reader.read (is, nl_au); + } + + db::compare_netlist (_this, nl, nl_au); +} + TEST(9_NetlistExtraction) { std::string rs = tl::testsrc (); @@ -380,27 +401,11 @@ TEST(9_NetlistExtraction) // verify - { - tl::InputStream is (output); - tl::InputStream is_au (au); + CHECKPOINT (); + compare_netlists (_this, output, au); - if (is.read_all () != is_au.read_all ()) { - _this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s", - tl::absolute_file_path (output), - tl::absolute_file_path (au))); - } - } - - { - tl::InputStream is (output_simplified); - tl::InputStream is_au (au_simplified); - - if (is.read_all () != is_au.read_all ()) { - _this->raise (tl::sprintf ("Compare failed (simplified netlist) - see\n actual: %s\n golden: %s", - tl::absolute_file_path (output_simplified), - tl::absolute_file_path (au_simplified))); - } - } + CHECKPOINT (); + compare_netlists (_this, output_simplified, au_simplified); } TEST(10_NetlistExtractionFlat) @@ -440,27 +445,11 @@ TEST(10_NetlistExtractionFlat) // verify - { - tl::InputStream is (output); - tl::InputStream is_au (au); + CHECKPOINT (); + compare_netlists (_this, output, au); - if (is.read_all () != is_au.read_all ()) { - _this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s", - tl::absolute_file_path (output), - tl::absolute_file_path (au))); - } - } - - { - tl::InputStream is (output_simplified); - tl::InputStream is_au (au_simplified); - - if (is.read_all () != is_au.read_all ()) { - _this->raise (tl::sprintf ("Compare failed (simplified netlist) - see\n actual: %s\n golden: %s", - tl::absolute_file_path (output_simplified), - tl::absolute_file_path (au_simplified))); - } - } + CHECKPOINT (); + compare_netlists (_this, output_simplified, au_simplified); } TEST(11_CustomDevices) @@ -500,25 +489,9 @@ TEST(11_CustomDevices) // verify - { - tl::InputStream is (output); - tl::InputStream is_au (au); + CHECKPOINT (); + compare_netlists (_this, output, au); - if (is.read_all () != is_au.read_all ()) { - _this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s", - tl::absolute_file_path (output), - tl::absolute_file_path (au))); - } - } - - { - tl::InputStream is (output_simplified); - tl::InputStream is_au (au_simplified); - - if (is.read_all () != is_au.read_all ()) { - _this->raise (tl::sprintf ("Compare failed (simplified netlist) - see\n actual: %s\n golden: %s", - tl::absolute_file_path (output_simplified), - tl::absolute_file_path (au_simplified))); - } - } + CHECKPOINT (); + compare_netlists (_this, output_simplified, au_simplified); }