From 764667d8e88b34b231228bf32d9b38d0d0a50777 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 24 Dec 2018 16:55:22 +0100 Subject: [PATCH] WIP: added algorithm for combining devices - needs testing. --- src/db/db/db.pro | 4 +- src/db/db/dbNetlist.cc | 169 +++++++++++++++++++++++++++ src/db/db/dbNetlist.h | 40 +++++++ src/db/db/dbNetlistDeviceClasses.h | 83 +++++++++++++ src/db/db/dbNetlistDeviceExtractor.h | 154 ++++++++++++++++++++++++ 5 files changed, 449 insertions(+), 1 deletion(-) create mode 100644 src/db/db/dbNetlistDeviceClasses.h create mode 100644 src/db/db/dbNetlistDeviceExtractor.h diff --git a/src/db/db/db.pro b/src/db/db/db.pro index b1714201f..335ea762c 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -256,7 +256,9 @@ HEADERS = \ dbLocalOperation.h \ dbHierProcessor.h \ dbNetlistProperty.h \ - dbNetlist.h + dbNetlist.h \ + dbNetlistDeviceClasses.h \ + dbNetlistDeviceExtractor.h !equals(HAVE_QT, "0") { diff --git a/src/db/db/dbNetlist.cc b/src/db/db/dbNetlist.cc index e89aab1db..277a3b21d 100644 --- a/src/db/db/dbNetlist.cc +++ b/src/db/db/dbNetlist.cc @@ -22,6 +22,8 @@ #include "dbNetlist.h" +#include + namespace db { @@ -648,6 +650,173 @@ void Circuit::connect_pin (size_t pin_id, Net *net) } } +void Circuit::purge_nets () +{ + std::vector nets_to_be_purged; + for (net_iterator n = begin_nets (); n != end_nets (); ++n) { + if (n->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 ()->port_definitions (); + for (std::vector::const_iterator p = pd.begin (); p != pd.end (); ++p) { + if (d->net_for_port (p->id ()) != 0) { + throw tl::Exception (tl::to_string (tr ("Internal error: Port still connected after removing device in device combination")) + ": name=" + d->name () + ", circuit=" + c->name () + ", port=" + p->name ()); + } + } +} + +void Circuit::combine_parallel_devices (const db::DeviceClass &cls) +{ + typedef std::vector key_type; + std::map > combination_candidates; + + // 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 &ports = cls.port_definitions (); + for (std::vector::const_iterator p = ports.begin (); p != ports.end (); ++p) { + const db::Net *n = d->net_for_port (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); + } else { + ++j; + } + } + } + + } +} + +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::port_iterator p = net.begin_ports (); + if (p == net.end_ports () || 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_ports () || 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_ports () || 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); +} + +void Circuit::combine_serial_devices (const db::DeviceClass &cls) +{ + 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 &ports = cls.port_definitions (); + for (std::vector::const_iterator p = ports.begin (); p != ports.end (); ++p) { + db::Net *on; + on = dd.first->net_for_port (p->id ()); + if (on && ! same_or_swapped (dd, attached_two_devices (*on, cls))) { + other_nets.push_back (on); + } + on = dd.second->net_for_port (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.port_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; + } + + } + + } +} + +void Circuit::combine_devices () +{ + tl_assert (netlist () != 0); + + for (Netlist::device_class_iterator dc = netlist ()->begin_device_classes (); dc != netlist ()->end_device_classes (); ++dc) { + combine_parallel_devices (*dc); + combine_serial_devices (*dc); + } +} + // -------------------------------------------------------------------------------- // DeviceClass class implementation diff --git a/src/db/db/dbNetlist.h b/src/db/db/dbNetlist.h index 83ebc36e9..c53b003b2 100644 --- a/src/db/db/dbNetlist.h +++ b/src/db/db/dbNetlist.h @@ -452,6 +452,14 @@ public: return m_ports.end (); } + /** + * @brief Returns true, if the net is floating (has no or only a single connection) + */ + bool floating () const + { + return (m_pins.size () + m_ports.size ()) < 2; + } + private: friend class Circuit; @@ -1056,6 +1064,21 @@ public: */ 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; @@ -1077,6 +1100,8 @@ private: void translate_circuits (const std::map &map); void translate_device_classes (const std::map &map); void set_netlist (Netlist *netlist); + void combine_parallel_devices (const db::DeviceClass &cls); + void combine_serial_devices (const db::DeviceClass &cls); }; /** @@ -1319,6 +1344,21 @@ public: */ virtual const std::string &description () const; + /** + * @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 Gets the port definitions * diff --git a/src/db/db/dbNetlistDeviceClasses.h b/src/db/db/dbNetlistDeviceClasses.h new file mode 100644 index 000000000..ab6511907 --- /dev/null +++ b/src/db/db/dbNetlistDeviceClasses.h @@ -0,0 +1,83 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 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_dbNetlistDeviceClasses +#define _HDR_dbNetlistDeviceClasses + +#include "dbCommon.h" +#include "dbNetlist.h" + +namespace db +{ + +class DB_PUBLIC DeviceClassResistor + : public db::DeviceClass +{ +public: + + + +}; + +class DB_PUBLIC DeviceClassCapacitor + : public db::DeviceClass +{ +public: + + +}; + +class DB_PUBLIC DeviceClassInductivity + : public db::DeviceClass +{ +public: + + +}; + +class DB_PUBLIC DeviceClassDiode + : public db::DeviceClass +{ +public: + + +}; + +class DB_PUBLIC DeviceClassMOSTransistor + : public db::DeviceClass +{ +public: + + +}; + +class DB_PUBLIC DeviceClassBipolarTransistor + : public db::DeviceClass +{ +public: + + +}; + +} + +#endif diff --git a/src/db/db/dbNetlistDeviceExtractor.h b/src/db/db/dbNetlistDeviceExtractor.h new file mode 100644 index 000000000..b486b4e23 --- /dev/null +++ b/src/db/db/dbNetlistDeviceExtractor.h @@ -0,0 +1,154 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 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_dbNetlistDeviceExtractor +#define _HDR_dbNetlistDeviceExtractor + +#include "dbCommon.h" +#include "dbNetlist.h" +#include "dbHierNetworkProcessor.h" +#include "dbLayout.h" + +#include "gsiObject.h" + +namespace db +{ + +class DB_PUBLIC NetlistDeviceExtractor + : public gsi::ObjectBase +{ +public: + /** + * @brief Default constructor + */ + NetlistDeviceExtractor (); + + /** + * @brief Destructor + */ + ~NetlistDeviceExtractor (); + + // TODO: Do we need to declare input layers? + + /** + * @brief Initializes the extractor + * This method will produce the device classes required for the device extraction. + */ + void initialize (db::Netlist *nl); + + /** + * @brief Performs the extraction + * + * The netlist will be filled with circuits (unless not present yet) to represent the + * cells from the layout. + * + * Devices will be generated inside the netlist's circuits as they are extracted + * from the layout. Inside the layout, device port annotation shapes are created with the + * corresponding DevicePortProperty objects attached. The will be used when extracting + * the nets later to associate nets with device ports. + * + * The definition of the input layers is device class specific. + */ + void extract (db::Layout *layout, const std::vector &layers); + + /** + * @brief Checks the input layers + * This method shall raise an error, if the input layer are not properly defined (e.g. + * too few etc.) + */ + virtual void check_input_layers (db::Layout *layout, const std::vector &layers) const; + + /** + * @brief Creates the device classes + * At least one device class needs to be defined. Use "register_device_class" to register + * the device classes you need. The first device class registered has device class index 0, + * the further ones 1, 2, etc. + */ + virtual void create_device_classes (); + + /** + * @brief Gets the connectivity object used to extract the device geometry + */ + virtual db::Connectivity get_connectivity (const std::vector &layers) const; + + /** + * @brief Extracts the devices from the given shape cluster + * + * The shape cluster is a set of geometries belonging together in terms of the + * connectivity defined by "get_connectivity". The cluster might cover multiple devices, + * so the implementation needs to consider this case. The geometries are already merged. + * + * The implementation of this method shall use "create_device" to create new + * devices based on the geometry found. It shall use "define_port" to define + * ports by which the nets extracted in the network extraction step connect + * to the new devices. + */ + virtual void extract_devices (const std::vector &layer_geometry); + +protected: + /** + * @brief Registers a device class + * The device class object will become owned by the netlist and must not be deleted by + * the caller. + */ + void register_device_class (DeviceClass *device_class); + + /** + * @brief Creates a device + * The device object returned can be configured by the caller, e.g. set parameters. + * It will be owned by the netlist and must not be deleted by the caller. + */ + Device *create_device (unsigned int device_class_index = 0); + + /** + * @brief Defines a device port in the layout (a polygon) + */ + void define_port (Device *device, size_t port_id, size_t layer_index, const db::Polygon &polygon); + + /** + * @brief Defines a device port in the layout (a box) + */ + void define_port (Device *device, size_t port_id, size_t layer_index, const db::Box &box); + + /** + * @brief Defines a point-like device port in the layout + */ + void define_port (Device *device, size_t port_id, size_t layer_index, const db::Point &point); + + /** + * @brief Gets the database unit + */ + double dbu () const + { + return mp_layout->dbu (); + } + +private: + db::Layout *mp_layout; + db::cell_index_type m_cell_index; + db::Netlist *mp_netlist; + db::Circuit *mp_circuit; +}; + +} + +#endif