Introducing netlist object properties.

This commit is contained in:
Matthias Koefferlein 2019-11-11 07:02:02 +01:00
parent b220374bd1
commit 0ce06125ca
16 changed files with 346 additions and 28 deletions

View File

@ -183,7 +183,8 @@ SOURCES = \
dbLayoutVsSchematicFormatDefs.cc \
dbLayoutVsSchematic.cc \
gsiDeclDbNetlistCrossReference.cc \
gsiDeclDbLayoutVsSchematic.cc
gsiDeclDbLayoutVsSchematic.cc \
dbNetlistObject.cc
HEADERS = \
dbArray.h \
@ -329,7 +330,8 @@ HEADERS = \
dbLayoutVsSchematicWriter.h \
dbLayoutVsSchematicReader.h \
dbLayoutVsSchematicFormatDefs.h \
dbLayoutVsSchematic.h
dbLayoutVsSchematic.h \
dbNetlistObject.h
!equals(HAVE_QT, "0") {

View File

@ -33,7 +33,7 @@ namespace db
// Circuit class implementation
Circuit::Circuit ()
: m_dont_purge (false), m_cell_index (0), mp_netlist (0),
: gsi::ObjectBase (), db::NetlistObject (), m_dont_purge (false), m_cell_index (0), mp_netlist (0),
m_device_by_id (this, &Circuit::begin_devices, &Circuit::end_devices),
m_subcircuit_by_id (this, &Circuit::begin_subcircuits, &Circuit::end_subcircuits),
m_net_by_cluster_id (this, &Circuit::begin_nets, &Circuit::end_nets),
@ -48,7 +48,7 @@ Circuit::Circuit ()
}
Circuit::Circuit (const db::Layout &layout, db::cell_index_type ci)
: m_name (layout.cell_name (ci)), m_dont_purge (false), m_cell_index (ci), mp_netlist (0),
: gsi::ObjectBase (), db::NetlistObject (), m_name (layout.cell_name (ci)), m_dont_purge (false), m_cell_index (ci), mp_netlist (0),
m_device_by_id (this, &Circuit::begin_devices, &Circuit::end_devices),
m_subcircuit_by_id (this, &Circuit::begin_subcircuits, &Circuit::end_subcircuits),
m_net_by_cluster_id (this, &Circuit::begin_nets, &Circuit::end_nets),
@ -65,7 +65,7 @@ Circuit::Circuit (const db::Layout &layout, db::cell_index_type ci)
}
Circuit::Circuit (const Circuit &other)
: gsi::ObjectBase (other), tl::Object (other), m_dont_purge (false), m_cell_index (0), mp_netlist (0),
: gsi::ObjectBase (other), db::NetlistObject (other), m_dont_purge (false), m_cell_index (0), mp_netlist (0),
m_device_by_id (this, &Circuit::begin_devices, &Circuit::end_devices),
m_subcircuit_by_id (this, &Circuit::begin_subcircuits, &Circuit::end_subcircuits),
m_net_by_cluster_id (this, &Circuit::begin_nets, &Circuit::end_nets),
@ -95,6 +95,8 @@ Circuit &Circuit::operator= (const Circuit &other)
{
if (this != &other) {
db::NetlistObject::operator= (other);
clear ();
m_name = other.m_name;

View File

@ -86,7 +86,7 @@ public:
* devices.
*/
class DB_PUBLIC Circuit
: public gsi::ObjectBase, public tl::Object
: public db::NetlistObject, public gsi::ObjectBase
{
public:
typedef tl::vector<Pin> pin_list;
@ -353,6 +353,14 @@ public:
*/
const Pin *pin_by_id (size_t id) const;
/**
* @brief Gets the pin by ID (the ID is basically the index) - non-const version
*/
Pin *pin_by_id (size_t id)
{
return const_cast<Pin *> (((const db::Circuit *) this)->pin_by_id (id));
}
/**
* @brief Gets the pin by name
*
@ -361,6 +369,14 @@ public:
*/
const Pin *pin_by_name (const std::string &name) const;
/**
* @brief Gets the pin by name - non-const version
*/
Pin *pin_by_name (const std::string &name)
{
return const_cast<Pin *> (((const db::Circuit *) this)->pin_by_name (name));
}
/**
* @brief Begin iterator for the pins of the circuit (const version)
*/

View File

@ -31,7 +31,7 @@ namespace db
// Device class implementation
Device::Device ()
: mp_device_class (0), mp_device_abstract (0), m_id (0), mp_circuit (0)
: db::NetlistObject (), mp_device_class (0), mp_device_abstract (0), m_id (0), mp_circuit (0)
{
// .. nothing yet ..
}
@ -46,19 +46,19 @@ Device::~Device ()
}
Device::Device (DeviceClass *device_class, const std::string &name)
: mp_device_class (device_class), mp_device_abstract (0), m_name (name), m_id (0), mp_circuit (0)
: db::NetlistObject (), mp_device_class (device_class), mp_device_abstract (0), m_name (name), m_id (0), mp_circuit (0)
{
// .. nothing yet ..
}
Device::Device (DeviceClass *device_class, DeviceAbstract *device_abstract, const std::string &name)
: mp_device_class (device_class), mp_device_abstract (device_abstract), m_name (name), m_id (0), mp_circuit (0)
: db::NetlistObject (), mp_device_class (device_class), mp_device_abstract (device_abstract), m_name (name), m_id (0), mp_circuit (0)
{
// .. nothing yet ..
}
Device::Device (const Device &other)
: tl::Object (other), mp_device_class (0), mp_device_abstract (0), m_id (0), mp_circuit (0)
: db::NetlistObject (other), mp_device_class (0), mp_device_abstract (0), m_id (0), mp_circuit (0)
{
operator= (other);
}
@ -66,6 +66,7 @@ Device::Device (const Device &other)
Device &Device::operator= (const Device &other)
{
if (this != &other) {
db::NetlistObject::operator= (other);
m_name = other.m_name;
m_trans = other.m_trans;
m_parameters = other.m_parameters;

View File

@ -95,7 +95,7 @@ struct DeviceAbstractRef
* a specific device class.
*/
class DB_PUBLIC Device
: public tl::Object
: public db::NetlistObject
{
public:
typedef std::vector<std::pair<size_t, size_t> > global_connections;

View File

@ -155,19 +155,19 @@ const Pin *NetSubcircuitPinRef::pin () const
// Net class implementation
Net::Net ()
: m_cluster_id (0), mp_circuit (0)
: NetlistObject (), m_cluster_id (0), mp_circuit (0)
{
// .. nothing yet ..
}
Net::Net (const std::string &name)
: m_cluster_id (0), mp_circuit (0)
: NetlistObject (), m_cluster_id (0), mp_circuit (0)
{
m_name = name;
}
Net::Net (const Net &other)
: tl::Object (other), m_cluster_id (0), mp_circuit (0)
: NetlistObject (other), m_cluster_id (0), mp_circuit (0)
{
operator= (other);
}
@ -176,6 +176,8 @@ Net &Net::operator= (const Net &other)
{
if (this != &other) {
db::NetlistObject::operator= (other);
clear ();
m_name = other.m_name;

View File

@ -24,6 +24,7 @@
#define _HDR_dbNet
#include "dbCommon.h"
#include "dbNetlistObject.h"
#include "tlObject.h"
@ -360,7 +361,7 @@ private:
* A net connects terminals of devices and pins or circuits
*/
class DB_PUBLIC Net
: public tl::Object
: public db::NetlistObject
{
public:
typedef std::list<NetTerminalRef> terminal_list;

View File

@ -0,0 +1,69 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2019 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 "dbNetlistObject.h"
namespace db
{
NetlistObject::NetlistObject ()
: tl::Object ()
{
// .. nothing yet ..
}
NetlistObject::NetlistObject (const db::NetlistObject &other)
: tl::Object (other), m_properties (other.m_properties)
{
// .. nothing yet ..
}
NetlistObject &NetlistObject::operator= (const NetlistObject &other)
{
if (this != &other) {
tl::Object::operator= (other);
m_properties = other.m_properties;
}
return *this;
}
tl::Variant NetlistObject::property (const tl::Variant &key) const
{
std::map<tl::Variant, tl::Variant>::const_iterator i = m_properties.find (key);
if (i == m_properties.end ()) {
return tl::Variant ();
} else {
return i->second;
}
}
void
NetlistObject::set_property (const tl::Variant &key, const tl::Variant &value)
{
if (value.is_nil ()) {
m_properties.erase (key);
} else {
m_properties [key] = value;
}
}
}

View File

@ -0,0 +1,76 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2019 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
*/
#ifndef _HDR_dbNetlistObject
#define _HDR_dbNetlistObject
#include "dbCommon.h"
#include "tlObject.h"
#include "tlVariant.h"
#include <list>
#include <string>
namespace db
{
/**
* @brief A base class for a objects in the netlist
*/
class DB_PUBLIC NetlistObject
: public tl::Object
{
public:
/**
* @brief Default constructor
*/
NetlistObject ();
/**
* @brief Copy constructor
*/
NetlistObject (const db::NetlistObject &object);
/**
* @brief Assignment
*/
NetlistObject &operator= (const NetlistObject &other);
/**
* @brief Gets the property value for a given key
* Returns nil if there is no property for the given key.
*/
tl::Variant property (const tl::Variant &key) const;
/**
* @brief Sets the property value for a given key
* Set the value to nil to clear a specific key
*/
void set_property (const tl::Variant &key, const tl::Variant &value);
private:
std::map<tl::Variant, tl::Variant> m_properties;
};
}
#endif

View File

@ -30,13 +30,13 @@ namespace db
// Pin class implementation
Pin::Pin ()
: m_id (0)
: db::NetlistObject (), m_id (0)
{
// .. nothing yet ..
}
Pin::Pin (const std::string &name)
: m_name (name), m_id (0)
: db::NetlistObject (), m_name (name), m_id (0)
{
// .. nothing yet ..
}

View File

@ -24,6 +24,7 @@
#define _HDR_dbPin
#include "dbCommon.h"
#include "dbNetlistObject.h"
#include <string>
@ -36,6 +37,7 @@ namespace db
* A pin is some place other nets can connect to a circuit.
*/
class DB_PUBLIC Pin
: public db::NetlistObject
{
public:
/**

View File

@ -30,7 +30,7 @@ namespace db
// SubCircuit class implementation
SubCircuit::SubCircuit ()
: m_id (0), mp_circuit (0)
: db::NetlistObject (), m_id (0), mp_circuit (0)
{
// .. nothing yet ..
}
@ -45,13 +45,13 @@ SubCircuit::~SubCircuit()
}
SubCircuit::SubCircuit (Circuit *circuit, const std::string &name)
: m_circuit_ref (0), m_name (name), m_id (0), mp_circuit (0)
: db::NetlistObject (), m_circuit_ref (0), m_name (name), m_id (0), mp_circuit (0)
{
set_circuit_ref (circuit);
}
SubCircuit::SubCircuit (const SubCircuit &other)
: tl::Object (other), m_id (0), mp_circuit (0)
: db::NetlistObject (other), m_id (0), mp_circuit (0)
{
operator= (other);
}
@ -59,6 +59,7 @@ SubCircuit::SubCircuit (const SubCircuit &other)
SubCircuit &SubCircuit::operator= (const SubCircuit &other)
{
if (this != &other) {
db::NetlistObject::operator= (other);
m_name = other.m_name;
m_trans = other.m_trans;
set_circuit_ref (const_cast<Circuit *> (other.circuit_ref ()));

View File

@ -43,7 +43,7 @@ class Circuit;
* This class essentially is a reference to another circuit
*/
class DB_PUBLIC SubCircuit
: public tl::Object
: public db::NetlistObject
{
public:
typedef tl::vector<const Net *> connected_net_list;

View File

@ -34,7 +34,21 @@
namespace gsi
{
Class<db::Pin> decl_dbPin ("db", "Pin",
Class<db::NetlistObject> decl_dbNetlistObject ("db", "NetlistObject",
gsi::method ("property", &db::NetlistObject::property, gsi::arg ("key"),
"@brief Gets the property value for the given key or nil if there is no value with this key."
) +
gsi::method ("set_property", &db::NetlistObject::set_property, gsi::arg ("key"), gsi::arg ("value"),
"@brief Sets the property value for the given key.\n"
"Use a nil value to erase the property with this key."
),
"@brief The base class for some netlist objects.\n"
"The main purpose of this class is to supply user properties for netlist objects.\n"
"\n"
"This class has been introduced in version 0.26.2"
);
Class<db::Pin> decl_dbPin (decl_dbNetlistObject, "db", "Pin",
gsi::method ("id", &db::Pin::id,
"@brief Gets the ID of the pin.\n"
) +
@ -225,7 +239,7 @@ static void add_other_abstracts (db::Device *device, const db::DeviceAbstractRef
device->other_abstracts ().push_back (ref);
}
Class<db::Device> decl_dbDevice ("db", "Device",
Class<db::Device> decl_dbDevice (decl_dbNetlistObject, "db", "Device",
gsi::method ("device_class", &db::Device::device_class,
"@brief Gets the device class the device belongs to.\n"
) +
@ -397,7 +411,7 @@ static void subcircuit_disconnect_pin1 (db::SubCircuit *subcircuit, const db::Pi
}
}
Class<db::SubCircuit> decl_dbSubCircuit ("db", "SubCircuit",
Class<db::SubCircuit> decl_dbSubCircuit (decl_dbNetlistObject, "db", "SubCircuit",
gsi::method ("circuit_ref", (const db::Circuit *(db::SubCircuit::*) () const) &db::SubCircuit::circuit_ref,
"@brief Gets the circuit referenced by the subcircuit.\n"
) +
@ -516,7 +530,7 @@ Class<db::NetSubcircuitPinRef> decl_dbNetSubcircuitPinRef ("db", "NetSubcircuitP
"This class has been added in version 0.26."
);
Class<db::Net> decl_dbNet ("db", "Net",
Class<db::Net> decl_dbNet (decl_dbNetlistObject, "db", "Net",
gsi::method ("circuit", (db::Circuit *(db::Net::*) ()) &db::Net::circuit,
"@brief Gets the circuit the net lives in."
) +
@ -1098,7 +1112,7 @@ static void circuit_disconnect_pin1 (db::Circuit *c, const db::Pin *pin)
}
}
Class<db::Circuit> decl_dbCircuit ("db", "Circuit",
Class<db::Circuit> decl_dbCircuit (decl_dbNetlistObject, "db", "Circuit",
gsi::method ("create_pin", &db::Circuit::add_pin, gsi::arg ("name"),
"@brief Creates a new \\Pin object inside the circuit\n"
"This object will describe a pin of the circuit. A circuit connects "
@ -1147,11 +1161,11 @@ Class<db::Circuit> decl_dbCircuit ("db", "Circuit",
"@brief Gets the net object for a given name.\n"
"If the ID is not a valid net name, nil is returned."
) +
gsi::method ("pin_by_id", &db::Circuit::pin_by_id, gsi::arg ("id"),
gsi::method ("pin_by_id", (db::Pin *(db::Circuit::*) (size_t)) &db::Circuit::pin_by_id, gsi::arg ("id"),
"@brief Gets the \\Pin object corresponding to a specific ID\n"
"If the ID is not a valid pin ID, nil is returned."
) +
gsi::method ("pin_by_name", &db::Circuit::pin_by_name, gsi::arg ("name"),
gsi::method ("pin_by_name", (db::Pin *(db::Circuit::*) (const std::string &)) &db::Circuit::pin_by_name, gsi::arg ("name"),
"@brief Gets the \\Pin object corresponding to a specific name\n"
"If the ID is not a valid pin name, nil is returned."
) +

View File

@ -345,7 +345,12 @@ TEST(3_CircuitBasic)
EXPECT_EQ (c.pin_by_name ("doesnt_exist") == 0, true);
EXPECT_EQ (c.pin_by_name ("p2")->name (), "p2");
EXPECT_EQ (c.pin_by_id (0)->property (17).to_string (), "nil");
c.pin_by_id (0)->set_property (17, 42);
EXPECT_EQ (c.pin_by_id (0)->property (17).to_string (), "42");
db::Circuit c2 = c;
EXPECT_EQ (c2.pin_by_id (0)->property (17).to_string (), "42");
EXPECT_EQ (c2.name (), "name");
EXPECT_EQ (pins2string (c), "p1#0,p2#1");
@ -1419,3 +1424,90 @@ TEST(22_BlankCircuit)
"end;\n"
);
}
TEST(23_NetlistObject)
{
db::NetlistObject nlo;
nlo.set_property (1, "hello");
EXPECT_EQ (nlo.property ("key").to_string (), "nil");
EXPECT_EQ (nlo.property (1).to_string (), "hello");
nlo.set_property ("key", 42);
EXPECT_EQ (nlo.property ("key").to_string (), "42");
nlo.set_property ("key", tl::Variant ());
EXPECT_EQ (nlo.property ("key").to_string (), "nil");
db::Net net ("net_name");
net.set_property (1, "hello");
EXPECT_EQ (net.property ("key").to_string (), "nil");
EXPECT_EQ (net.property (1).to_string (), "hello");
db::Net net2 (net);
EXPECT_EQ (net.property ("key").to_string (), "nil");
EXPECT_EQ (net.property (1).to_string (), "hello");
db::Net net3;
EXPECT_EQ (net3.property ("key").to_string (), "nil");
EXPECT_EQ (net3.property (1).to_string (), "nil");
net3 = net2;
EXPECT_EQ (net3.property (1).to_string (), "hello");
db::SubCircuit sc;
sc.set_property (1, "hello");
EXPECT_EQ (sc.property ("key").to_string (), "nil");
EXPECT_EQ (sc.property (1).to_string (), "hello");
db::SubCircuit sc2 (sc);
EXPECT_EQ (sc.property ("key").to_string (), "nil");
EXPECT_EQ (sc.property (1).to_string (), "hello");
db::SubCircuit sc3;
EXPECT_EQ (sc3.property ("key").to_string (), "nil");
EXPECT_EQ (sc3.property (1).to_string (), "nil");
sc3 = sc2;
EXPECT_EQ (sc3.property (1).to_string (), "hello");
db::Device dev;
dev.set_property (1, "hello");
EXPECT_EQ (dev.property ("key").to_string (), "nil");
EXPECT_EQ (dev.property (1).to_string (), "hello");
db::Device dev2 (dev);
EXPECT_EQ (dev.property ("key").to_string (), "nil");
EXPECT_EQ (dev.property (1).to_string (), "hello");
db::Device dev3;
EXPECT_EQ (dev3.property ("key").to_string (), "nil");
EXPECT_EQ (dev3.property (1).to_string (), "nil");
dev3 = dev2;
EXPECT_EQ (dev3.property (1).to_string (), "hello");
db::Circuit circuit;
circuit.set_property (1, "hello");
EXPECT_EQ (circuit.property ("key").to_string (), "nil");
EXPECT_EQ (circuit.property (1).to_string (), "hello");
db::Circuit circuit2 (circuit);
EXPECT_EQ (circuit.property ("key").to_string (), "nil");
EXPECT_EQ (circuit.property (1).to_string (), "hello");
db::Circuit circuit3;
EXPECT_EQ (circuit3.property ("key").to_string (), "nil");
EXPECT_EQ (circuit3.property (1).to_string (), "nil");
circuit3 = circuit2;
EXPECT_EQ (circuit3.property (1).to_string (), "hello");
db::Pin pin ("pin_name");
pin.set_property (1, "hello");
EXPECT_EQ (pin.property ("key").to_string (), "nil");
EXPECT_EQ (pin.property (1).to_string (), "hello");
db::Pin pin2 (pin);
EXPECT_EQ (pin.property ("key").to_string (), "nil");
EXPECT_EQ (pin.property (1).to_string (), "hello");
db::Pin pin3;
EXPECT_EQ (pin3.property ("key").to_string (), "nil");
EXPECT_EQ (pin3.property (1).to_string (), "nil");
pin3 = pin2;
EXPECT_EQ (pin3.property (1).to_string (), "hello");
}

View File

@ -25,6 +25,21 @@ load("test_prologue.rb")
class DBNetlist_TestClass < TestBase
def test_0_NetlistObject
nlo = RBA::NetlistObject::new
assert_equal(nlo.property(17), nil)
nlo.set_property(17, 42)
assert_equal(nlo.property(17), 42)
nlo2 = nlo.dup
assert_equal(nlo2.property(17), 42)
nlo.set_property(17, nil)
assert_equal(nlo.property(17), nil)
assert_equal(nlo2.property(17), 42)
end
def test_1_NetlistBasicCircuit
nl = RBA::Netlist::new
@ -141,6 +156,10 @@ class DBNetlist_TestClass < TestBase
p1 = c.create_pin("A")
p2 = c.create_pin("B")
assert_equal(p1.property(17), nil)
p1.set_property(17, 42)
assert_equal(p1.property(17), 42)
assert_equal(p1.id, 0)
assert_equal(p2.id, 1)
@ -188,6 +207,10 @@ class DBNetlist_TestClass < TestBase
assert_equal(c.device_by_id(2).inspect, "nil")
assert_equal(c.device_by_name("doesnt_exist").inspect, "nil")
assert_equal(d1.property(17), nil)
d1.set_property(17, 42)
assert_equal(d1.property(17), 42)
d2 = c.create_device(dc)
assert_equal(d2.device_class.id, dc.id)
assert_equal(d2.device_class.object_id, dc.object_id) # by virtue of Ruby-to-C++ object mapping
@ -215,6 +238,10 @@ class DBNetlist_TestClass < TestBase
net = c.create_net("NET")
assert_equal(net.property(17), nil)
net.set_property(17, 42)
assert_equal(net.property(17), 42)
assert_equal(net.is_floating?, true)
assert_equal(net.is_internal?, false)
assert_equal(net.terminal_count, 0)
@ -370,6 +397,10 @@ class DBNetlist_TestClass < TestBase
assert_equal(c.subcircuit_by_id(2).inspect, "nil")
assert_equal(c.subcircuit_by_name("doesnt_exist").inspect, "nil")
assert_equal(sc1.property(17), nil)
sc1.set_property(17, 42)
assert_equal(sc1.property(17), 42)
refs = []
cc.each_ref { |r| refs << r.name }
assert_equal(refs.join(","), "SC1")
@ -564,6 +595,10 @@ class DBNetlist_TestClass < TestBase
c.cell_index = 42
assert_equal(c.cell_index, 42)
assert_equal(c.property(17), nil)
c.set_property(17, 42)
assert_equal(c.property(17), 42)
pina1 = c.create_pin("A1")
pina2 = c.create_pin("A2")
pinb1 = c.create_pin("B1")
@ -581,6 +616,11 @@ class DBNetlist_TestClass < TestBase
assert_equal(c.pin_by_id(17).inspect, "nil")
assert_equal(c.pin_by_name("DOESNOTEXIST").inspect, "nil")
assert_equal(c.pin_by_id(0).property(17), nil)
c.pin_by_id(0).set_property(17, 42)
assert_equal(c.pin_by_id(0).property(17), 42)
assert_equal(c.pin_by_name("A1").property(17), 42)
names = []
c.each_pin { |p| names << p.name }
assert_equal(names, [ "A1", "A2", "B1", "B2" ])