diff --git a/src/db/db/db.pro b/src/db/db/db.pro index dde3156b3..ba81bd02b 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -150,7 +150,8 @@ SOURCES = \ dbNetlistExtractor.cc \ gsiDeclDbNetlistDeviceClasses.cc \ gsiDeclDbNetlistDeviceExtractor.cc \ - gsiDeclDbHierNetworkProcessor.cc + gsiDeclDbHierNetworkProcessor.cc \ + dbNetlistDeviceExtractorClasses.cc HEADERS = \ dbArray.h \ @@ -264,7 +265,8 @@ HEADERS = \ dbNetlist.h \ dbNetlistDeviceClasses.h \ dbNetlistDeviceExtractor.h \ - dbNetlistExtractor.h + dbNetlistExtractor.h \ + dbNetlistDeviceExtractorClasses.h !equals(HAVE_QT, "0") { diff --git a/src/db/db/dbNetlistDeviceExtractorClasses.cc b/src/db/db/dbNetlistDeviceExtractorClasses.cc new file mode 100644 index 000000000..0eb21f6cc --- /dev/null +++ b/src/db/db/dbNetlistDeviceExtractorClasses.cc @@ -0,0 +1,128 @@ + +/* + + 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 "dbNetlistDeviceExtractorClasses.h" +#include "dbNetlistDeviceClasses.h" + +// --------------------------------------------------------------------------------- +// NetlistDeviceExtractorMOS3Transistor implementation + +namespace db +{ + +NetlistDeviceExtractorMOS3Transistor::NetlistDeviceExtractorMOS3Transistor (const std::string &name) + : db::NetlistDeviceExtractor (name) +{ + // .. nothing yet .. +} + +void NetlistDeviceExtractorMOS3Transistor::setup () +{ + define_layer ("SD", "Source/drain diffusion"); + define_layer ("G", "Gate"); + define_layer ("P", "Poly"); + + register_device_class (new db::DeviceClassMOS3Transistor ()); +} + +db::Connectivity NetlistDeviceExtractorMOS3Transistor::get_connectivity (const db::Layout & /*layout*/, const std::vector &layers) const +{ + tl_assert (layers.size () == 3); + + unsigned int diff = layers [0]; + unsigned int gate = layers [1]; + // not used for device recognition: poly (2), but used for producing the gate terminals + + // The layer definition is diff, gate + db::Connectivity conn; + // collect all connected diffusion shapes + conn.connect (diff, diff); + // collect all connected gate shapes + conn.connect (gate, gate); + // connect gate with diff to detect gate/diffusion boundary + conn.connect (diff, gate); + return conn; +} + +void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector &layer_geometry) +{ + const db::Region &rdiff = layer_geometry [0]; + const db::Region &rgates = layer_geometry [1]; + + for (db::Region::const_iterator p = rgates.begin_merged (); !p.at_end (); ++p) { + + db::Region rgate (*p); + db::Region rdiff2gate = rdiff.selected_interacting (rgate); + + if (rdiff2gate.empty ()) { + error (tl::to_string (tr ("Gate shape touches no diffusion - ignored")), *p); + } else { + + unsigned int terminal_geometry_index = 0; + unsigned int gate_geometry_index = 2; + + if (rdiff2gate.size () != 2) { + error (tl::sprintf (tl::to_string (tr ("Expected two polygons on diff interacting one gate shape (found %d) - gate shape ignored")), int (rdiff2gate.size ())), *p); + continue; + } + + db::Edges edges (rgate.edges () & rdiff2gate.edges ()); + if (edges.size () != 2) { + error (tl::sprintf (tl::to_string (tr ("Expected two edges interacting gate/diff (found %d) - width and length may be incorrect")), int (edges.size ())), *p); + continue; + } + + if (! p->is_box ()) { + error (tl::to_string (tr ("Gate shape is not a box - width and length may be incorrect")), *p); + } + + db::Device *device = create_device (); + + device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, dbu () * edges.length () * 0.5); + device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, dbu () * (p->perimeter () - edges.length ()) * 0.5); + + int diff_index = 0; + for (db::Region::const_iterator d = rdiff2gate.begin (); !d.at_end () && diff_index < 2; ++d, ++diff_index) { + + // count the number of gate shapes attached to this shape and distribute the area of the + // diffusion region to the number of gates + int n = rgates.selected_interacting (db::Region (*d)).size (); + tl_assert (n > 0); + + device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_AS : db::DeviceClassMOS3Transistor::param_id_AD, dbu () * dbu () * d->area () / double (n)); + + define_terminal (device, diff_index == 0 ? db::DeviceClassMOS3Transistor::terminal_id_S : db::DeviceClassMOS3Transistor::terminal_id_D, terminal_geometry_index, *d); + + } + + define_terminal (device, db::DeviceClassMOS3Transistor::terminal_id_G, gate_geometry_index, *p); + + // output the device for debugging + device_out (device, rdiff2gate, rgate); + + } + + } +} + +} diff --git a/src/db/db/dbNetlistDeviceExtractorClasses.h b/src/db/db/dbNetlistDeviceExtractorClasses.h new file mode 100644 index 000000000..7d8e9e09f --- /dev/null +++ b/src/db/db/dbNetlistDeviceExtractorClasses.h @@ -0,0 +1,81 @@ + +/* + + 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_dbNetlistDeviceExtractorClasses +#define _HDR_dbNetlistDeviceExtractorClasses + +#include "dbNetlistDeviceExtractor.h" + +namespace db +{ + +/** + * @brief A device extractor for a three-terminal MOS transistor + * + * This class supplies the generic extractor for a MOS device. + * The device is defined by two basic input layers: the diffusion area + * (source and drain) and the gate area. It requires a third layer + * (poly) to put the gate terminals on. The separation between poly + * and allows separating the device recognition layer (gate) from the + * conductive layer. + * + * The device class produced by this extractor is DeviceClassMOS3Transistor. + * The extractor extracts the four parameters of this class: L, W, AS and AD. + * + * The diffusion area is distributed on the number of gates connecting to + * the particular source or drain area. + */ +class DB_PUBLIC NetlistDeviceExtractorMOS3Transistor + : public db::NetlistDeviceExtractor +{ +public: + NetlistDeviceExtractorMOS3Transistor (const std::string &name); + + virtual void setup (); + virtual db::Connectivity get_connectivity (const db::Layout &layout, const std::vector &layers) const; + virtual void extract_devices (const std::vector &layer_geometry); + +protected: + /** + * @brief A cappback when the device is produced + * This callback is provided as a debugging port + */ + virtual void device_out (const db::Device * /*device*/, const db::Region & /*diff*/, const db::Region & /*gate*/) + { + // .. no specific implementation .. + } +}; + +} + +namespace tl +{ + +template<> struct tl::type_traits : public tl::type_traits +{ + typedef tl::false_tag has_copy_constructor; + typedef tl::false_tag has_default_constructor; +}; + +} + +#endif diff --git a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc index 87fe8df86..f56ffcb94 100644 --- a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc +++ b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc @@ -22,6 +22,7 @@ #include "gsiDecl.h" #include "dbNetlistDeviceExtractor.h" +#include "dbNetlistDeviceExtractorClasses.h" namespace { @@ -212,16 +213,32 @@ Class decl_dbNetlistDeviceExtractorLa "This class has been introduced in version 0.26." ); -Class decl_dbNetlistDeviceExtractor ("db", "NetlistDeviceExtractorImpl", - gsi::method ("name", &NetlistDeviceExtractorImpl::name, +Class decl_dbNetlistDeviceExtractor ("db", "DeviceExtractorBase", + gsi::method ("name", &db::NetlistDeviceExtractor::name, "@brief Gets the name of the device extractor and the device class." ) + + gsi::iterator ("each_layer_definition", &db::NetlistDeviceExtractor::begin_layer_definitions, &db::NetlistDeviceExtractor::end_layer_definitions, + "@brief Iterates over all layer definitions." + ) + + gsi::iterator ("each_error", &db::NetlistDeviceExtractor::begin_errors, &db::NetlistDeviceExtractor::end_errors, + "@brief Iterates over all errors collected in the device extractor." + ), + "@brief The base class for all device extractors.\n" + "This is an abstract base class for device extractors. See \\NetlistDeviceExtractor for a generic " + "class which you can reimplement to supply your own customized device extractor. " + "In many cases using one of the preconfigured specific device extractors may be useful already and " + "it's not required to implement a custom one. For an example about a preconfigured device extractor see " + "\\DeviceExtractorMOS3Transistor.\n" + "\n" + "This class cannot and should not be instantiated explicitly. Use one of the subclasses instead.\n" + "\n" + "This class has been introduced in version 0.26." +); + +Class decl_NetlistDeviceExtractorImpl (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractor", gsi::method ("name=", &NetlistDeviceExtractorImpl::set_name, "@brief Sets the name of the device extractor and the device class." ) + - gsi::iterator ("each_layer_definition", &NetlistDeviceExtractorImpl::begin_layer_definitions, &NetlistDeviceExtractorImpl::end_layer_definitions, - "@brief Iterates over all layer definitions." - ) + gsi::callback ("setup", &NetlistDeviceExtractorImpl::setup, &NetlistDeviceExtractorImpl::cb_setup, "@brief Sets up the extractor.\n" "This method is supposed to set up the device extractor. This involves three basic steps:\n" @@ -368,4 +385,34 @@ Class decl_dbNetlistDeviceExtractor ("db", "NetlistD "This class has been introduced in version 0.26." ); +db::NetlistDeviceExtractorMOS3Transistor *make_mos3_extractor (const std::string &name) +{ + return new db::NetlistDeviceExtractorMOS3Transistor (name); +} + +Class decl_NetlistDeviceExtractorMOS3Transistor (decl_dbNetlistDeviceExtractor, "db", "DeviceExtractorMOS3Transistor", + gsi::constructor ("new", &make_mos3_extractor, gsi::arg ("name"), + "@brief Creates a new device extractor with the given name." + ), + "@brief A device extractor for a three-terminal MOS transistor\n" + "\n" + "This class supplies the generic extractor for a MOS device.\n" + "The device is defined by two basic input layers: the diffusion area\n" + "(source and drain) and the gate area. It requires a third layer\n" + "(poly) to put the gate terminals on. The separation between poly\n" + "and allows separating the device recognition layer (gate) from the\n" + "conductive layer.\n" + "\n" + "The device class produced by this extractor is \\DeviceClassMOS3Transistor.\n" + "The extractor extracts the four parameters of this class: L, W, AS and AD.\n" + "\n" + "The diffusion area is distributed on the number of gates connecting to\n" + "the particular source or drain area.\n" + "\n" + "This class is a closed one and methods cannot be reimplemented. To reimplement " + "specific methods, see \\DeviceExtractor.\n" + "\n" + "This class has been introduced in version 0.26." +); + } diff --git a/src/db/unit_tests/dbNetlistExtractorTests.cc b/src/db/unit_tests/dbNetlistExtractorTests.cc index 3ee586167..2f50910af 100644 --- a/src/db/unit_tests/dbNetlistExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistExtractorTests.cc @@ -21,7 +21,7 @@ */ -#include "dbNetlistDeviceExtractor.h" +#include "dbNetlistDeviceExtractorClasses.h" #include "dbNetlistExtractor.h" #include "dbNetlistDeviceClasses.h" #include "dbLayout.h" @@ -59,11 +59,11 @@ static std::string device_name (const db::Device &device) } class MOSFETExtractor - : public db::NetlistDeviceExtractor + : public db::NetlistDeviceExtractorMOS3Transistor { public: MOSFETExtractor (const std::string &name, db::Layout *debug_out) - : db::NetlistDeviceExtractor (name), mp_debug_out (debug_out), m_ldiff (0), m_lgate (0) + : db::NetlistDeviceExtractorMOS3Transistor (name), mp_debug_out (debug_out), m_ldiff (0), m_lgate (0) { if (mp_debug_out) { m_ldiff = mp_debug_out->insert_layer (db::LayerProperties (100, 0)); @@ -71,95 +71,6 @@ public: } } - virtual void setup () - { - define_layer ("SD", "Source/drain diffusion"); - define_layer ("G", "Gate"); - define_layer ("P", "Poly"); - - register_device_class (new db::DeviceClassMOS3Transistor ()); - } - - virtual db::Connectivity get_connectivity (const db::Layout & /*layout*/, const std::vector &layers) const - { - tl_assert (layers.size () == 3); - - unsigned int diff = layers [0]; - unsigned int gate = layers [1]; - // not used for device recognition: poly (2), but used for producing the gate terminals - - // The layer definition is diff, gate - db::Connectivity conn; - // collect all connected diffusion shapes - conn.connect (diff, diff); - // collect all connected gate shapes - conn.connect (gate, gate); - // connect gate with diff to detect gate/diffusion boundary - conn.connect (diff, gate); - return conn; - } - - virtual void extract_devices (const std::vector &layer_geometry) - { - const db::Region &rdiff = layer_geometry [0]; - const db::Region &rgates = layer_geometry [1]; - - for (db::Region::const_iterator p = rgates.begin_merged (); !p.at_end (); ++p) { - - db::Region rgate (*p); - db::Region rdiff2gate = rdiff.selected_interacting (rgate); - - if (rdiff2gate.empty ()) { - error (tl::to_string (tr ("Gate shape touches no diffusion - ignored")), *p); - } else { - - unsigned int terminal_geometry_index = 0; - unsigned int gate_geometry_index = 2; - - if (rdiff2gate.size () != 2) { - error (tl::sprintf (tl::to_string (tr ("Expected two polygons on diff interacting one gate shape (found %d) - gate shape ignored")), int (rdiff2gate.size ())), *p); - continue; - } - - db::Edges edges (rgate.edges () & rdiff2gate.edges ()); - if (edges.size () != 2) { - error (tl::sprintf (tl::to_string (tr ("Expected two edges interacting gate/diff (found %d) - width and length may be incorrect")), int (edges.size ())), *p); - continue; - } - - if (! p->is_box ()) { - error (tl::to_string (tr ("Gate shape is not a box - width and length may be incorrect")), *p); - } - - db::Device *device = create_device (); - - device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_W, dbu () * edges.length () * 0.5); - device->set_parameter_value (db::DeviceClassMOS3Transistor::param_id_L, dbu () * (p->perimeter () - edges.length ()) * 0.5); - - int diff_index = 0; - for (db::Region::const_iterator d = rdiff2gate.begin (); !d.at_end () && diff_index < 2; ++d, ++diff_index) { - - // count the number of gate shapes attached to this shape and distribute the area of the - // diffusion region to the number of gates - int n = rgates.selected_interacting (db::Region (*d)).size (); - tl_assert (n > 0); - - device->set_parameter_value (diff_index == 0 ? db::DeviceClassMOS3Transistor::param_id_AS : db::DeviceClassMOS3Transistor::param_id_AD, dbu () * dbu () * d->area () / double (n)); - - define_terminal (device, diff_index == 0 ? db::DeviceClassMOS3Transistor::terminal_id_S : db::DeviceClassMOS3Transistor::terminal_id_D, terminal_geometry_index, *d); - - } - - define_terminal (device, db::DeviceClassMOS3Transistor::terminal_id_G, gate_geometry_index, *p); - - // output the device for debugging - device_out (device, rdiff2gate, rgate); - - } - - } - } - private: db::Layout *mp_debug_out; unsigned int m_ldiff, m_lgate;