From 97a1abb73fe580ea4f34ddd67c8cde1c17739d3c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 25 Dec 2018 02:02:18 +0100 Subject: [PATCH] WIP: implementation of basic device classes, device extractor. --- src/db/db/db.pro | 4 +- src/db/db/dbNetlistDeviceClasses.cc | 220 ++++++++++++++++++++++++++ src/db/db/dbNetlistDeviceClasses.h | 91 +++++++++-- src/db/db/dbNetlistDeviceExtractor.cc | 170 ++++++++++++++++++++ src/db/db/dbNetlistDeviceExtractor.h | 29 ++-- 5 files changed, 489 insertions(+), 25 deletions(-) create mode 100644 src/db/db/dbNetlistDeviceClasses.cc create mode 100644 src/db/db/dbNetlistDeviceExtractor.cc diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 335ea762c..e2bc42515 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -145,7 +145,9 @@ SOURCES = \ dbNetlistProperty.cc \ gsiDeclDbNetlistProperty.cc \ dbNetlist.cc \ - gsiDeclDbNetlist.cc + gsiDeclDbNetlist.cc \ + dbNetlistDeviceClasses.cc \ + dbNetlistDeviceExtractor.cc HEADERS = \ dbArray.h \ diff --git a/src/db/db/dbNetlistDeviceClasses.cc b/src/db/db/dbNetlistDeviceClasses.cc new file mode 100644 index 000000000..47ccc5702 --- /dev/null +++ b/src/db/db/dbNetlistDeviceClasses.cc @@ -0,0 +1,220 @@ + +/* + + 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 + +*/ + +#include "dbNetlistDeviceClasses.h" + +namespace db +{ + +// ------------------------------------------------------------------------------------ +// DeviceClassTwoPortDevice implementation + +bool DeviceClassTwoPortDevice::combine_devices (Device *a, Device *b) const +{ + db::Net *na1 = a->net_for_port (0); + db::Net *na2 = a->net_for_port (1); + db::Net *nb1 = b->net_for_port (0); + db::Net *nb2 = b->net_for_port (1); + + bool res = true; + + if ((na1 == nb1 && na2 == nb2) || (na1 == nb2 && na2 == nb1)) { + + parallel (a, b); + + } else if (na2 == nb1 || na2 == nb2) { + + // serial a(B) to b(A or B) + serial (a, b); + a->connect_port (1, (na2 == nb1 ? nb2 : nb1)); + + } else if (na1 == nb1 || na1 == nb2) { + + // serial a(A) to b(A or B) + serial (a, b); + a->connect_port (0, (na1 == nb1 ? nb2 : nb1)); + + } + + if (res) { + b->connect_port (0, 0); + b->connect_port (1, 0); + return true; + } else { + return false; + } +} + + +// ------------------------------------------------------------------------------------ +// DeviceClassResistor implementation + +DeviceClassResistor::DeviceClassResistor () +{ + add_port_definition (db::DevicePortDefinition ("A", "Port A")); + add_port_definition (db::DevicePortDefinition ("B", "Port B")); + + add_parameter_definition (db::DeviceParameterDefinition ("R", "Resistance (Ohm)", 0.0)); +} + +void DeviceClassResistor::parallel (Device *a, Device *b) const +{ + double va = a->parameter_value (0); + double vb = b->parameter_value (0); + a->set_parameter_value (0, va + vb < 1e-10 ? 0.0 : va * vb / (va + vb)); +} + +void DeviceClassResistor::serial (Device *a, Device *b) const +{ + double va = a->parameter_value (0); + double vb = b->parameter_value (0); + a->set_parameter_value (0, va + vb); +} + +// ------------------------------------------------------------------------------------ +// DeviceClassCapacitor implementation + +DeviceClassCapacitor::DeviceClassCapacitor () +{ + add_port_definition (db::DevicePortDefinition ("A", "Port A")); + add_port_definition (db::DevicePortDefinition ("B", "Port B")); + + add_parameter_definition (db::DeviceParameterDefinition ("C", "Capacitance (Farad)", 0.0)); +} + +void DeviceClassCapacitor::serial (Device *a, Device *b) const +{ + double va = a->parameter_value (0); + double vb = b->parameter_value (0); + a->set_parameter_value (0, va + vb < 1e-10 ? 0.0 : va * vb / (va + vb)); +} + +void DeviceClassCapacitor::parallel (Device *a, Device *b) const +{ + double va = a->parameter_value (0); + double vb = b->parameter_value (0); + a->set_parameter_value (0, va + vb); +} + +// ------------------------------------------------------------------------------------ +// DeviceClassInductor implementation + +DeviceClassInductor::DeviceClassInductor () +{ + add_port_definition (db::DevicePortDefinition ("A", "Port A")); + add_port_definition (db::DevicePortDefinition ("B", "Port B")); + + add_parameter_definition (db::DeviceParameterDefinition ("L", "Inductance (Henry)", 0.0)); +} + +void DeviceClassInductor::parallel (Device *a, Device *b) const +{ + double va = a->parameter_value (0); + double vb = b->parameter_value (0); + a->set_parameter_value (0, va + vb < 1e-10 ? 0.0 : va * vb / (va + vb)); +} + +void DeviceClassInductor::serial (Device *a, Device *b) const +{ + double va = a->parameter_value (0); + double vb = b->parameter_value (0); + a->set_parameter_value (0, va + vb); +} + +// ------------------------------------------------------------------------------------ +// DeviceClassInductor implementation + +DeviceClassDiode::DeviceClassDiode () +{ + add_port_definition (db::DevicePortDefinition ("A", "Anode")); + add_port_definition (db::DevicePortDefinition ("C", "Cathode")); + + add_parameter_definition (db::DeviceParameterDefinition ("A", "Area (square micrometer)", 0.0)); +} + +bool DeviceClassDiode::combine_devices (Device *a, Device *b) const +{ + const db::Net *na1 = a->net_for_port (0); + const db::Net *na2 = a->net_for_port (1); + const db::Net *nb1 = b->net_for_port (0); + const db::Net *nb2 = b->net_for_port (1); + + if ((na1 == nb1 && na2 == nb2) || (na1 == nb2 && na2 == nb1)) { + + a->set_parameter_value (0, a->parameter_value (0) + b->parameter_value (0)); + b->connect_port (0, 0); + b->connect_port (1, 0); + + return true; + + } else { + return false; + } +} + +// ------------------------------------------------------------------------------------ +// DeviceClassInductor implementation + +DeviceClassMOSTransistor::DeviceClassMOSTransistor () +{ + add_port_definition (db::DevicePortDefinition ("S", "Source")); + add_port_definition (db::DevicePortDefinition ("G", "Gate")); + add_port_definition (db::DevicePortDefinition ("D", "Drain")); + + add_parameter_definition (db::DeviceParameterDefinition ("L", "Gate length (micrometer)", 0.0)); + add_parameter_definition (db::DeviceParameterDefinition ("W", "Gate width (micrometer)", 0.0)); + add_parameter_definition (db::DeviceParameterDefinition ("AS", "Source area (square micrometer)", 0.0)); + add_parameter_definition (db::DeviceParameterDefinition ("AD", "Drain area (square micrometer)", 0.0)); +} + +bool DeviceClassMOSTransistor::combine_devices (Device *a, Device *b) const +{ + const db::Net *nas = a->net_for_port (0); + const db::Net *nag = a->net_for_port (1); + const db::Net *nad = a->net_for_port (2); + const db::Net *nbs = b->net_for_port (0); + const db::Net *nbg = b->net_for_port (1); + const db::Net *nbd = b->net_for_port (2); + + // parallel transistors can be combined into one + if (((nas == nbs && nad == nbd) || (nas == nbd && nad == nbs)) && nag == nbg) { + + // for combination the gate length must be identical + if (fabs (a->parameter_value (0) - b->parameter_value (0)) < 1e-6) { + + a->set_parameter_value (1, a->parameter_value (1) + b->parameter_value (1)); + a->set_parameter_value (2, a->parameter_value (2) + b->parameter_value (2)); + a->set_parameter_value (3, a->parameter_value (3) + b->parameter_value (3)); + b->connect_port (0, 0); + b->connect_port (1, 0); + b->connect_port (2, 0); + + return true; + + } + + } + + return false; +} + +} diff --git a/src/db/db/dbNetlistDeviceClasses.h b/src/db/db/dbNetlistDeviceClasses.h index 255154033..b90edd82c 100644 --- a/src/db/db/dbNetlistDeviceClasses.h +++ b/src/db/db/dbNetlistDeviceClasses.h @@ -29,54 +29,117 @@ namespace db { +/** + * @brief A basic two-port device class + */ +class DB_PUBLIC DeviceClassTwoPortDevice + : public db::DeviceClass +{ +public: + virtual bool combine_devices (Device *a, Device *b) const; + + virtual void parallel (Device *a, Device *b) const = 0; + virtual void serial (Device *a, Device *b) const = 0; +}; + +/** + * @brief A basic resistor device class + * A resistor defines a single parameter, "R", which is the resistance in Ohm. + * It defines two ports, "A" and "B" for the two terminals. + */ class DB_PUBLIC DeviceClassResistor - : public db::DeviceClass + : public db::DeviceClassTwoPortDevice { public: + DeviceClassResistor (); + virtual db::DeviceClass *clone () const + { + return new DeviceClassResistor (*this); + } - - + virtual void parallel (Device *a, Device *b) const; + virtual void serial (Device *a, Device *b) const; }; +/** + * @brief A basic capacitor device class + * A capacitor defines a single parameter, "C", which is the capacitance in Farad. + * It defines two ports, "A" and "B" for the two terminals. + */ class DB_PUBLIC DeviceClassCapacitor - : public db::DeviceClass + : public db::DeviceClassTwoPortDevice { public: + DeviceClassCapacitor (); + virtual db::DeviceClass *clone () const + { + return new DeviceClassCapacitor (*this); + } + virtual void parallel (Device *a, Device *b) const; + virtual void serial (Device *a, Device *b) const; }; -class DB_PUBLIC DeviceClassInductivity - : public db::DeviceClass +/** + * @brief A basic inductor device class + * An inductor defines a single parameter, "L", which is the inductance in Henry. + * It defines two ports, "A" and "B" for the two terminals. + */ +class DB_PUBLIC DeviceClassInductor + : public db::DeviceClassTwoPortDevice { public: + DeviceClassInductor (); + virtual db::DeviceClass *clone () const + { + return new DeviceClassInductor (*this); + } + virtual void parallel (Device *a, Device *b) const; + virtual void serial (Device *a, Device *b) const; }; +/** + * @brief A basic diode device class + * A diode defines a single parameter, "A", which is the area in square micrometers (YES: micrometers, as this is the basic unit of measure + * in KLayout). + * It defines two ports, "A" and "C" for anode and cathode. + */ class DB_PUBLIC DeviceClassDiode : public db::DeviceClass { public: + DeviceClassDiode (); + virtual db::DeviceClass *clone () const + { + return new DeviceClassDiode (*this); + } + virtual bool combine_devices (Device *a, Device *b) const; }; +/** + * @brief A basic MOSFET device class + * A MOSFET defines four parameters: "W" for the gate width in micrometers, "L" for the gate length in micrometers, + * "AS" for the source area and "AD" for the drain area. + * The MOSFET device defines three ports, "S", "D" and "G" for source, drain and gate. + */ class DB_PUBLIC DeviceClassMOSTransistor : public db::DeviceClass { public: + DeviceClassMOSTransistor (); + virtual db::DeviceClass *clone () const + { + return new DeviceClassMOSTransistor (*this); + } -}; - -class DB_PUBLIC DeviceClassBipolarTransistor - : public db::DeviceClass -{ -public: - - + virtual bool combine_devices (Device *a, Device *b) const; }; } diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc new file mode 100644 index 000000000..8e5b30908 --- /dev/null +++ b/src/db/db/dbNetlistDeviceExtractor.cc @@ -0,0 +1,170 @@ + +/* + + 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 + +*/ + +#include "dbNetlistDeviceExtractor.h" +#include "dbHierNetworkProcessor.h" +#include "dbNetlistProperty.h" +#include "dbRegion.h" + +namespace db +{ + +NetlistDeviceExtractor::NetlistDeviceExtractor () + : mp_layout (0), m_cell_index (0), mp_circuit (0) +{ + m_device_name_index = 0; + m_propname_id = 0; +} + +NetlistDeviceExtractor::~NetlistDeviceExtractor () +{ + // .. nothing yet .. +} + +void NetlistDeviceExtractor::initialize (db::Netlist *nl) +{ + m_device_classes.clear (); + m_device_name_index = 0; + m_propname_id = 0; + m_netlist.reset (nl); + create_device_classes (); +} + +static void insert_into_region (const db::PolygonRef &s, const db::ICplxTrans &tr, db::Region ®ion) +{ + region.insert (s.obj ().transformed (tr * db::ICplxTrans (s.trans ()))); +} + +void NetlistDeviceExtractor::extract (db::Layout &layout, db::Cell &cell, const std::vector &layers) +{ + typedef db::PolygonRef shape_type; + db::ShapeIterator::flags_type shape_iter_flags = db::ShapeIterator::Polygons; + + mp_layout = &layout; + // port properties are kept in property index 0 + m_propname_id = mp_layout->properties_repository ().prop_name_id (tl::Variant (int (0))); + + tl_assert (m_netlist.get () != 0); + + std::set called_cells; + called_cells.insert (cell.cell_index ()); + cell.collect_called_cells (called_cells); + + db::Connectivity device_conn = get_connectivity (layout, layers); + + db::hier_clusters device_clusters; + device_clusters.build (layout, cell, shape_iter_flags, device_conn); + + for (std::set::const_iterator ci = called_cells.begin (); ci != called_cells.end (); ++ci) { + + m_cell_index = *ci; + + mp_circuit = new db::Circuit (); + mp_circuit->set_cell_index (*ci); + mp_circuit->set_name (layout.cell_name (*ci)); + m_netlist->add_circuit (mp_circuit); + + db::connected_clusters cc = device_clusters.clusters_per_cell (*ci); + for (db::connected_clusters::all_iterator c = cc.begin_all (); !c.at_end(); ++c) { + + if (! cc.is_root (*c)) { + continue; + } + + // build layer geometry from the cluster found + + std::vector layer_geometry; + layer_geometry.resize (layers.size ()); + + for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { + db::Region &r = layer_geometry [l - layers.begin ()]; + for (db::recursive_cluster_shape_iterator si (device_clusters, *l, *ci, *c); ! si.at_end(); ++si) { + insert_into_region (*si, si.trans (), r); + } + } + + extract_devices (layer_geometry); + + } + + } +} + +void NetlistDeviceExtractor::create_device_classes () +{ + // .. the default implementation does nothing .. +} + +db::Connectivity NetlistDeviceExtractor::get_connectivity (const db::Layout & /*layout*/, const std::vector & /*layers*/) const +{ + // .. the default implementation does nothing .. + return db::Connectivity (); +} + +void NetlistDeviceExtractor::extract_devices (const std::vector & /*layer_geometry*/) +{ + // .. the default implementation does nothing .. +} + +void NetlistDeviceExtractor::register_device_class (DeviceClass *device_class) +{ + tl_assert (m_netlist.get () != 0); + m_netlist->add_device_class (device_class); + m_device_classes.push_back (device_class); +} + +Device *NetlistDeviceExtractor::create_device (unsigned int device_class_index) +{ + tl_assert (mp_circuit != 0); + tl_assert (device_class_index < m_device_classes.size ()); + Device *device = new Device (m_device_classes[device_class_index], tl::to_string (++m_device_name_index)); + mp_circuit->add_device (device); + return device; +} + +void NetlistDeviceExtractor::define_port (Device *device, size_t port_id, size_t layer_index, const db::Polygon &polygon) +{ + tl_assert (mp_layout != 0); + + // Build a property set for the DevicePortProperty + db::PropertiesRepository::properties_set ps; + tl::Variant &v = ps.insert (std::make_pair (m_propname_id, tl::Variant ()))->second; + v = tl::Variant (new db::DevicePortProperty (db::NetPortRef (device, port_id)), db::NetlistProperty::variant_class (), true); + db::properties_id_type pi = mp_layout->properties_repository ().properties_id (ps); + + db::PolygonRef pr (polygon, mp_layout->shape_repository ()); + mp_layout->cell (m_cell_index).shapes (layer_index).insert (db::PolygonRefWithProperties (pr, pi)); +} + +void NetlistDeviceExtractor::define_port (Device *device, size_t port_id, size_t layer_index, const db::Box &box) +{ + define_port (device, port_id, layer_index, db::Polygon (box)); +} + +void NetlistDeviceExtractor::define_port (Device *device, size_t port_id, size_t layer_index, const db::Point &point) +{ + // NOTE: we add one DBU to the "point" to prevent it from vanishing + db::Vector dv (1, 1); + define_port (device, port_id, layer_index, db::Polygon (db::Box (point - dv, point + dv))); +} + +} diff --git a/src/db/db/dbNetlistDeviceExtractor.h b/src/db/db/dbNetlistDeviceExtractor.h index b486b4e23..cf585e3e6 100644 --- a/src/db/db/dbNetlistDeviceExtractor.h +++ b/src/db/db/dbNetlistDeviceExtractor.h @@ -33,6 +33,12 @@ namespace db { +/** + * @brief Implements the device extraction for a specific setup + * + * This class can be reimplemented to provide the basic algorithms for + * device extraction. See the virtual methods below. + */ class DB_PUBLIC NetlistDeviceExtractor : public gsi::ObjectBase { @@ -58,6 +64,9 @@ public: /** * @brief Performs the extraction * + * layout and cell specify the layout and the top cell from which to perform the + * extraction. + * * The netlist will be filled with circuits (unless not present yet) to represent the * cells from the layout. * @@ -67,15 +76,10 @@ public: * the nets later to associate nets with device ports. * * The definition of the input layers is device class specific. + * + * NOTE: The extractor expects "PolygonRef" type layers. */ - 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; + void extract (Layout &layout, Cell &cell, const std::vector &layers); /** * @brief Creates the device classes @@ -87,8 +91,10 @@ public: /** * @brief Gets the connectivity object used to extract the device geometry + * This method shall raise an error, if the input layer are not properly defined (e.g. + * too few etc.) */ - virtual db::Connectivity get_connectivity (const std::vector &layers) const; + virtual db::Connectivity get_connectivity (const db::Layout &layout, const std::vector &layers) const; /** * @brief Extracts the devices from the given shape cluster @@ -143,10 +149,13 @@ protected: } private: + tl::weak_ptr m_netlist; db::Layout *mp_layout; + db::properties_id_type m_propname_id; db::cell_index_type m_cell_index; - db::Netlist *mp_netlist; db::Circuit *mp_circuit; + std::vector m_device_classes; + unsigned int m_device_name_index; }; }