WIP: added tests for dbNetlist classes.

This commit is contained in:
Matthias Koefferlein 2018-12-20 23:29:01 +01:00
parent 18346945df
commit 4dd17c3cd4
4 changed files with 419 additions and 64 deletions

View File

@ -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<const Device *, Device *> &map)
void Net::translate_subcircuits (const std::map<const SubCircuit *, SubCircuit *> &map)
{
for (pin_list::iterator i = m_pins.begin (); i != m_pins.end (); ++i) {
std::map<const SubCircuit *, SubCircuit *>::const_iterator m = map.find (i->subcircuit ());
tl_assert (m != map.end ());
i->set_subcircuit (m->second);
if (i->subcircuit ()) {
std::map<const SubCircuit *, SubCircuit *>::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<DevicePortDefinition> &DeviceClass::port_definitions () const
void DeviceClass::add_port_definition (const DevicePortDefinition &pd)
{
static std::vector<DevicePortDefinition> 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;
}

View File

@ -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<DeviceClass> 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<DevicePortDefinition> &port_definitions () const;
virtual const std::vector<DevicePortDefinition> &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<DevicePortDefinition> 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<DevicePortDefinition> &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<DevicePortDefinition> m_port_definitions;
std::string m_name, m_description;
};

View File

@ -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 <memory>
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<db::Circuit> 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<db::Netlist> 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"
);
}

View File

@ -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