From 9a9482d7c74e7436e6b7965bfdd3f185c4b570dc Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 22 Dec 2018 23:12:45 +0100 Subject: [PATCH] Added netlist editing features. --- src/db/db/dbNetlist.cc | 379 ++++++++------- src/db/db/dbNetlist.h | 692 +++++++++++++++++----------- src/db/unit_tests/dbNetlistTests.cc | 234 +++++++++- 3 files changed, 861 insertions(+), 444 deletions(-) diff --git a/src/db/db/dbNetlist.cc b/src/db/db/dbNetlist.cc index 12bdc12fe..e1866f114 100644 --- a/src/db/db/dbNetlist.cc +++ b/src/db/db/dbNetlist.cc @@ -48,6 +48,15 @@ Device::Device () // .. nothing yet .. } +Device::~Device () +{ + for (std::vector::const_iterator p = m_port_refs.begin (); p != m_port_refs.end (); ++p) { + if (*p != Net::port_iterator () && (*p)->net ()) { + (*p)->net ()->erase_port (*p); + } + } +} + Device::Device (DeviceClass *device_class, const std::string &name) : m_device_class (device_class), m_name (name) { @@ -64,7 +73,6 @@ 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; } @@ -74,32 +82,41 @@ void Device::set_name (const std::string &n) m_name = n; } -void Device::clear_nets_per_port () +void Device::set_port_ref_for_port (size_t port_id, Net::port_iterator iter) { - 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; + if (m_port_refs.size () < port_id + 1) { + m_port_refs.resize (port_id + 1, Net::port_iterator ()); } + m_port_refs [port_id] = iter; } 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; + if (port_id < m_port_refs.size ()) { + Net::port_iterator p = m_port_refs [port_id]; + if (p != Net::port_iterator ()) { + return p->net (); + } + } + return 0; +} + +void Device::connect_port (size_t port_id, Net *net) +{ + if (net_for_port (port_id) == net) { + return; + } + + if (port_id < m_port_refs.size ()) { + Net::port_iterator p = m_port_refs [port_id]; + if (p != Net::port_iterator () && p->net ()) { + p->net ()->erase_port (p); + } + m_port_refs [port_id] = Net::port_iterator (); + } + + if (net) { + net->add_port (NetPortRef (this, port_id)); } } @@ -111,6 +128,15 @@ SubCircuit::SubCircuit () // .. nothing yet .. } +SubCircuit::~SubCircuit() +{ + for (std::vector::const_iterator p = m_pin_refs.begin (); p != m_pin_refs.end (); ++p) { + if (*p != Net::pin_iterator () && (*p)->net ()) { + (*p)->net ()->erase_pin (*p); + } + } +} + SubCircuit::SubCircuit (Circuit *circuit, const std::string &name) : m_circuit (circuit), m_name (name) { @@ -128,7 +154,6 @@ SubCircuit &SubCircuit::operator= (const SubCircuit &other) m_name = other.m_name; m_circuit = other.m_circuit; m_trans = other.m_trans; - m_nets_per_pin.clear (); } return *this; } @@ -143,32 +168,41 @@ void SubCircuit::set_trans (const db::DCplxTrans &t) m_trans = t; } -void SubCircuit::clear_nets_per_pin () +void SubCircuit::set_pin_ref_for_pin (size_t pin_id, Net::pin_iterator iter) { - 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; + if (m_pin_refs.size () < pin_id + 1) { + m_pin_refs.resize (pin_id + 1, Net::pin_iterator ()); } + m_pin_refs [pin_id] = iter; } 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; + if (pin_id < m_pin_refs.size ()) { + Net::pin_iterator p = m_pin_refs [pin_id]; + if (p != Net::pin_iterator ()) { + return p->net (); + } + } + return 0; +} + +void SubCircuit::connect_pin (size_t pin_id, Net *net) +{ + if (net_for_pin (pin_id) == net) { + return; + } + + if (pin_id < m_pin_refs.size ()) { + Net::pin_iterator p = m_pin_refs [pin_id]; + if (p != Net::pin_iterator () && p->net ()) { + p->net ()->erase_pin (p); + } + m_pin_refs [pin_id] = Net::pin_iterator (); + } + + if (net) { + net->add_pin (NetPinRef (this, pin_id)); } } @@ -176,16 +210,32 @@ const Net *SubCircuit::net_for_pin (size_t pin_id) const // NetPortRef class implementation NetPortRef::NetPortRef () + : m_port_id (0), mp_device (0), mp_net (0) { // .. nothing yet .. } NetPortRef::NetPortRef (Device *device, size_t port_id) - : m_device (device), m_port_id (port_id) + : m_port_id (port_id), mp_device (device), mp_net (0) { // .. nothing yet .. } +NetPortRef::NetPortRef (const NetPortRef &other) + : m_port_id (other.m_port_id), mp_device (other.mp_device), mp_net (0) +{ + // .. nothing yet .. +} + +NetPortRef &NetPortRef::operator= (const NetPortRef &other) +{ + if (this != &other) { + m_port_id = other.m_port_id; + mp_device = other.mp_device; + } + return *this; +} + const DevicePortDefinition * NetPortRef::port_def () const { @@ -200,38 +250,53 @@ NetPortRef::port_def () const const DeviceClass * NetPortRef::device_class () const { - const Device *device = m_device.get (); - return device ? device->device_class () : 0; + return mp_device ? mp_device->device_class () : 0; } // -------------------------------------------------------------------------------- // NetPinRef class implementation NetPinRef::NetPinRef () + : m_pin_id (0), mp_subcircuit (0), mp_net (0) { // .. nothing yet .. } NetPinRef::NetPinRef (size_t pin_id) - : m_pin_id (pin_id) + : m_pin_id (pin_id), mp_subcircuit (0), mp_net (0) { // .. nothing yet .. } -NetPinRef::NetPinRef (size_t pin_id, SubCircuit *circuit) - : m_pin_id (pin_id), m_subcircuit (circuit) +NetPinRef::NetPinRef (SubCircuit *circuit, size_t pin_id) + : m_pin_id (pin_id), mp_subcircuit (circuit), mp_net (0) { // .. nothing yet .. } +NetPinRef::NetPinRef (const NetPinRef &other) + : m_pin_id (other.m_pin_id), mp_subcircuit (other.mp_subcircuit), mp_net (0) +{ + // .. nothing yet .. +} + +NetPinRef &NetPinRef::operator= (const NetPinRef &other) +{ + if (this != &other) { + m_pin_id = other.m_pin_id; + mp_subcircuit = other.mp_subcircuit; + } + return *this; +} + const Pin *NetPinRef::pin (const db::Circuit *c) const { - if (! m_subcircuit.get ()) { + if (! mp_subcircuit) { 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); + tl_assert (mp_subcircuit->circuit () != 0); + return mp_subcircuit->circuit ()->pin_by_id (m_pin_id); } } @@ -253,20 +318,41 @@ Net::Net (const Net &other) Net &Net::operator= (const Net &other) { if (this != &other) { + + clear (); + m_name = other.m_name; - m_pins = other.m_pins; - m_ports = other.m_ports; m_cluster_id = other.m_cluster_id; + + for (const_pin_iterator i = other.begin_pins (); i != other.end_pins (); ++i) { + add_pin (*i); + } + + for (const_port_iterator i = other.begin_ports (); i != other.end_ports (); ++i) { + add_port (*i); + } + } return *this; } +Net::~Net () +{ + clear (); +} + void Net::clear () { m_name.clear (); - m_ports.clear (); - m_pins.clear (); m_cluster_id = 0; + + while (! m_ports.empty ()) { + erase_port (begin_ports ()); + } + + while (! m_pins.empty ()) { + erase_pin (begin_pins ()); + } } void Net::set_name (const std::string &name) @@ -282,37 +368,46 @@ 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 (); + NetPinRef &new_pin = m_pins.back (); + new_pin.set_net (this); + + if (! pin.subcircuit ()) { + if (mp_circuit) { + mp_circuit->set_pin_ref_for_pin (new_pin.pin_id (), --m_pins.end ()); + } + } else { + new_pin.subcircuit ()->set_pin_ref_for_pin (new_pin.pin_id (), --m_pins.end ()); } } +void Net::erase_pin (pin_iterator iter) +{ + if (iter->subcircuit ()) { + iter->subcircuit ()->set_pin_ref_for_pin (iter->pin_id (), pin_iterator ()); + } else if (mp_circuit) { + mp_circuit->set_pin_ref_for_pin (iter->pin_id (), pin_iterator ()); + } + m_pins.erase (iter); +} + void Net::add_port (const NetPortRef &port) { + if (! port.device ()) { + return; + } + m_ports.push_back (port); - if (mp_circuit) { - mp_circuit->invalidate_nets_per_pin (); - } + NetPortRef &new_port = m_ports.back (); + new_port.set_net (this); + new_port.device ()->set_port_ref_for_port (new_port.port_id (), --m_ports.end ()); } -void Net::translate_devices (const std::map &map) +void Net::erase_port (port_iterator iter) { - for (port_list::iterator i = m_ports.begin (); i != m_ports.end (); ++i) { - std::map::const_iterator m = map.find (i->device ()); - tl_assert (m != map.end ()); - i->set_device (m->second); - } -} - -void Net::translate_subcircuits (const std::map &map) -{ - for (pin_list::iterator i = m_pins.begin (); i != m_pins.end (); ++i) { - if (i->subcircuit ()) { - std::map::const_iterator m = map.find (i->subcircuit ()); - tl_assert (m != map.end ()); - i->set_subcircuit (m->second); - } + if (iter->device ()) { + iter->device ()->set_port_ref_for_port (iter->port_id (), port_iterator ()); } + m_ports.erase (iter); } void Net::set_circuit (Circuit *circuit) @@ -324,13 +419,13 @@ void Net::set_circuit (Circuit *circuit) // Circuit class implementation Circuit::Circuit () - : mp_netlist (0), m_nets_per_pin_valid (false) + : mp_netlist (0) { // .. nothing yet .. } Circuit::Circuit (const Circuit &other) - : mp_netlist (0), m_nets_per_pin_valid (false) + : mp_netlist (0) { operator= (other); } @@ -340,9 +435,6 @@ 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); @@ -363,13 +455,33 @@ Circuit &Circuit::operator= (const Circuit &other) } for (const_net_iterator i = other.begin_nets (); i != other.end_nets (); ++i) { - Net *n = new Net (*i); - n->translate_devices (device_table); - n->translate_subcircuits (sc_table); + + // translate the net + Net *n = new Net (); + n->set_cluster_id (i->cluster_id ()); + n->set_name (i->name ()); add_net (n); + + for (Net::const_port_iterator p = i->begin_ports (); p != i->end_ports (); ++p) { + std::map::const_iterator m = device_table.find (p->device ()); + tl_assert (m != device_table.end ()); + n->add_port (NetPortRef (m->second, p->port_id ())); + } + + for (Net::const_pin_iterator p = i->begin_pins (); p != i->end_pins (); ++p) { + if (! p->subcircuit ()) { + n->add_pin (NetPinRef (p->pin_id ())); + } else { + std::map::const_iterator m = sc_table.find (p->subcircuit ()); + tl_assert (m != sc_table.end ()); + n->add_pin (NetPinRef (m->second, p->pin_id ())); + } + } + } } + return *this; } @@ -394,7 +506,6 @@ 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) @@ -411,44 +522,37 @@ 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) @@ -469,85 +573,42 @@ 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]; + if (pin_id < m_pin_refs.size ()) { + Net::pin_iterator p = m_pin_refs [pin_id]; + if (p != Net::pin_iterator ()) { + return p->net (); + } } + return 0; } -const Net *Circuit::net_for_pin (const SubCircuit *sub_circuit, size_t pin_id) const +void Circuit::connect_pin (size_t pin_id, Net *net) { - if (! m_nets_per_pin_valid) { - const_cast (this)->validate_nets_per_pin (); + if (net_for_pin (pin_id) == net) { + return; } - 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 (); + if (pin_id < m_pin_refs.size ()) { + Net::pin_iterator p = m_pin_refs [pin_id]; + if (p != Net::pin_iterator () && p->net ()) { + p->net ()->erase_pin (p); } - - 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 (); + m_pin_refs [pin_id] = Net::pin_iterator (); } - for (device_iterator i = begin_devices (); i != end_devices (); ++i) { - i->reserve_nets_per_port (); + if (net) { + net->add_pin (NetPinRef (pin_id)); } - - 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; } // -------------------------------------------------------------------------------- diff --git a/src/db/db/dbNetlist.h b/src/db/db/dbNetlist.h index c52bd1db1..d31a294f4 100644 --- a/src/db/db/dbNetlist.h +++ b/src/db/db/dbNetlist.h @@ -38,235 +38,13 @@ namespace db { class Circuit; +class SubCircuit; +class Pin; class Device; class DeviceClass; class DevicePortDefinition; class Netlist; class Net; -/** - * @brief The definition of a pin of a circuit - * - * A pin is some place other nets can connect to a circuit. - */ -class DB_PUBLIC Pin -{ -public: - /** - * @brief Default constructor - */ - Pin (); - - /** - * @brief Creates a pin with the given name. - */ - Pin (const std::string &name); - - /** - * @brief Gets the name of the pin - */ - const std::string &name () const - { - return m_name; - } - - /** - * @brief Gets the ID of the pin (only pins inside circuits have valid ID's) - */ - size_t id () const - { - return m_id; - } - -private: - friend class Circuit; - - tl::weak_ptr m_circuit; - std::string m_name; - size_t m_id; - - void set_id (size_t id) - { - m_id = id; - } -}; - -/** - * @brief An actual device - * - * This class represents the incarnation of a specific device. - * The device has a class which specifies a type. This class - * is intended for subclassing. - * A specific device subclass is supposed to correspond to - * a specific device class. - */ -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 - */ - const DeviceClass *device_class () const - { - return m_device_class.get (); - } - - /** - * @brief Sets the name - */ - void set_name (const std::string &n); - - /** - * @brief Gets the name - */ - const std::string &name () const - { - return m_name; - } - -private: - friend class Circuit; - - 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 - */ - void set_device_class (DeviceClass *dc) - { - m_device_class.reset (dc); - } -}; - -/** - * @brief A subcircuit of a circuit - * - * This class essentially is a reference to another circuit - */ -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 - */ - SubCircuit (Circuit *circuit, const std::string &name = std::string ()); - - /** - * @brief Gets the circuit the reference points to (const version) - */ - const Circuit *circuit () const - { - return m_circuit.get (); - } - - /** - * @brief Gets the circuit the reference points to (non-const version) - */ - Circuit *circuit () - { - return m_circuit.get (); - } - - /** - * @brief Sets the name of the subcircuit - * - * The name is one way to identify the subcircuit. The transformation is - * another one. - */ - void set_name (const std::string &n); - - /** - * @brief Gets the name of the subcircuit - */ - const std::string &name () const - { - return m_name; - } - - /** - * @brief Sets the transformation describing the subcircuit - * - * The transformation is a natural description of a subcircuit - * (in contrast to the name) when deriving it from a layout. - */ - void set_trans (const db::DCplxTrans &trans); - - /** - * @brief Gets the transformation describing the subcircuit - */ - const db::DCplxTrans &trans () const - { - return m_trans; - } - -private: - friend class Circuit; - - 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 - */ - void set_circuit (Circuit *c) - { - m_circuit.reset (c); - } -}; /** * @brief A reference to a port of a device @@ -286,12 +64,22 @@ public: */ NetPortRef (Device *device, size_t port_id); + /** + * @brief Copy constructor + */ + NetPortRef (const NetPortRef &other); + + /** + * @brief Assignment + */ + NetPortRef &operator= (const NetPortRef &other); + /** * @brief Gets the device reference */ Device *device () { - return m_device.get (); + return mp_device; } /** @@ -299,15 +87,7 @@ public: */ const Device *device () const { - return m_device.get (); - } - - /** - * @brief Sets the device reference - */ - void set_device (Device *d) - { - m_device.reset (d); + return mp_device; } /** @@ -330,9 +110,36 @@ public: */ const DeviceClass *device_class () const; + /** + * @brief Gets the net the port lives in + */ + Net *net () + { + return mp_net; + } + + /** + * @brief Gets the net the port lives in (const version) + */ + const Net *net () const + { + return mp_net; + } + private: - tl::weak_ptr m_device; + friend class Net; + size_t m_port_id; + Device *mp_device; + Net *mp_net; + + /** + * @brief Sets the net the port lives in + */ + void set_net (Net *net) + { + mp_net = net; + } }; /** @@ -358,7 +165,17 @@ public: /** * @brief Creates a pin reference to the given pin of the given subcircuit */ - NetPinRef (size_t pin_id, SubCircuit *circuit); + NetPinRef (SubCircuit *circuit, size_t pin_id); + + /** + * @brief Copy constructor + */ + NetPinRef (const NetPinRef &other); + + /** + * @brief Assignment + */ + NetPinRef &operator= (const NetPinRef &other); /** * @brief Gets the pin reference (const version) @@ -381,7 +198,7 @@ public: */ SubCircuit *subcircuit () { - return m_subcircuit.get (); + return mp_subcircuit; } /** @@ -389,20 +206,39 @@ public: */ const SubCircuit *subcircuit () const { - return m_subcircuit.get (); + return mp_subcircuit; } /** - * @brief Sets the subcircuit reference + * @brief Gets the net the pin lives in */ - void set_subcircuit (SubCircuit *s) + Net *net () { - m_subcircuit.reset (s); + return mp_net; + } + + /** + * @brief Gets the net the pin lives in (const version) + */ + const Net *net () const + { + return mp_net; } private: + friend class Net; + size_t m_pin_id; - tl::weak_ptr m_subcircuit; + SubCircuit *mp_subcircuit; + Net *mp_net; + + /** + * @brief Sets the net the port lives in + */ + void set_net (Net *net) + { + mp_net = net; + } }; /** @@ -416,12 +252,13 @@ class DB_PUBLIC Net public: typedef std::list port_list; typedef port_list::const_iterator const_port_iterator; + typedef port_list::iterator port_iterator; typedef std::list pin_list; typedef pin_list::const_iterator const_pin_iterator; + typedef pin_list::iterator pin_iterator; /** * @brief Constructor - * * Creates an empty circuit. */ Net (); @@ -431,6 +268,11 @@ public: */ Net (const Net &other); + /** + * @brief Destructor + */ + ~Net (); + /** * @brief Assignment */ @@ -493,6 +335,11 @@ public: */ void add_pin (const NetPinRef &pin); + /** + * @brief Erases the given pin from this net + */ + void erase_pin (pin_iterator iter); + /** * @brief Begin iterator for the pins of the net (const version) */ @@ -509,11 +356,32 @@ public: return m_pins.end (); } + /** + * @brief Begin iterator for the pins of the net (non-const version) + */ + pin_iterator begin_pins () + { + return m_pins.begin (); + } + + /** + * @brief End iterator for the pins of the net (non-const version) + */ + pin_iterator end_pins () + { + return m_pins.end (); + } + /** * @brief Adds a port to this net */ void add_port (const NetPortRef &port); + /** + * @brief Erases the given port from this net + */ + void erase_port (port_iterator iter); + /** * @brief Begin iterator for the ports of the net (const version) */ @@ -530,6 +398,22 @@ public: return m_ports.end (); } + /** + * @brief Begin iterator for the ports of the net (non-const version) + */ + port_iterator begin_ports () + { + return m_ports.begin (); + } + + /** + * @brief End iterator for the ports of the net (non-const version) + */ + port_iterator end_ports () + { + return m_ports.end (); + } + private: friend class Circuit; @@ -539,11 +423,290 @@ private: size_t m_cluster_id; Circuit *mp_circuit; - void translate_devices (const std::map &map); - void translate_subcircuits (const std::map &map); void set_circuit (Circuit *circuit); }; +/** + * @brief The definition of a pin of a circuit + * + * A pin is some place other nets can connect to a circuit. + */ +class DB_PUBLIC Pin +{ +public: + /** + * @brief Default constructor + */ + Pin (); + + /** + * @brief Creates a pin with the given name. + */ + Pin (const std::string &name); + + /** + * @brief Gets the name of the pin + */ + const std::string &name () const + { + return m_name; + } + + /** + * @brief Gets the ID of the pin (only pins inside circuits have valid ID's) + */ + size_t id () const + { + return m_id; + } + +private: + friend class Circuit; + + tl::weak_ptr m_circuit; + std::string m_name; + size_t m_id; + + void set_id (size_t id) + { + m_id = id; + } +}; + +/** + * @brief An actual device + * + * This class represents the incarnation of a specific device. + * The device has a class which specifies a type. This class + * is intended for subclassing. + * A specific device subclass is supposed to correspond to + * a specific device class. + */ +class DB_PUBLIC Device + : public tl::Object +{ +public: + /** + * @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 Destructor + */ + ~Device (); + + /** + * @brief Gets the device class + */ + const DeviceClass *device_class () const + { + return m_device_class.get (); + } + + /** + * @brief Sets the name + */ + void set_name (const std::string &n); + + /** + * @brief Gets the name + */ + const std::string &name () const + { + return m_name; + } + + /** + * @brief Gets the net attached to a specific port + * Returns 0 if no net is attached. + */ + const Net *net_for_port (size_t port_id) const; + + /** + * @brief Gets the net attached to a specific port (non-const version) + * Returns 0 if no net is attached. + */ + Net *net_for_port (size_t port_id) + { + return const_cast (((const Device *) this)->net_for_port (port_id)); + } + + /** + * @brief Connects the given port to the given net + * If the net is 0 the port is disconnected. + * If non-null, a NetPortRef object will be inserted into the + * net and connected with the given port. + */ + void connect_port (size_t port_id, Net *net); + +private: + friend class Circuit; + friend class Net; + + tl::weak_ptr m_device_class; + std::string m_name; + std::vector m_port_refs; + + /** + * @brief Sets the port reference for a specific port + */ + void set_port_ref_for_port (size_t port_id, Net::port_iterator iter); + + /** + * @brief Sets the device class + */ + void set_device_class (DeviceClass *dc) + { + m_device_class.reset (dc); + } +}; + +/** + * @brief A subcircuit of a circuit + * + * This class essentially is a reference to another circuit + */ +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 + */ + SubCircuit (Circuit *circuit, const std::string &name = std::string ()); + + /** + * @brief Destructor + */ + ~SubCircuit (); + + /** + * @brief Gets the circuit the reference points to (const version) + */ + const Circuit *circuit () const + { + return m_circuit.get (); + } + + /** + * @brief Gets the circuit the reference points to (non-const version) + */ + Circuit *circuit () + { + return m_circuit.get (); + } + + /** + * @brief Sets the name of the subcircuit + * + * The name is one way to identify the subcircuit. The transformation is + * another one. + */ + void set_name (const std::string &n); + + /** + * @brief Gets the name of the subcircuit + */ + const std::string &name () const + { + return m_name; + } + + /** + * @brief Sets the transformation describing the subcircuit + * + * The transformation is a natural description of a subcircuit + * (in contrast to the name) when deriving it from a layout. + */ + void set_trans (const db::DCplxTrans &trans); + + /** + * @brief Gets the transformation describing the subcircuit + */ + const db::DCplxTrans &trans () const + { + return m_trans; + } + + /** + * @brief Gets the net attached to a specific pin + * Returns 0 if no net is attached. + */ + const Net *net_for_pin (size_t pin_id) const; + + /** + * @brief Gets the net attached to a specific pin (non-const version) + * Returns 0 if no net is attached. + */ + Net *net_for_pin (size_t pin_id) + { + return const_cast (((const SubCircuit *) this)->net_for_pin (pin_id)); + } + + /** + * @brief Connects the given pin to the given net + * If the net is 0 the pin is disconnected. + * If non-null, a NetPinRef object will be inserted into the + * net and connected with the given pin. + */ + void connect_pin (size_t pin_id, Net *net); + +private: + friend class Circuit; + friend class Net; + + tl::weak_ptr m_circuit; + std::string m_name; + db::DCplxTrans m_trans; + std::vector m_pin_refs; + + /** + * @brief Sets the pin reference for a specific pin + */ + void set_pin_ref_for_pin (size_t ppin_id, Net::pin_iterator iter); + + /** + * @brief Sets the circuit reference + */ + void set_circuit (Circuit *c) + { + m_circuit.reset (c); + } +}; + /** * @brief A circuit * @@ -566,7 +729,6 @@ 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 @@ -838,30 +1000,12 @@ public: } /** - * @brief Gets the net for a given pin of a subcircuit + * @brief Connects the given pin to the given net + * If the net is 0 the pin is disconnected. + * If non-null, a NetPinRef object will be inserted into the + * net and connected with the given pin. */ - 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)); - } + void connect_pin (size_t pin_id, Net *net); private: friend class Netlist; @@ -874,14 +1018,16 @@ 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; + std::vector m_pin_refs; + + /** + * @brief Sets the pin reference for a specific pin + */ + void set_pin_ref_for_pin (size_t ppin_id, Net::pin_iterator iter); void translate_circuits (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 cb95eff06..1a58b856e 100644 --- a/src/db/unit_tests/dbNetlistTests.cc +++ b/src/db/unit_tests/dbNetlistTests.cc @@ -191,7 +191,7 @@ static std::string netlist2 (const db::Circuit &c) if (! pins.empty ()) { pins += ","; } - const db::Net *net = c.net_for_port (d.operator-> (), i); + const db::Net *net = d->net_for_port (i); pins += d->device_class ()->port_definitions () [i].name (); pins += "="; pins += net ? net->name () : std::string ("(null)"); @@ -210,7 +210,7 @@ static std::string netlist2 (const db::Circuit &c) } pins += s->circuit ()->pin_by_id (i)->name (); pins += "="; - const db::Net *net = c.net_for_pin (s.operator-> (), i); + const db::Net *net = s->net_for_pin (i); pins += net ? net->name () : std::string ("(null)"); } res += " X" + s->name () + ":" + pins + "\n"; @@ -234,6 +234,11 @@ TEST(4_CircuitDevices) std::auto_ptr c (new db::Circuit ()); c->set_name ("c"); + + EXPECT_EQ (netlist2 (*c), + "c:\n" + ); + db::Device *d1 = new db::Device (&dc1, "d1"); db::Device *d2a = new db::Device (&dc2, "d2a"); db::Device *d2b = new db::Device (&dc2, "d2b"); @@ -241,6 +246,13 @@ TEST(4_CircuitDevices) c->add_device (d2a); c->add_device (d2b); + EXPECT_EQ (netlist2 (*c), + "c:\n" + " Dd1:S=(null),G=(null),D=(null)\n" + " Dd2a:A=(null),B=(null)\n" + " Dd2b:A=(null),B=(null)\n" + ); + db::Net *n1 = new db::Net (); n1->set_name ("n1"); EXPECT_EQ (n1->circuit (), 0); @@ -256,6 +268,13 @@ TEST(4_CircuitDevices) n2->add_port (db::NetPortRef (d2a, 1)); n2->add_port (db::NetPortRef (d2b, 0)); + EXPECT_EQ (netlist2 (*c), + "c:\n" + " Dd1:S=n1,G=n2,D=(null)\n" + " Dd2a:A=n1,B=n2\n" + " Dd2b:A=n2,B=(null)\n" + ); + db::Net *n3 = new db::Net (); n3->set_name ("n3"); c->add_net (n3); @@ -349,34 +368,34 @@ TEST(4_NetlistSubcircuits) c1->add_sub_circuit (sc2); db::Net *n2a = new db::Net (); + c2->add_net (n2a); 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 (); + c2->add_net (n2b); 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 (); + c1->add_net (n1a); n1a->set_name ("n1a"); n1a->add_pin (db::NetPinRef (0)); - n1a->add_pin (db::NetPinRef (0, sc1)); - c1->add_net (n1a); + n1a->add_pin (db::NetPinRef (sc1, 0)); 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); + n1b->set_name ("n1b"); + n1b->add_pin (db::NetPinRef (sc1, 1)); + n1b->add_pin (db::NetPinRef (sc2, 0)); 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); + n1c->set_name ("n1c"); + n1c->add_pin (db::NetPinRef (sc2, 1)); + n1c->add_pin (db::NetPinRef (1)); EXPECT_EQ (nl2string (*nl), "[c1]\n" @@ -396,6 +415,18 @@ TEST(4_NetlistSubcircuits) " DD:A=n2a,B=n2b\n" ); + // check netlist + for (db::Netlist::circuit_iterator c = nl->begin_circuits (); c != nl->end_circuits (); ++c) { + for (db::Circuit::net_iterator n = c->begin_nets (); n != c->end_nets (); ++n) { + for (db::Net::port_iterator i = n->begin_ports (); i != n->end_ports (); ++i) { + EXPECT_EQ (i->net (), n.operator-> ()); + } + for (db::Net::pin_iterator i = n->begin_pins (); i != n->end_pins (); ++i) { + EXPECT_EQ (i->net (), n.operator-> ()); + } + } + } + db::Netlist nl2 = *nl; nl.reset (0); @@ -418,6 +449,18 @@ TEST(4_NetlistSubcircuits) "c2:c2p1=n2a,c2p2=n2b\n" " DD:A=n2a,B=n2b\n" ); + + // check netlist + for (db::Netlist::circuit_iterator c = nl2.begin_circuits (); c != nl2.end_circuits (); ++c) { + for (db::Circuit::net_iterator n = c->begin_nets (); n != c->end_nets (); ++n) { + for (db::Net::port_iterator i = n->begin_ports (); i != n->end_ports (); ++i) { + EXPECT_EQ (i->net (), n.operator-> ()); + } + for (db::Net::pin_iterator i = n->begin_pins (); i != n->end_pins (); ++i) { + EXPECT_EQ (i->net (), n.operator-> ()); + } + } + } } TEST(5_SubCircuit) @@ -451,3 +494,170 @@ TEST(6_Net) EXPECT_EQ (n.name (), ""); EXPECT_EQ (int (n.cluster_id ()), 0); } + +TEST(7_NetPortsEditing) +{ + db::Circuit c; + db::GenericDeviceClass dc; + dc.add_port_definition (db::DevicePortDefinition ("A", "")); + dc.add_port_definition (db::DevicePortDefinition ("B", "")); + + db::Device *d1 = new db::Device (&dc, "D1"); + c.add_device (d1); + db::Device *d2 = new db::Device (&dc, "D2"); + c.add_device (d2); + + db::Net *n1 = new db::Net (); + n1->set_name ("n1"); + c.add_net (n1); + + db::Net *n2 = new db::Net (); + n2->set_name ("n2"); + c.add_net (n2); + + d1->connect_port (0, n1); + d1->connect_port (1, n2); + + d2->connect_port (1, n1); + d2->connect_port (0, n2); + + EXPECT_EQ (d1->net_for_port (0), n1); + EXPECT_EQ (d1->net_for_port (1), n2); + EXPECT_EQ (d2->net_for_port (0), n2); + EXPECT_EQ (d2->net_for_port (1), n1); + + EXPECT_EQ (net2string (*n1, &c), "D1:A,D2:B"); + EXPECT_EQ (net2string (*n2, &c), "D1:B,D2:A"); + + d1->connect_port (0, n2); + d1->connect_port (1, n1); + + EXPECT_EQ (d1->net_for_port (0), n2); + EXPECT_EQ (d1->net_for_port (1), n1); + + EXPECT_EQ (net2string (*n1, &c), "D2:B,D1:B"); + EXPECT_EQ (net2string (*n2, &c), "D2:A,D1:A"); + + d1->connect_port (0, 0); + EXPECT_EQ (d1->net_for_port (0), 0); + + EXPECT_EQ (net2string (*n1, &c), "D2:B,D1:B"); + EXPECT_EQ (net2string (*n2, &c), "D2:A"); + + delete d1; + d1 = 0; + + EXPECT_EQ (c.begin_devices ()->name (), "D2"); + EXPECT_EQ (++c.begin_devices () == c.end_devices (), true); + + EXPECT_EQ (net2string (*n1, &c), "D2:B"); + EXPECT_EQ (net2string (*n2, &c), "D2:A"); + + delete n1; + n1 = 0; + + EXPECT_EQ (c.begin_nets ()->name (), "n2"); + EXPECT_EQ (++c.begin_nets () == c.end_nets (), true); + + EXPECT_EQ (net2string (*n2, &c), "D2:A"); + + EXPECT_EQ (d2->net_for_port (0), n2); + EXPECT_EQ (d2->net_for_port (1), 0); +} + +TEST(8_NetSubCircuitsEditing) +{ + db::Circuit c; + c.set_name ("c"); + c.add_pin (db::Pin ("X")); + c.add_pin (db::Pin ("Y")); + + db::Circuit cc1; + cc1.set_name ("sc1"); + cc1.add_pin (db::Pin ("A")); + cc1.add_pin (db::Pin ("B")); + + db::Circuit cc2; + cc2.set_name ("sc2"); + cc2.add_pin (db::Pin ("A")); + cc2.add_pin (db::Pin ("B")); + + db::SubCircuit *sc1 = new db::SubCircuit (&cc1, "sc1"); + c.add_sub_circuit (sc1); + + db::SubCircuit *sc2 = new db::SubCircuit (&cc2, "sc2"); + c.add_sub_circuit (sc2); + + db::Net *n1 = new db::Net (); + n1->set_name ("n1"); + c.add_net (n1); + + db::Net *n2 = new db::Net (); + n2->set_name ("n2"); + c.add_net (n2); + + c.connect_pin (0, n1); + EXPECT_EQ (c.net_for_pin (0), n1); + EXPECT_EQ (c.net_for_pin (1), 0); + + sc1->connect_pin (0, n1); + sc1->connect_pin (1, n2); + + sc2->connect_pin (1, n1); + sc2->connect_pin (0, n2); + + EXPECT_EQ (sc1->net_for_pin (0), n1); + EXPECT_EQ (sc1->net_for_pin (1), n2); + EXPECT_EQ (sc2->net_for_pin (0), n2); + EXPECT_EQ (sc2->net_for_pin (1), n1); + + EXPECT_EQ (net2string (*n1, &c), "+X,sc1:A,sc2:B"); + EXPECT_EQ (net2string (*n2, &c), "sc1:B,sc2:A"); + + c.connect_pin (0, 0); + EXPECT_EQ (c.net_for_pin (0), 0); + + EXPECT_EQ (net2string (*n1, &c), "sc1:A,sc2:B"); + EXPECT_EQ (net2string (*n2, &c), "sc1:B,sc2:A"); + + sc1->connect_pin (0, n2); + sc1->connect_pin (1, n1); + + EXPECT_EQ (sc1->net_for_pin (0), n2); + EXPECT_EQ (sc1->net_for_pin (1), n1); + + EXPECT_EQ (net2string (*n1, &c), "sc2:B,sc1:B"); + EXPECT_EQ (net2string (*n2, &c), "sc2:A,sc1:A"); + + sc1->connect_pin (0, 0); + EXPECT_EQ (sc1->net_for_pin (0), 0); + + EXPECT_EQ (net2string (*n1, &c), "sc2:B,sc1:B"); + EXPECT_EQ (net2string (*n2, &c), "sc2:A"); + + delete sc1; + sc1 = 0; + + EXPECT_EQ (c.begin_sub_circuits ()->name (), "sc2"); + EXPECT_EQ (++c.begin_sub_circuits () == c.end_sub_circuits (), true); + + EXPECT_EQ (net2string (*n1, &c), "sc2:B"); + EXPECT_EQ (net2string (*n2, &c), "sc2:A"); + + c.connect_pin (1, n1); + EXPECT_EQ (net2string (*n1, &c), "sc2:B,+Y"); + EXPECT_EQ (c.net_for_pin (1), n1); + + delete n1; + n1 = 0; + + EXPECT_EQ (c.net_for_pin (1), 0); + + EXPECT_EQ (c.begin_nets ()->name (), "n2"); + EXPECT_EQ (++c.begin_nets () == c.end_nets (), true); + + EXPECT_EQ (net2string (*n2, &c), "sc2:A"); + + EXPECT_EQ (sc2->net_for_pin (0), n2); + EXPECT_EQ (sc2->net_for_pin (1), 0); +}