WIP: implementation of basic device classes, device extractor.

This commit is contained in:
Matthias Koefferlein 2018-12-25 02:02:18 +01:00
parent 792a420e23
commit 97a1abb73f
5 changed files with 489 additions and 25 deletions

View File

@ -145,7 +145,9 @@ SOURCES = \
dbNetlistProperty.cc \
gsiDeclDbNetlistProperty.cc \
dbNetlist.cc \
gsiDeclDbNetlist.cc
gsiDeclDbNetlist.cc \
dbNetlistDeviceClasses.cc \
dbNetlistDeviceExtractor.cc
HEADERS = \
dbArray.h \

View File

@ -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;
}
}

View File

@ -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;
};
}

View File

@ -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 &region)
{
region.insert (s.obj ().transformed (tr * db::ICplxTrans (s.trans ())));
}
void NetlistDeviceExtractor::extract (db::Layout &layout, db::Cell &cell, const std::vector<unsigned int> &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<db::cell_index_type> 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<shape_type> device_clusters;
device_clusters.build (layout, cell, shape_iter_flags, device_conn);
for (std::set<db::cell_index_type>::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<shape_type> cc = device_clusters.clusters_per_cell (*ci);
for (db::connected_clusters<shape_type>::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<db::Region> layer_geometry;
layer_geometry.resize (layers.size ());
for (std::vector<unsigned int>::const_iterator l = layers.begin (); l != layers.end (); ++l) {
db::Region &r = layer_geometry [l - layers.begin ()];
for (db::recursive_cluster_shape_iterator<shape_type> 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<unsigned int> & /*layers*/) const
{
// .. the default implementation does nothing ..
return db::Connectivity ();
}
void NetlistDeviceExtractor::extract_devices (const std::vector<db::Region> & /*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)));
}
}

View File

@ -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<unsigned int> &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<unsigned int> &layers) const;
void extract (Layout &layout, Cell &cell, const std::vector<unsigned int> &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<unsigned int> &layers) const;
virtual db::Connectivity get_connectivity (const db::Layout &layout, const std::vector<unsigned int> &layers) const;
/**
* @brief Extracts the devices from the given shape cluster
@ -143,10 +149,13 @@ protected:
}
private:
tl::weak_ptr<db::Netlist> 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<db::DeviceClass *> m_device_classes;
unsigned int m_device_name_index;
};
}