diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 9d22a4990..7a30f7331 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -153,7 +153,13 @@ SOURCES = \ gsiDeclDbHierNetworkProcessor.cc \ dbNetlistDeviceExtractorClasses.cc \ dbLayoutToNetlist.cc \ - gsiDeclDbLayoutToNetlist.cc + gsiDeclDbLayoutToNetlist.cc \ + dbCircuit.cc \ + dbDevice.cc \ + dbDeviceClass.cc \ + dbNet.cc \ + dbSubCircuit.cc \ + dbPin.cc HEADERS = \ dbArray.h \ @@ -270,7 +276,14 @@ HEADERS = \ dbNetlistExtractor.h \ dbNetlistDeviceExtractorClasses.h \ dbLayoutToNetlist.h \ - dbHierNetworkProcessor.h + dbHierNetworkProcessor.h \ + dbNetlistUtils.h \ + dbNet.h \ + dbCircuit.h \ + dbDevice.h \ + dbDeviceClass.h \ + dbPin.h \ + dbSubCircuit.h !equals(HAVE_QT, "0") { diff --git a/src/db/db/dbCircuit.cc b/src/db/db/dbCircuit.cc new file mode 100644 index 000000000..e0c85f08c --- /dev/null +++ b/src/db/db/dbCircuit.cc @@ -0,0 +1,567 @@ + +/* + + 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 "dbCircuit.h" +#include "dbNetlist.h" + +namespace db +{ + +// -------------------------------------------------------------------------------- +// Circuit class implementation + +Circuit::Circuit () + : 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), + m_device_by_name (this, &Circuit::begin_devices, &Circuit::end_devices), + m_subcircuit_by_name (this, &Circuit::begin_subcircuits, &Circuit::end_subcircuits), + m_net_by_name (this, &Circuit::begin_nets, &Circuit::end_nets), + m_index (0) +{ + m_devices.changed ().add (this, &Circuit::devices_changed); + m_nets.changed ().add (this, &Circuit::nets_changed); + m_subcircuits.changed ().add (this, &Circuit::subcircuits_changed); +} + +Circuit::Circuit (const Circuit &other) + : 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), + m_device_by_name (this, &Circuit::begin_devices, &Circuit::end_devices), + m_subcircuit_by_name (this, &Circuit::begin_subcircuits, &Circuit::end_subcircuits), + m_net_by_name (this, &Circuit::begin_nets, &Circuit::end_nets), + m_index (0) +{ + operator= (other); + m_devices.changed ().add (this, &Circuit::devices_changed); + m_nets.changed ().add (this, &Circuit::nets_changed); + m_subcircuits.changed ().add (this, &Circuit::subcircuits_changed); +} + +Circuit::~Circuit () +{ + m_devices.changed ().remove (this, &Circuit::devices_changed); + m_nets.changed ().remove (this, &Circuit::nets_changed); + m_subcircuits.changed ().remove (this, &Circuit::subcircuits_changed); + + // the default destructor will make the nets access "this" to unregister the + // objects - hence we have to do this explicitly. + m_nets.clear (); + m_subcircuits.clear (); + m_devices.clear (); +} + +Circuit &Circuit::operator= (const Circuit &other) +{ + if (this != &other) { + + clear (); + + m_name = other.m_name; + m_pins = other.m_pins; + + std::map device_table; + for (const_device_iterator i = other.begin_devices (); i != other.end_devices (); ++i) { + Device *d = new Device (*i); + device_table [i.operator-> ()] = d; + add_device (d); + } + + std::map sc_table; + for (const_subcircuit_iterator i = other.begin_subcircuits (); i != other.end_subcircuits (); ++i) { + SubCircuit *sc = new SubCircuit (*i); + sc_table [i.operator-> ()] = sc; + add_subcircuit (sc); + } + + for (const_net_iterator i = other.begin_nets (); i != other.end_nets (); ++i) { + + // 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_terminal_iterator p = i->begin_terminals (); p != i->end_terminals (); ++p) { + std::map::const_iterator m = device_table.find (p->device ()); + tl_assert (m != device_table.end ()); + n->add_terminal (NetTerminalRef (m->second, p->terminal_id ())); + } + + for (Net::const_pin_iterator p = i->begin_pins (); p != i->end_pins (); ++p) { + n->add_pin (NetPinRef (p->pin_id ())); + } + + for (Net::const_subcircuit_pin_iterator p = i->begin_subcircuit_pins (); p != i->end_subcircuit_pins (); ++p) { + std::map::const_iterator m = sc_table.find (p->subcircuit ()); + tl_assert (m != sc_table.end ()); + n->add_subcircuit_pin (NetSubcircuitPinRef (m->second, p->pin_id ())); + } + + } + + } + + return *this; +} + +void Circuit::set_netlist (Netlist *netlist) +{ + mp_netlist = netlist; +} + +const Pin *Circuit::pin_by_id (size_t id) const +{ + if (id >= m_pins.size ()) { + return 0; + } else { + return &m_pins [id]; + } +} + +const Pin *Circuit::pin_by_name (const std::string &name) const +{ + for (Circuit::const_pin_iterator p = begin_pins (); p != end_pins (); ++p) { + if (p->name () == name) { + return p.operator-> (); + } + } + return 0; +} + +void Circuit::devices_changed () +{ + m_device_by_id.invalidate (); + m_device_by_name.invalidate (); +} + +void Circuit::subcircuits_changed () +{ + m_subcircuit_by_id.invalidate (); + m_subcircuit_by_name.invalidate (); + + if (mp_netlist) { + mp_netlist->invalidate_topology (); + } +} + +void Circuit::nets_changed () +{ + m_net_by_cluster_id.invalidate (); + m_net_by_name.invalidate (); +} + +void Circuit::clear () +{ + m_name.clear (); + m_pins.clear (); + m_devices.clear (); + m_nets.clear (); + m_subcircuits.clear (); +} + +void Circuit::set_name (const std::string &name) +{ + m_name = name; + if (mp_netlist) { + mp_netlist->m_circuit_by_name.invalidate (); + } +} + +void Circuit::set_cell_index (const db::cell_index_type ci) +{ + m_cell_index = ci; + if (mp_netlist) { + mp_netlist->m_circuit_by_cell_index.invalidate (); + } +} + +Circuit::child_circuit_iterator Circuit::begin_children () +{ + tl_assert (mp_netlist != 0); + return mp_netlist->child_circuits (this).begin (); +} + +Circuit::child_circuit_iterator Circuit::end_children () +{ + tl_assert (mp_netlist != 0); + return mp_netlist->child_circuits (this).end (); +} + +Circuit::const_child_circuit_iterator Circuit::begin_children () const +{ + tl_assert (mp_netlist != 0); + return reinterpret_cast &> (mp_netlist->child_circuits (const_cast (this))).begin (); +} + +Circuit::const_child_circuit_iterator Circuit::end_children () const +{ + tl_assert (mp_netlist != 0); + return reinterpret_cast &> (mp_netlist->child_circuits (const_cast (this))).end (); +} + +Circuit::child_circuit_iterator Circuit::begin_parents () +{ + tl_assert (mp_netlist != 0); + return mp_netlist->parent_circuits (this).begin (); +} + +Circuit::child_circuit_iterator Circuit::end_parents () +{ + tl_assert (mp_netlist != 0); + return mp_netlist->parent_circuits (this).end (); +} + +Circuit::const_child_circuit_iterator Circuit::begin_parents () const +{ + tl_assert (mp_netlist != 0); + return reinterpret_cast &> (mp_netlist->parent_circuits (const_cast (this))).begin (); +} + +Circuit::const_child_circuit_iterator Circuit::end_parents () const +{ + tl_assert (mp_netlist != 0); + return reinterpret_cast &> (mp_netlist->parent_circuits (const_cast (this))).end (); +} + +const Pin &Circuit::add_pin (const std::string &name) +{ + m_pins.push_back (Pin (name)); + m_pins.back ().set_id (m_pins.size () - 1); + return m_pins.back (); +} + +void Circuit::add_net (Net *net) +{ + m_nets.push_back (net); + net->set_circuit (this); +} + +void Circuit::remove_net (Net *net) +{ + m_nets.erase (net); +} + +void Circuit::add_device (Device *device) +{ + device->set_circuit (this); + + size_t id = 0; + if (! m_devices.empty ()) { + tl_assert (m_devices.back () != 0); + id = m_devices.back ()->id (); + } + device->set_id (id + 1); + + m_devices.push_back (device); +} + +void Circuit::remove_device (Device *device) +{ + m_devices.erase (device); +} + +void Circuit::add_subcircuit (SubCircuit *subcircuit) +{ + subcircuit->set_circuit (this); + + size_t id = 0; + if (! m_subcircuits.empty ()) { + tl_assert (m_subcircuits.back () != 0); + id = m_subcircuits.back ()->id (); + } + subcircuit->set_id (id + 1); + + m_subcircuits.push_back (subcircuit); +} + +void Circuit::remove_subcircuit (SubCircuit *subcircuit) +{ + m_subcircuits.erase (subcircuit); +} + +void Circuit::register_ref (SubCircuit *r) +{ + m_refs.push_back (r); +} + +void Circuit::unregister_ref (SubCircuit *r) +{ + m_refs.erase (r); +} + +void Circuit::translate_circuits (const std::map &map) +{ + for (subcircuit_iterator i = m_subcircuits.begin (); i != m_subcircuits.end (); ++i) { + std::map::const_iterator m = map.find (i->circuit_ref ()); + tl_assert (m != map.end ()); + i->set_circuit_ref (m->second); + } +} + +void Circuit::translate_device_classes (const std::map &map) +{ + for (device_iterator i = m_devices.begin (); i != m_devices.end (); ++i) { + std::map::const_iterator m = map.find (i->device_class ()); + tl_assert (m != map.end ()); + i->set_device_class (m->second); + } +} + +void Circuit::set_pin_ref_for_pin (size_t pin_id, Net::pin_iterator iter) +{ + 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 *Circuit::net_for_pin (size_t pin_id) const +{ + 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 Circuit::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 (pin_id)); + } +} + +void Circuit::purge_nets () +{ + std::vector nets_to_be_purged; + for (net_iterator n = begin_nets (); n != end_nets (); ++n) { + if (n->is_floating ()) { + nets_to_be_purged.push_back (n.operator-> ()); + } + } + for (std::vector::const_iterator n = nets_to_be_purged.begin (); n != nets_to_be_purged.end (); ++n) { + delete *n; + } +} + +/** + * @brief Sanity check for device to be removed + */ +static void check_device_before_remove (db::Circuit *c, const db::Device *d) +{ + if (d->device_class () == 0) { + throw tl::Exception (tl::to_string (tr ("Internal error: No device class after removing device in device combination")) + ": name=" + d->name () + ", circuit=" + c->name ()); + } + const std::vector &pd = d->device_class ()->terminal_definitions (); + for (std::vector::const_iterator p = pd.begin (); p != pd.end (); ++p) { + if (d->net_for_terminal (p->id ()) != 0) { + throw tl::Exception (tl::to_string (tr ("Internal error: Terminal still connected after removing device in device combination")) + ": name=" + d->name () + ", circuit=" + c->name () + ", terminal=" + p->name ()); + } + } +} + +bool Circuit::combine_parallel_devices (const db::DeviceClass &cls) +{ + typedef std::vector key_type; + std::map > combination_candidates; + + bool any = false; + + // identify the candidates for combination - all devices sharing the same nets + // are candidates for combination in parallel mode + for (device_iterator d = begin_devices (); d != end_devices (); ++d) { + + if (tl::id_of (d->device_class ()) != tl::id_of (&cls)) { + continue; + } + + key_type k; + const std::vector &terminals = cls.terminal_definitions (); + for (std::vector::const_iterator p = terminals.begin (); p != terminals.end (); ++p) { + const db::Net *n = d->net_for_terminal (p->id ()); + if (n) { + k.push_back (n); + } + } + + std::sort (k.begin (), k.end ()); + k.erase (std::unique (k.begin (), k.end ()), k.end ()); + combination_candidates[k].push_back (d.operator-> ()); + + } + + // actually combine the devices + for (std::map >::iterator cc = combination_candidates.begin (); cc != combination_candidates.end (); ++cc) { + + std::vector &cl = cc->second; + for (size_t i = 0; i < cl.size () - 1; ++i) { + for (size_t j = i + 1; j < cl.size (); ) { + if (cls.combine_devices (cl [i], cl [j])) { + check_device_before_remove (this, cl [j]); // sanity check + delete cl [j]; + cl.erase (cl.begin () + j); + any = true; + } else { + ++j; + } + } + } + + } + + return any; +} + +static std::pair attached_two_devices (db::Net &net, const db::DeviceClass &cls) +{ + if (net.begin_pins () != net.end_pins ()) { + return std::make_pair ((db::Device *) 0, (db::Device *) 0); + } + + db::Device *d1 = 0, *d2 = 0; + + Net::terminal_iterator p = net.begin_terminals (); + if (p == net.end_terminals () || tl::id_of (p->device_class ()) != tl::id_of (&cls)) { + return std::make_pair ((db::Device *) 0, (db::Device *) 0); + } else { + d1 = p->device (); + } + + ++p; + if (p == net.end_terminals () || tl::id_of (p->device_class ()) != tl::id_of (&cls)) { + return std::make_pair ((db::Device *) 0, (db::Device *) 0); + } else { + d2 = p->device (); + } + + ++p; + if (p != net.end_terminals () || d1 == d2 || !d1 || !d2) { + return std::make_pair ((db::Device *) 0, (db::Device *) 0); + } else { + return std::make_pair (d1, d2); + } +} + +template +static bool same_or_swapped (const std::pair &p1, const std::pair &p2) +{ + return (p1.first == p2.first && p1.second == p2.second) || (p1.first == p2.second && p1.second == p2.first); +} + +bool Circuit::combine_serial_devices(const db::DeviceClass &cls) +{ + bool any = false; + + for (net_iterator n = begin_nets (); n != end_nets (); ++n) { + + std::pair dd = attached_two_devices (*n, cls); + if (! dd.first) { + continue; + } + + // The net is an internal node: the devices attached to this internal node are + // combination candidates if the number of nets emerging from the attached device pair (not counting + // the internal node we just found) does not exceed the number of pins available for the + // new device. + + std::vector other_nets; + + const std::vector &terminals = cls.terminal_definitions (); + for (std::vector::const_iterator p = terminals.begin (); p != terminals.end (); ++p) { + db::Net *on; + on = dd.first->net_for_terminal (p->id ()); + if (on && ! same_or_swapped (dd, attached_two_devices (*on, cls))) { + other_nets.push_back (on); + } + on = dd.second->net_for_terminal (p->id ()); + if (on && ! same_or_swapped (dd, attached_two_devices (*on, cls))) { + other_nets.push_back (on); + } + } + + std::sort (other_nets.begin (), other_nets.end ()); + other_nets.erase (std::unique (other_nets.begin (), other_nets.end ()), other_nets.end ()); + + if (other_nets.size () <= cls.terminal_definitions().size ()) { + + // found a combination candidate + if (cls.combine_devices (dd.first, dd.second)) { + check_device_before_remove (this, dd.second); // sanity check + delete dd.second; + any = true; + } + + } + + } + + return any; +} + +void Circuit::combine_devices () +{ + tl_assert (netlist () != 0); + + for (Netlist::device_class_iterator dc = netlist ()->begin_device_classes (); dc != netlist ()->end_device_classes (); ++dc) { + + // repeat the combination step unless no combination happens - this is required to take care of combinations that arise after + // other combinations have been realized. + bool any = true; + while (any) { + + any = false; + + if (dc->supports_parallel_combination ()) { + if (combine_parallel_devices (*dc)) { + any = true; + } + } + if (dc->supports_serial_combination ()) { + if (combine_serial_devices (*dc)) { + any = true; + } + } + + } + + } +} + +} diff --git a/src/db/db/dbCircuit.h b/src/db/db/dbCircuit.h new file mode 100644 index 000000000..98c01ecdb --- /dev/null +++ b/src/db/db/dbCircuit.h @@ -0,0 +1,634 @@ + +/* + + 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_dbCircuit +#define _HDR_dbCircuit + +#include "dbCommon.h" +#include "dbTypes.h" +#include "dbNet.h" +#include "dbDevice.h" +#include "dbPin.h" +#include "dbSubCircuit.h" +#include "dbNetlistUtils.h" + +#include "tlObject.h" +#include "tlObjectCollection.h" +#include "tlVector.h" +#include "gsiObject.h" + +namespace db +{ + +class Netlist; + +/** + * @brief A circuit + * + * A circuit is a list of nets, of subcircuit references and actual + * devices. + */ +class DB_PUBLIC Circuit + : public gsi::ObjectBase, public tl::Object +{ +public: + typedef tl::vector pin_list; + typedef pin_list::const_iterator const_pin_iterator; + typedef pin_list::iterator pin_iterator; + typedef tl::shared_collection device_list; + typedef device_list::const_iterator const_device_iterator; + typedef device_list::iterator device_iterator; + typedef tl::shared_collection net_list; + typedef net_list::const_iterator const_net_iterator; + typedef net_list::iterator net_iterator; + typedef tl::shared_collection subcircuit_list; + typedef subcircuit_list::const_iterator const_subcircuit_iterator; + typedef subcircuit_list::iterator subcircuit_iterator; + typedef tl::weak_collection::const_iterator const_refs_iterator; + typedef tl::weak_collection::iterator refs_iterator; + typedef tl::vector::const_iterator child_circuit_iterator; + typedef tl::vector::const_iterator const_child_circuit_iterator; + typedef tl::vector::const_iterator parent_circuit_iterator; + typedef tl::vector::const_iterator const_parent_circuit_iterator; + + /** + * @brief Constructor + * + * Creates an empty circuit. + */ + Circuit (); + + /** + * @brief Copy constructor + */ + Circuit (const Circuit &other); + + /** + * @brief Destructor + */ + ~Circuit (); + + /** + * @brief Assignment + */ + Circuit &operator= (const Circuit &other); + + /** + * @brief Gets the netlist the circuit lives in + * This pointer is 0 if the circuit is not part of a netlist. + */ + Netlist *netlist () + { + return mp_netlist; + } + + /** + * @brief Gets the netlist the circuit lives in (const version) + * This pointer is 0 if the circuit is not part of a netlist. + */ + const Netlist *netlist () const + { + return mp_netlist; + } + + /** + * @brief Clears the circuit + */ + void clear (); + + /** + * @brief Sets the name of the circuit + */ + void set_name (const std::string &name); + + /** + * @brief Gets the name of the circuit + */ + const std::string &name () const + { + return m_name; + } + + /** + * @brief The index of the circuit in the netlist + * CAUTION: this attribute is used for internal purposes and may not be valid always. + */ + size_t index () const + { + return m_index; + } + + /** + * @brief Sets the layout cell reference for this circuit + * + * The layout cell reference links a circuit to a layout cell. + */ + void set_cell_index (const db::cell_index_type ci); + + /** + * @brief Gets the layout cell index + */ + db::cell_index_type cell_index () const + { + return m_cell_index; + } + + /** + * @brief Gets the references to this circuit (begin, non-const version) + * This iterator will deliver all subcircuits referencing this circuit + */ + refs_iterator begin_refs () + { + return m_refs.begin (); + } + + /** + * @brief Gets the references to this circuit (end, non-const version) + * This iterator will deliver all subcircuits referencing this circuit + */ + refs_iterator end_refs () + { + return m_refs.end (); + } + + /** + * @brief Gets the references to this circuit (begin, const version) + * This iterator will deliver all subcircuits referencing this circuit + */ + const_refs_iterator begin_refs () const + { + return m_refs.begin (); + } + + /** + * @brief Gets the child circuits iterator (begin) + * The child circuits are the circuits referenced by all subcircuits + * in the circuit. + */ + child_circuit_iterator begin_children (); + + /** + * @brief Gets the child circuits iterator (end) + */ + child_circuit_iterator end_children (); + + /** + * @brief Gets the child circuits iterator (begin, const version) + * The child circuits are the circuits referenced by all subcircuits + * in the circuit. + */ + const_child_circuit_iterator begin_children () const; + + /** + * @brief Gets the child circuits iterator (end, const version) + */ + const_child_circuit_iterator end_children () const; + + /** + * @brief Gets the parent circuits iterator (begin) + * The parents circuits are the circuits referencing this circuit via subcircuits. + */ + parent_circuit_iterator begin_parents (); + + /** + * @brief Gets the parent circuits iterator (end) + */ + parent_circuit_iterator end_parents (); + + /** + * @brief Gets the parent circuits iterator (begin, const version) + * The parents circuits are the circuits referencing this circuit via subcircuits. + */ + const_parent_circuit_iterator begin_parents () const; + + /** + * @brief Gets the parent circuits iterator (end, const version) + */ + const_parent_circuit_iterator end_parents () const; + + /** + * @brief Gets the references to this circuit (end, const version) + * This iterator will deliver all subcircuits referencing this circuit + */ + const_refs_iterator end_refs () const + { + return m_refs.end (); + } + + /** + * @brief Adds a pin to this circuit + * The circuit takes over ownership of the object. + */ + const Pin &add_pin(const std::string &name); + + /** + * @brief Begin iterator for the pins of the circuit (non-const version) + */ + pin_iterator begin_pins () + { + return m_pins.begin (); + } + + /** + * @brief End iterator for the pins of the circuit (non-const version) + */ + pin_iterator end_pins () + { + 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) + */ + const Pin *pin_by_id (size_t id) const; + + /** + * @brief Gets the pin by name + * + * If there is no pin with that name, null is returned. + * NOTE: this is a linear search, so it's performance may not be good for many pins. + */ + const Pin *pin_by_name (const std::string &name) const; + + /** + * @brief Begin iterator for the pins of the circuit (const version) + */ + const_pin_iterator begin_pins () const + { + return m_pins.begin (); + } + + /** + * @brief End iterator for the pins of the circuit (const version) + */ + const_pin_iterator end_pins () const + { + return m_pins.end (); + } + + /** + * @brief Adds a net to this circuit + * + * The circuit takes over ownership of the object. + */ + void add_net (Net *net); + + /** + * @brief Deletes a net from the circuit + */ + void remove_net (Net *net); + + /** + * @brief Begin iterator for the nets of the circuit (non-const version) + */ + net_iterator begin_nets () + { + return m_nets.begin (); + } + + /** + * @brief End iterator for the nets of the circuit (non-const version) + */ + net_iterator end_nets () + { + return m_nets.end (); + } + + /** + * @brief Begin iterator for the nets of the circuit (const version) + */ + const_net_iterator begin_nets () const + { + return m_nets.begin (); + } + + /** + * @brief End iterator for the nets of the circuit (const version) + */ + const_net_iterator end_nets () const + { + return m_nets.end (); + } + + /** + * @brief Gets the net from a given cluster ID (const version) + * + * If the cluster ID is not valid, null is returned. + */ + const Net *net_by_cluster_id (size_t cluster_id) const + { + return (const_cast (this)->net_by_cluster_id (cluster_id)); + } + + /** + * @brief Gets the net from a given cluster ID (non-const version) + * + * If the cluster ID is not valid, null is returned. + */ + Net *net_by_cluster_id (size_t cluster_id) + { + return m_net_by_cluster_id.object_by (cluster_id); + } + + /** + * @brief Gets the net from a given name (const version) + * + * If the name is not valid, null is returned. + */ + const Net *net_by_name (const std::string &name) const + { + return (const_cast (this)->net_by_name (name)); + } + + /** + * @brief Gets the net from a given name (non-const version) + * + * If the name is not valid, null is returned. + */ + Net *net_by_name (const std::string &name) + { + return m_net_by_name.object_by (name); + } + + /** + * @brief Adds a device to this circuit + * + * The circuit takes over ownership of the object. + */ + void add_device (Device *device); + + /** + * @brief Deletes a device from the circuit + */ + void remove_device (Device *device); + + /** + * @brief Gets the device from a given ID (const version) + * + * If the ID is not valid, null is returned. + */ + const Device *device_by_id (size_t id) const + { + return (const_cast (this)->device_by_id (id)); + } + + /** + * @brief Gets the device from a given ID (non-const version) + * + * If the ID is not valid, null is returned. + */ + Device *device_by_id (size_t id) + { + return m_device_by_id.object_by (id); + } + + /** + * @brief Gets the device from a given name (const version) + * + * If the name is not valid, null is returned. + */ + const Device *device_by_name (const std::string &name) const + { + return (const_cast (this)->device_by_name (name)); + } + + /** + * @brief Gets the device from a given name (non-const version) + * + * If the name is not valid, null is returned. + */ + Device *device_by_name (const std::string &name) + { + return m_device_by_name.object_by (name); + } + + /** + * @brief Begin iterator for the devices of the circuit (non-const version) + */ + device_iterator begin_devices () + { + return m_devices.begin (); + } + + /** + * @brief End iterator for the devices of the circuit (non-const version) + */ + device_iterator end_devices () + { + return m_devices.end (); + } + + /** + * @brief Begin iterator for the devices of the circuit (const version) + */ + const_device_iterator begin_devices () const + { + return m_devices.begin (); + } + + /** + * @brief End iterator for the devices of the circuit (const version) + */ + const_device_iterator end_devices () const + { + return m_devices.end (); + } + + /** + * @brief Adds a subcircuit to this circuit + * + * The circuit takes over ownership of the object. + */ + void add_subcircuit (SubCircuit *subcircuit); + + /** + * @brief Deletes a subcircuit from the circuit + */ + void remove_subcircuit (SubCircuit *subcircuit); + + /** + * @brief Gets the subcircuit from a given ID (const version) + * + * If the ID is not valid, null is returned. + */ + const SubCircuit *subcircuit_by_id (size_t id) const + { + return (const_cast (this)->subcircuit_by_id (id)); + } + + /** + * @brief Gets the subcircuit from a given ID (non-const version) + * + * If the ID is not valid, null is returned. + */ + SubCircuit *subcircuit_by_id (size_t id) + { + return m_subcircuit_by_id.object_by (id); + } + + /** + * @brief Gets the subcircuit from a given name (const version) + * + * If the name is not valid, null is returned. + */ + const SubCircuit *subcircuit_by_name (const std::string &name) const + { + return (const_cast (this)->subcircuit_by_name (name)); + } + + /** + * @brief Gets the subcircuit from a given name (non-const version) + * + * If the name is not valid, null is returned. + */ + SubCircuit *subcircuit_by_name (const std::string &name) + { + return m_subcircuit_by_name.object_by (name); + } + + /** + * @brief Begin iterator for the subcircuits of the circuit (non-const version) + */ + subcircuit_iterator begin_subcircuits () + { + return m_subcircuits.begin (); + } + + /** + * @brief End iterator for the subcircuits of the circuit (non-const version) + */ + subcircuit_iterator end_subcircuits () + { + return m_subcircuits.end (); + } + + /** + * @brief Begin iterator for the subcircuits of the circuit (const version) + */ + const_subcircuit_iterator begin_subcircuits () const + { + return m_subcircuits.begin (); + } + + /** + * @brief End iterator for the subcircuits of the circuit (const version) + */ + const_subcircuit_iterator end_subcircuits () const + { + return m_subcircuits.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 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); + + /** + * @brief Purge unused nets + * + * This method will purge all nets which return "floating". + */ + void purge_nets (); + + /** + * @brief Combine devices + * + * This method will combine devices that can be combined according + * to their device classes "combine_devices" method. + */ + void combine_devices (); + +private: + friend class Netlist; + friend class Net; + friend class SubCircuit; + friend class Device; + + std::string m_name; + db::cell_index_type m_cell_index; + net_list m_nets; + pin_list m_pins; + device_list m_devices; + subcircuit_list m_subcircuits; + Netlist *mp_netlist; + std::vector m_pin_refs; + object_by_attr > m_device_by_id; + object_by_attr > m_subcircuit_by_id; + object_by_attr > m_net_by_cluster_id; + object_by_attr > m_device_by_name; + object_by_attr > m_subcircuit_by_name; + object_by_attr > m_net_by_name; + tl::weak_collection m_refs; + size_t m_index; + + void set_index (size_t index) + { + m_index = index; + } + + void set_pin_ref_for_pin (size_t ppin_id, Net::pin_iterator iter); + + void register_ref (SubCircuit *sc); + void unregister_ref (SubCircuit *sc); + + void translate_circuits (const std::map &map); + void translate_device_classes (const std::map &map); + void set_netlist (Netlist *netlist); + bool combine_parallel_devices (const db::DeviceClass &cls); + bool combine_serial_devices (const db::DeviceClass &cls); + + void devices_changed (); + void subcircuits_changed (); + void nets_changed (); +}; + +} + +#endif diff --git a/src/db/db/dbDevice.cc b/src/db/db/dbDevice.cc new file mode 100644 index 000000000..dd9b8d8cf --- /dev/null +++ b/src/db/db/dbDevice.cc @@ -0,0 +1,167 @@ + +/* + + 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 "dbDevice.h" +#include "dbCircuit.h" +#include "dbDeviceClass.h" + +namespace db +{ + +// -------------------------------------------------------------------------------- +// Device class implementation + +Device::Device () + : mp_device_class (0), m_id (0), mp_circuit (0) +{ + // .. nothing yet .. +} + +Device::~Device () +{ + for (std::vector::const_iterator t = m_terminal_refs.begin (); t != m_terminal_refs.end (); ++t) { + if (*t != Net::terminal_iterator () && (*t)->net ()) { + (*t)->net ()->erase_terminal (*t); + } + } +} + +Device::Device (DeviceClass *device_class, const std::string &name) + : mp_device_class (device_class), m_name (name), m_id (0), mp_circuit (0) +{ + // .. nothing yet .. +} + +Device::Device (const Device &other) + : mp_device_class (0), m_id (0), mp_circuit (0) +{ + operator= (other); +} + +Device &Device::operator= (const Device &other) +{ + if (this != &other) { + m_name = other.m_name; + mp_device_class = other.mp_device_class; + } + return *this; +} + +void Device::set_circuit (Circuit *circuit) +{ + mp_circuit = circuit; +} + +void Device::set_name (const std::string &n) +{ + m_name = n; + if (mp_circuit) { + mp_circuit->m_device_by_name.invalidate (); + } +} + +void Device::set_terminal_ref_for_terminal (size_t terminal_id, Net::terminal_iterator iter) +{ + if (m_terminal_refs.size () < terminal_id + 1) { + m_terminal_refs.resize (terminal_id + 1, Net::terminal_iterator ()); + } + m_terminal_refs [terminal_id] = iter; +} + +const Net *Device::net_for_terminal (size_t terminal_id) const +{ + if (terminal_id < m_terminal_refs.size ()) { + Net::terminal_iterator p = m_terminal_refs [terminal_id]; + if (p != Net::terminal_iterator ()) { + return p->net (); + } + } + return 0; +} + +void Device::connect_terminal (size_t terminal_id, Net *net) +{ + if (net_for_terminal (terminal_id) == net) { + return; + } + + if (terminal_id < m_terminal_refs.size ()) { + Net::terminal_iterator p = m_terminal_refs [terminal_id]; + if (p != Net::terminal_iterator () && p->net ()) { + p->net ()->erase_terminal (p); + } + m_terminal_refs [terminal_id] = Net::terminal_iterator (); + } + + if (net) { + net->add_terminal (NetTerminalRef (this, terminal_id)); + } +} + +double Device::parameter_value (size_t param_id) const +{ + if (m_parameters.size () > param_id) { + return m_parameters [param_id]; + } else if (mp_device_class) { + const db::DeviceParameterDefinition *pd = mp_device_class->parameter_definition (param_id); + if (pd) { + return pd->default_value (); + } + } + return 0.0; +} + +void Device::set_parameter_value (size_t param_id, double v) +{ + if (m_parameters.size () <= param_id) { + + // resize the parameter vector with default values + size_t from_size = m_parameters.size (); + m_parameters.resize (param_id + 1, 0.0); + + if (mp_device_class) { + for (size_t n = from_size; n < param_id; ++n) { + const db::DeviceParameterDefinition *pd = mp_device_class->parameter_definition (n); + if (pd) { + m_parameters [n] = pd->default_value (); + } + } + } + + } + + m_parameters [param_id] = v; +} + +double Device::parameter_value (const std::string &name) const +{ + return device_class () ? parameter_value (device_class ()->parameter_id_for_name (name)) : 0.0; +} + +void Device::set_parameter_value (const std::string &name, double v) +{ + if (device_class ()) { + set_parameter_value (device_class ()->parameter_id_for_name (name), v); + } +} + +} diff --git a/src/db/db/dbDevice.h b/src/db/db/dbDevice.h new file mode 100644 index 000000000..c918cbe35 --- /dev/null +++ b/src/db/db/dbDevice.h @@ -0,0 +1,217 @@ + +/* + + 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_dbDevice +#define _HDR_dbDevice + +#include "dbCommon.h" +#include "dbNet.h" + +#include "tlObject.h" + +#include + +namespace db +{ + +class Circuit; +class DeviceClass; + +/** + * @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 std::vector > global_connections; + typedef global_connections::const_iterator global_connections_iterator; + + /** + * @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 mp_device_class; + } + + /** + * @brief Gets the device ID + * The ID is a unique integer which identifies the device. + * It can be used to retrieve the device from the circuit using Circuit::device_by_id. + * When assigned, the device ID is not 0. + */ + size_t id () const + { + return m_id; + } + + /** + * @brief Gets the circuit the device lives in (const version) + * This pointer is 0 if the device isn't added to a circuit + */ + const Circuit *circuit () const + { + return mp_circuit; + } + + /** + * @brief Gets the circuit the device lives in (non-const version) + * This pointer is 0 if the device isn't added to a circuit + */ + Circuit *circuit () + { + return mp_circuit; + } + + /** + * @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 terminal + * Returns 0 if no net is attached. + */ + const Net *net_for_terminal (size_t terminal_id) const; + + /** + * @brief Gets the net attached to a specific terminal (non-const version) + * Returns 0 if no net is attached. + */ + Net *net_for_terminal (size_t terminal_id) + { + return const_cast (((const Device *) this)->net_for_terminal (terminal_id)); + } + + /** + * @brief Connects the given terminal to the given net + * If the net is 0 the terminal is disconnected. + * If non-null, a NetTerminalRef object will be inserted into the + * net and connected with the given terminal. + * If the terminal is connected to a global net, it will be + * disconnected from there. + */ + void connect_terminal (size_t terminal_id, Net *net); + + /** + * @brief Gets the value for the parameter with the given ID + */ + double parameter_value (size_t param_id) const; + + /** + * @brief Sets the value for the parameter with the given ID + */ + void set_parameter_value (size_t param_id, double v); + + /** + * @brief Gets the value for the parameter with the given name + * If the name is not valid, an exception is thrown. + */ + double parameter_value (const std::string &name) const; + + /** + * @brief Sets the value for the parameter with the given name + * If the name is not valid, an exception is thrown. + */ + void set_parameter_value (const std::string &name, double v); + +private: + friend class Circuit; + friend class Net; + + DeviceClass *mp_device_class; + std::string m_name; + std::vector m_terminal_refs; + std::vector m_parameters; + size_t m_id; + Circuit *mp_circuit; + + /** + * @brief Sets the terminal reference for a specific terminal + */ + void set_terminal_ref_for_terminal (size_t terminal_id, Net::terminal_iterator iter); + + /** + * @brief Sets the device class + */ + void set_device_class (DeviceClass *dc) + { + mp_device_class = dc; + } + + /** + * @brief Sets the device ID + */ + void set_id (size_t id) + { + m_id = id; + } + + /** + * @brief Sets the circuit + */ + void set_circuit (Circuit *circuit); +}; + +} + +#endif diff --git a/src/db/db/dbDeviceClass.cc b/src/db/db/dbDeviceClass.cc new file mode 100644 index 000000000..46a2c1a80 --- /dev/null +++ b/src/db/db/dbDeviceClass.cc @@ -0,0 +1,139 @@ + +/* + + 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 "dbDeviceClass.h" + +namespace db +{ + +// -------------------------------------------------------------------------------- +// DeviceClass class implementation + +DeviceClass::DeviceClass () + : mp_netlist (0) +{ + // .. nothing yet .. +} + +DeviceClass::DeviceClass (const DeviceClass &other) + : mp_netlist (0) +{ + operator= (other); +} + +DeviceClass &DeviceClass::operator= (const DeviceClass &other) +{ + if (this != &other) { + m_terminal_definitions = other.m_terminal_definitions; + m_name = other.m_name; + m_description = other.m_description; + } + return *this; +} + +const DeviceTerminalDefinition &DeviceClass::add_terminal_definition (const DeviceTerminalDefinition &pd) +{ + m_terminal_definitions.push_back (pd); + m_terminal_definitions.back ().set_id (m_terminal_definitions.size () - 1); + return m_terminal_definitions.back (); +} + +void DeviceClass::clear_terminal_definitions () +{ + m_terminal_definitions.clear (); +} + +const DeviceTerminalDefinition *DeviceClass::terminal_definition (size_t id) const +{ + if (id < m_terminal_definitions.size ()) { + return & m_terminal_definitions [id]; + } else { + return 0; + } +} + +const DeviceParameterDefinition &DeviceClass::add_parameter_definition (const DeviceParameterDefinition &pd) +{ + m_parameter_definitions.push_back (pd); + m_parameter_definitions.back ().set_id (m_parameter_definitions.size () - 1); + return m_parameter_definitions.back (); +} + +void DeviceClass::clear_parameter_definitions () +{ + m_parameter_definitions.clear (); +} + +const DeviceParameterDefinition *DeviceClass::parameter_definition (size_t id) const +{ + if (id < m_parameter_definitions.size ()) { + return & m_parameter_definitions [id]; + } else { + return 0; + } +} + +bool DeviceClass::has_parameter_with_name (const std::string &name) const +{ + const std::vector &pd = parameter_definitions (); + for (std::vector::const_iterator i = pd.begin (); i != pd.end (); ++i) { + if (i->name () == name) { + return true; + } + } + return false; +} + +size_t DeviceClass::parameter_id_for_name (const std::string &name) const +{ + const std::vector &pd = parameter_definitions (); + for (std::vector::const_iterator i = pd.begin (); i != pd.end (); ++i) { + if (i->name () == name) { + return i->id (); + } + } + throw tl::Exception (tl::to_string (tr ("Invalid parameter name")) + ": '" + name + "'"); +} + +bool DeviceClass::has_terminal_with_name (const std::string &name) const +{ + const std::vector &td = terminal_definitions (); + for (std::vector::const_iterator i = td.begin (); i != td.end (); ++i) { + if (i->name () == name) { + return true; + } + } + return false; +} + +size_t DeviceClass::terminal_id_for_name (const std::string &name) const +{ + const std::vector &td = terminal_definitions (); + for (std::vector::const_iterator i = td.begin (); i != td.end (); ++i) { + if (i->name () == name) { + return i->id (); + } + } + throw tl::Exception (tl::to_string (tr ("Invalid terminal name")) + ": '" + name + "'"); +} + +} diff --git a/src/db/db/dbDeviceClass.h b/src/db/db/dbDeviceClass.h new file mode 100644 index 000000000..8c4b34aca --- /dev/null +++ b/src/db/db/dbDeviceClass.h @@ -0,0 +1,422 @@ + +/* + + 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_dbDeviceClass +#define _HDR_dbDeviceClass + +#include "dbCommon.h" + +#include "gsiObject.h" +#include "tlObject.h" +#include "tlUniqueId.h" + +#include +#include + +namespace db +{ + +class Netlist; +class Device; + +/** + * @brief A device terminal definition + */ +class DB_PUBLIC DeviceTerminalDefinition +{ +public: + /** + * @brief Creates an empty device terminal definition + */ + DeviceTerminalDefinition () + : m_name (), m_description (), m_id (0) + { + // .. nothing yet .. + } + + /** + * @brief Creates a device terminal definition with the given name and description + */ + DeviceTerminalDefinition (const std::string &name, const std::string &description) + : m_name (name), m_description (description), m_id (0) + { + // .. nothing yet .. + } + + /** + * @brief Gets the terminal name + */ + const std::string &name () const + { + return m_name; + } + + /** + * @brief Sets the terminal name + */ + void set_name (const std::string &n) + { + m_name = n; + } + + /** + * @brief Gets the terminal description + */ + const std::string &description () const + { + return m_description; + } + + /** + * @brief Sets the terminal description + */ + void set_description (const std::string &d) + { + m_description = d; + } + + /** + * @brief Gets the terminal ID + */ + size_t id () const + { + return m_id; + } + +private: + friend class DeviceClass; + + std::string m_name, m_description; + size_t m_id; + + void set_id (size_t id) + { + m_id = id; + } +}; + +/** + * @brief A device parameter definition + */ +class DB_PUBLIC DeviceParameterDefinition +{ +public: + /** + * @brief Creates an empty device parameter definition + */ + DeviceParameterDefinition () + : m_name (), m_description (), m_default_value (0.0), m_id (0) + { + // .. nothing yet .. + } + + /** + * @brief Creates a device parameter definition with the given name and description + */ + DeviceParameterDefinition (const std::string &name, const std::string &description, double default_value = 0.0) + : m_name (name), m_description (description), m_default_value (default_value), m_id (0) + { + // .. nothing yet .. + } + + /** + * @brief Gets the parameter name + */ + const std::string &name () const + { + return m_name; + } + + /** + * @brief Sets the parameter name + */ + void set_name (const std::string &n) + { + m_name = n; + } + + /** + * @brief Gets the parameter description + */ + const std::string &description () const + { + return m_description; + } + + /** + * @brief Sets the parameter description + */ + void set_description (const std::string &d) + { + m_description = d; + } + + /** + * @brief Gets the parameter default value + */ + double default_value () const + { + return m_default_value; + } + + /** + * @brief Sets the parameter description + */ + void set_default_value (double d) + { + m_default_value = d; + } + + /** + * @brief Gets the parameter ID + */ + size_t id () const + { + return m_id; + } + +private: + friend class DeviceClass; + + std::string m_name, m_description; + double m_default_value; + size_t m_id; + + void set_id (size_t id) + { + m_id = id; + } +}; + +/** + * @brief A device class + * + * A device class describes a type of device. + */ +class DB_PUBLIC DeviceClass + : public gsi::ObjectBase, public tl::Object, public tl::UniqueId +{ +public: + typedef size_t terminal_id_type; + + /** + * @brief Constructor + * + * Creates an empty circuit. + */ + DeviceClass (); + + /** + * @brief Copy constructor + * NOTE: do not use this copy constructor as the device class + * is intended to subclassing. + */ + DeviceClass (const DeviceClass &other); + + /** + * @brief Assignment + * NOTE: do not use this copy constructor as the device class + * is intended to subclassing. + */ + DeviceClass &operator= (const DeviceClass &other); + + /** + * @brief Gets the netlist the device class lives in + */ + db::Netlist *netlist () + { + return mp_netlist; + } + + /** + * @brief Gets the netlist the device class lives in (const version) + */ + const db::Netlist *netlist () const + { + return mp_netlist; + } + + /** + * @brief Gets the name of the device class + * + * The name is a formal name which identifies the class. + */ + const std::string &name () const + { + return m_name; + } + + /** + * @brief Sets the device name + */ + void set_name (const std::string &n) + { + m_name = n; + } + + /** + * @brief Gets the description text for the device class + * + * The description text is a human-readable text that + * identifies the device class. + */ + const std::string &description () const + { + return m_description; + } + + /** + * @brief Sets the description text + */ + void set_description (const std::string &d) + { + m_description = d; + } + + /** + * @brief Gets the terminal definitions + * + * The terminal definitions indicate what terminals the device offers. + * The number of terminals is constant per class. The index of the terminal + * is used as an ID of the terminal, hence the order must be static. + */ + const std::vector &terminal_definitions () const + { + return m_terminal_definitions; + } + + /** + * @brief Adds a terminal definition + */ + const DeviceTerminalDefinition &add_terminal_definition (const DeviceTerminalDefinition &pd); + + /** + * @brief Clears the terminal definition + */ + void clear_terminal_definitions (); + + /** + * @brief Gets the terminal definition from the ID + */ + const DeviceTerminalDefinition *terminal_definition (size_t id) const; + + /** + * @brief Gets the parameter definitions + */ + const std::vector ¶meter_definitions () const + { + return m_parameter_definitions; + } + + /** + * @brief Adds a parameter definition + */ + const DeviceParameterDefinition &add_parameter_definition (const DeviceParameterDefinition &pd); + + /** + * @brief Clears the parameter definition + */ + void clear_parameter_definitions (); + + /** + * @brief Gets the parameter definition from the ID + */ + const DeviceParameterDefinition *parameter_definition (size_t id) const; + + /** + * @brief Returns true, if the device has a parameter with the given name + */ + bool has_parameter_with_name (const std::string &name) const; + + /** + * @brief Returns the parameter ID for the parameter with the given name + * If the name is invalid, an exception is thrown. + */ + size_t parameter_id_for_name (const std::string &name) const; + + /** + * @brief Returns true, if the device has a terminal with the given name + */ + bool has_terminal_with_name (const std::string &name) const; + + /** + * @brief Returns the parameter ID for the terminal with the given name + * If the name is invalid, an exception is thrown. + */ + size_t terminal_id_for_name (const std::string &name) const; + + /** + * @brief Clears the circuit + */ + virtual DeviceClass *clone () const + { + return new DeviceClass (*this); + } + + /** + * @brief Combines two devices + * + * This method shall test, whether the two devices can be combined. Both devices + * are guaranteed to share the same device class (this). + * If they cannot be combined, this method shall do nothing and return false. + * If they can be combined, this method shall reconnect the nets of the first + * device and entirely disconnect the nets of the second device. + * The second device will be deleted afterwards. + */ + virtual bool combine_devices (db::Device * /*a*/, db::Device * /*b*/) const + { + return false; + } + + /** + * @brief Returns true if the device class supports device combination in parallel mode + */ + virtual bool supports_parallel_combination () const + { + return false; + } + + /** + * @brief Returns true if the device class supports device combination in serial mode + */ + virtual bool supports_serial_combination () const + { + return false; + } + +private: + friend class Netlist; + + std::string m_name, m_description; + std::vector m_terminal_definitions; + std::vector m_parameter_definitions; + db::Netlist *mp_netlist; + + void set_netlist (db::Netlist *nl) + { + mp_netlist = nl; + } +}; + +} + +#endif diff --git a/src/db/db/dbNet.cc b/src/db/db/dbNet.cc new file mode 100644 index 000000000..20733d442 --- /dev/null +++ b/src/db/db/dbNet.cc @@ -0,0 +1,324 @@ + +/* + + 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 "dbNet.h" +#include "dbDevice.h" +#include "dbDeviceClass.h" +#include "dbCircuit.h" +#include "dbSubCircuit.h" + +namespace db +{ + +// -------------------------------------------------------------------------------- +// NetTerminalRef class implementation + +NetTerminalRef::NetTerminalRef () + : m_terminal_id (0), mp_device (0), mp_net (0) +{ + // .. nothing yet .. +} + +NetTerminalRef::NetTerminalRef (Device *device, size_t terminal_id) + : m_terminal_id (terminal_id), mp_device (device), mp_net (0) +{ + // .. nothing yet .. +} + +NetTerminalRef::NetTerminalRef (const NetTerminalRef &other) + : m_terminal_id (other.m_terminal_id), mp_device (other.mp_device), mp_net (0) +{ + // .. nothing yet .. +} + +NetTerminalRef &NetTerminalRef::operator= (const NetTerminalRef &other) +{ + if (this != &other) { + m_terminal_id = other.m_terminal_id; + mp_device = other.mp_device; + } + return *this; +} + +const DeviceTerminalDefinition * +NetTerminalRef::terminal_def () const +{ + const DeviceClass *dc = device_class (); + if (dc) { + return dc->terminal_definition (m_terminal_id); + } else { + return 0; + } +} + +const DeviceClass * +NetTerminalRef::device_class () const +{ + return mp_device ? mp_device->device_class () : 0; +} + +// -------------------------------------------------------------------------------- +// NetPinRef class implementation + +NetPinRef::NetPinRef () + : m_pin_id (0), mp_net (0) +{ + // .. nothing yet .. +} + +NetPinRef::NetPinRef (size_t pin_id) + : m_pin_id (pin_id), mp_net (0) +{ + // .. nothing yet .. +} + +NetPinRef::NetPinRef (const NetPinRef &other) + : m_pin_id (other.m_pin_id), mp_net (0) +{ + // .. nothing yet .. +} + +NetPinRef &NetPinRef::operator= (const NetPinRef &other) +{ + if (this != &other) { + m_pin_id = other.m_pin_id; + } + return *this; +} + +const Pin *NetPinRef::pin () const +{ + if (mp_net && mp_net->circuit ()) { + return mp_net->circuit ()->pin_by_id (m_pin_id); + } + return 0; +} + +// -------------------------------------------------------------------------------- +// NetSubcircuitPinRef class implementation + +NetSubcircuitPinRef::NetSubcircuitPinRef () + : m_pin_id (0), mp_subcircuit (0), mp_net (0) +{ + // .. nothing yet .. +} + +NetSubcircuitPinRef::NetSubcircuitPinRef (SubCircuit *circuit, size_t pin_id) + : m_pin_id (pin_id), mp_subcircuit (circuit), mp_net (0) +{ + // .. nothing yet .. +} + +NetSubcircuitPinRef::NetSubcircuitPinRef (const NetSubcircuitPinRef &other) + : m_pin_id (other.m_pin_id), mp_subcircuit (other.mp_subcircuit), mp_net (0) +{ + // .. nothing yet .. +} + +NetSubcircuitPinRef &NetSubcircuitPinRef::operator= (const NetSubcircuitPinRef &other) +{ + if (this != &other) { + m_pin_id = other.m_pin_id; + mp_subcircuit = other.mp_subcircuit; + } + return *this; +} + +const Pin *NetSubcircuitPinRef::pin () const +{ + if (mp_subcircuit && mp_subcircuit->circuit_ref ()) { + return mp_subcircuit->circuit_ref ()->pin_by_id (m_pin_id); + } + return 0; +} + +// -------------------------------------------------------------------------------- +// Net class implementation + +Net::Net () + : m_cluster_id (0), mp_circuit (0) +{ + // .. nothing yet .. +} + +Net::Net (const std::string &name) + : m_cluster_id (0), mp_circuit (0) +{ + m_name = name; +} + +Net::Net (const Net &other) + : m_cluster_id (0), mp_circuit (0) +{ + operator= (other); +} + +Net &Net::operator= (const Net &other) +{ + if (this != &other) { + + clear (); + + m_name = other.m_name; + m_cluster_id = other.m_cluster_id; + + for (const_subcircuit_pin_iterator i = other.begin_subcircuit_pins (); i != other.end_subcircuit_pins (); ++i) { + add_subcircuit_pin (*i); + } + + for (const_pin_iterator i = other.begin_pins (); i != other.end_pins (); ++i) { + add_pin (*i); + } + + for (const_terminal_iterator i = other.begin_terminals (); i != other.end_terminals (); ++i) { + add_terminal (*i); + } + + } + return *this; +} + +Net::~Net () +{ + clear (); +} + +void Net::clear () +{ + m_name.clear (); + m_cluster_id = 0; + + while (! m_terminals.empty ()) { + erase_terminal (begin_terminals ()); + } + + while (! m_pins.empty ()) { + erase_pin (begin_pins ()); + } + + while (! m_subcircuit_pins.empty ()) { + erase_subcircuit_pin (begin_subcircuit_pins ()); + } +} + +void Net::set_name (const std::string &name) +{ + m_name = name; + if (mp_circuit) { + mp_circuit->m_net_by_name.invalidate (); + } +} + +std::string Net::qname () const +{ + if (circuit ()) { + return circuit ()->name () + ":" + expanded_name (); + } else { + return expanded_name (); + } +} + +std::string Net::expanded_name () const +{ + if (name ().empty ()) { + if (cluster_id () > std::numeric_limits::max () / 2) { + // avoid printing huge ID numbers for internal cluster IDs + return "$I" + tl::to_string ((std::numeric_limits::max () - cluster_id ()) + 1); + } else { + return "$" + tl::to_string (cluster_id ()); + } + } else { + return name (); + } +} + +void Net::set_cluster_id (size_t ci) +{ + m_cluster_id = ci; + if (mp_circuit) { + mp_circuit->m_net_by_cluster_id.invalidate (); + } +} + +void Net::add_pin (const NetPinRef &pin) +{ + m_pins.push_back (pin); + NetPinRef &new_pin = m_pins.back (); + new_pin.set_net (this); + + if (mp_circuit) { + mp_circuit->set_pin_ref_for_pin (new_pin.pin_id (), --m_pins.end ()); + } +} + +void Net::add_subcircuit_pin (const NetSubcircuitPinRef &pin) +{ + m_subcircuit_pins.push_back (pin); + NetSubcircuitPinRef &new_pin = m_subcircuit_pins.back (); + new_pin.set_net (this); + + tl_assert (pin.subcircuit () != 0); + new_pin.subcircuit ()->set_pin_ref_for_pin (new_pin.pin_id (), --m_subcircuit_pins.end ()); +} + +void Net::erase_pin (pin_iterator iter) +{ + if (mp_circuit) { + mp_circuit->set_pin_ref_for_pin (iter->pin_id (), pin_iterator ()); + } + m_pins.erase (iter); +} + +void Net::erase_subcircuit_pin (subcircuit_pin_iterator iter) +{ + if (iter->subcircuit ()) { + iter->subcircuit ()->set_pin_ref_for_pin (iter->pin_id (), subcircuit_pin_iterator ()); + } + m_subcircuit_pins.erase (iter); +} + +void Net::add_terminal (const NetTerminalRef &terminal) +{ + if (! terminal.device ()) { + return; + } + + m_terminals.push_back (terminal); + NetTerminalRef &new_terminal = m_terminals.back (); + new_terminal.set_net (this); + new_terminal.device ()->set_terminal_ref_for_terminal (new_terminal.terminal_id (), --m_terminals.end ()); +} + +void Net::erase_terminal (terminal_iterator iter) +{ + if (iter->device ()) { + iter->device ()->set_terminal_ref_for_terminal (iter->terminal_id (), terminal_iterator ()); + } + m_terminals.erase (iter); +} + +void Net::set_circuit (Circuit *circuit) +{ + mp_circuit = circuit; +} + +} diff --git a/src/db/db/dbNet.h b/src/db/db/dbNet.h new file mode 100644 index 000000000..6baa895b9 --- /dev/null +++ b/src/db/db/dbNet.h @@ -0,0 +1,651 @@ + +/* + + 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_dbNet +#define _HDR_dbNet + +#include "dbCommon.h" + +#include "tlObject.h" + +#include +#include + +namespace db +{ + +class Device; +class Net; +class SubCircuit; +class Circuit; +class DeviceTerminalDefinition; +class DeviceClass; +class Pin; + +/** + * @brief A reference to a terminal of a device + * + * A terminal must always refer to a device inside the current circuit. + */ +class DB_PUBLIC NetTerminalRef +{ +public: + /** + * @brief Default constructor + */ + NetTerminalRef (); + + /** + * @brief Creates a pin reference to the given pin of the current circuit + */ + NetTerminalRef (Device *device, size_t terminal_id); + + /** + * @brief Copy constructor + */ + NetTerminalRef (const NetTerminalRef &other); + + /** + * @brief Assignment + */ + NetTerminalRef &operator= (const NetTerminalRef &other); + + /** + * @brief Comparison + */ + bool operator< (const NetTerminalRef &other) const + { + if (mp_device != other.mp_device) { + return mp_device < other.mp_device; + } + return m_terminal_id < other.m_terminal_id; + } + + /** + * @brief Equality + */ + bool operator== (const NetTerminalRef &other) const + { + return (mp_device == other.mp_device && m_terminal_id == other.m_terminal_id); + } + + /** + * @brief Gets the device reference + */ + Device *device () + { + return mp_device; + } + + /** + * @brief Gets the device reference (const version) + */ + const Device *device () const + { + return mp_device; + } + + /** + * @brief Gets the terminal index + */ + size_t terminal_id () const + { + return m_terminal_id; + } + + /** + * @brief Gets the terminal definition + * + * Returns 0 if the terminal is not a valid terminal reference. + */ + const DeviceTerminalDefinition *terminal_def () const; + + /** + * @brief Returns the device class + */ + const DeviceClass *device_class () const; + + /** + * @brief Gets the net the terminal lives in + */ + Net *net () + { + return mp_net; + } + + /** + * @brief Gets the net the terminal lives in (const version) + */ + const Net *net () const + { + return mp_net; + } + +private: + friend class Net; + + size_t m_terminal_id; + Device *mp_device; + Net *mp_net; + + /** + * @brief Sets the net the terminal lives in + */ + void set_net (Net *net) + { + mp_net = net; + } +}; + +/** + * @brief A reference to a pin inside a net + * + * This object describes a connection to an outgoing pin. + */ +class DB_PUBLIC NetPinRef +{ +public: + /** + * @brief Default constructor + */ + NetPinRef (); + + /** + * @brief Creates a pin reference to the given pin of the current circuit + */ + NetPinRef (size_t pin_id); + + /** + * @brief Copy constructor + */ + NetPinRef (const NetPinRef &other); + + /** + * @brief Assignment + */ + NetPinRef &operator= (const NetPinRef &other); + + /** + * @brief Comparison + */ + bool operator< (const NetPinRef &other) const + { + return m_pin_id < other.m_pin_id; + } + + /** + * @brief Equality + */ + bool operator== (const NetPinRef &other) const + { + return (m_pin_id == other.m_pin_id); + } + + /** + * @brief Gets the pin reference (const version) + */ + size_t pin_id () const + { + return m_pin_id; + } + + /** + * @brief Gets the pin reference from the pin id + * If the pin cannot be resolved, null is returned. + */ + const Pin *pin () const; + + /** + * @brief Gets the net the pin lives in + */ + Net *net () + { + 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; + Net *mp_net; + + /** + * @brief Sets the net the terminal lives in + */ + void set_net (Net *net) + { + mp_net = net; + } +}; + +/** + * @brief A reference to a pin inside a net + * + * This object describes a connection to a pin of a subcircuit. + */ +class DB_PUBLIC NetSubcircuitPinRef +{ +public: + /** + * @brief Default constructor + */ + NetSubcircuitPinRef (); + + /** + * @brief Creates a pin reference to the given pin of the given subcircuit + */ + NetSubcircuitPinRef (SubCircuit *circuit, size_t pin_id); + + /** + * @brief Copy constructor + */ + NetSubcircuitPinRef (const NetSubcircuitPinRef &other); + + /** + * @brief Assignment + */ + NetSubcircuitPinRef &operator= (const NetSubcircuitPinRef &other); + + /** + * @brief Comparison + */ + bool operator< (const NetSubcircuitPinRef &other) const + { + if (mp_subcircuit != other.mp_subcircuit) { + return mp_subcircuit < other.mp_subcircuit; + } + return m_pin_id < other.m_pin_id; + } + + /** + * @brief Equality + */ + bool operator== (const NetSubcircuitPinRef &other) const + { + return (mp_subcircuit == other.mp_subcircuit && m_pin_id == other.m_pin_id); + } + + /** + * @brief Gets the pin reference (const version) + */ + size_t pin_id () const + { + return m_pin_id; + } + + /** + * @brief Gets the pin reference from the pin id + * If the pin cannot be resolved, null is returned. + */ + const Pin *pin () const; + + /** + * @brief Gets the subcircuit reference + */ + SubCircuit *subcircuit () + { + return mp_subcircuit; + } + + /** + * @brief Gets the subcircuit reference (const version) + */ + const SubCircuit *subcircuit () const + { + return mp_subcircuit; + } + + /** + * @brief Gets the net the pin lives in + */ + Net *net () + { + 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; + SubCircuit *mp_subcircuit; + Net *mp_net; + + /** + * @brief Sets the net the terminal lives in + */ + void set_net (Net *net) + { + mp_net = net; + } +}; + +/** + * @brief A net + * + * A net connects terminals of devices and pins or circuits + */ +class DB_PUBLIC Net + : public tl::Object +{ +public: + typedef std::list terminal_list; + typedef terminal_list::const_iterator const_terminal_iterator; + typedef terminal_list::iterator terminal_iterator; + typedef std::list pin_list; + typedef pin_list::const_iterator const_pin_iterator; + typedef pin_list::iterator pin_iterator; + typedef std::list subcircuit_pin_list; + typedef subcircuit_pin_list::const_iterator const_subcircuit_pin_iterator; + typedef subcircuit_pin_list::iterator subcircuit_pin_iterator; + + /** + * @brief Constructor + * Creates an empty circuit. + */ + Net (); + + /** + * @brief Creates a empty net with the give name + */ + Net (const std::string &name); + + /** + * @brief Copy constructor + */ + Net (const Net &other); + + /** + * @brief Destructor + */ + ~Net (); + + /** + * @brief Assignment + */ + Net &operator= (const Net &other); + + /** + * @brief Gets the circuit the net lives in + * This pointer is 0 if the net is not part of a circuit. + */ + Circuit *circuit () + { + return mp_circuit; + } + + /** + * @brief Gets the circuit the net lives in (const version) + * This pointer is 0 if the net is not part of a circuit. + */ + const Circuit *circuit () const + { + return mp_circuit; + } + + /** + * @brief Clears the circuit + */ + void clear (); + + /** + * @brief Sets the name of the circuit + */ + void set_name (const std::string &name); + + /** + * @brief Gets the name of the circuit + */ + const std::string &name () const + { + return m_name; + } + + /** + * @brief Gets the expanded name + * + * The "expanded name" is a non-empty name for the net. It uses the + * cluster ID if no name is set. + */ + std::string expanded_name () const; + + /** + * @brief Gets the qualified name + * + * The qualified name is like the expanded name, but preceeded with the + * Circuit name if known (e.g. "CIRCUIT:NET") + */ + std::string qname () const; + + /** + * @brief Sets the cluster ID of this net + * + * The cluster ID links the net to a cluster from the + * hierarchical layout netlist extractor. + */ + void set_cluster_id (size_t ci); + + /** + * @brief Gets the cluster ID + */ + size_t cluster_id () const + { + return m_cluster_id; + } + + /** + * @brief Adds a pin to this net + */ + 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) + */ + const_pin_iterator begin_pins () const + { + return m_pins.begin (); + } + + /** + * @brief End iterator for the pins of the net (const version) + */ + const_pin_iterator end_pins () const + { + 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 subcircuit pin to this net + */ + void add_subcircuit_pin (const NetSubcircuitPinRef &pin); + + /** + * @brief Erases the given subcircuit pin from this net + */ + void erase_subcircuit_pin (subcircuit_pin_iterator iter); + + /** + * @brief Begin iterator for the pins of the net (const version) + */ + const_subcircuit_pin_iterator begin_subcircuit_pins () const + { + return m_subcircuit_pins.begin (); + } + + /** + * @brief End iterator for the pins of the net (const version) + */ + const_subcircuit_pin_iterator end_subcircuit_pins () const + { + return m_subcircuit_pins.end (); + } + + /** + * @brief Begin iterator for the pins of the net (non-const version) + */ + subcircuit_pin_iterator begin_subcircuit_pins () + { + return m_subcircuit_pins.begin (); + } + + /** + * @brief End iterator for the pins of the net (non-const version) + */ + subcircuit_pin_iterator end_subcircuit_pins () + { + return m_subcircuit_pins.end (); + } + + /** + * @brief Adds a terminal to this net + */ + void add_terminal (const NetTerminalRef &terminal); + + /** + * @brief Erases the given terminal from this net + */ + void erase_terminal (terminal_iterator iter); + + /** + * @brief Begin iterator for the terminals of the net (const version) + */ + const_terminal_iterator begin_terminals () const + { + return m_terminals.begin (); + } + + /** + * @brief End iterator for the terminals of the net (const version) + */ + const_terminal_iterator end_terminals () const + { + return m_terminals.end (); + } + + /** + * @brief Begin iterator for the terminals of the net (non-const version) + */ + terminal_iterator begin_terminals () + { + return m_terminals.begin (); + } + + /** + * @brief End iterator for the terminals of the net (non-const version) + */ + terminal_iterator end_terminals () + { + return m_terminals.end (); + } + + /** + * @brief Returns true, if the net is floating (has no or only a single connection) + */ + bool is_floating () const + { + return (m_pins.size () + m_subcircuit_pins.size () + m_terminals.size ()) < 2; + } + + /** + * @brief Returns true, if the net is an internal node (connects two terminals only) + */ + bool is_internal () const + { + return m_pins.size () == 0 && m_subcircuit_pins.size () == 0 && m_terminals.size () == 2; + } + + /** + * @brief Returns the number of outgoing pins connected + */ + size_t pin_count () const + { + return m_pins.size (); + } + + /** + * @brief Returns the number of subcircuit pins connected + */ + size_t subcircuit_pin_count () const + { + return m_subcircuit_pins.size (); + } + + /** + * @brief Returns the number of terminals connected + */ + size_t terminal_count () const + { + return m_terminals.size (); + } + +private: + friend class Circuit; + + terminal_list m_terminals; + pin_list m_pins; + subcircuit_pin_list m_subcircuit_pins; + std::string m_name; + size_t m_cluster_id; + Circuit *mp_circuit; + + void set_circuit (Circuit *circuit); +}; + +} + +#endif diff --git a/src/db/db/dbNetlist.cc b/src/db/db/dbNetlist.cc index 8ca118e60..21dced73c 100644 --- a/src/db/db/dbNetlist.cc +++ b/src/db/db/dbNetlist.cc @@ -27,1202 +27,6 @@ namespace db { -// -------------------------------------------------------------------------------- -// Pin class implementation - -Pin::Pin () - : m_id (0) -{ - // .. nothing yet .. -} - -Pin::Pin (const std::string &name) - : m_name (name), m_id (0) -{ - // .. nothing yet .. -} - -// -------------------------------------------------------------------------------- -// Device class implementation - -Device::Device () - : mp_device_class (0), m_id (0), mp_circuit (0) -{ - // .. nothing yet .. -} - -Device::~Device () -{ - for (std::vector::const_iterator t = m_terminal_refs.begin (); t != m_terminal_refs.end (); ++t) { - if (*t != Net::terminal_iterator () && (*t)->net ()) { - (*t)->net ()->erase_terminal (*t); - } - } -} - -Device::Device (DeviceClass *device_class, const std::string &name) - : mp_device_class (device_class), m_name (name), m_id (0), mp_circuit (0) -{ - // .. nothing yet .. -} - -Device::Device (const Device &other) - : mp_device_class (0), m_id (0), mp_circuit (0) -{ - operator= (other); -} - -Device &Device::operator= (const Device &other) -{ - if (this != &other) { - m_name = other.m_name; - mp_device_class = other.mp_device_class; - } - return *this; -} - -void Device::set_circuit (Circuit *circuit) -{ - mp_circuit = circuit; -} - -void Device::set_name (const std::string &n) -{ - m_name = n; - if (mp_circuit) { - mp_circuit->m_device_by_name.invalidate (); - } -} - -void Device::set_terminal_ref_for_terminal (size_t terminal_id, Net::terminal_iterator iter) -{ - if (m_terminal_refs.size () < terminal_id + 1) { - m_terminal_refs.resize (terminal_id + 1, Net::terminal_iterator ()); - } - m_terminal_refs [terminal_id] = iter; -} - -const Net *Device::net_for_terminal (size_t terminal_id) const -{ - if (terminal_id < m_terminal_refs.size ()) { - Net::terminal_iterator p = m_terminal_refs [terminal_id]; - if (p != Net::terminal_iterator ()) { - return p->net (); - } - } - return 0; -} - -void Device::connect_terminal (size_t terminal_id, Net *net) -{ - if (net_for_terminal (terminal_id) == net) { - return; - } - - if (terminal_id < m_terminal_refs.size ()) { - Net::terminal_iterator p = m_terminal_refs [terminal_id]; - if (p != Net::terminal_iterator () && p->net ()) { - p->net ()->erase_terminal (p); - } - m_terminal_refs [terminal_id] = Net::terminal_iterator (); - } - - if (net) { - net->add_terminal (NetTerminalRef (this, terminal_id)); - } -} - -double Device::parameter_value (size_t param_id) const -{ - if (m_parameters.size () > param_id) { - return m_parameters [param_id]; - } else if (mp_device_class) { - const db::DeviceParameterDefinition *pd = mp_device_class->parameter_definition (param_id); - if (pd) { - return pd->default_value (); - } - } - return 0.0; -} - -void Device::set_parameter_value (size_t param_id, double v) -{ - if (m_parameters.size () <= param_id) { - - // resize the parameter vector with default values - size_t from_size = m_parameters.size (); - m_parameters.resize (param_id + 1, 0.0); - - if (mp_device_class) { - for (size_t n = from_size; n < param_id; ++n) { - const db::DeviceParameterDefinition *pd = mp_device_class->parameter_definition (n); - if (pd) { - m_parameters [n] = pd->default_value (); - } - } - } - - } - - m_parameters [param_id] = v; -} - -double Device::parameter_value (const std::string &name) const -{ - return device_class () ? parameter_value (device_class ()->parameter_id_for_name (name)) : 0.0; -} - -void Device::set_parameter_value (const std::string &name, double v) -{ - if (device_class ()) { - set_parameter_value (device_class ()->parameter_id_for_name (name), v); - } -} - - -// -------------------------------------------------------------------------------- -// SubCircuit class implementation - -SubCircuit::SubCircuit () - : m_id (0), mp_circuit (0) -{ - // .. nothing yet .. -} - -SubCircuit::~SubCircuit() -{ - for (std::vector::const_iterator p = m_pin_refs.begin (); p != m_pin_refs.end (); ++p) { - if (*p != Net::subcircuit_pin_iterator () && (*p)->net ()) { - (*p)->net ()->erase_subcircuit_pin (*p); - } - } -} - -SubCircuit::SubCircuit (Circuit *circuit, const std::string &name) - : m_circuit_ref (0), m_name (name), m_id (0), mp_circuit (0) -{ - set_circuit_ref (circuit); -} - -SubCircuit::SubCircuit (const SubCircuit &other) - : m_id (0), mp_circuit (0) -{ - operator= (other); -} - -SubCircuit &SubCircuit::operator= (const SubCircuit &other) -{ - if (this != &other) { - m_name = other.m_name; - m_trans = other.m_trans; - set_circuit_ref (const_cast (other.circuit_ref ())); - } - return *this; -} - -void SubCircuit::set_name (const std::string &n) -{ - m_name = n; - if (mp_circuit) { - mp_circuit->m_subcircuit_by_name.invalidate (); - } -} - -void SubCircuit::set_trans (const db::DCplxTrans &t) -{ - m_trans = t; -} - -void SubCircuit::set_pin_ref_for_pin (size_t pin_id, Net::subcircuit_pin_iterator iter) -{ - if (m_pin_refs.size () < pin_id + 1) { - m_pin_refs.resize (pin_id + 1, Net::subcircuit_pin_iterator ()); - } - m_pin_refs [pin_id] = iter; -} - -void SubCircuit::set_circuit_ref (Circuit *c) -{ - if (m_circuit_ref.get ()) { - m_circuit_ref->unregister_ref (this); - } - m_circuit_ref.reset (c); - if (m_circuit_ref.get ()) { - m_circuit_ref->register_ref (this); - } -} - -const Net *SubCircuit::net_for_pin (size_t pin_id) const -{ - if (pin_id < m_pin_refs.size ()) { - Net::subcircuit_pin_iterator p = m_pin_refs [pin_id]; - if (p != Net::subcircuit_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::subcircuit_pin_iterator p = m_pin_refs [pin_id]; - if (p != Net::subcircuit_pin_iterator () && p->net ()) { - p->net ()->erase_subcircuit_pin (p); - } - m_pin_refs [pin_id] = Net::subcircuit_pin_iterator (); - } - - if (net) { - net->add_subcircuit_pin (NetSubcircuitPinRef (this, pin_id)); - } -} - -// -------------------------------------------------------------------------------- -// NetTerminalRef class implementation - -NetTerminalRef::NetTerminalRef () - : m_terminal_id (0), mp_device (0), mp_net (0) -{ - // .. nothing yet .. -} - -NetTerminalRef::NetTerminalRef (Device *device, size_t terminal_id) - : m_terminal_id (terminal_id), mp_device (device), mp_net (0) -{ - // .. nothing yet .. -} - -NetTerminalRef::NetTerminalRef (const NetTerminalRef &other) - : m_terminal_id (other.m_terminal_id), mp_device (other.mp_device), mp_net (0) -{ - // .. nothing yet .. -} - -NetTerminalRef &NetTerminalRef::operator= (const NetTerminalRef &other) -{ - if (this != &other) { - m_terminal_id = other.m_terminal_id; - mp_device = other.mp_device; - } - return *this; -} - -const DeviceTerminalDefinition * -NetTerminalRef::terminal_def () const -{ - const DeviceClass *dc = device_class (); - if (dc) { - return dc->terminal_definition (m_terminal_id); - } else { - return 0; - } -} - -const DeviceClass * -NetTerminalRef::device_class () const -{ - return mp_device ? mp_device->device_class () : 0; -} - -// -------------------------------------------------------------------------------- -// NetPinRef class implementation - -NetPinRef::NetPinRef () - : m_pin_id (0), mp_net (0) -{ - // .. nothing yet .. -} - -NetPinRef::NetPinRef (size_t pin_id) - : m_pin_id (pin_id), mp_net (0) -{ - // .. nothing yet .. -} - -NetPinRef::NetPinRef (const NetPinRef &other) - : m_pin_id (other.m_pin_id), mp_net (0) -{ - // .. nothing yet .. -} - -NetPinRef &NetPinRef::operator= (const NetPinRef &other) -{ - if (this != &other) { - m_pin_id = other.m_pin_id; - } - return *this; -} - -const Pin *NetPinRef::pin () const -{ - if (mp_net && mp_net->circuit ()) { - return mp_net->circuit ()->pin_by_id (m_pin_id); - } - return 0; -} - -// -------------------------------------------------------------------------------- -// NetSubcircuitPinRef class implementation - -NetSubcircuitPinRef::NetSubcircuitPinRef () - : m_pin_id (0), mp_subcircuit (0), mp_net (0) -{ - // .. nothing yet .. -} - -NetSubcircuitPinRef::NetSubcircuitPinRef (SubCircuit *circuit, size_t pin_id) - : m_pin_id (pin_id), mp_subcircuit (circuit), mp_net (0) -{ - // .. nothing yet .. -} - -NetSubcircuitPinRef::NetSubcircuitPinRef (const NetSubcircuitPinRef &other) - : m_pin_id (other.m_pin_id), mp_subcircuit (other.mp_subcircuit), mp_net (0) -{ - // .. nothing yet .. -} - -NetSubcircuitPinRef &NetSubcircuitPinRef::operator= (const NetSubcircuitPinRef &other) -{ - if (this != &other) { - m_pin_id = other.m_pin_id; - mp_subcircuit = other.mp_subcircuit; - } - return *this; -} - -const Pin *NetSubcircuitPinRef::pin () const -{ - if (mp_subcircuit && mp_subcircuit->circuit_ref ()) { - return mp_subcircuit->circuit_ref ()->pin_by_id (m_pin_id); - } - return 0; -} - -// -------------------------------------------------------------------------------- -// Net class implementation - -Net::Net () - : m_cluster_id (0), mp_circuit (0) -{ - // .. nothing yet .. -} - -Net::Net (const std::string &name) - : m_cluster_id (0), mp_circuit (0) -{ - m_name = name; -} - -Net::Net (const Net &other) - : m_cluster_id (0), mp_circuit (0) -{ - operator= (other); -} - -Net &Net::operator= (const Net &other) -{ - if (this != &other) { - - clear (); - - m_name = other.m_name; - m_cluster_id = other.m_cluster_id; - - for (const_subcircuit_pin_iterator i = other.begin_subcircuit_pins (); i != other.end_subcircuit_pins (); ++i) { - add_subcircuit_pin (*i); - } - - for (const_pin_iterator i = other.begin_pins (); i != other.end_pins (); ++i) { - add_pin (*i); - } - - for (const_terminal_iterator i = other.begin_terminals (); i != other.end_terminals (); ++i) { - add_terminal (*i); - } - - } - return *this; -} - -Net::~Net () -{ - clear (); -} - -void Net::clear () -{ - m_name.clear (); - m_cluster_id = 0; - - while (! m_terminals.empty ()) { - erase_terminal (begin_terminals ()); - } - - while (! m_pins.empty ()) { - erase_pin (begin_pins ()); - } - - while (! m_subcircuit_pins.empty ()) { - erase_subcircuit_pin (begin_subcircuit_pins ()); - } -} - -void Net::set_name (const std::string &name) -{ - m_name = name; - if (mp_circuit) { - mp_circuit->m_net_by_name.invalidate (); - } -} - -std::string Net::qname () const -{ - if (circuit ()) { - return circuit ()->name () + ":" + expanded_name (); - } else { - return expanded_name (); - } -} - -std::string Net::expanded_name () const -{ - if (name ().empty ()) { - if (cluster_id () > std::numeric_limits::max () / 2) { - // avoid printing huge ID numbers for internal cluster IDs - return "$I" + tl::to_string ((std::numeric_limits::max () - cluster_id ()) + 1); - } else { - return "$" + tl::to_string (cluster_id ()); - } - } else { - return name (); - } -} - -void Net::set_cluster_id (size_t ci) -{ - m_cluster_id = ci; - if (mp_circuit) { - mp_circuit->m_net_by_cluster_id.invalidate (); - } -} - -void Net::add_pin (const NetPinRef &pin) -{ - m_pins.push_back (pin); - NetPinRef &new_pin = m_pins.back (); - new_pin.set_net (this); - - if (mp_circuit) { - mp_circuit->set_pin_ref_for_pin (new_pin.pin_id (), --m_pins.end ()); - } -} - -void Net::add_subcircuit_pin (const NetSubcircuitPinRef &pin) -{ - m_subcircuit_pins.push_back (pin); - NetSubcircuitPinRef &new_pin = m_subcircuit_pins.back (); - new_pin.set_net (this); - - tl_assert (pin.subcircuit () != 0); - new_pin.subcircuit ()->set_pin_ref_for_pin (new_pin.pin_id (), --m_subcircuit_pins.end ()); -} - -void Net::erase_pin (pin_iterator iter) -{ - if (mp_circuit) { - mp_circuit->set_pin_ref_for_pin (iter->pin_id (), pin_iterator ()); - } - m_pins.erase (iter); -} - -void Net::erase_subcircuit_pin (subcircuit_pin_iterator iter) -{ - if (iter->subcircuit ()) { - iter->subcircuit ()->set_pin_ref_for_pin (iter->pin_id (), subcircuit_pin_iterator ()); - } - m_subcircuit_pins.erase (iter); -} - -void Net::add_terminal (const NetTerminalRef &terminal) -{ - if (! terminal.device ()) { - return; - } - - m_terminals.push_back (terminal); - NetTerminalRef &new_terminal = m_terminals.back (); - new_terminal.set_net (this); - new_terminal.device ()->set_terminal_ref_for_terminal (new_terminal.terminal_id (), --m_terminals.end ()); -} - -void Net::erase_terminal (terminal_iterator iter) -{ - if (iter->device ()) { - iter->device ()->set_terminal_ref_for_terminal (iter->terminal_id (), terminal_iterator ()); - } - m_terminals.erase (iter); -} - -void Net::set_circuit (Circuit *circuit) -{ - mp_circuit = circuit; -} - -// -------------------------------------------------------------------------------- -// Circuit class implementation - -Circuit::Circuit () - : 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), - m_device_by_name (this, &Circuit::begin_devices, &Circuit::end_devices), - m_subcircuit_by_name (this, &Circuit::begin_subcircuits, &Circuit::end_subcircuits), - m_net_by_name (this, &Circuit::begin_nets, &Circuit::end_nets), - m_index (0) -{ - m_devices.changed ().add (this, &Circuit::devices_changed); - m_nets.changed ().add (this, &Circuit::nets_changed); - m_subcircuits.changed ().add (this, &Circuit::subcircuits_changed); -} - -Circuit::Circuit (const Circuit &other) - : 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), - m_device_by_name (this, &Circuit::begin_devices, &Circuit::end_devices), - m_subcircuit_by_name (this, &Circuit::begin_subcircuits, &Circuit::end_subcircuits), - m_net_by_name (this, &Circuit::begin_nets, &Circuit::end_nets), - m_index (0) -{ - operator= (other); - m_devices.changed ().add (this, &Circuit::devices_changed); - m_nets.changed ().add (this, &Circuit::nets_changed); - m_subcircuits.changed ().add (this, &Circuit::subcircuits_changed); -} - -Circuit::~Circuit () -{ - m_devices.changed ().remove (this, &Circuit::devices_changed); - m_nets.changed ().remove (this, &Circuit::nets_changed); - m_subcircuits.changed ().remove (this, &Circuit::subcircuits_changed); - - // the default destructor will make the nets access "this" to unregister the - // objects - hence we have to do this explicitly. - m_nets.clear (); - m_subcircuits.clear (); - m_devices.clear (); -} - -Circuit &Circuit::operator= (const Circuit &other) -{ - if (this != &other) { - - clear (); - - m_name = other.m_name; - m_pins = other.m_pins; - - std::map device_table; - for (const_device_iterator i = other.begin_devices (); i != other.end_devices (); ++i) { - Device *d = new Device (*i); - device_table [i.operator-> ()] = d; - add_device (d); - } - - std::map sc_table; - for (const_subcircuit_iterator i = other.begin_subcircuits (); i != other.end_subcircuits (); ++i) { - SubCircuit *sc = new SubCircuit (*i); - sc_table [i.operator-> ()] = sc; - add_subcircuit (sc); - } - - for (const_net_iterator i = other.begin_nets (); i != other.end_nets (); ++i) { - - // 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_terminal_iterator p = i->begin_terminals (); p != i->end_terminals (); ++p) { - std::map::const_iterator m = device_table.find (p->device ()); - tl_assert (m != device_table.end ()); - n->add_terminal (NetTerminalRef (m->second, p->terminal_id ())); - } - - for (Net::const_pin_iterator p = i->begin_pins (); p != i->end_pins (); ++p) { - n->add_pin (NetPinRef (p->pin_id ())); - } - - for (Net::const_subcircuit_pin_iterator p = i->begin_subcircuit_pins (); p != i->end_subcircuit_pins (); ++p) { - std::map::const_iterator m = sc_table.find (p->subcircuit ()); - tl_assert (m != sc_table.end ()); - n->add_subcircuit_pin (NetSubcircuitPinRef (m->second, p->pin_id ())); - } - - } - - } - - return *this; -} - -void Circuit::set_netlist (Netlist *netlist) -{ - mp_netlist = netlist; -} - -const Pin *Circuit::pin_by_id (size_t id) const -{ - if (id >= m_pins.size ()) { - return 0; - } else { - return &m_pins [id]; - } -} - -const Pin *Circuit::pin_by_name (const std::string &name) const -{ - for (Circuit::const_pin_iterator p = begin_pins (); p != end_pins (); ++p) { - if (p->name () == name) { - return p.operator-> (); - } - } - return 0; -} - -void Circuit::devices_changed () -{ - m_device_by_id.invalidate (); - m_device_by_name.invalidate (); -} - -void Circuit::subcircuits_changed () -{ - m_subcircuit_by_id.invalidate (); - m_subcircuit_by_name.invalidate (); - - if (mp_netlist) { - mp_netlist->invalidate_topology (); - } -} - -void Circuit::nets_changed () -{ - m_net_by_cluster_id.invalidate (); - m_net_by_name.invalidate (); -} - -void Circuit::clear () -{ - m_name.clear (); - m_pins.clear (); - m_devices.clear (); - m_nets.clear (); - m_subcircuits.clear (); -} - -void Circuit::set_name (const std::string &name) -{ - m_name = name; - if (mp_netlist) { - mp_netlist->m_circuit_by_name.invalidate (); - } -} - -void Circuit::set_cell_index (const db::cell_index_type ci) -{ - m_cell_index = ci; - if (mp_netlist) { - mp_netlist->m_circuit_by_cell_index.invalidate (); - } -} - -Circuit::child_circuit_iterator Circuit::begin_children () -{ - tl_assert (mp_netlist != 0); - return mp_netlist->child_circuits (this).begin (); -} - -Circuit::child_circuit_iterator Circuit::end_children () -{ - tl_assert (mp_netlist != 0); - return mp_netlist->child_circuits (this).end (); -} - -Circuit::const_child_circuit_iterator Circuit::begin_children () const -{ - tl_assert (mp_netlist != 0); - return reinterpret_cast &> (mp_netlist->child_circuits (const_cast (this))).begin (); -} - -Circuit::const_child_circuit_iterator Circuit::end_children () const -{ - tl_assert (mp_netlist != 0); - return reinterpret_cast &> (mp_netlist->child_circuits (const_cast (this))).end (); -} - -Circuit::child_circuit_iterator Circuit::begin_parents () -{ - tl_assert (mp_netlist != 0); - return mp_netlist->parent_circuits (this).begin (); -} - -Circuit::child_circuit_iterator Circuit::end_parents () -{ - tl_assert (mp_netlist != 0); - return mp_netlist->parent_circuits (this).end (); -} - -Circuit::const_child_circuit_iterator Circuit::begin_parents () const -{ - tl_assert (mp_netlist != 0); - return reinterpret_cast &> (mp_netlist->parent_circuits (const_cast (this))).begin (); -} - -Circuit::const_child_circuit_iterator Circuit::end_parents () const -{ - tl_assert (mp_netlist != 0); - return reinterpret_cast &> (mp_netlist->parent_circuits (const_cast (this))).end (); -} - -const Pin &Circuit::add_pin (const std::string &name) -{ - m_pins.push_back (Pin (name)); - m_pins.back ().set_id (m_pins.size () - 1); - return m_pins.back (); -} - -void Circuit::add_net (Net *net) -{ - m_nets.push_back (net); - net->set_circuit (this); -} - -void Circuit::remove_net (Net *net) -{ - m_nets.erase (net); -} - -void Circuit::add_device (Device *device) -{ - device->set_circuit (this); - - size_t id = 0; - if (! m_devices.empty ()) { - tl_assert (m_devices.back () != 0); - id = m_devices.back ()->id (); - } - device->set_id (id + 1); - - m_devices.push_back (device); -} - -void Circuit::remove_device (Device *device) -{ - m_devices.erase (device); -} - -void Circuit::add_subcircuit (SubCircuit *subcircuit) -{ - subcircuit->set_circuit (this); - - size_t id = 0; - if (! m_subcircuits.empty ()) { - tl_assert (m_subcircuits.back () != 0); - id = m_subcircuits.back ()->id (); - } - subcircuit->set_id (id + 1); - - m_subcircuits.push_back (subcircuit); -} - -void Circuit::remove_subcircuit (SubCircuit *subcircuit) -{ - m_subcircuits.erase (subcircuit); -} - -void Circuit::register_ref (SubCircuit *r) -{ - m_refs.push_back (r); -} - -void Circuit::unregister_ref (SubCircuit *r) -{ - m_refs.erase (r); -} - -void Circuit::translate_circuits (const std::map &map) -{ - for (subcircuit_iterator i = m_subcircuits.begin (); i != m_subcircuits.end (); ++i) { - std::map::const_iterator m = map.find (i->circuit_ref ()); - tl_assert (m != map.end ()); - i->set_circuit_ref (m->second); - } -} - -void Circuit::translate_device_classes (const std::map &map) -{ - for (device_iterator i = m_devices.begin (); i != m_devices.end (); ++i) { - std::map::const_iterator m = map.find (i->device_class ()); - tl_assert (m != map.end ()); - i->set_device_class (m->second); - } -} - -void Circuit::set_pin_ref_for_pin (size_t pin_id, Net::pin_iterator iter) -{ - 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 *Circuit::net_for_pin (size_t pin_id) const -{ - 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 Circuit::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 (pin_id)); - } -} - -void Circuit::purge_nets () -{ - std::vector nets_to_be_purged; - for (net_iterator n = begin_nets (); n != end_nets (); ++n) { - if (n->is_floating ()) { - nets_to_be_purged.push_back (n.operator-> ()); - } - } - for (std::vector::const_iterator n = nets_to_be_purged.begin (); n != nets_to_be_purged.end (); ++n) { - delete *n; - } -} - -/** - * @brief Sanity check for device to be removed - */ -static void check_device_before_remove (db::Circuit *c, const db::Device *d) -{ - if (d->device_class () == 0) { - throw tl::Exception (tl::to_string (tr ("Internal error: No device class after removing device in device combination")) + ": name=" + d->name () + ", circuit=" + c->name ()); - } - const std::vector &pd = d->device_class ()->terminal_definitions (); - for (std::vector::const_iterator p = pd.begin (); p != pd.end (); ++p) { - if (d->net_for_terminal (p->id ()) != 0) { - throw tl::Exception (tl::to_string (tr ("Internal error: Terminal still connected after removing device in device combination")) + ": name=" + d->name () + ", circuit=" + c->name () + ", terminal=" + p->name ()); - } - } -} - -bool Circuit::combine_parallel_devices (const db::DeviceClass &cls) -{ - typedef std::vector key_type; - std::map > combination_candidates; - - bool any = false; - - // identify the candidates for combination - all devices sharing the same nets - // are candidates for combination in parallel mode - for (device_iterator d = begin_devices (); d != end_devices (); ++d) { - - if (tl::id_of (d->device_class ()) != tl::id_of (&cls)) { - continue; - } - - key_type k; - const std::vector &terminals = cls.terminal_definitions (); - for (std::vector::const_iterator p = terminals.begin (); p != terminals.end (); ++p) { - const db::Net *n = d->net_for_terminal (p->id ()); - if (n) { - k.push_back (n); - } - } - - std::sort (k.begin (), k.end ()); - k.erase (std::unique (k.begin (), k.end ()), k.end ()); - combination_candidates[k].push_back (d.operator-> ()); - - } - - // actually combine the devices - for (std::map >::iterator cc = combination_candidates.begin (); cc != combination_candidates.end (); ++cc) { - - std::vector &cl = cc->second; - for (size_t i = 0; i < cl.size () - 1; ++i) { - for (size_t j = i + 1; j < cl.size (); ) { - if (cls.combine_devices (cl [i], cl [j])) { - check_device_before_remove (this, cl [j]); // sanity check - delete cl [j]; - cl.erase (cl.begin () + j); - any = true; - } else { - ++j; - } - } - } - - } - - return any; -} - -static std::pair attached_two_devices (db::Net &net, const db::DeviceClass &cls) -{ - if (net.begin_pins () != net.end_pins ()) { - return std::make_pair ((db::Device *) 0, (db::Device *) 0); - } - - db::Device *d1 = 0, *d2 = 0; - - Net::terminal_iterator p = net.begin_terminals (); - if (p == net.end_terminals () || tl::id_of (p->device_class ()) != tl::id_of (&cls)) { - return std::make_pair ((db::Device *) 0, (db::Device *) 0); - } else { - d1 = p->device (); - } - - ++p; - if (p == net.end_terminals () || tl::id_of (p->device_class ()) != tl::id_of (&cls)) { - return std::make_pair ((db::Device *) 0, (db::Device *) 0); - } else { - d2 = p->device (); - } - - ++p; - if (p != net.end_terminals () || d1 == d2 || !d1 || !d2) { - return std::make_pair ((db::Device *) 0, (db::Device *) 0); - } else { - return std::make_pair (d1, d2); - } -} - -template -static bool same_or_swapped (const std::pair &p1, const std::pair &p2) -{ - return (p1.first == p2.first && p1.second == p2.second) || (p1.first == p2.second && p1.second == p2.first); -} - -bool Circuit::combine_serial_devices(const db::DeviceClass &cls) -{ - bool any = false; - - for (net_iterator n = begin_nets (); n != end_nets (); ++n) { - - std::pair dd = attached_two_devices (*n, cls); - if (! dd.first) { - continue; - } - - // The net is an internal node: the devices attached to this internal node are - // combination candidates if the number of nets emerging from the attached device pair (not counting - // the internal node we just found) does not exceed the number of pins available for the - // new device. - - std::vector other_nets; - - const std::vector &terminals = cls.terminal_definitions (); - for (std::vector::const_iterator p = terminals.begin (); p != terminals.end (); ++p) { - db::Net *on; - on = dd.first->net_for_terminal (p->id ()); - if (on && ! same_or_swapped (dd, attached_two_devices (*on, cls))) { - other_nets.push_back (on); - } - on = dd.second->net_for_terminal (p->id ()); - if (on && ! same_or_swapped (dd, attached_two_devices (*on, cls))) { - other_nets.push_back (on); - } - } - - std::sort (other_nets.begin (), other_nets.end ()); - other_nets.erase (std::unique (other_nets.begin (), other_nets.end ()), other_nets.end ()); - - if (other_nets.size () <= cls.terminal_definitions().size ()) { - - // found a combination candidate - if (cls.combine_devices (dd.first, dd.second)) { - check_device_before_remove (this, dd.second); // sanity check - delete dd.second; - any = true; - } - - } - - } - - return any; -} - -void Circuit::combine_devices () -{ - tl_assert (netlist () != 0); - - for (Netlist::device_class_iterator dc = netlist ()->begin_device_classes (); dc != netlist ()->end_device_classes (); ++dc) { - - // repeat the combination step unless no combination happens - this is required to take care of combinations that arise after - // other combinations have been realized. - bool any = true; - while (any) { - - any = false; - - if (dc->supports_parallel_combination ()) { - if (combine_parallel_devices (*dc)) { - any = true; - } - } - if (dc->supports_serial_combination ()) { - if (combine_serial_devices (*dc)) { - any = true; - } - } - - } - - } -} - -// -------------------------------------------------------------------------------- -// DeviceClass class implementation - -DeviceClass::DeviceClass () - : mp_netlist (0) -{ - // .. nothing yet .. -} - -DeviceClass::DeviceClass (const DeviceClass &other) - : mp_netlist (0) -{ - operator= (other); -} - -DeviceClass &DeviceClass::operator= (const DeviceClass &other) -{ - if (this != &other) { - m_terminal_definitions = other.m_terminal_definitions; - m_name = other.m_name; - m_description = other.m_description; - } - return *this; -} - -const DeviceTerminalDefinition &DeviceClass::add_terminal_definition (const DeviceTerminalDefinition &pd) -{ - m_terminal_definitions.push_back (pd); - m_terminal_definitions.back ().set_id (m_terminal_definitions.size () - 1); - return m_terminal_definitions.back (); -} - -void DeviceClass::clear_terminal_definitions () -{ - m_terminal_definitions.clear (); -} - -const DeviceTerminalDefinition *DeviceClass::terminal_definition (size_t id) const -{ - if (id < m_terminal_definitions.size ()) { - return & m_terminal_definitions [id]; - } else { - return 0; - } -} - -const DeviceParameterDefinition &DeviceClass::add_parameter_definition (const DeviceParameterDefinition &pd) -{ - m_parameter_definitions.push_back (pd); - m_parameter_definitions.back ().set_id (m_parameter_definitions.size () - 1); - return m_parameter_definitions.back (); -} - -void DeviceClass::clear_parameter_definitions () -{ - m_parameter_definitions.clear (); -} - -const DeviceParameterDefinition *DeviceClass::parameter_definition (size_t id) const -{ - if (id < m_parameter_definitions.size ()) { - return & m_parameter_definitions [id]; - } else { - return 0; - } -} - -bool DeviceClass::has_parameter_with_name (const std::string &name) const -{ - const std::vector &pd = parameter_definitions (); - for (std::vector::const_iterator i = pd.begin (); i != pd.end (); ++i) { - if (i->name () == name) { - return true; - } - } - return false; -} - -size_t DeviceClass::parameter_id_for_name (const std::string &name) const -{ - const std::vector &pd = parameter_definitions (); - for (std::vector::const_iterator i = pd.begin (); i != pd.end (); ++i) { - if (i->name () == name) { - return i->id (); - } - } - throw tl::Exception (tl::to_string (tr ("Invalid parameter name")) + ": '" + name + "'"); -} - -bool DeviceClass::has_terminal_with_name (const std::string &name) const -{ - const std::vector &td = terminal_definitions (); - for (std::vector::const_iterator i = td.begin (); i != td.end (); ++i) { - if (i->name () == name) { - return true; - } - } - return false; -} - -size_t DeviceClass::terminal_id_for_name (const std::string &name) const -{ - const std::vector &td = terminal_definitions (); - for (std::vector::const_iterator i = td.begin (); i != td.end (); ++i) { - if (i->name () == name) { - return i->id (); - } - } - throw tl::Exception (tl::to_string (tr ("Invalid terminal name")) + ": '" + name + "'"); -} - // -------------------------------------------------------------------------------- // Netlist class implementation diff --git a/src/db/db/dbNetlist.h b/src/db/db/dbNetlist.h index c944f325a..36dc2676c 100644 --- a/src/db/db/dbNetlist.h +++ b/src/db/db/dbNetlist.h @@ -24,2092 +24,16 @@ #define _HDR_dbNetlist #include "dbCommon.h" -#include "dbTypes.h" -#include "dbTrans.h" -#include "tlObjectCollection.h" +#include "dbCircuit.h" +#include "dbDeviceClass.h" + #include "tlVector.h" -#include "tlUniqueId.h" -#include "gsiObject.h" -#include -#include #include - namespace db { -class Circuit; -class SubCircuit; -class Pin; -class Device; -class DeviceClass; -class DeviceTerminalDefinition; -class Netlist; -class Net; - -/** - * @brief A getter for the ID of an object - */ -template -struct id_attribute -{ - typedef size_t attr_type; - size_t operator() (const T *t) const { return t->id (); } - bool has (const T * /*t*/) const { return true; } -}; - -/** - * @brief A getter for the cluster ID of an object - */ -template -struct cluster_id_attribute -{ - typedef size_t attr_type; - attr_type operator() (const T *t) const { return t->cluster_id (); } - bool has (const T * /*t*/) const { return true; } -}; - -/** - * @brief A getter for the cluster ID of an object - */ -template -struct cell_index_attribute -{ - typedef db::cell_index_type attr_type; - attr_type operator() (const T *t) const { return t->cell_index (); } - bool has (const T * /*t*/) const { return true; } -}; - -/** - * @brief A getter for the name of an object - */ -template -struct name_attribute -{ - typedef std::string attr_type; - const attr_type &operator() (const T *t) const { return t->name (); } - bool has (const T *t) const { return ! t->name ().empty (); } -}; - -/** - * @brief An id-to-object translation table - */ -template -class object_by_attr -{ -public: - typedef typename ATTR::attr_type attr_type; - typedef typename I::value_type value_type; - - object_by_attr (T *self, I (T::*bi) (), I (T::*ei) ()) : mp_self (self), m_bi (bi), m_ei (ei), m_valid (false) - { - // .. nothing yet .. - } - - void invalidate () - { - m_valid = false; - m_map.clear (); - } - - value_type *object_by (const attr_type &attr) const - { - if (! m_valid) { - validate (); - } - typename std::map::const_iterator m = m_map.find (attr); - return m == m_map.end () ? 0 : m->second; - } - -private: - T *mp_self; - I (T::*m_bi) (); - I (T::*m_ei) (); - mutable bool m_valid; - mutable std::map m_map; - - void validate () const - { - ATTR attr; - m_map.clear (); - for (I i = (mp_self->*m_bi) (); i != (mp_self->*m_ei) (); ++i) { - if (attr.has (i.operator-> ())) { - m_map.insert (std::make_pair (attr (i.operator-> ()), i.operator-> ())); - } - } - m_valid = true; - } -}; - -/** - * @brief A reference to a terminal of a device - * - * A terminal must always refer to a device inside the current circuit. - */ -class DB_PUBLIC NetTerminalRef -{ -public: - /** - * @brief Default constructor - */ - NetTerminalRef (); - - /** - * @brief Creates a pin reference to the given pin of the current circuit - */ - NetTerminalRef (Device *device, size_t terminal_id); - - /** - * @brief Copy constructor - */ - NetTerminalRef (const NetTerminalRef &other); - - /** - * @brief Assignment - */ - NetTerminalRef &operator= (const NetTerminalRef &other); - - /** - * @brief Comparison - */ - bool operator< (const NetTerminalRef &other) const - { - if (mp_device != other.mp_device) { - return mp_device < other.mp_device; - } - return m_terminal_id < other.m_terminal_id; - } - - /** - * @brief Equality - */ - bool operator== (const NetTerminalRef &other) const - { - return (mp_device == other.mp_device && m_terminal_id == other.m_terminal_id); - } - - /** - * @brief Gets the device reference - */ - Device *device () - { - return mp_device; - } - - /** - * @brief Gets the device reference (const version) - */ - const Device *device () const - { - return mp_device; - } - - /** - * @brief Gets the terminal index - */ - size_t terminal_id () const - { - return m_terminal_id; - } - - /** - * @brief Gets the terminal definition - * - * Returns 0 if the terminal is not a valid terminal reference. - */ - const DeviceTerminalDefinition *terminal_def () const; - - /** - * @brief Returns the device class - */ - const DeviceClass *device_class () const; - - /** - * @brief Gets the net the terminal lives in - */ - Net *net () - { - return mp_net; - } - - /** - * @brief Gets the net the terminal lives in (const version) - */ - const Net *net () const - { - return mp_net; - } - -private: - friend class Net; - - size_t m_terminal_id; - Device *mp_device; - Net *mp_net; - - /** - * @brief Sets the net the terminal lives in - */ - void set_net (Net *net) - { - mp_net = net; - } -}; - -/** - * @brief A reference to a pin inside a net - * - * This object describes a connection to an outgoing pin. - */ -class DB_PUBLIC NetPinRef -{ -public: - /** - * @brief Default constructor - */ - NetPinRef (); - - /** - * @brief Creates a pin reference to the given pin of the current circuit - */ - NetPinRef (size_t pin_id); - - /** - * @brief Copy constructor - */ - NetPinRef (const NetPinRef &other); - - /** - * @brief Assignment - */ - NetPinRef &operator= (const NetPinRef &other); - - /** - * @brief Comparison - */ - bool operator< (const NetPinRef &other) const - { - return m_pin_id < other.m_pin_id; - } - - /** - * @brief Equality - */ - bool operator== (const NetPinRef &other) const - { - return (m_pin_id == other.m_pin_id); - } - - /** - * @brief Gets the pin reference (const version) - */ - size_t pin_id () const - { - return m_pin_id; - } - - /** - * @brief Gets the pin reference from the pin id - * If the pin cannot be resolved, null is returned. - */ - const Pin *pin () const; - - /** - * @brief Gets the net the pin lives in - */ - Net *net () - { - 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; - Net *mp_net; - - /** - * @brief Sets the net the terminal lives in - */ - void set_net (Net *net) - { - mp_net = net; - } -}; - -/** - * @brief A reference to a pin inside a net - * - * This object describes a connection to a pin of a subcircuit. - */ -class DB_PUBLIC NetSubcircuitPinRef -{ -public: - /** - * @brief Default constructor - */ - NetSubcircuitPinRef (); - - /** - * @brief Creates a pin reference to the given pin of the given subcircuit - */ - NetSubcircuitPinRef (SubCircuit *circuit, size_t pin_id); - - /** - * @brief Copy constructor - */ - NetSubcircuitPinRef (const NetSubcircuitPinRef &other); - - /** - * @brief Assignment - */ - NetSubcircuitPinRef &operator= (const NetSubcircuitPinRef &other); - - /** - * @brief Comparison - */ - bool operator< (const NetSubcircuitPinRef &other) const - { - if (mp_subcircuit != other.mp_subcircuit) { - return mp_subcircuit < other.mp_subcircuit; - } - return m_pin_id < other.m_pin_id; - } - - /** - * @brief Equality - */ - bool operator== (const NetSubcircuitPinRef &other) const - { - return (mp_subcircuit == other.mp_subcircuit && m_pin_id == other.m_pin_id); - } - - /** - * @brief Gets the pin reference (const version) - */ - size_t pin_id () const - { - return m_pin_id; - } - - /** - * @brief Gets the pin reference from the pin id - * If the pin cannot be resolved, null is returned. - */ - const Pin *pin () const; - - /** - * @brief Gets the subcircuit reference - */ - SubCircuit *subcircuit () - { - return mp_subcircuit; - } - - /** - * @brief Gets the subcircuit reference (const version) - */ - const SubCircuit *subcircuit () const - { - return mp_subcircuit; - } - - /** - * @brief Gets the net the pin lives in - */ - Net *net () - { - 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; - SubCircuit *mp_subcircuit; - Net *mp_net; - - /** - * @brief Sets the net the terminal lives in - */ - void set_net (Net *net) - { - mp_net = net; - } -}; - -/** - * @brief A net - * - * A net connects terminals of devices and pins or circuits - */ -class DB_PUBLIC Net - : public tl::Object -{ -public: - typedef std::list terminal_list; - typedef terminal_list::const_iterator const_terminal_iterator; - typedef terminal_list::iterator terminal_iterator; - typedef std::list pin_list; - typedef pin_list::const_iterator const_pin_iterator; - typedef pin_list::iterator pin_iterator; - typedef std::list subcircuit_pin_list; - typedef subcircuit_pin_list::const_iterator const_subcircuit_pin_iterator; - typedef subcircuit_pin_list::iterator subcircuit_pin_iterator; - - /** - * @brief Constructor - * Creates an empty circuit. - */ - Net (); - - /** - * @brief Creates a empty net with the give name - */ - Net (const std::string &name); - - /** - * @brief Copy constructor - */ - Net (const Net &other); - - /** - * @brief Destructor - */ - ~Net (); - - /** - * @brief Assignment - */ - Net &operator= (const Net &other); - - /** - * @brief Gets the circuit the net lives in - * This pointer is 0 if the net is not part of a circuit. - */ - Circuit *circuit () - { - return mp_circuit; - } - - /** - * @brief Gets the circuit the net lives in (const version) - * This pointer is 0 if the net is not part of a circuit. - */ - const Circuit *circuit () const - { - return mp_circuit; - } - - /** - * @brief Clears the circuit - */ - void clear (); - - /** - * @brief Sets the name of the circuit - */ - void set_name (const std::string &name); - - /** - * @brief Gets the name of the circuit - */ - const std::string &name () const - { - return m_name; - } - - /** - * @brief Gets the expanded name - * - * The "expanded name" is a non-empty name for the net. It uses the - * cluster ID if no name is set. - */ - std::string expanded_name () const; - - /** - * @brief Gets the qualified name - * - * The qualified name is like the expanded name, but preceeded with the - * Circuit name if known (e.g. "CIRCUIT:NET") - */ - std::string qname () const; - - /** - * @brief Sets the cluster ID of this net - * - * The cluster ID links the net to a cluster from the - * hierarchical layout netlist extractor. - */ - void set_cluster_id (size_t ci); - - /** - * @brief Gets the cluster ID - */ - size_t cluster_id () const - { - return m_cluster_id; - } - - /** - * @brief Adds a pin to this net - */ - 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) - */ - const_pin_iterator begin_pins () const - { - return m_pins.begin (); - } - - /** - * @brief End iterator for the pins of the net (const version) - */ - const_pin_iterator end_pins () const - { - 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 subcircuit pin to this net - */ - void add_subcircuit_pin (const NetSubcircuitPinRef &pin); - - /** - * @brief Erases the given subcircuit pin from this net - */ - void erase_subcircuit_pin (subcircuit_pin_iterator iter); - - /** - * @brief Begin iterator for the pins of the net (const version) - */ - const_subcircuit_pin_iterator begin_subcircuit_pins () const - { - return m_subcircuit_pins.begin (); - } - - /** - * @brief End iterator for the pins of the net (const version) - */ - const_subcircuit_pin_iterator end_subcircuit_pins () const - { - return m_subcircuit_pins.end (); - } - - /** - * @brief Begin iterator for the pins of the net (non-const version) - */ - subcircuit_pin_iterator begin_subcircuit_pins () - { - return m_subcircuit_pins.begin (); - } - - /** - * @brief End iterator for the pins of the net (non-const version) - */ - subcircuit_pin_iterator end_subcircuit_pins () - { - return m_subcircuit_pins.end (); - } - - /** - * @brief Adds a terminal to this net - */ - void add_terminal (const NetTerminalRef &terminal); - - /** - * @brief Erases the given terminal from this net - */ - void erase_terminal (terminal_iterator iter); - - /** - * @brief Begin iterator for the terminals of the net (const version) - */ - const_terminal_iterator begin_terminals () const - { - return m_terminals.begin (); - } - - /** - * @brief End iterator for the terminals of the net (const version) - */ - const_terminal_iterator end_terminals () const - { - return m_terminals.end (); - } - - /** - * @brief Begin iterator for the terminals of the net (non-const version) - */ - terminal_iterator begin_terminals () - { - return m_terminals.begin (); - } - - /** - * @brief End iterator for the terminals of the net (non-const version) - */ - terminal_iterator end_terminals () - { - return m_terminals.end (); - } - - /** - * @brief Returns true, if the net is floating (has no or only a single connection) - */ - bool is_floating () const - { - return (m_pins.size () + m_subcircuit_pins.size () + m_terminals.size ()) < 2; - } - - /** - * @brief Returns true, if the net is an internal node (connects two terminals only) - */ - bool is_internal () const - { - return m_pins.size () == 0 && m_subcircuit_pins.size () == 0 && m_terminals.size () == 2; - } - - /** - * @brief Returns the number of outgoing pins connected - */ - size_t pin_count () const - { - return m_pins.size (); - } - - /** - * @brief Returns the number of subcircuit pins connected - */ - size_t subcircuit_pin_count () const - { - return m_subcircuit_pins.size (); - } - - /** - * @brief Returns the number of terminals connected - */ - size_t terminal_count () const - { - return m_terminals.size (); - } - -private: - friend class Circuit; - - terminal_list m_terminals; - pin_list m_pins; - subcircuit_pin_list m_subcircuit_pins; - std::string m_name; - size_t m_cluster_id; - Circuit *mp_circuit; - - 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; - - 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 std::vector > global_connections; - typedef global_connections::const_iterator global_connections_iterator; - - /** - * @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 mp_device_class; - } - - /** - * @brief Gets the device ID - * The ID is a unique integer which identifies the device. - * It can be used to retrieve the device from the circuit using Circuit::device_by_id. - * When assigned, the device ID is not 0. - */ - size_t id () const - { - return m_id; - } - - /** - * @brief Gets the circuit the device lives in (const version) - * This pointer is 0 if the device isn't added to a circuit - */ - const Circuit *circuit () const - { - return mp_circuit; - } - - /** - * @brief Gets the circuit the device lives in (non-const version) - * This pointer is 0 if the device isn't added to a circuit - */ - Circuit *circuit () - { - return mp_circuit; - } - - /** - * @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 terminal - * Returns 0 if no net is attached. - */ - const Net *net_for_terminal (size_t terminal_id) const; - - /** - * @brief Gets the net attached to a specific terminal (non-const version) - * Returns 0 if no net is attached. - */ - Net *net_for_terminal (size_t terminal_id) - { - return const_cast (((const Device *) this)->net_for_terminal (terminal_id)); - } - - /** - * @brief Connects the given terminal to the given net - * If the net is 0 the terminal is disconnected. - * If non-null, a NetTerminalRef object will be inserted into the - * net and connected with the given terminal. - * If the terminal is connected to a global net, it will be - * disconnected from there. - */ - void connect_terminal (size_t terminal_id, Net *net); - - /** - * @brief Gets the value for the parameter with the given ID - */ - double parameter_value (size_t param_id) const; - - /** - * @brief Sets the value for the parameter with the given ID - */ - void set_parameter_value (size_t param_id, double v); - - /** - * @brief Gets the value for the parameter with the given name - * If the name is not valid, an exception is thrown. - */ - double parameter_value (const std::string &name) const; - - /** - * @brief Sets the value for the parameter with the given name - * If the name is not valid, an exception is thrown. - */ - void set_parameter_value (const std::string &name, double v); - -private: - friend class Circuit; - friend class Net; - - DeviceClass *mp_device_class; - std::string m_name; - std::vector m_terminal_refs; - std::vector m_parameters; - size_t m_id; - Circuit *mp_circuit; - - /** - * @brief Sets the terminal reference for a specific terminal - */ - void set_terminal_ref_for_terminal (size_t terminal_id, Net::terminal_iterator iter); - - /** - * @brief Sets the device class - */ - void set_device_class (DeviceClass *dc) - { - mp_device_class = dc; - } - - /** - * @brief Sets the device ID - */ - void set_id (size_t id) - { - m_id = id; - } - - /** - * @brief Sets the circuit - */ - void set_circuit (Circuit *circuit); -}; - -/** - * @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_ref, const std::string &name = std::string ()); - - /** - * @brief Destructor - */ - ~SubCircuit (); - - /** - * @brief Gets the subcircuit ID - * The ID is a unique integer which identifies the subcircuit. - * It can be used to retrieve the subcircuit from the circuit using Circuit::subcircuit_by_id. - * When assigned, the subcircuit ID is not 0. - */ - size_t id () const - { - return m_id; - } - - /** - * @brief Gets the circuit the subcircuit lives in (const version) - * This pointer is 0 if the subcircuit isn't added to a circuit - */ - const Circuit *circuit () const - { - return mp_circuit; - } - - /** - * @brief Gets the circuit the subcircuit lives in (non-const version) - * This pointer is 0 if the subcircuit isn't added to a circuit - */ - Circuit *circuit () - { - return mp_circuit; - } - - /** - * @brief Gets the circuit the reference points to (const version) - */ - const Circuit *circuit_ref () const - { - return m_circuit_ref.get (); - } - - /** - * @brief Gets the circuit the reference points to (non-const version) - */ - Circuit *circuit_ref () - { - return m_circuit_ref.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_ref; - std::string m_name; - db::DCplxTrans m_trans; - std::vector m_pin_refs; - size_t m_id; - Circuit *mp_circuit; - - /** - * @brief Sets the pin reference for a specific pin - */ - void set_pin_ref_for_pin (size_t ppin_id, Net::subcircuit_pin_iterator iter); - - /** - * @brief Sets the circuit reference - */ - void set_circuit_ref (Circuit *c); - - /** - * @brief Sets the circuit the subcircuit belongs to - */ - void set_circuit (Circuit *c) - { - mp_circuit = c; - } - - /** - * @brief Sets the device ID - */ - void set_id (size_t id) - { - m_id = id; - } -}; - -/** - * @brief A circuit - * - * A circuit is a list of nets, of subcircuit references and actual - * devices. - */ -class DB_PUBLIC Circuit - : public gsi::ObjectBase, public tl::Object -{ -public: - typedef tl::vector pin_list; - typedef pin_list::const_iterator const_pin_iterator; - typedef pin_list::iterator pin_iterator; - typedef tl::shared_collection device_list; - typedef device_list::const_iterator const_device_iterator; - typedef device_list::iterator device_iterator; - typedef tl::shared_collection net_list; - typedef net_list::const_iterator const_net_iterator; - typedef net_list::iterator net_iterator; - typedef tl::shared_collection subcircuit_list; - typedef subcircuit_list::const_iterator const_subcircuit_iterator; - typedef subcircuit_list::iterator subcircuit_iterator; - typedef tl::weak_collection::const_iterator const_refs_iterator; - typedef tl::weak_collection::iterator refs_iterator; - typedef tl::vector::const_iterator child_circuit_iterator; - typedef tl::vector::const_iterator const_child_circuit_iterator; - typedef tl::vector::const_iterator parent_circuit_iterator; - typedef tl::vector::const_iterator const_parent_circuit_iterator; - - /** - * @brief Constructor - * - * Creates an empty circuit. - */ - Circuit (); - - /** - * @brief Copy constructor - */ - Circuit (const Circuit &other); - - /** - * @brief Destructor - */ - ~Circuit (); - - /** - * @brief Assignment - */ - Circuit &operator= (const Circuit &other); - - /** - * @brief Gets the netlist the circuit lives in - * This pointer is 0 if the circuit is not part of a netlist. - */ - Netlist *netlist () - { - return mp_netlist; - } - - /** - * @brief Gets the netlist the circuit lives in (const version) - * This pointer is 0 if the circuit is not part of a netlist. - */ - const Netlist *netlist () const - { - return mp_netlist; - } - - /** - * @brief Clears the circuit - */ - void clear (); - - /** - * @brief Sets the name of the circuit - */ - void set_name (const std::string &name); - - /** - * @brief Gets the name of the circuit - */ - const std::string &name () const - { - return m_name; - } - - /** - * @brief The index of the circuit in the netlist - * CAUTION: this attribute is used for internal purposes and may not be valid always. - */ - size_t index () const - { - return m_index; - } - - /** - * @brief Sets the layout cell reference for this circuit - * - * The layout cell reference links a circuit to a layout cell. - */ - void set_cell_index (const db::cell_index_type ci); - - /** - * @brief Gets the layout cell index - */ - db::cell_index_type cell_index () const - { - return m_cell_index; - } - - /** - * @brief Gets the references to this circuit (begin, non-const version) - * This iterator will deliver all subcircuits referencing this circuit - */ - refs_iterator begin_refs () - { - return m_refs.begin (); - } - - /** - * @brief Gets the references to this circuit (end, non-const version) - * This iterator will deliver all subcircuits referencing this circuit - */ - refs_iterator end_refs () - { - return m_refs.end (); - } - - /** - * @brief Gets the references to this circuit (begin, const version) - * This iterator will deliver all subcircuits referencing this circuit - */ - const_refs_iterator begin_refs () const - { - return m_refs.begin (); - } - - /** - * @brief Gets the child circuits iterator (begin) - * The child circuits are the circuits referenced by all subcircuits - * in the circuit. - */ - child_circuit_iterator begin_children (); - - /** - * @brief Gets the child circuits iterator (end) - */ - child_circuit_iterator end_children (); - - /** - * @brief Gets the child circuits iterator (begin, const version) - * The child circuits are the circuits referenced by all subcircuits - * in the circuit. - */ - const_child_circuit_iterator begin_children () const; - - /** - * @brief Gets the child circuits iterator (end, const version) - */ - const_child_circuit_iterator end_children () const; - - /** - * @brief Gets the parent circuits iterator (begin) - * The parents circuits are the circuits referencing this circuit via subcircuits. - */ - parent_circuit_iterator begin_parents (); - - /** - * @brief Gets the parent circuits iterator (end) - */ - parent_circuit_iterator end_parents (); - - /** - * @brief Gets the parent circuits iterator (begin, const version) - * The parents circuits are the circuits referencing this circuit via subcircuits. - */ - const_parent_circuit_iterator begin_parents () const; - - /** - * @brief Gets the parent circuits iterator (end, const version) - */ - const_parent_circuit_iterator end_parents () const; - - /** - * @brief Gets the references to this circuit (end, const version) - * This iterator will deliver all subcircuits referencing this circuit - */ - const_refs_iterator end_refs () const - { - return m_refs.end (); - } - - /** - * @brief Adds a pin to this circuit - * The circuit takes over ownership of the object. - */ - const Pin &add_pin(const std::string &name); - - /** - * @brief Begin iterator for the pins of the circuit (non-const version) - */ - pin_iterator begin_pins () - { - return m_pins.begin (); - } - - /** - * @brief End iterator for the pins of the circuit (non-const version) - */ - pin_iterator end_pins () - { - 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) - */ - const Pin *pin_by_id (size_t id) const; - - /** - * @brief Gets the pin by name - * - * If there is no pin with that name, null is returned. - * NOTE: this is a linear search, so it's performance may not be good for many pins. - */ - const Pin *pin_by_name (const std::string &name) const; - - /** - * @brief Begin iterator for the pins of the circuit (const version) - */ - const_pin_iterator begin_pins () const - { - return m_pins.begin (); - } - - /** - * @brief End iterator for the pins of the circuit (const version) - */ - const_pin_iterator end_pins () const - { - return m_pins.end (); - } - - /** - * @brief Adds a net to this circuit - * - * The circuit takes over ownership of the object. - */ - void add_net (Net *net); - - /** - * @brief Deletes a net from the circuit - */ - void remove_net (Net *net); - - /** - * @brief Begin iterator for the nets of the circuit (non-const version) - */ - net_iterator begin_nets () - { - return m_nets.begin (); - } - - /** - * @brief End iterator for the nets of the circuit (non-const version) - */ - net_iterator end_nets () - { - return m_nets.end (); - } - - /** - * @brief Begin iterator for the nets of the circuit (const version) - */ - const_net_iterator begin_nets () const - { - return m_nets.begin (); - } - - /** - * @brief End iterator for the nets of the circuit (const version) - */ - const_net_iterator end_nets () const - { - return m_nets.end (); - } - - /** - * @brief Gets the net from a given cluster ID (const version) - * - * If the cluster ID is not valid, null is returned. - */ - const Net *net_by_cluster_id (size_t cluster_id) const - { - return (const_cast (this)->net_by_cluster_id (cluster_id)); - } - - /** - * @brief Gets the net from a given cluster ID (non-const version) - * - * If the cluster ID is not valid, null is returned. - */ - Net *net_by_cluster_id (size_t cluster_id) - { - return m_net_by_cluster_id.object_by (cluster_id); - } - - /** - * @brief Gets the net from a given name (const version) - * - * If the name is not valid, null is returned. - */ - const Net *net_by_name (const std::string &name) const - { - return (const_cast (this)->net_by_name (name)); - } - - /** - * @brief Gets the net from a given name (non-const version) - * - * If the name is not valid, null is returned. - */ - Net *net_by_name (const std::string &name) - { - return m_net_by_name.object_by (name); - } - - /** - * @brief Adds a device to this circuit - * - * The circuit takes over ownership of the object. - */ - void add_device (Device *device); - - /** - * @brief Deletes a device from the circuit - */ - void remove_device (Device *device); - - /** - * @brief Gets the device from a given ID (const version) - * - * If the ID is not valid, null is returned. - */ - const Device *device_by_id (size_t id) const - { - return (const_cast (this)->device_by_id (id)); - } - - /** - * @brief Gets the device from a given ID (non-const version) - * - * If the ID is not valid, null is returned. - */ - Device *device_by_id (size_t id) - { - return m_device_by_id.object_by (id); - } - - /** - * @brief Gets the device from a given name (const version) - * - * If the name is not valid, null is returned. - */ - const Device *device_by_name (const std::string &name) const - { - return (const_cast (this)->device_by_name (name)); - } - - /** - * @brief Gets the device from a given name (non-const version) - * - * If the name is not valid, null is returned. - */ - Device *device_by_name (const std::string &name) - { - return m_device_by_name.object_by (name); - } - - /** - * @brief Begin iterator for the devices of the circuit (non-const version) - */ - device_iterator begin_devices () - { - return m_devices.begin (); - } - - /** - * @brief End iterator for the devices of the circuit (non-const version) - */ - device_iterator end_devices () - { - return m_devices.end (); - } - - /** - * @brief Begin iterator for the devices of the circuit (const version) - */ - const_device_iterator begin_devices () const - { - return m_devices.begin (); - } - - /** - * @brief End iterator for the devices of the circuit (const version) - */ - const_device_iterator end_devices () const - { - return m_devices.end (); - } - - /** - * @brief Adds a subcircuit to this circuit - * - * The circuit takes over ownership of the object. - */ - void add_subcircuit (SubCircuit *subcircuit); - - /** - * @brief Deletes a subcircuit from the circuit - */ - void remove_subcircuit (SubCircuit *subcircuit); - - /** - * @brief Gets the subcircuit from a given ID (const version) - * - * If the ID is not valid, null is returned. - */ - const SubCircuit *subcircuit_by_id (size_t id) const - { - return (const_cast (this)->subcircuit_by_id (id)); - } - - /** - * @brief Gets the subcircuit from a given ID (non-const version) - * - * If the ID is not valid, null is returned. - */ - SubCircuit *subcircuit_by_id (size_t id) - { - return m_subcircuit_by_id.object_by (id); - } - - /** - * @brief Gets the subcircuit from a given name (const version) - * - * If the name is not valid, null is returned. - */ - const SubCircuit *subcircuit_by_name (const std::string &name) const - { - return (const_cast (this)->subcircuit_by_name (name)); - } - - /** - * @brief Gets the subcircuit from a given name (non-const version) - * - * If the name is not valid, null is returned. - */ - SubCircuit *subcircuit_by_name (const std::string &name) - { - return m_subcircuit_by_name.object_by (name); - } - - /** - * @brief Begin iterator for the subcircuits of the circuit (non-const version) - */ - subcircuit_iterator begin_subcircuits () - { - return m_subcircuits.begin (); - } - - /** - * @brief End iterator for the subcircuits of the circuit (non-const version) - */ - subcircuit_iterator end_subcircuits () - { - return m_subcircuits.end (); - } - - /** - * @brief Begin iterator for the subcircuits of the circuit (const version) - */ - const_subcircuit_iterator begin_subcircuits () const - { - return m_subcircuits.begin (); - } - - /** - * @brief End iterator for the subcircuits of the circuit (const version) - */ - const_subcircuit_iterator end_subcircuits () const - { - return m_subcircuits.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 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); - - /** - * @brief Purge unused nets - * - * This method will purge all nets which return "floating". - */ - void purge_nets (); - - /** - * @brief Combine devices - * - * This method will combine devices that can be combined according - * to their device classes "combine_devices" method. - */ - void combine_devices (); - -private: - friend class Netlist; - friend class Net; - friend class SubCircuit; - friend class Device; - - std::string m_name; - db::cell_index_type m_cell_index; - net_list m_nets; - pin_list m_pins; - device_list m_devices; - subcircuit_list m_subcircuits; - Netlist *mp_netlist; - std::vector m_pin_refs; - object_by_attr > m_device_by_id; - object_by_attr > m_subcircuit_by_id; - object_by_attr > m_net_by_cluster_id; - object_by_attr > m_device_by_name; - object_by_attr > m_subcircuit_by_name; - object_by_attr > m_net_by_name; - tl::weak_collection m_refs; - size_t m_index; - - void set_index (size_t index) - { - m_index = index; - } - - void set_pin_ref_for_pin (size_t ppin_id, Net::pin_iterator iter); - - void register_ref (SubCircuit *sc); - void unregister_ref (SubCircuit *sc); - - void translate_circuits (const std::map &map); - void translate_device_classes (const std::map &map); - void set_netlist (Netlist *netlist); - bool combine_parallel_devices (const db::DeviceClass &cls); - bool combine_serial_devices (const db::DeviceClass &cls); - - void devices_changed (); - void subcircuits_changed (); - void nets_changed (); -}; - -/** - * @brief A device terminal definition - */ -class DB_PUBLIC DeviceTerminalDefinition -{ -public: - /** - * @brief Creates an empty device terminal definition - */ - DeviceTerminalDefinition () - : m_name (), m_description (), m_id (0) - { - // .. nothing yet .. - } - - /** - * @brief Creates a device terminal definition with the given name and description - */ - DeviceTerminalDefinition (const std::string &name, const std::string &description) - : m_name (name), m_description (description), m_id (0) - { - // .. nothing yet .. - } - - /** - * @brief Gets the terminal name - */ - const std::string &name () const - { - return m_name; - } - - /** - * @brief Sets the terminal name - */ - void set_name (const std::string &n) - { - m_name = n; - } - - /** - * @brief Gets the terminal description - */ - const std::string &description () const - { - return m_description; - } - - /** - * @brief Sets the terminal description - */ - void set_description (const std::string &d) - { - m_description = d; - } - - /** - * @brief Gets the terminal ID - */ - size_t id () const - { - return m_id; - } - -private: - friend class DeviceClass; - - std::string m_name, m_description; - size_t m_id; - - void set_id (size_t id) - { - m_id = id; - } -}; - -/** - * @brief A device parameter definition - */ -class DB_PUBLIC DeviceParameterDefinition -{ -public: - /** - * @brief Creates an empty device parameter definition - */ - DeviceParameterDefinition () - : m_name (), m_description (), m_default_value (0.0), m_id (0) - { - // .. nothing yet .. - } - - /** - * @brief Creates a device parameter definition with the given name and description - */ - DeviceParameterDefinition (const std::string &name, const std::string &description, double default_value = 0.0) - : m_name (name), m_description (description), m_default_value (default_value), m_id (0) - { - // .. nothing yet .. - } - - /** - * @brief Gets the parameter name - */ - const std::string &name () const - { - return m_name; - } - - /** - * @brief Sets the parameter name - */ - void set_name (const std::string &n) - { - m_name = n; - } - - /** - * @brief Gets the parameter description - */ - const std::string &description () const - { - return m_description; - } - - /** - * @brief Sets the parameter description - */ - void set_description (const std::string &d) - { - m_description = d; - } - - /** - * @brief Gets the parameter default value - */ - double default_value () const - { - return m_default_value; - } - - /** - * @brief Sets the parameter description - */ - void set_default_value (double d) - { - m_default_value = d; - } - - /** - * @brief Gets the parameter ID - */ - size_t id () const - { - return m_id; - } - -private: - friend class DeviceClass; - - std::string m_name, m_description; - double m_default_value; - size_t m_id; - - void set_id (size_t id) - { - m_id = id; - } -}; - -/** - * @brief A device class - * - * A device class describes a type of device. - */ -class DB_PUBLIC DeviceClass - : public gsi::ObjectBase, public tl::Object, public tl::UniqueId -{ -public: - typedef size_t terminal_id_type; - - /** - * @brief Constructor - * - * Creates an empty circuit. - */ - DeviceClass (); - - /** - * @brief Copy constructor - * NOTE: do not use this copy constructor as the device class - * is intended to subclassing. - */ - DeviceClass (const DeviceClass &other); - - /** - * @brief Assignment - * NOTE: do not use this copy constructor as the device class - * is intended to subclassing. - */ - DeviceClass &operator= (const DeviceClass &other); - - /** - * @brief Gets the netlist the device class lives in - */ - db::Netlist *netlist () - { - return mp_netlist; - } - - /** - * @brief Gets the netlist the device class lives in (const version) - */ - const db::Netlist *netlist () const - { - return mp_netlist; - } - - /** - * @brief Gets the name of the device class - * - * The name is a formal name which identifies the class. - */ - const std::string &name () const - { - return m_name; - } - - /** - * @brief Sets the device name - */ - void set_name (const std::string &n) - { - m_name = n; - } - - /** - * @brief Gets the description text for the device class - * - * The description text is a human-readable text that - * identifies the device class. - */ - const std::string &description () const - { - return m_description; - } - - /** - * @brief Sets the description text - */ - void set_description (const std::string &d) - { - m_description = d; - } - - /** - * @brief Gets the terminal definitions - * - * The terminal definitions indicate what terminals the device offers. - * The number of terminals is constant per class. The index of the terminal - * is used as an ID of the terminal, hence the order must be static. - */ - const std::vector &terminal_definitions () const - { - return m_terminal_definitions; - } - - /** - * @brief Adds a terminal definition - */ - const DeviceTerminalDefinition &add_terminal_definition (const DeviceTerminalDefinition &pd); - - /** - * @brief Clears the terminal definition - */ - void clear_terminal_definitions (); - - /** - * @brief Gets the terminal definition from the ID - */ - const DeviceTerminalDefinition *terminal_definition (size_t id) const; - - /** - * @brief Gets the parameter definitions - */ - const std::vector ¶meter_definitions () const - { - return m_parameter_definitions; - } - - /** - * @brief Adds a parameter definition - */ - const DeviceParameterDefinition &add_parameter_definition (const DeviceParameterDefinition &pd); - - /** - * @brief Clears the parameter definition - */ - void clear_parameter_definitions (); - - /** - * @brief Gets the parameter definition from the ID - */ - const DeviceParameterDefinition *parameter_definition (size_t id) const; - - /** - * @brief Returns true, if the device has a parameter with the given name - */ - bool has_parameter_with_name (const std::string &name) const; - - /** - * @brief Returns the parameter ID for the parameter with the given name - * If the name is invalid, an exception is thrown. - */ - size_t parameter_id_for_name (const std::string &name) const; - - /** - * @brief Returns true, if the device has a terminal with the given name - */ - bool has_terminal_with_name (const std::string &name) const; - - /** - * @brief Returns the parameter ID for the terminal with the given name - * If the name is invalid, an exception is thrown. - */ - size_t terminal_id_for_name (const std::string &name) const; - - /** - * @brief Clears the circuit - */ - virtual DeviceClass *clone () const - { - return new DeviceClass (*this); - } - - /** - * @brief Combines two devices - * - * This method shall test, whether the two devices can be combined. Both devices - * are guaranteed to share the same device class (this). - * If they cannot be combined, this method shall do nothing and return false. - * If they can be combined, this method shall reconnect the nets of the first - * device and entirely disconnect the nets of the second device. - * The second device will be deleted afterwards. - */ - virtual bool combine_devices (db::Device * /*a*/, db::Device * /*b*/) const - { - return false; - } - - /** - * @brief Returns true if the device class supports device combination in parallel mode - */ - virtual bool supports_parallel_combination () const - { - return false; - } - - /** - * @brief Returns true if the device class supports device combination in serial mode - */ - virtual bool supports_serial_combination () const - { - return false; - } - -private: - friend class Netlist; - - std::string m_name, m_description; - std::vector m_terminal_definitions; - std::vector m_parameter_definitions; - db::Netlist *mp_netlist; - - void set_netlist (db::Netlist *nl) - { - mp_netlist = nl; - } -}; - /** * @brief The netlist class * diff --git a/src/db/db/dbNetlistUtils.h b/src/db/db/dbNetlistUtils.h new file mode 100644 index 000000000..47911283f --- /dev/null +++ b/src/db/db/dbNetlistUtils.h @@ -0,0 +1,127 @@ + +/* + + 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_dbNetlistUtils +#define _HDR_dbNetlistUtils + +#include "dbCommon.h" + +namespace db +{ + +/** + * @brief A getter for the ID of an object + */ +template +struct id_attribute +{ + typedef size_t attr_type; + size_t operator() (const T *t) const { return t->id (); } + bool has (const T * /*t*/) const { return true; } +}; + +/** + * @brief A getter for the cluster ID of an object + */ +template +struct cluster_id_attribute +{ + typedef size_t attr_type; + attr_type operator() (const T *t) const { return t->cluster_id (); } + bool has (const T * /*t*/) const { return true; } +}; + +/** + * @brief A getter for the cluster ID of an object + */ +template +struct cell_index_attribute +{ + typedef db::cell_index_type attr_type; + attr_type operator() (const T *t) const { return t->cell_index (); } + bool has (const T * /*t*/) const { return true; } +}; + +/** + * @brief A getter for the name of an object + */ +template +struct name_attribute +{ + typedef std::string attr_type; + const attr_type &operator() (const T *t) const { return t->name (); } + bool has (const T *t) const { return ! t->name ().empty (); } +}; + +/** + * @brief An id-to-object translation table + */ +template +class object_by_attr +{ +public: + typedef typename ATTR::attr_type attr_type; + typedef typename I::value_type value_type; + + object_by_attr (T *self, I (T::*bi) (), I (T::*ei) ()) : mp_self (self), m_bi (bi), m_ei (ei), m_valid (false) + { + // .. nothing yet .. + } + + void invalidate () + { + m_valid = false; + m_map.clear (); + } + + value_type *object_by (const attr_type &attr) const + { + if (! m_valid) { + validate (); + } + typename std::map::const_iterator m = m_map.find (attr); + return m == m_map.end () ? 0 : m->second; + } + +private: + T *mp_self; + I (T::*m_bi) (); + I (T::*m_ei) (); + mutable bool m_valid; + mutable std::map m_map; + + void validate () const + { + ATTR attr; + m_map.clear (); + for (I i = (mp_self->*m_bi) (); i != (mp_self->*m_ei) (); ++i) { + if (attr.has (i.operator-> ())) { + m_map.insert (std::make_pair (attr (i.operator-> ()), i.operator-> ())); + } + } + m_valid = true; + } +}; + +} + +#endif diff --git a/src/db/db/dbPin.cc b/src/db/db/dbPin.cc new file mode 100644 index 000000000..74b98b51d --- /dev/null +++ b/src/db/db/dbPin.cc @@ -0,0 +1,43 @@ + +/* + + 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 "dbPin.h" + +namespace db +{ + +// -------------------------------------------------------------------------------- +// Pin class implementation + +Pin::Pin () + : m_id (0) +{ + // .. nothing yet .. +} + +Pin::Pin (const std::string &name) + : m_name (name), m_id (0) +{ + // .. nothing yet .. +} + +} diff --git a/src/db/db/dbPin.h b/src/db/db/dbPin.h new file mode 100644 index 000000000..925d6e023 --- /dev/null +++ b/src/db/db/dbPin.h @@ -0,0 +1,81 @@ + +/* + + 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_dbPin +#define _HDR_dbPin + +#include "dbCommon.h" + +#include + +namespace db +{ + +/** + * @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; + + std::string m_name; + size_t m_id; + + void set_id (size_t id) + { + m_id = id; + } +}; + +} + +#endif diff --git a/src/db/db/dbSubCircuit.cc b/src/db/db/dbSubCircuit.cc new file mode 100644 index 000000000..8e6407326 --- /dev/null +++ b/src/db/db/dbSubCircuit.cc @@ -0,0 +1,131 @@ + +/* + + 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 "dbSubCircuit.h" +#include "dbCircuit.h" + +namespace db +{ + +// -------------------------------------------------------------------------------- +// SubCircuit class implementation + +SubCircuit::SubCircuit () + : m_id (0), mp_circuit (0) +{ + // .. nothing yet .. +} + +SubCircuit::~SubCircuit() +{ + for (std::vector::const_iterator p = m_pin_refs.begin (); p != m_pin_refs.end (); ++p) { + if (*p != Net::subcircuit_pin_iterator () && (*p)->net ()) { + (*p)->net ()->erase_subcircuit_pin (*p); + } + } +} + +SubCircuit::SubCircuit (Circuit *circuit, const std::string &name) + : m_circuit_ref (0), m_name (name), m_id (0), mp_circuit (0) +{ + set_circuit_ref (circuit); +} + +SubCircuit::SubCircuit (const SubCircuit &other) + : m_id (0), mp_circuit (0) +{ + operator= (other); +} + +SubCircuit &SubCircuit::operator= (const SubCircuit &other) +{ + if (this != &other) { + m_name = other.m_name; + m_trans = other.m_trans; + set_circuit_ref (const_cast (other.circuit_ref ())); + } + return *this; +} + +void SubCircuit::set_name (const std::string &n) +{ + m_name = n; + if (mp_circuit) { + mp_circuit->m_subcircuit_by_name.invalidate (); + } +} + +void SubCircuit::set_trans (const db::DCplxTrans &t) +{ + m_trans = t; +} + +void SubCircuit::set_pin_ref_for_pin (size_t pin_id, Net::subcircuit_pin_iterator iter) +{ + if (m_pin_refs.size () < pin_id + 1) { + m_pin_refs.resize (pin_id + 1, Net::subcircuit_pin_iterator ()); + } + m_pin_refs [pin_id] = iter; +} + +void SubCircuit::set_circuit_ref (Circuit *c) +{ + if (m_circuit_ref.get ()) { + m_circuit_ref->unregister_ref (this); + } + m_circuit_ref.reset (c); + if (m_circuit_ref.get ()) { + m_circuit_ref->register_ref (this); + } +} + +const Net *SubCircuit::net_for_pin (size_t pin_id) const +{ + if (pin_id < m_pin_refs.size ()) { + Net::subcircuit_pin_iterator p = m_pin_refs [pin_id]; + if (p != Net::subcircuit_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::subcircuit_pin_iterator p = m_pin_refs [pin_id]; + if (p != Net::subcircuit_pin_iterator () && p->net ()) { + p->net ()->erase_subcircuit_pin (p); + } + m_pin_refs [pin_id] = Net::subcircuit_pin_iterator (); + } + + if (net) { + net->add_subcircuit_pin (NetSubcircuitPinRef (this, pin_id)); + } +} + +} diff --git a/src/db/db/dbSubCircuit.h b/src/db/db/dbSubCircuit.h new file mode 100644 index 000000000..a28b8211a --- /dev/null +++ b/src/db/db/dbSubCircuit.h @@ -0,0 +1,216 @@ + +/* + + 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_dbSubCircuit +#define _HDR_dbSubCircuit + +#include "dbCommon.h" +#include "dbTrans.h" +#include "dbNet.h" + +#include "tlObject.h" + +#include +#include + +namespace db +{ + +class Circuit; + +/** + * @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_ref, const std::string &name = std::string ()); + + /** + * @brief Destructor + */ + ~SubCircuit (); + + /** + * @brief Gets the subcircuit ID + * The ID is a unique integer which identifies the subcircuit. + * It can be used to retrieve the subcircuit from the circuit using Circuit::subcircuit_by_id. + * When assigned, the subcircuit ID is not 0. + */ + size_t id () const + { + return m_id; + } + + /** + * @brief Gets the circuit the subcircuit lives in (const version) + * This pointer is 0 if the subcircuit isn't added to a circuit + */ + const Circuit *circuit () const + { + return mp_circuit; + } + + /** + * @brief Gets the circuit the subcircuit lives in (non-const version) + * This pointer is 0 if the subcircuit isn't added to a circuit + */ + Circuit *circuit () + { + return mp_circuit; + } + + /** + * @brief Gets the circuit the reference points to (const version) + */ + const Circuit *circuit_ref () const + { + return m_circuit_ref.get (); + } + + /** + * @brief Gets the circuit the reference points to (non-const version) + */ + Circuit *circuit_ref () + { + return m_circuit_ref.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_ref; + std::string m_name; + db::DCplxTrans m_trans; + std::vector m_pin_refs; + size_t m_id; + Circuit *mp_circuit; + + /** + * @brief Sets the pin reference for a specific pin + */ + void set_pin_ref_for_pin (size_t ppin_id, Net::subcircuit_pin_iterator iter); + + /** + * @brief Sets the circuit reference + */ + void set_circuit_ref (Circuit *c); + + /** + * @brief Sets the circuit the subcircuit belongs to + */ + void set_circuit (Circuit *c) + { + mp_circuit = c; + } + + /** + * @brief Sets the device ID + */ + void set_id (size_t id) + { + m_id = id; + } +}; + +} + +#endif diff --git a/src/db/unit_tests/dbNetlistTests.cc b/src/db/unit_tests/dbNetlistTests.cc index 833f42f95..ab1e4df29 100644 --- a/src/db/unit_tests/dbNetlistTests.cc +++ b/src/db/unit_tests/dbNetlistTests.cc @@ -28,6 +28,8 @@ #include +// ---------------------------------------------------------------------------------------- + static std::string pd2string (const db::DeviceTerminalDefinition &pd) { return pd.name () + "(" + pd.description () + ") #" + tl::to_string (pd.id ()); @@ -38,78 +40,6 @@ static std::string pd2string (const db::DeviceParameterDefinition &pd) return pd.name () + "(" + pd.description () + ")=" + tl::to_string (pd.default_value ()) + " #" + tl::to_string (pd.id ()); } -TEST(1_DeviceTerminalDefinition) -{ - db::DeviceTerminalDefinition pd; - - EXPECT_EQ (pd2string (pd), "() #0"); - pd.set_name ("name"); - pd.set_description ("nothing yet"); - EXPECT_EQ (pd2string (pd), "name(nothing yet) #0"); - - db::DeviceTerminalDefinition pd2; - pd2 = pd; - EXPECT_EQ (pd2string (pd2), "name(nothing yet) #0"); - pd2.set_name ("name2"); - pd2.set_description ("now it has something"); - EXPECT_EQ (pd2string (pd2), "name2(now it has something) #0"); - - db::DeviceClass dc; - dc.add_terminal_definition (pd); - dc.add_terminal_definition (pd2); - EXPECT_EQ (pd2string (dc.terminal_definitions ()[0]), "name(nothing yet) #0"); - EXPECT_EQ (pd2string (dc.terminal_definitions ()[1]), "name2(now it has something) #1"); - - dc.clear_terminal_definitions (); - EXPECT_EQ (dc.terminal_definitions ().empty (), true); - - db::DeviceParameterDefinition ppd ("P1", "Parameter 1", 1.0); - dc.add_parameter_definition (ppd); - - db::DeviceParameterDefinition ppd2 ("P2", "Parameter 2"); - dc.add_parameter_definition (ppd2); - - EXPECT_EQ (pd2string (dc.parameter_definitions ()[0]), "P1(Parameter 1)=1 #0"); - EXPECT_EQ (pd2string (dc.parameter_definitions ()[1]), "P2(Parameter 2)=0 #1"); - - dc.clear_parameter_definitions (); - EXPECT_EQ (dc.parameter_definitions ().empty (), true); -} - -TEST(2_DeviceClass) -{ - db::DeviceTerminalDefinition pd; - pd.set_name ("name"); - pd.set_description ("nothing yet"); - - db::DeviceTerminalDefinition pd2; - pd2.set_name ("name2"); - pd2.set_description ("now it has something"); - - db::DeviceClass dc; - dc.set_name ("devname"); - dc.set_description ("devdesc"); - EXPECT_EQ (dc.name (), "devname"); - EXPECT_EQ (dc.description (), "devdesc"); - dc.add_terminal_definition (pd); - dc.add_terminal_definition (pd2); - EXPECT_EQ (dc.terminal_definitions ().size (), size_t (2)); - EXPECT_EQ (pd2string (dc.terminal_definitions ()[0]), "name(nothing yet) #0"); - EXPECT_EQ (pd2string (dc.terminal_definitions ()[1]), "name2(now it has something) #1"); - - EXPECT_EQ (pd2string (*dc.terminal_definition (dc.terminal_definitions ()[0].id ())), "name(nothing yet) #0"); - EXPECT_EQ (pd2string (*dc.terminal_definition (dc.terminal_definitions ()[1].id ())), "name2(now it has something) #1"); - EXPECT_EQ (dc.terminal_definition (3), 0); - - db::DeviceClass dc2 = dc; - EXPECT_EQ (dc2.name (), "devname"); - EXPECT_EQ (dc2.description (), "devdesc"); - EXPECT_EQ (dc2.terminal_definitions ().size (), size_t (2)); - EXPECT_EQ (pd2string (*dc2.terminal_definition (dc2.terminal_definitions ()[0].id ())), "name(nothing yet) #0"); - EXPECT_EQ (pd2string (*dc2.terminal_definition (dc2.terminal_definitions ()[1].id ())), "name2(now it has something) #1"); - EXPECT_EQ (dc2.terminal_definition (3), 0); -} - static std::string pins2string (const db::Circuit &c) { std::string res; @@ -123,32 +53,6 @@ static std::string pins2string (const db::Circuit &c) return res; } -TEST(3_CircuitBasic) -{ - db::Circuit c; - c.set_name ("name"); - EXPECT_EQ (c.name (), "name"); - - db::Pin p1 = c.add_pin ("p1"); - db::Pin p2 = c.add_pin ("p2"); - EXPECT_EQ (pins2string (c), "p1#0,p2#1"); - - EXPECT_EQ (c.pin_by_id (0)->name (), "p1"); - EXPECT_EQ (c.pin_by_id (1)->name (), "p2"); - EXPECT_EQ (c.pin_by_id (2), 0); - EXPECT_EQ (c.pin_by_name ("p1")->name (), "p1"); - EXPECT_EQ (c.pin_by_name ("doesnt_exist") == 0, true); - EXPECT_EQ (c.pin_by_name ("p2")->name (), "p2"); - - db::Circuit c2 = c; - EXPECT_EQ (c2.name (), "name"); - EXPECT_EQ (pins2string (c), "p1#0,p2#1"); - - EXPECT_EQ (c2.pin_by_id (0)->name (), "p1"); - EXPECT_EQ (c2.pin_by_id (1)->name (), "p2"); - EXPECT_EQ (c2.pin_by_id (2), 0); -} - static std::string net2string (const db::Net &n) { std::string res; @@ -243,6 +147,186 @@ static std::string netlist2 (const db::Circuit &c) return res; } +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) { + res += "[" + c->name () + "]\n"; + res += nets2string (*c); + } + 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; +} + +static std::string refs2string (const db::Circuit *c) +{ + std::string res; + for (db::Circuit::const_refs_iterator r = c->begin_refs (); r != c->end_refs (); ++r) { + if (!res.empty ()) { + res += ","; + } + res += r->name (); + } + return res; +} + +static std::string children2string (const db::Circuit *c) +{ + std::string res; + for (db::Circuit::const_child_circuit_iterator r = c->begin_children (); r != c->end_children (); ++r) { + if (!res.empty ()) { + res += ","; + } + res += (*r)->name (); + } + return res; +} + +static std::string parents2string (const db::Circuit *c) +{ + std::string res; + for (db::Circuit::const_parent_circuit_iterator r = c->begin_parents (); r != c->end_parents (); ++r) { + if (!res.empty ()) { + res += ","; + } + res += (*r)->name (); + } + return res; +} + +static std::string td2string (const db::Netlist *nl) +{ + std::string res; + for (db::Netlist::const_top_down_circuit_iterator r = nl->begin_top_down (); r != nl->end_top_down (); ++r) { + if (!res.empty ()) { + res += ","; + } + res += (*r)->name (); + } + return res; +} + +static std::string bu2string (const db::Netlist *nl) +{ + std::string res; + for (db::Netlist::const_bottom_up_circuit_iterator r = nl->begin_bottom_up (); r != nl->end_bottom_up (); ++r) { + if (!res.empty ()) { + res += ","; + } + res += (*r)->name (); + } + return res; +} + +// ---------------------------------------------------------------------------------------- + +TEST(1_DeviceTerminalDefinition) +{ + db::DeviceTerminalDefinition pd; + + EXPECT_EQ (pd2string (pd), "() #0"); + pd.set_name ("name"); + pd.set_description ("nothing yet"); + EXPECT_EQ (pd2string (pd), "name(nothing yet) #0"); + + db::DeviceTerminalDefinition pd2; + pd2 = pd; + EXPECT_EQ (pd2string (pd2), "name(nothing yet) #0"); + pd2.set_name ("name2"); + pd2.set_description ("now it has something"); + EXPECT_EQ (pd2string (pd2), "name2(now it has something) #0"); + + db::DeviceClass dc; + dc.add_terminal_definition (pd); + dc.add_terminal_definition (pd2); + EXPECT_EQ (pd2string (dc.terminal_definitions ()[0]), "name(nothing yet) #0"); + EXPECT_EQ (pd2string (dc.terminal_definitions ()[1]), "name2(now it has something) #1"); + + dc.clear_terminal_definitions (); + EXPECT_EQ (dc.terminal_definitions ().empty (), true); + + db::DeviceParameterDefinition ppd ("P1", "Parameter 1", 1.0); + dc.add_parameter_definition (ppd); + + db::DeviceParameterDefinition ppd2 ("P2", "Parameter 2"); + dc.add_parameter_definition (ppd2); + + EXPECT_EQ (pd2string (dc.parameter_definitions ()[0]), "P1(Parameter 1)=1 #0"); + EXPECT_EQ (pd2string (dc.parameter_definitions ()[1]), "P2(Parameter 2)=0 #1"); + + dc.clear_parameter_definitions (); + EXPECT_EQ (dc.parameter_definitions ().empty (), true); +} + +TEST(2_DeviceClass) +{ + db::DeviceTerminalDefinition pd; + pd.set_name ("name"); + pd.set_description ("nothing yet"); + + db::DeviceTerminalDefinition pd2; + pd2.set_name ("name2"); + pd2.set_description ("now it has something"); + + db::DeviceClass dc; + dc.set_name ("devname"); + dc.set_description ("devdesc"); + EXPECT_EQ (dc.name (), "devname"); + EXPECT_EQ (dc.description (), "devdesc"); + dc.add_terminal_definition (pd); + dc.add_terminal_definition (pd2); + EXPECT_EQ (dc.terminal_definitions ().size (), size_t (2)); + EXPECT_EQ (pd2string (dc.terminal_definitions ()[0]), "name(nothing yet) #0"); + EXPECT_EQ (pd2string (dc.terminal_definitions ()[1]), "name2(now it has something) #1"); + + EXPECT_EQ (pd2string (*dc.terminal_definition (dc.terminal_definitions ()[0].id ())), "name(nothing yet) #0"); + EXPECT_EQ (pd2string (*dc.terminal_definition (dc.terminal_definitions ()[1].id ())), "name2(now it has something) #1"); + EXPECT_EQ (dc.terminal_definition (3), 0); + + db::DeviceClass dc2 = dc; + EXPECT_EQ (dc2.name (), "devname"); + EXPECT_EQ (dc2.description (), "devdesc"); + EXPECT_EQ (dc2.terminal_definitions ().size (), size_t (2)); + EXPECT_EQ (pd2string (*dc2.terminal_definition (dc2.terminal_definitions ()[0].id ())), "name(nothing yet) #0"); + EXPECT_EQ (pd2string (*dc2.terminal_definition (dc2.terminal_definitions ()[1].id ())), "name2(now it has something) #1"); + EXPECT_EQ (dc2.terminal_definition (3), 0); +} + +TEST(3_CircuitBasic) +{ + db::Circuit c; + c.set_name ("name"); + EXPECT_EQ (c.name (), "name"); + + db::Pin p1 = c.add_pin ("p1"); + db::Pin p2 = c.add_pin ("p2"); + EXPECT_EQ (pins2string (c), "p1#0,p2#1"); + + EXPECT_EQ (c.pin_by_id (0)->name (), "p1"); + EXPECT_EQ (c.pin_by_id (1)->name (), "p2"); + EXPECT_EQ (c.pin_by_id (2), 0); + EXPECT_EQ (c.pin_by_name ("p1")->name (), "p1"); + EXPECT_EQ (c.pin_by_name ("doesnt_exist") == 0, true); + EXPECT_EQ (c.pin_by_name ("p2")->name (), "p2"); + + db::Circuit c2 = c; + EXPECT_EQ (c2.name (), "name"); + EXPECT_EQ (pins2string (c), "p1#0,p2#1"); + + EXPECT_EQ (c2.pin_by_id (0)->name (), "p1"); + EXPECT_EQ (c2.pin_by_id (1)->name (), "p2"); + EXPECT_EQ (c2.pin_by_id (2), 0); +} + TEST(4_CircuitDevices) { db::DeviceClass dc1; @@ -403,38 +487,6 @@ TEST(4_CircuitDevices) ); } -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) { - res += "[" + c->name () + "]\n"; - res += nets2string (*c); - } - 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; -} - -static std::string refs2string (const db::Circuit *c) -{ - std::string res; - for (db::Circuit::const_refs_iterator r = c->begin_refs (); r != c->end_refs (); ++r) { - if (!res.empty ()) { - res += ","; - } - res += r->name (); - } - return res; -} - TEST(4_NetlistSubcircuits) { std::auto_ptr nl (new db::Netlist ()); @@ -897,54 +949,6 @@ TEST(11_NetlistCircuitRefs) EXPECT_EQ (refs2string (c2), "sc1,sc2"); } -static std::string children2string (const db::Circuit *c) -{ - std::string res; - for (db::Circuit::const_child_circuit_iterator r = c->begin_children (); r != c->end_children (); ++r) { - if (!res.empty ()) { - res += ","; - } - res += (*r)->name (); - } - return res; -} - -static std::string parents2string (const db::Circuit *c) -{ - std::string res; - for (db::Circuit::const_parent_circuit_iterator r = c->begin_parents (); r != c->end_parents (); ++r) { - if (!res.empty ()) { - res += ","; - } - res += (*r)->name (); - } - return res; -} - -static std::string td2string (const db::Netlist *nl) -{ - std::string res; - for (db::Netlist::const_top_down_circuit_iterator r = nl->begin_top_down (); r != nl->end_top_down (); ++r) { - if (!res.empty ()) { - res += ","; - } - res += (*r)->name (); - } - return res; -} - -static std::string bu2string (const db::Netlist *nl) -{ - std::string res; - for (db::Netlist::const_bottom_up_circuit_iterator r = nl->begin_bottom_up (); r != nl->end_bottom_up (); ++r) { - if (!res.empty ()) { - res += ","; - } - res += (*r)->name (); - } - return res; -} - TEST(12_NetlistTopology) { std::auto_ptr nl (new db::Netlist ());