From 4dd17c3cd48e161a4735a2e0271ab74c116ca71e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 20 Dec 2018 23:29:01 +0100 Subject: [PATCH] WIP: added tests for dbNetlist classes. --- src/db/db/dbNetlist.cc | 67 ++++-- src/db/db/dbNetlist.h | 105 ++++++---- src/db/unit_tests/dbNetlistTests.cc | 308 ++++++++++++++++++++++++++++ src/db/unit_tests/unit_tests.pro | 3 +- 4 files changed, 419 insertions(+), 64 deletions(-) create mode 100644 src/db/unit_tests/dbNetlistTests.cc diff --git a/src/db/db/dbNetlist.cc b/src/db/db/dbNetlist.cc index 2f9d43a2c..7cb00d18e 100644 --- a/src/db/db/dbNetlist.cc +++ b/src/db/db/dbNetlist.cc @@ -34,8 +34,8 @@ Pin::Pin () // .. nothing yet .. } -Pin::Pin (Circuit *circuit, const std::string &name) - : m_circuit (circuit), m_name (name), m_id (0) +Pin::Pin (const std::string &name) + : m_name (name), m_id (0) { // .. nothing yet .. } @@ -43,12 +43,17 @@ Pin::Pin (Circuit *circuit, const std::string &name) // -------------------------------------------------------------------------------- // Device class implementation -Device::Device (DeviceClass *device_class) - : m_device_class (device_class) +Device::Device (DeviceClass *device_class, const std::string &name) + : m_device_class (device_class), m_name (name) { // .. nothing yet .. } +void Device::set_name (const std::string &n) +{ + m_name = n; +} + // -------------------------------------------------------------------------------- // SubCircuit class implementation @@ -81,8 +86,8 @@ const DevicePortDefinition * NetPortRef::port_def () const { const DeviceClass *dc = device_class (); - if (dc && m_port_id < dc->port_definitions ().size ()) { - return &dc->port_definitions ()[m_port_id]; + if (dc) { + return dc->port_definition (m_port_id); } else { return 0; } @@ -115,9 +120,15 @@ NetPinRef::NetPinRef (size_t pin_id, SubCircuit *circuit) // .. nothing yet .. } -const Pin *NetPinRef::pin () const +const Pin *NetPinRef::pin (const db::Circuit *c) const { - return m_subcircuit->circuit ()->pin_by_id (m_pin_id); + if (! m_subcircuit.get ()) { + tl_assert (c != 0); + return c->pin_by_id (m_pin_id); + } else { + tl_assert (m_subcircuit->circuit () != 0); + return m_subcircuit->circuit ()->pin_by_id (m_pin_id); + } } // -------------------------------------------------------------------------------- @@ -177,9 +188,11 @@ void Net::translate_devices (const std::map &map) void Net::translate_subcircuits (const std::map &map) { for (pin_list::iterator i = m_pins.begin (); i != m_pins.end (); ++i) { - std::map::const_iterator m = map.find (i->subcircuit ()); - tl_assert (m != map.end ()); - i->set_subcircuit (m->second); + if (i->subcircuit ()) { + std::map::const_iterator m = map.find (i->subcircuit ()); + tl_assert (m != map.end ()); + i->set_subcircuit (m->second); + } } } @@ -321,14 +334,16 @@ DeviceClass::DeviceClass () // .. nothing yet .. } -DeviceClass::DeviceClass (const DeviceClass & /*other*/) +DeviceClass::DeviceClass (const DeviceClass &other) { - // .. nothing yet .. + operator= (other); } -DeviceClass &DeviceClass::operator= (const DeviceClass & /*other*/) +DeviceClass &DeviceClass::operator= (const DeviceClass &other) { - // .. nothing yet .. + if (this != &other) { + m_port_definitions = other.m_port_definitions; + } return *this; } @@ -344,10 +359,24 @@ const std::string &DeviceClass::description () const return no_description; } -const std::vector &DeviceClass::port_definitions () const +void DeviceClass::add_port_definition (const DevicePortDefinition &pd) { - static std::vector no_defs; - return no_defs; + m_port_definitions.push_back (pd); + m_port_definitions.back ().set_id (m_port_definitions.size () - 1); +} + +void DeviceClass::clear_port_definitions () +{ + m_port_definitions.clear (); +} + +const DevicePortDefinition *DeviceClass::port_definition (size_t id) const +{ + if (id < m_port_definitions.size ()) { + return & m_port_definitions [id]; + } else { + return 0; + } } // -------------------------------------------------------------------------------- @@ -366,7 +395,7 @@ GenericDeviceClass::GenericDeviceClass (const GenericDeviceClass &other) GenericDeviceClass &GenericDeviceClass::operator= (const GenericDeviceClass &other) { if (this != &other) { - m_port_definitions = other.m_port_definitions; + DeviceClass::operator= (other); m_name = other.m_name; m_description = other.m_description; } diff --git a/src/db/db/dbNetlist.h b/src/db/db/dbNetlist.h index 84e541049..4e4d90de9 100644 --- a/src/db/db/dbNetlist.h +++ b/src/db/db/dbNetlist.h @@ -55,17 +55,9 @@ public: Pin (); /** - * @brief Creates a port of the given circuit with the given name. + * @brief Creates a pin with the given name. */ - Pin (Circuit *circuit, const std::string &name); - - /** - * @brief Gets the circuit reference - */ - const Circuit *circuit () const - { - return m_circuit.get (); - } + Pin (const std::string &name); /** * @brief Gets the name of the pin @@ -112,7 +104,7 @@ public: /** * @brief The constructor */ - Device (DeviceClass *device_class); + Device (DeviceClass *device_class, const std::string &name = std::string ()); /** * @brief Gets the device class @@ -130,8 +122,22 @@ public: m_device_class.reset (cls); } + /** + * @brief Sets the name + */ + void set_name (const std::string &n); + + /** + * @brief Gets the name + */ + const std::string &name () const + { + return m_name; + } + private: tl::weak_ptr m_device_class; + std::string m_name; }; /** @@ -283,8 +289,11 @@ public: /** * @brief Gets the pin reference from the pin id + * + * The circuit is the one where the net is defined. It is used to + * resolve outgoing pints. */ - const Pin *pin () const; + const Pin *pin (const Circuit *c) const; /** * @brief Gets the subcircuit reference @@ -695,7 +704,7 @@ public: * @brief Creates an empty device port definition */ DevicePortDefinition () - : m_name (), m_description () + : m_name (), m_description (), m_id (0) { // .. nothing yet .. } @@ -704,7 +713,7 @@ public: * @brief Creates a device port definition with the given name and description */ DevicePortDefinition (const std::string &name, const std::string &description) - : m_name (name), m_description (description) + : m_name (name), m_description (description), m_id (0) { // .. nothing yet .. } @@ -741,8 +750,24 @@ public: m_description = d; } + /** + * @brief Gets the port ID + */ + size_t id () const + { + return m_id; + } + private: + friend class DeviceClass; + std::string m_name, m_description; + size_t m_id; + + void set_id (size_t id) + { + m_id = id; + } }; /** @@ -807,7 +832,28 @@ public: * The number of ports is constant per class. The index of the port * is used as an ID of the port, hence the order must be static. */ - virtual const std::vector &port_definitions () const; + virtual const std::vector &port_definitions () const + { + return m_port_definitions; + } + + /** + * @brief Adds a port definition + */ + void add_port_definition (const DevicePortDefinition &pd); + + /** + * @brief Clears the port definition + */ + void clear_port_definitions (); + + /** + * @brief Gets the port definition from the ID + */ + const DevicePortDefinition *port_definition (size_t id) const; + +private: + std::vector m_port_definitions; }; /** @@ -881,36 +927,7 @@ public: m_description = d; } - /** - * @brief Gets the port definitions - * - * The port definitions indicate what ports the device offers. - * The number of ports is constant per class. The index of the port - * is used as an ID of the port, hence the order must be static. - */ - virtual const std::vector &port_definitions () const - { - return m_port_definitions; - } - - /** - * @brief Adds a port definition - */ - void add_port_definition (const DevicePortDefinition &pd) - { - m_port_definitions.push_back (pd); - } - - /** - * @brief Clears the port definition - */ - void clear_port_definitions () - { - m_port_definitions.clear (); - } - private: - std::vector m_port_definitions; std::string m_name, m_description; }; diff --git a/src/db/unit_tests/dbNetlistTests.cc b/src/db/unit_tests/dbNetlistTests.cc new file mode 100644 index 000000000..c13d22e09 --- /dev/null +++ b/src/db/unit_tests/dbNetlistTests.cc @@ -0,0 +1,308 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "dbNetlist.h" + +#include "tlUnitTest.h" +#include "tlString.h" + +#include + +static std::string pd2string (const db::DevicePortDefinition &pd) +{ + return pd.name () + "(" + pd.description () + ") #" + tl::to_string (pd.id ()); +} + +TEST(1_DevicePortDefinition) +{ + db::DevicePortDefinition pd; + + EXPECT_EQ (pd2string (pd), "() #0"); + pd.set_name ("name"); + pd.set_description ("nothing yet"); + EXPECT_EQ (pd2string (pd), "name(nothing yet) #0"); + + db::DevicePortDefinition pd2; + pd2 = pd; + EXPECT_EQ (pd2string (pd2), "name(nothing yet) #0"); + pd2.set_name ("name2"); + pd2.set_description ("now it has something"); + EXPECT_EQ (pd2string (pd2), "name2(now it has something) #0"); + + db::DeviceClass dc; + dc.add_port_definition (pd); + dc.add_port_definition (pd2); + EXPECT_EQ (pd2string (dc.port_definitions ()[0]), "name(nothing yet) #0"); + EXPECT_EQ (pd2string (dc.port_definitions ()[1]), "name2(now it has something) #1"); +} + +TEST(2_DeviceClass) +{ + db::DevicePortDefinition pd; + pd.set_name ("name"); + pd.set_description ("nothing yet"); + + db::DevicePortDefinition pd2; + pd2.set_name ("name2"); + pd2.set_description ("now it has something"); + + db::GenericDeviceClass dc; + dc.set_name ("devname"); + dc.set_description ("devdesc"); + EXPECT_EQ (dc.name (), "devname"); + EXPECT_EQ (dc.description (), "devdesc"); + dc.add_port_definition (pd); + dc.add_port_definition (pd2); + EXPECT_EQ (dc.port_definitions ().size (), size_t (2)); + EXPECT_EQ (pd2string (dc.port_definitions ()[0]), "name(nothing yet) #0"); + EXPECT_EQ (pd2string (dc.port_definitions ()[1]), "name2(now it has something) #1"); + + EXPECT_EQ (pd2string (*dc.port_definition (dc.port_definitions ()[0].id ())), "name(nothing yet) #0"); + EXPECT_EQ (pd2string (*dc.port_definition (dc.port_definitions ()[1].id ())), "name2(now it has something) #1"); + EXPECT_EQ (dc.port_definition (3), 0); + + db::GenericDeviceClass dc2 = dc; + EXPECT_EQ (dc2.name (), "devname"); + EXPECT_EQ (dc2.description (), "devdesc"); + EXPECT_EQ (dc2.port_definitions ().size (), size_t (2)); + EXPECT_EQ (pd2string (*dc2.port_definition (dc2.port_definitions ()[0].id ())), "name(nothing yet) #0"); + EXPECT_EQ (pd2string (*dc2.port_definition (dc2.port_definitions ()[1].id ())), "name2(now it has something) #1"); + EXPECT_EQ (dc2.port_definition (3), 0); +} + +static std::string pins2string (const db::Circuit &c) +{ + std::string res; + for (db::Circuit::const_pin_iterator i = c.begin_pins (); i != c.end_pins (); ++i) { + if (!res.empty ()) { + res += ","; + } + res += i->name (); + res += "#" + tl::to_string (i->id ()); + } + return res; +} + +TEST(3_CircuitBasic) +{ + db::Circuit c; + c.set_name ("name"); + EXPECT_EQ (c.name (), "name"); + + db::Pin p1 ("p1"); + db::Pin p2 ("p2"); + c.add_pin (p1); + c.add_pin (p2); + EXPECT_EQ (pins2string (c), "p1#0,p2#1"); + + EXPECT_EQ (c.pin_by_id (0)->name (), "p1"); + EXPECT_EQ (c.pin_by_id (1)->name (), "p2"); + EXPECT_EQ (c.pin_by_id (2), 0); + + db::Circuit c2 = c; + EXPECT_EQ (c2.name (), "name"); + EXPECT_EQ (pins2string (c), "p1#0,p2#1"); + + EXPECT_EQ (c2.pin_by_id (0)->name (), "p1"); + EXPECT_EQ (c2.pin_by_id (1)->name (), "p2"); + EXPECT_EQ (c2.pin_by_id (2), 0); +} + +static std::string net2string (const db::Net &n, const db::Circuit *c = 0) +{ + std::string res; + for (db::Net::const_port_iterator i = n.begin_ports (); i != n.end_ports (); ++i) { + if (! res.empty ()) { + res += ","; + } + res += i->device () ? i->device ()->name () : "(null)"; + res += ":"; + res += i->port_def () ? i->port_def ()->name () : "(null)"; + } + for (db::Net::const_pin_iterator i = n.begin_pins (); i != n.end_pins (); ++i) { + if (! res.empty ()) { + res += ","; + } + if (i->subcircuit ()) { + res += i->subcircuit ()->circuit () ? i->subcircuit ()->circuit ()->name () : "(null)"; + res += ":"; + } else { + res += "+"; + } + res += i->pin (c) ? i->pin (c)->name () : "(null)"; + } + return res; +} + +static std::string nets2string (const db::Circuit &c) +{ + std::string res; + for (db::Circuit::const_net_iterator n = c.begin_nets (); n != c.end_nets (); ++n) { + res += net2string (*n, &c); + res += "\n"; + } + return res; +} + +TEST(4_CircuitDevices) +{ + db::GenericDeviceClass dc1; + dc1.set_name ("dc1"); + dc1.add_port_definition (db::DevicePortDefinition ("S", "Source")); + dc1.add_port_definition (db::DevicePortDefinition ("G", "Gate")); + dc1.add_port_definition (db::DevicePortDefinition ("D", "Drain")); + + db::GenericDeviceClass dc2; + dc2.set_name ("dc2"); + dc2.add_port_definition (db::DevicePortDefinition ("A", "")); + dc2.add_port_definition (db::DevicePortDefinition ("B", "")); + + std::auto_ptr c (new db::Circuit ()); + db::Device *d1 = new db::Device (&dc1, "d1"); + db::Device *d2a = new db::Device (&dc2, "d2a"); + db::Device *d2b = new db::Device (&dc2, "d2b"); + c->add_device (d1); + c->add_device (d2a); + c->add_device (d2b); + + db::Net *n1 = new db::Net (); + c->add_net (n1); + n1->add_port (db::NetPortRef (d1, 0)); + n1->add_port (db::NetPortRef (d2a, 0)); + + db::Net *n2 = new db::Net (); + c->add_net (n2); + n2->add_port (db::NetPortRef (d1, 1)); + n2->add_port (db::NetPortRef (d2a, 1)); + n2->add_port (db::NetPortRef (d2b, 0)); + + db::Net *n3 = new db::Net (); + c->add_net (n3); + n3->add_port (db::NetPortRef (d1, 2)); + n3->add_port (db::NetPortRef (d2b, 1)); + + EXPECT_EQ (nets2string (*c), + "d1:S,d2a:A\n" + "d1:G,d2a:B,d2b:A\n" + "d1:D,d2b:B\n" + ); + + db::Circuit cc = *c; + c.reset (0); + + EXPECT_EQ (nets2string (cc), + "d1:S,d2a:A\n" + "d1:G,d2a:B,d2b:A\n" + "d1:D,d2b:B\n" + ); +} + +static std::string netlist2string (const db::Netlist &nl) +{ + std::string res; + for (db::Netlist::const_circuit_iterator c = nl.begin_circuits (); c != nl.end_circuits (); ++c) { + res += "[" + c->name () + "]\n"; + res += nets2string (*c); + } + return res; +} + +TEST(4_NetlistSubcircuits) +{ + std::auto_ptr nl (new db::Netlist ()); + + db::GenericDeviceClass *dc = new db::GenericDeviceClass (); + dc->set_name ("dc2"); + dc->add_port_definition (db::DevicePortDefinition ("A", "")); + dc->add_port_definition (db::DevicePortDefinition ("B", "")); + nl->add_device_class (dc); + + db::Circuit *c1 = new db::Circuit (); + c1->set_name ("c1"); + c1->add_pin (db::Pin ("c1p1")); + c1->add_pin (db::Pin ("c1p2")); + nl->add_circuit (c1); + + db::Circuit *c2 = new db::Circuit (); + c2->set_name ("c2"); + c2->add_pin (db::Pin ("c2p1")); + c2->add_pin (db::Pin ("c2p2")); + nl->add_circuit (c2); + + db::Device *d = new db::Device (dc, "D"); + c2->add_device (d); + + db::SubCircuit *sc1 = new db::SubCircuit (c2); + c1->add_sub_circuit (sc1); + + db::SubCircuit *sc2 = new db::SubCircuit (c2); + c1->add_sub_circuit (sc2); + + db::Net *n2a = new db::Net (); + n2a->add_pin (db::NetPinRef (0)); + n2a->add_port (db::NetPortRef (d, 0)); + c2->add_net (n2a); + + db::Net *n2b = new db::Net (); + n2b->add_port (db::NetPortRef (d, 1)); + n2b->add_pin (db::NetPinRef (1)); + c2->add_net (n2b); + + db::Net *n1a = new db::Net (); + n1a->add_pin (db::NetPinRef (0)); + n1a->add_pin (db::NetPinRef (0, sc1)); + c1->add_net (n1a); + + db::Net *n1b = new db::Net (); + n1b->add_pin (db::NetPinRef (1, sc1)); + n1b->add_pin (db::NetPinRef (0, sc2)); + c1->add_net (n1b); + + db::Net *n1c = new db::Net (); + n1c->add_pin (db::NetPinRef (1, sc2)); + n1c->add_pin (db::NetPinRef (1)); + c1->add_net (n1c); + + EXPECT_EQ (netlist2string (*nl), + "[c1]\n" + "+c1p1,c2:c2p1\n" + "c2:c2p2,c2:c2p1\n" + "c2:c2p2,+c1p2\n" + "[c2]\n" + "D:A,+c2p1\n" + "D:B,+c2p2\n" + ); + + db::Netlist nl2 = *nl; + nl.reset (0); + + EXPECT_EQ (netlist2string (nl2), + "[c1]\n" + "+c1p1,c2:c2p1\n" + "c2:c2p2,c2:c2p1\n" + "c2:c2p2,+c1p2\n" + "[c2]\n" + "D:A,+c2p1\n" + "D:B,+c2p2\n" + ); +} diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index f67e2f202..63a29945c 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -59,7 +59,8 @@ SOURCES = \ dbDeepRegionTests.cc \ dbDeepShapeStoreTests.cc \ dbHierNetworkProcessorTests.cc \ - dbNetlistPropertyTests.cc + dbNetlistPropertyTests.cc \ + dbNetlistTests.cc INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC