mirror of https://github.com/KLayout/klayout.git
WIP: added algorithm for combining devices - needs testing.
This commit is contained in:
parent
e3b795e334
commit
764667d8e8
|
|
@ -256,7 +256,9 @@ HEADERS = \
|
|||
dbLocalOperation.h \
|
||||
dbHierProcessor.h \
|
||||
dbNetlistProperty.h \
|
||||
dbNetlist.h
|
||||
dbNetlist.h \
|
||||
dbNetlistDeviceClasses.h \
|
||||
dbNetlistDeviceExtractor.h
|
||||
|
||||
!equals(HAVE_QT, "0") {
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
#include "dbNetlist.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
|
|
@ -648,6 +650,173 @@ void Circuit::connect_pin (size_t pin_id, Net *net)
|
|||
}
|
||||
}
|
||||
|
||||
void Circuit::purge_nets ()
|
||||
{
|
||||
std::vector<db::Net *> 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<db::Net *>::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<db::DevicePortDefinition> &pd = d->device_class ()->port_definitions ();
|
||||
for (std::vector<db::DevicePortDefinition>::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<const db::Net *> key_type;
|
||||
std::map<key_type, std::vector<db::Device *> > 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<db::DevicePortDefinition> &ports = cls.port_definitions ();
|
||||
for (std::vector<db::DevicePortDefinition>::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<key_type, std::vector<db::Device *> >::iterator cc = combination_candidates.begin (); cc != combination_candidates.end (); ++cc) {
|
||||
|
||||
std::vector<db::Device *> &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<db::Device *, db::Device *> 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 <class T>
|
||||
static bool same_or_swapped (const std::pair<T, T> &p1, const std::pair<T, T> &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<db::Device *, db::Device *> 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<const db::Net *> other_nets;
|
||||
|
||||
const std::vector<db::DevicePortDefinition> &ports = cls.port_definitions ();
|
||||
for (std::vector<db::DevicePortDefinition>::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
|
||||
|
||||
|
|
|
|||
|
|
@ -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<const Circuit *, Circuit *> &map);
|
||||
void translate_device_classes (const std::map<const DeviceClass *, DeviceClass *> &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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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<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;
|
||||
|
||||
/**
|
||||
* @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<unsigned int> &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<db::Region> &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
|
||||
Loading…
Reference in New Issue