diff --git a/src/db/db/dbNetlist.cc b/src/db/db/dbNetlist.cc index 85719f6d3..a1fdcab96 100644 --- a/src/db/db/dbNetlist.cc +++ b/src/db/db/dbNetlist.cc @@ -369,6 +369,16 @@ void Netlist::remove_circuit (Circuit *circuit) m_circuits.erase (circuit); } +DeviceClass *Netlist::device_class_by_name (const std::string &name) +{ + for (device_class_iterator d = begin_device_classes (); d != end_device_classes (); ++d) { + if (d->name () == name) { + return d.operator-> (); + } + } + return 0; +} + void Netlist::add_device_class (DeviceClass *device_class) { m_device_classes.push_back (device_class); diff --git a/src/db/db/dbNetlist.h b/src/db/db/dbNetlist.h index aeae88923..98d47f84b 100644 --- a/src/db/db/dbNetlist.h +++ b/src/db/db/dbNetlist.h @@ -281,6 +281,23 @@ public: */ void remove_device_class (DeviceClass *device_class); + /** + * @brief Gets a device class by it's name (const version) + * + * This method returns 0 if there is no class with this name. + */ + const DeviceClass *device_class_by_name (const std::string &name) const + { + return const_cast (this)->device_class_by_name (name); + } + + /** + * @brief Gets a device class by it's name (non-const version) + * + * This method returns 0 if there is no class with this name. + */ + DeviceClass *device_class_by_name (const std::string &name); + /** * @brief Begin iterator for the device classes of the netlist (non-const version) */ diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index 94c152521..5dc648258 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -959,7 +959,7 @@ Class decl_dbNetlist ("db", "Netlist", ) + gsi::method ("circuit_by_name", (db::Circuit *(db::Netlist::*) (const std::string &)) &db::Netlist::circuit_by_name, gsi::arg ("name"), "@brief Gets the circuit object for a given name.\n" - "If the ID is not a valid circuit name, nil is returned." + "If the name is not a valid circuit name, nil is returned." ) + gsi::iterator ("each_circuit_top_down", (db::Netlist::top_down_circuit_iterator (db::Netlist::*) ()) &db::Netlist::begin_top_down, (db::Netlist::top_down_circuit_iterator (db::Netlist::*) ()) &db::Netlist::end_top_down, "@brief Iterates over the circuits top-down\n" @@ -990,6 +990,10 @@ Class decl_dbNetlist ("db", "Netlist", "Use this method with care as it may corrupt the internal structure of the netlist. " "Only use this method when device refers to this device class." ) + + gsi::method ("device_class_by_name", (db::DeviceClass *(db::Netlist::*) (const std::string &)) &db::Netlist::device_class_by_name, gsi::arg ("name"), + "@brief Gets the device class for a given name.\n" + "If the name is not a valid device class name, nil is returned." + ) + gsi::iterator ("each_device_class", (db::Netlist::device_class_iterator (db::Netlist::*) ()) &db::Netlist::begin_device_classes, (db::Netlist::device_class_iterator (db::Netlist::*) ()) &db::Netlist::end_device_classes, "@brief Iterates over the device classes of the netlist" ) + diff --git a/src/db/unit_tests/dbNetlistCompareTests.cc b/src/db/unit_tests/dbNetlistCompareTests.cc index 61a2ad786..1bf6e0fb9 100644 --- a/src/db/unit_tests/dbNetlistCompareTests.cc +++ b/src/db/unit_tests/dbNetlistCompareTests.cc @@ -1511,6 +1511,11 @@ public: return tl::join (m_texts, "\n"); } + void clear () + { + m_texts.clear (); + } + private: std::vector m_texts; @@ -1552,6 +1557,14 @@ static void prep_nl (db::Netlist &nl, const char *str) dc->set_name ("NMOS"); nl.add_device_class (dc); + dc = new db::DeviceClassMOS3Transistor (); + dc->set_name ("PMOSB"); + nl.add_device_class (dc); + + dc = new db::DeviceClassMOS3Transistor (); + dc->set_name ("NMOSB"); + nl.add_device_class (dc); + dc = new db::DeviceClassMOS4Transistor (); dc->set_name ("PMOS4"); nl.add_device_class (dc); @@ -1619,6 +1632,52 @@ TEST(1_SimpleInverter) EXPECT_EQ (good, true); } +TEST(1_SimpleInverterMatchedDeviceClasses) +{ + const char *nls1 = + "circuit INV ($1=IN,$2=OUT,$3=VDD,$4=VSS);\n" + " device PMOS $1 (S=VDD,G=IN,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + " device NMOS $2 (S=VSS,G=IN,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + "end;\n"; + + const char *nls2 = + "circuit INV ($1=VDD,$2=IN,$3=VSS,$4=OUT);\n" + " device NMOSB $1 (S=OUT,G=IN,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + " device PMOSB $2 (S=VDD,G=IN,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + "end;\n"; + + db::Netlist nl1, nl2; + prep_nl (nl1, nls1); + prep_nl (nl2, nls2); + + NetlistCompareTestLogger logger; + db::NetlistComparer comp (&logger); + comp.same_device_classes (nl1.device_class_by_name ("PMOS"), nl2.device_class_by_name ("PMOSB")); + + bool good = comp.compare (&nl1, &nl2); + EXPECT_EQ (good, false); + + logger.clear (); + comp.same_device_classes (nl1.device_class_by_name ("NMOS"), nl2.device_class_by_name ("NMOSB")); + good = comp.compare (&nl1, &nl2); + + EXPECT_EQ (logger.text (), + "begin_circuit INV INV\n" + "match_nets VDD VDD\n" + "match_nets VSS VSS\n" + "match_nets OUT OUT\n" + "match_nets IN IN\n" + "match_pins $2 $0\n" + "match_pins $3 $2\n" + "match_pins $1 $3\n" + "match_pins $0 $1\n" + "match_devices $2 $1\n" + "match_devices $1 $2\n" + "end_circuit INV INV MATCH" + ); + EXPECT_EQ (good, true); +} + TEST(2_SimpleInverterWithForcedNetAssignment) { const char *nls1 = diff --git a/testdata/ruby/dbNetlist.rb b/testdata/ruby/dbNetlist.rb index 96d5d6c51..0897f9ad2 100644 --- a/testdata/ruby/dbNetlist.rb +++ b/testdata/ruby/dbNetlist.rb @@ -105,6 +105,9 @@ class DBNetlist_TestClass < TestBase nl.add(cc) cc.name = "UVW" + assert_equal(nl.device_class_by_name("UVW") == cc, true) + assert_equal(nl.device_class_by_name("doesntexist") == nil, true) + names = [] nl.each_device_class { |i| names << i.name } assert_equal(names, [ c.name, cc.name ])