diff --git a/src/db/db/dbNetlist.cc b/src/db/db/dbNetlist.cc index e18052b1a..12bdc12fe 100644 --- a/src/db/db/dbNetlist.cc +++ b/src/db/db/dbNetlist.cc @@ -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 &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 &map) @@ -358,6 +469,87 @@ void Circuit::translate_device_classes (const std::map (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 (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 (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 (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 (p->device ()))->set_net_for_port (p->port_id (), n.operator-> ()); + } + + } + + m_nets_per_pin_valid = true; +} + // -------------------------------------------------------------------------------- // DeviceClass class implementation diff --git a/src/db/db/dbNetlist.h b/src/db/db/dbNetlist.h index 8935dca49..c52bd1db1 100644 --- a/src/db/db/dbNetlist.h +++ b/src/db/db/dbNetlist.h @@ -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 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 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 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 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 sub_circuit_list; typedef sub_circuit_list::const_iterator const_sub_circuit_iterator; typedef sub_circuit_list::iterator sub_circuit_iterator; + typedef tl::vector 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 (((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 (((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 (((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 &map); - void translate_device_classes (const std::map &map); + void translate_device_classes (const std::map &map); void set_netlist (Netlist *netlist); + void invalidate_nets_per_pin (); + void validate_nets_per_pin (); }; /** diff --git a/src/db/unit_tests/dbNetlistTests.cc b/src/db/unit_tests/dbNetlistTests.cc index c2c37ba3a..cb95eff06 100644 --- a/src/db/unit_tests/dbNetlistTests.cc +++ b/src/db/unit_tests/dbNetlistTests.cc @@ -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 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 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)