Dual netlist representation (nets attached to pins and ports).

This commit is contained in:
Matthias Koefferlein 2018-12-22 00:29:44 +01:00
parent 654afa3ec2
commit e51a3a9ed9
3 changed files with 403 additions and 11 deletions

View File

@ -43,17 +43,66 @@ Pin::Pin (const std::string &name)
// --------------------------------------------------------------------------------
// Device class implementation
Device::Device ()
{
// .. nothing yet ..
}
Device::Device (DeviceClass *device_class, const std::string &name)
: m_device_class (device_class), m_name (name)
{
// .. nothing yet ..
}
Device::Device (const Device &other)
{
operator= (other);
}
Device &Device::operator= (const Device &other)
{
if (this != &other) {
m_name = other.m_name;
m_device_class = other.m_device_class;
m_nets_per_port.clear ();
}
return *this;
}
void Device::set_name (const std::string &n)
{
m_name = n;
}
void Device::clear_nets_per_port ()
{
m_nets_per_port.clear ();
}
void Device::reserve_nets_per_port ()
{
if (m_device_class.get ()) {
m_nets_per_port.clear ();
m_nets_per_port.resize (m_device_class->port_definitions ().size (), 0);
}
}
void Device::set_net_for_port (size_t port_id, const Net *net)
{
if (port_id < m_nets_per_port.size ()) {
m_nets_per_port [port_id] = net;
}
}
const Net *Device::net_for_port (size_t port_id) const
{
if (port_id < m_nets_per_port.size ()) {
return m_nets_per_port [port_id];
} else {
return 0;
}
}
// --------------------------------------------------------------------------------
// SubCircuit class implementation
@ -68,6 +117,22 @@ SubCircuit::SubCircuit (Circuit *circuit, const std::string &name)
// .. nothing yet ..
}
SubCircuit::SubCircuit (const SubCircuit &other)
{
operator= (other);
}
SubCircuit &SubCircuit::operator= (const SubCircuit &other)
{
if (this != &other) {
m_name = other.m_name;
m_circuit = other.m_circuit;
m_trans = other.m_trans;
m_nets_per_pin.clear ();
}
return *this;
}
void SubCircuit::set_name (const std::string &n)
{
m_name = n;
@ -78,6 +143,35 @@ void SubCircuit::set_trans (const db::DCplxTrans &t)
m_trans = t;
}
void SubCircuit::clear_nets_per_pin ()
{
m_nets_per_pin.clear ();
}
void SubCircuit::reserve_nets_per_pin ()
{
if (m_circuit.get ()) {
m_nets_per_pin.clear ();
m_nets_per_pin.resize (m_circuit->pin_count (), 0);
}
}
void SubCircuit::set_net_for_pin (size_t pin_id, const Net *net)
{
if (pin_id < m_nets_per_pin.size ()) {
m_nets_per_pin [pin_id] = net;
}
}
const Net *SubCircuit::net_for_pin (size_t pin_id) const
{
if (pin_id < m_nets_per_pin.size ()) {
return m_nets_per_pin [pin_id];
} else {
return 0;
}
}
// --------------------------------------------------------------------------------
// NetPortRef class implementation
@ -188,11 +282,17 @@ void Net::set_cluster_id (size_t ci)
void Net::add_pin (const NetPinRef &pin)
{
m_pins.push_back (pin);
if (mp_circuit) {
mp_circuit->invalidate_nets_per_pin ();
}
}
void Net::add_port (const NetPortRef &port)
{
m_ports.push_back (port);
if (mp_circuit) {
mp_circuit->invalidate_nets_per_pin ();
}
}
void Net::translate_devices (const std::map<const Device *, Device *> &map)
@ -224,13 +324,13 @@ void Net::set_circuit (Circuit *circuit)
// Circuit class implementation
Circuit::Circuit ()
: mp_netlist (0)
: mp_netlist (0), m_nets_per_pin_valid (false)
{
// .. nothing yet ..
}
Circuit::Circuit (const Circuit &other)
: mp_netlist (0)
: mp_netlist (0), m_nets_per_pin_valid (false)
{
operator= (other);
}
@ -240,6 +340,9 @@ Circuit &Circuit::operator= (const Circuit &other)
if (this != &other) {
m_name = other.m_name;
m_nets_per_pin_valid = false;
m_nets_per_pin.clear ();
invalidate_nets_per_pin ();
for (const_pin_iterator i = other.begin_pins (); i != other.end_pins (); ++i) {
add_pin (*i);
@ -291,6 +394,7 @@ void Circuit::clear ()
m_devices.clear ();
m_nets.clear ();
m_sub_circuits.clear ();
invalidate_nets_per_pin ();
}
void Circuit::set_name (const std::string &name)
@ -307,37 +411,44 @@ void Circuit::add_pin (const Pin &pin)
{
m_pins.push_back (pin);
m_pins.back ().set_id (m_pins.size () - 1);
invalidate_nets_per_pin ();
}
void Circuit::add_net (Net *net)
{
m_nets.push_back (net);
net->set_circuit (this);
invalidate_nets_per_pin ();
}
void Circuit::remove_net (Net *net)
{
m_nets.erase (net);
invalidate_nets_per_pin ();
}
void Circuit::add_device (Device *device)
{
m_devices.push_back (device);
invalidate_nets_per_pin ();
}
void Circuit::remove_device (Device *device)
{
m_devices.erase (device);
invalidate_nets_per_pin ();
}
void Circuit::add_sub_circuit (SubCircuit *sub_circuit)
{
m_sub_circuits.push_back (sub_circuit);
invalidate_nets_per_pin ();
}
void Circuit::remove_sub_circuit (SubCircuit *sub_circuit)
{
m_sub_circuits.erase (sub_circuit);
invalidate_nets_per_pin ();
}
void Circuit::translate_circuits (const std::map<const Circuit *, Circuit *> &map)
@ -358,6 +469,87 @@ void Circuit::translate_device_classes (const std::map<const DeviceClass *, Devi
}
}
const Net *Circuit::net_for_pin (size_t pin_id) const
{
if (! m_nets_per_pin_valid) {
const_cast<Circuit *> (this)->validate_nets_per_pin ();
}
if (pin_id >= m_nets_per_pin.size ()) {
return 0;
} else {
return m_nets_per_pin [pin_id];
}
}
const Net *Circuit::net_for_pin (const SubCircuit *sub_circuit, size_t pin_id) const
{
if (! m_nets_per_pin_valid) {
const_cast<Circuit *> (this)->validate_nets_per_pin ();
}
return sub_circuit->net_for_pin (pin_id);
}
const Net *Circuit::net_for_port (const Device *device, size_t port_id) const
{
if (! m_nets_per_pin_valid) {
const_cast<Circuit *> (this)->validate_nets_per_pin ();
}
return device->net_for_port (port_id);
}
void Circuit::invalidate_nets_per_pin ()
{
if (m_nets_per_pin_valid) {
m_nets_per_pin_valid = false;
m_nets_per_pin.clear ();
for (sub_circuit_iterator i = begin_sub_circuits (); i != end_sub_circuits (); ++i) {
i->clear_nets_per_pin ();
}
for (device_iterator i = begin_devices (); i != end_devices (); ++i) {
i->clear_nets_per_port ();
}
}
}
void Circuit::validate_nets_per_pin ()
{
m_nets_per_pin.clear ();
m_nets_per_pin.resize (m_pins.size (), 0);
for (sub_circuit_iterator i = begin_sub_circuits (); i != end_sub_circuits (); ++i) {
i->reserve_nets_per_pin ();
}
for (device_iterator i = begin_devices (); i != end_devices (); ++i) {
i->reserve_nets_per_port ();
}
for (net_iterator n = begin_nets (); n != end_nets (); ++n) {
for (Net::const_pin_iterator p = n->begin_pins (); p != n->end_pins (); ++p) {
size_t id = p->pin_id ();
if (p->subcircuit () == 0) {
if (id < m_nets_per_pin.size ()) {
m_nets_per_pin [id] = n.operator-> ();
}
} else {
(const_cast<SubCircuit *> (p->subcircuit ()))->set_net_for_pin (id, n.operator-> ());
}
}
for (Net::const_port_iterator p = n->begin_ports (); p != n->end_ports (); ++p) {
(const_cast<Device *> (p->device ()))->set_net_for_port (p->port_id (), n.operator-> ());
}
}
m_nets_per_pin_valid = true;
}
// --------------------------------------------------------------------------------
// DeviceClass class implementation

