From 856fe4a8d377ffe11adfd3908253a57bd61aca84 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 8 Mar 2024 22:00:20 +0100 Subject: [PATCH] LVS: Consider net names identical that differ in signal type suffix only - e.g. 'NET:I' is identical to 'NET' --- src/db/db/dbNetlist.cc | 14 ---- src/db/db/dbNetlist.h | 5 -- src/db/db/dbNetlistCompareUtils.cc | 33 +++++++- src/db/db/dbNetlistCompareUtils.h | 10 +-- src/db/unit_tests/dbNetlistCompareTests.cc | 96 ++++++++++++++++++++++ 5 files changed, 133 insertions(+), 25 deletions(-) diff --git a/src/db/db/dbNetlist.cc b/src/db/db/dbNetlist.cc index 9c7c724ba..f0f8d177c 100644 --- a/src/db/db/dbNetlist.cc +++ b/src/db/db/dbNetlist.cc @@ -126,20 +126,6 @@ void Netlist::set_case_sensitive (bool f) m_case_sensitive = f; } -int Netlist::name_compare (bool case_sensitive, const std::string &n1, const std::string &n2) -{ - // TODO: unicode support? - if (case_sensitive) { - return strcmp (n1.c_str (), n2.c_str ()); - } else { -#if defined(_WIN32) - return _stricmp (n1.c_str (), n2.c_str ()); -#else - return strcasecmp (n1.c_str (), n2.c_str ()); -#endif - } -} - std::string Netlist::normalize_name (bool case_sensitive, const std::string &n) { if (case_sensitive) { diff --git a/src/db/db/dbNetlist.h b/src/db/db/dbNetlist.h index 397417d04..9e5221796 100644 --- a/src/db/db/dbNetlist.h +++ b/src/db/db/dbNetlist.h @@ -515,11 +515,6 @@ public: */ void combine_devices (); - /** - * @brief Compares two names with the given case sensitivity - */ - static int name_compare (bool case_sensitive, const std::string &n1, const std::string &n2); - /** * @brief Normalizes a name with the given case sensitivity */ diff --git a/src/db/db/dbNetlistCompareUtils.cc b/src/db/db/dbNetlistCompareUtils.cc index b4b50b9ca..97951ca25 100644 --- a/src/db/db/dbNetlistCompareUtils.cc +++ b/src/db/db/dbNetlistCompareUtils.cc @@ -125,9 +125,40 @@ const std::string &extended_net_name (const db::Net *n) } } +static int net_name_compare (bool case_sensitive, const std::string &n1, const std::string &n2) +{ + const char *n1p = n1.c_str (); + const char *n2p = n2.c_str (); + + while (*n1p && *n2p) { + + uint32_t c1 = tl::utf32_from_utf8 (n1p); + uint32_t c2 = tl::utf32_from_utf8 (n2p); + + if (! case_sensitive) { + c1 = tl::utf32_downcase (c1); + c2 = tl::utf32_downcase (c2); + } + + if (c1 != c2) { + return c1 < c2 ? -1 : 1; + } + + } + + // colon terminates net name, such that NET:I is identical to NET. + if (*n2p && *n2p != ':') { + return -1; + } else if (*n1p && *n1p != ':') { + return 1; + } else { + return 0; + } +} + int name_compare (const db::Net *a, const db::Net *b) { - return db::Netlist::name_compare (combined_case_sensitive (a->netlist (), b->netlist ()), extended_net_name (a), extended_net_name (b)); + return net_name_compare (combined_case_sensitive (a->netlist (), b->netlist ()), extended_net_name (a), extended_net_name (b)); } bool net_names_are_different (const db::Net *a, const db::Net *b) diff --git a/src/db/db/dbNetlistCompareUtils.h b/src/db/db/dbNetlistCompareUtils.h index bb4bd2948..55614577a 100644 --- a/src/db/db/dbNetlistCompareUtils.h +++ b/src/db/db/dbNetlistCompareUtils.h @@ -92,30 +92,30 @@ std::string nets2string (const std::pair &np); /** * @brief Derives the common case sensitivity for two netlists */ -bool combined_case_sensitive (const db::Netlist *a, const db::Netlist *b); +DB_PUBLIC bool combined_case_sensitive (const db::Netlist *a, const db::Netlist *b); /** * @brief Gets the extended net name * This name is used for comparing the net names and also employs the pin name if one is given */ -const std::string &extended_net_name (const db::Net *n); +DB_PUBLIC const std::string &extended_net_name (const db::Net *n); /** * @brief Compare two nets by name */ -int name_compare (const db::Net *a, const db::Net *b); +DB_PUBLIC int name_compare (const db::Net *a, const db::Net *b); /** * @brief Returns a value indicating whether two nets are different by name * Two unnamed nets are never different. */ -bool net_names_are_different (const db::Net *a, const db::Net *b); +DB_PUBLIC bool net_names_are_different (const db::Net *a, const db::Net *b); /** * @brief Returns a value indicating whether two nets are equal by name * Two unnamed nets are never equal. */ -bool net_names_are_equal (const db::Net *a, const db::Net *b); +DB_PUBLIC bool net_names_are_equal (const db::Net *a, const db::Net *b); // -------------------------------------------------------------------------------------------------------------------- // DeviceCompare definition and implementation diff --git a/src/db/unit_tests/dbNetlistCompareTests.cc b/src/db/unit_tests/dbNetlistCompareTests.cc index 6d75f7be3..edf6727dd 100644 --- a/src/db/unit_tests/dbNetlistCompareTests.cc +++ b/src/db/unit_tests/dbNetlistCompareTests.cc @@ -25,6 +25,7 @@ #include "dbNetlistCompare.h" #include "dbNetlistCrossReference.h" #include "dbNetlistSpiceReader.h" +#include "dbNetlistCompareUtils.h" class NetlistCompareTestLogger : public db::NetlistCompareLogger @@ -437,6 +438,101 @@ TEST(0_EqualDeviceParameters) EXPECT_EQ (dc.less (d2, d1), false); } +TEST(0_NetNameEquivalence) +{ + db::Netlist a, b; + a.set_case_sensitive (true); + b.set_case_sensitive (false); + + EXPECT_EQ (db::combined_case_sensitive (&a, &b), false); + + b.set_case_sensitive (true); + EXPECT_EQ (db::combined_case_sensitive (&a, &b), true); + + a.set_case_sensitive (false); + EXPECT_EQ (db::combined_case_sensitive (&a, &b), false); + + db::Circuit *ca = new db::Circuit (); + ca->set_name ("C"); + a.add_circuit (ca); + + db::Circuit *cb = new db::Circuit (); + cb->set_name ("C"); + b.add_circuit (cb); + + db::Net *na = new db::Net ("net1"); + ca->add_net (na); + + db::Net *nb = new db::Net ("net1"); + cb->add_net (nb); + + EXPECT_EQ (db::name_compare (na, nb), 0); + + nb->set_name ("NET1"); + EXPECT_EQ (db::name_compare (na, nb), 0); + + nb->set_name ("NET2"); + EXPECT_EQ (db::name_compare (na, nb), -1); + + nb->set_name ("NET11"); + EXPECT_EQ (db::name_compare (na, nb), -1); + + nb->set_name ("net11"); + EXPECT_EQ (db::name_compare (na, nb), -1); + + nb->set_name ("net0abc"); + EXPECT_EQ (db::name_compare (na, nb), 1); + + nb->set_name ("NET0"); + EXPECT_EQ (db::name_compare (na, nb), 1); + + a.set_case_sensitive (true); + b.set_case_sensitive (true); + + nb->set_name ("net1"); + EXPECT_EQ (db::name_compare (na, nb), 0); + + nb->set_name ("net2"); + EXPECT_EQ (db::name_compare (na, nb), -1); + + nb->set_name ("net11"); + EXPECT_EQ (db::name_compare (na, nb), -1); + + nb->set_name ("net0"); + EXPECT_EQ (db::name_compare (na, nb), 1); + + nb->set_name ("NET1"); + EXPECT_EQ (db::name_compare (na, nb), 1); + + na->set_name ("NET1"); + nb->set_name ("net1"); + EXPECT_EQ (db::name_compare (na, nb), -1); + + b.set_case_sensitive (false); + + // colon terminates the net name, so that NET:I and NET and identical + + na->set_name ("NET1:I"); + nb->set_name ("net1"); + EXPECT_EQ (db::name_compare (na, nb), 0); + + na->set_name ("NET1:I"); + nb->set_name ("net1:O"); + EXPECT_EQ (db::name_compare (na, nb), -1); + + na->set_name ("NET1"); + nb->set_name ("net1:O"); + EXPECT_EQ (db::name_compare (na, nb), 0); + + na->set_name ("NET2"); + nb->set_name ("net1:O"); + EXPECT_EQ (db::name_compare (na, nb), 1); + + na->set_name ("NET1"); + nb->set_name ("net1abc:O"); + EXPECT_EQ (db::name_compare (na, nb), -1); +} + TEST(1_SimpleInverter) { const char *nls1 =