View File

@ -42,6 +42,7 @@ class Device;
class DeviceClass;
class DevicePortDefinition;
class Netlist;
class Net;
/**
* @brief The definition of a pin of a circuit
*
@ -102,11 +103,28 @@ class DB_PUBLIC Device
: public tl::Object
{
public:
typedef tl::vector<const Net *> connected_net_list;
/**
* @brief Default constructor
*/
Device ();
/**
* @brief The constructor
*/
Device (DeviceClass *device_class, const std::string &name = std::string ());
/**
* @brief Copy constructor
*/
Device (const Device &other);
/**
* @brief Assignment
*/
Device &operator= (const Device &other);
/**
* @brief Gets the device class
*/
@ -133,6 +151,12 @@ private:
tl::weak_ptr<DeviceClass> m_device_class;
std::string m_name;
mutable connected_net_list m_nets_per_port;
void clear_nets_per_port ();
void reserve_nets_per_port ();
void set_net_for_port (size_t port_id, const Net *net);
const Net *net_for_port (size_t port_id) const;
/**
* @brief Sets the device class
@ -152,11 +176,23 @@ class DB_PUBLIC SubCircuit
: public tl::Object
{
public:
typedef tl::vector<const Net *> connected_net_list;
/**
* @brief Default constructor
*/
SubCircuit ();
/**
* @brief Copy constructor
*/
SubCircuit (const SubCircuit &other);
/**
* @brief Assignment
*/
SubCircuit &operator= (const SubCircuit &other);
/**
* @brief Creates a subcircuit reference to the given circuit
*/
@ -216,6 +252,12 @@ private:
tl::weak_ptr<Circuit> m_circuit;
std::string m_name;
db::DCplxTrans m_trans;
mutable connected_net_list m_nets_per_pin;
void clear_nets_per_pin ();
void reserve_nets_per_pin ();
void set_net_for_pin (size_t pin_id, const Net *net);
const Net *net_for_pin (size_t pin_id) const;
/**
* @brief Sets the circuit reference
@ -524,6 +566,7 @@ public:
typedef tl::shared_collection<SubCircuit> sub_circuit_list;
typedef sub_circuit_list::const_iterator const_sub_circuit_iterator;
typedef sub_circuit_list::iterator sub_circuit_iterator;
typedef tl::vector<const Net *> connected_net_list;
/**
* @brief Constructor
@ -600,11 +643,6 @@ public:
*/
void add_pin (const Pin &pin);
/**
* @brief Deletes a pin from the circuit
*/
void remove_pin (Pin *pin);
/**
* @brief Begin iterator for the pins of the circuit (non-const version)
*/
@ -621,6 +659,14 @@ public:
return m_pins.end ();
}
/**
* @brief Gets the pin count
*/
size_t pin_count () const
{
return m_pins.size ();
}
/**
* @brief Gets the pin by ID (the ID is basically the index)
*/
@ -774,8 +820,52 @@ public:
return m_sub_circuits.end ();
}
/**
* @brief Gets the connected net for a pin with the given id
*
* Returns 0 if the pin is not connected to a net.
*/
const Net *net_for_pin (size_t pin_id) const;
/**
* @brief Gets the connected net for a pin with the given id (non-const version)
*
* Returns 0 if the pin is not connected to a net.
*/
Net *net_for_pin (size_t pin_id)
{
return const_cast<Net *> (((const Circuit *) this)->net_for_pin (pin_id));
}
/**
* @brief Gets the net for a given pin of a subcircuit
*/
const Net *net_for_pin (const SubCircuit *sub_circuit, size_t pin_id) const;
/**
* @brief Gets the net for a given pin of a subcircuit (non-const version)
*/
Net *net_for_pin (SubCircuit *sub_circuit, size_t pin_id)
{
return const_cast<Net *> (((const Circuit *) this)->net_for_pin (sub_circuit, pin_id));
}
/**
* @brief Gets the net for a given port of a device
*/
const Net *net_for_port (const Device *device, size_t port_id) const;
/**
* @brief Gets the net for a given port of a device (non-const version)
*/
Net *net_for_port (Device *device, size_t port_id)
{
return const_cast<Net *> (((const Circuit *) this)->net_for_port (device, port_id));
}
private:
friend class Netlist;
friend class Net;
std::string m_name;
db::cell_index_type m_cell_index;
@ -784,10 +874,14 @@ private:
device_list m_devices;
sub_circuit_list m_sub_circuits;
Netlist *mp_netlist;
connected_net_list m_nets_per_pin;
bool m_nets_per_pin_valid;
void translate_circuits (const std::map<const Circuit *, Circuit *> &map);
void translate_device_classes (const std::map<const db::DeviceClass *, db::DeviceClass *> &map);
void translate_device_classes (const std::map<const DeviceClass *, DeviceClass *> &map);
void set_netlist (Netlist *netlist);
void invalidate_nets_per_pin ();
void validate_nets_per_pin ();
};
/**

View File

@ -164,6 +164,61 @@ static std::string nets2string (const db::Circuit &c)
return res;
}
// dual form of netlist
static std::string netlist2 (const db::Circuit &c)
{
std::string res;
std::string pins;
for (db::Circuit::const_pin_iterator p = c.begin_pins (); p != c.end_pins (); ++p) {
if (! pins.empty ()) {
pins += ",";
}
const db::Net *net = c.net_for_pin (p->id ());
pins += p->name ();
pins += "=";
pins += net ? net->name () : std::string ("(null)");
}
res += c.name () + ":" + pins + "\n";
for (db::Circuit::const_device_iterator d = c.begin_devices (); d != c.end_devices (); ++d) {
if (! d->device_class ()) {
continue;
}
pins.clear ();
for (size_t i = 0; i < d->device_class ()->port_definitions ().size (); ++i) {
if (! pins.empty ()) {
pins += ",";
}
const db::Net *net = c.net_for_port (d.operator-> (), i);
pins += d->device_class ()->port_definitions () [i].name ();
pins += "=";
pins += net ? net->name () : std::string ("(null)");
}
res += " D" + d->name () + ":" + pins + "\n";
}
for (db::Circuit::const_sub_circuit_iterator s = c.begin_sub_circuits (); s != c.end_sub_circuits (); ++s) {
if (! s->circuit ()) {
continue;
}
pins.clear ();
for (size_t i = 0; i < s->circuit ()->pin_count (); ++i) {
if (! pins.empty ()) {
pins += ",";
}
pins += s->circuit ()->pin_by_id (i)->name ();
pins += "=";
const db::Net *net = c.net_for_pin (s.operator-> (), i);
pins += net ? net->name () : std::string ("(null)");
}
res += " X" + s->name () + ":" + pins + "\n";
}
return res;
}
TEST(4_CircuitDevices)
{
db::GenericDeviceClass dc1;
@ -178,6 +233,7 @@ TEST(4_CircuitDevices)
dc2.add_port_definition (db::DevicePortDefinition ("B", ""));
std::auto_ptr<db::Circuit> c (new db::Circuit ());
c->set_name ("c");
db::Device *d1 = new db::Device (&dc1, "d1");
db::Device *d2a = new db::Device (&dc2, "d2a");
db::Device *d2b = new db::Device (&dc2, "d2b");
@ -186,6 +242,7 @@ TEST(4_CircuitDevices)
c->add_device (d2b);
db::Net *n1 = new db::Net ();
n1->set_name ("n1");
EXPECT_EQ (n1->circuit (), 0);
c->add_net (n1);
n1->add_port (db::NetPortRef (d1, 0));
@ -193,12 +250,14 @@ TEST(4_CircuitDevices)
EXPECT_EQ (n1->circuit (), c.get ());
db::Net *n2 = new db::Net ();
n2->set_name ("n2");
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 ();
n3->set_name ("n3");
c->add_net (n3);
n3->add_port (db::NetPortRef (d1, 2));
n3->add_port (db::NetPortRef (d2b, 1));
@ -209,6 +268,13 @@ TEST(4_CircuitDevices)
"d1:D,d2b:B\n"
);
EXPECT_EQ (netlist2 (*c),
"c:\n"
" Dd1:S=n1,G=n2,D=n3\n"
" Dd2a:A=n1,B=n2\n"
" Dd2b:A=n2,B=n3\n"
);
db::Circuit cc = *c;
c.reset (0);
EXPECT_EQ (cc.begin_nets ()->circuit (), &cc);
@ -218,9 +284,16 @@ TEST(4_CircuitDevices)
"d1:G,d2a:B,d2b:A\n"
"d1:D,d2b:B\n"
);
EXPECT_EQ (netlist2 (cc),
"c:\n"
" Dd1:S=n1,G=n2,D=n3\n"
" Dd2a:A=n1,B=n2\n"
" Dd2b:A=n2,B=n3\n"
);
}
static std::string netlist2string (const db::Netlist &nl)
static std::string nl2string (const db::Netlist &nl)
{
std::string res;
for (db::Netlist::const_circuit_iterator c = nl.begin_circuits (); c != nl.end_circuits (); ++c) {
@ -230,6 +303,16 @@ static std::string netlist2string (const db::Netlist &nl)
return res;
}
// dual form of netlist
static std::string netlist2 (const db::Netlist &nl)
{
std::string res;
for (db::Netlist::const_circuit_iterator c = nl.begin_circuits (); c != nl.end_circuits (); ++c) {
res += netlist2 (*c);
}
return res;
}
TEST(4_NetlistSubcircuits)
{
std::auto_ptr<db::Netlist> nl (new db::Netlist ());
@ -258,37 +341,44 @@ TEST(4_NetlistSubcircuits)
c2->add_device (d);
db::SubCircuit *sc1 = new db::SubCircuit (c2);
sc1->set_name ("sc1");
c1->add_sub_circuit (sc1);
db::SubCircuit *sc2 = new db::SubCircuit (c2);
sc2->set_name ("sc2");
c1->add_sub_circuit (sc2);
db::Net *n2a = new db::Net ();
n2a->set_name ("n2a");
n2a->add_pin (db::NetPinRef (0));
n2a->add_port (db::NetPortRef (d, 0));
c2->add_net (n2a);
db::Net *n2b = new db::Net ();
n2b->set_name ("n2b");
n2b->add_port (db::NetPortRef (d, 1));
n2b->add_pin (db::NetPinRef (1));
c2->add_net (n2b);
db::Net *n1a = new db::Net ();
n1a->set_name ("n1a");
n1a->add_pin (db::NetPinRef (0));
n1a->add_pin (db::NetPinRef (0, sc1));
c1->add_net (n1a);
db::Net *n1b = new db::Net ();
n1b->set_name ("n1b");
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->set_name ("n1c");
n1c->add_pin (db::NetPinRef (1, sc2));
n1c->add_pin (db::NetPinRef (1));
c1->add_net (n1c);
EXPECT_EQ (netlist2string (*nl),
EXPECT_EQ (nl2string (*nl),
"[c1]\n"
"+c1p1,c2:c2p1\n"
"c2:c2p2,c2:c2p1\n"
@ -298,12 +388,20 @@ TEST(4_NetlistSubcircuits)
"D:B,+c2p2\n"
);
EXPECT_EQ (netlist2 (*nl),
"c1:c1p1=n1a,c1p2=n1c\n"
" Xsc1:c2p1=n1a,c2p2=n1b\n"
" Xsc2:c2p1=n1b,c2p2=n1c\n"
"c2:c2p1=n2a,c2p2=n2b\n"
" DD:A=n2a,B=n2b\n"
);
db::Netlist nl2 = *nl;
nl.reset (0);
EXPECT_EQ (nl2.begin_circuits ()->netlist (), &nl2);
EXPECT_EQ (netlist2string (nl2),
EXPECT_EQ (nl2string (nl2),
"[c1]\n"
"+c1p1,c2:c2p1\n"
"c2:c2p2,c2:c2p1\n"
@ -312,6 +410,14 @@ TEST(4_NetlistSubcircuits)
"D:A,+c2p1\n"
"D:B,+c2p2\n"
);
EXPECT_EQ (netlist2 (nl2),
"c1:c1p1=n1a,c1p2=n1c\n"
" Xsc1:c2p1=n1a,c2p2=n1b\n"
" Xsc2:c2p1=n1b,c2p2=n1c\n"
"c2:c2p1=n2a,c2p2=n2b\n"
" DD:A=n2a,B=n2b\n"
);
}
TEST(5_SubCircuit)