klayout/src/db/db/dbNetlistDeviceExtractor.h

575 lines
16 KiB
C++

/*
KLayout Layout Viewer
Copyright (C) 2006-2022 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 "dbLayout.h"
#include "dbHierNetworkProcessor.h"
#include "dbDeepShapeStore.h"
#include "dbRegion.h"
#include "dbNetShape.h"
#include "gsiObject.h"
namespace db
{
/**
* @brief An error object for the netlist device extractor
*
* The device extractor will keep errors using objects of this kind.
*/
class DB_PUBLIC NetlistDeviceExtractorError
{
public:
/**
* @brief Creates an error
*/
NetlistDeviceExtractorError ();
/**
* @brief Creates an error with a cell name and a message (the minimum information)
*/
NetlistDeviceExtractorError (const std::string &cell_name, const std::string &msg);
/**
* @brief The category name of the error
* Specifying the category name is optional. If a category is given, it will be used for
* the report.
*/
const std::string &category_name () const
{
return m_category_name;
}
/**
* @brief Sets the category name
*/
void set_category_name (const std::string &s)
{
m_category_name = s;
}
/**
* @brief The category description of the error
* Specifying the category description is optional. If a category is given, this attribute will
* be used for the category description.
*/
const std::string &category_description () const
{
return m_category_description;
}
/**
* @brief Sets the category description
*/
void set_category_description (const std::string &s)
{
m_category_description = s;
}
/**
* @brief Gets the geometry for this error
* Not all errors may specify a geometry. In this case, the polygon is empty.
*/
const db::DPolygon &geometry () const
{
return m_geometry;
}
/**
* @brief Sets the geometry
*/
void set_geometry (const db::DPolygon &g)
{
m_geometry = g;
}
/**
* @brief Gets the message for this error
*/
const std::string &message () const
{
return m_message;
}
/**
* @brief Sets the message
*/
void set_message (const std::string &n)
{
m_message = n;
}
/**
* @brief Gets the cell name the error occurred in
*/
const std::string &cell_name () const
{
return m_cell_name;
}
/**
* @brief Sets the cell name
*/
void set_cell_name (const std::string &n)
{
m_cell_name = n;
}
/**
* @brief Formats this message for printing
*/
std::string to_string () const;
private:
std::string m_cell_name;
std::string m_message;
db::DPolygon m_geometry;
std::string m_category_name, m_category_description;
};
/**
* @brief Specifies a single layer from the device extractor
*/
class DB_PUBLIC NetlistDeviceExtractorLayerDefinition
{
public:
NetlistDeviceExtractorLayerDefinition ()
: index (0)
{
// .. nothing yet ..
}
NetlistDeviceExtractorLayerDefinition (const std::string &_name, const std::string &_description, size_t _index, size_t _fallback_index)
: name (_name), description (_description), index (_index), fallback_index (_fallback_index)
{
// .. nothing yet ..
}
/**
* @brief The formal name
*/
std::string name;
/**
* @brief The human-readable description
*/
std::string description;
/**
* @brief The index of the layer
*/
size_t index;
/**
* @brief The index of the fallback layer
* This is the layer to be used when this layer isn't specified for input or (more important) output
*/
size_t fallback_index;
};
/**
* @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, public tl::Object
{
public:
typedef std::list<db::NetlistDeviceExtractorError> error_list;
typedef error_list::const_iterator error_iterator;
typedef std::vector<db::NetlistDeviceExtractorLayerDefinition> layer_definitions;
typedef layer_definitions::const_iterator layer_definitions_iterator;
typedef std::map<std::string, db::ShapeCollection *> input_layers;
typedef db::hier_clusters<db::NetShape> hier_clusters_type;
/**
* @brief Constructor
*
* The name is the name of the device class of the devices generated.
*/
NetlistDeviceExtractor (const std::string &name);
/**
* @brief Destructor
*/
~NetlistDeviceExtractor ();
/**
* @brief Gets the name of the extractor and the device class
*/
const std::string &name ()
{
return m_name;
}
/**
* @brief Gets the property name for the device terminal annotation
* This name is used to attach the terminal ID to terminal shapes.
*/
static const tl::Variant &terminal_id_property_name ();
/**
* @brief Gets the property name for the device id annotation
* This name is used to attach the device ID to instances.
*/
static const tl::Variant &device_id_property_name ();
/**
* @brief Gets the property name for the device class annotation
* This name is used to attach the device class name to cells.
*/
static const tl::Variant &device_class_property_name ();
/**
* @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.
*
* Devices will be generated inside the netlist's circuits as they are extracted
* from the layout. Inside the layout, device terminal annotation shapes are created with the
* corresponding DeviceTerminalProperty objects attached. The will be used when extracting
* the nets later to associate nets with device terminals.
*
* The definition of the input layers is device class specific.
*/
void extract (Layout &layout, Cell &cell, const std::vector<unsigned int> &layers, Netlist *netlist, hier_clusters_type &clusters, double device_scaling = 1.0, const std::set<cell_index_type> *breakout_cells = 0);
/**
* @brief Extracts the devices from a list of regions
*
* This method behaves identical to the other "extract" method, but accepts
* named regions for input. These regions need to be of deep region type and
* originate from the same layout than the DeepShapeStore.
*/
void extract (DeepShapeStore &dss, unsigned int layout_index, const input_layers &layers, Netlist &netlist, hier_clusters_type &clusters, double device_scaling = 1.0);
/**
* @brief Gets the error iterator, begin
*/
error_iterator begin_errors ()
{
return m_errors.begin ();
}
/**
* @brief Gets the error iterator, end
*/
error_iterator end_errors ()
{
return m_errors.end ();
}
/**
* @brief Returns true, if there are errors
*/
bool has_errors () const
{
return ! m_errors.empty ();
}
/**
* @brief Gets the layer definition iterator, begin
*/
layer_definitions_iterator begin_layer_definitions () const
{
return m_layer_definitions.begin ();
}
/**
* @brief Gets the layer definition iterator, end
*/
layer_definitions_iterator end_layer_definitions () const
{
return m_layer_definitions.end ();
}
/**
* @brief Sets the name of the device class and the device extractor
*/
void set_name (const std::string &name)
{
m_name = name;
}
/**
* @brief Sets up the extractor
*
* This method is supposed to set up the device extractor. This involves two basic steps:
* defining the device classes and setting up the device layers.
*
* Use "register_device_class" to register the device class you need.
*
* The device layers need to be defined by calling "define_layer" once or several times.
*/
virtual void setup ();
/**
* @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 db::Layout &layout, 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_terminal" to define
* terminals 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);
/**
* @brief Registers a device class
* The device class object will become owned by the netlist and must not be deleted by
* the caller. The name of the device class will be changed to the name given to
* the device extractor.
* This method shall be used inside the implementation of "setup" to register
* the device classes.
*/
void register_device_class (DeviceClass *device_class);
/**
* @brief Defines a layer
* Each call will define one more layer for the device extraction.
* This method shall be used inside the implementation of "setup" to define
* the device layers. The actual geometries are later available to "extract_devices"
* in the order the layers are defined.
*/
const db::NetlistDeviceExtractorLayerDefinition &define_layer (const std::string &name, const std::string &description = std::string ());
/**
* @brief Defines a layer with a fallback layer
* Like "define_layer" without fallback layer, but will fall back to the given layer
* (by index) if this layer isn't specified for input or terminal markup.
*/
const db::NetlistDeviceExtractorLayerDefinition &define_layer (const std::string &name, size_t fallback, const std::string &description = std::string ());
/**
* @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 ();
/**
* @brief Gets the device class used during extraction
*
* This member is set in 'extract_devices' and holds the device class object used during extraction.
*/
DeviceClass *device_class ()
{
return mp_device_class.get ();
}
/**
* @brief Defines a device terminal in the layout (a region)
*/
void define_terminal (Device *device, size_t terminal_id, size_t layer_index, const db::Region &region);
/**
* @brief Defines a device terminal in the layout (a polygon)
*/
void define_terminal (Device *device, size_t terminal_id, size_t layer_index, const db::Polygon &polygon);
/**
* @brief Defines a device terminal in the layout (a box)
*/
void define_terminal (Device *device, size_t terminal_id, size_t layer_index, const db::Box &box);
/**
* @brief Defines a point-like device terminal in the layout
*/
void define_terminal (Device *device, size_t terminal_id, size_t layer_index, const db::Point &point);
/**
* @brief Gets the database unit
*/
double dbu () const
{
return mp_layout->dbu ();
}
/**
* @brief Gets the scaled database unit
* Use this unit to compute device properties. It is the database unit multiplied with the
* device scaling factor.
*/
double sdbu () const
{
return m_device_scaling * mp_layout->dbu ();
}
/**
* @brief Gets the layout the shapes are taken from
* NOTE: this method is provided for testing purposes mainly.
*/
db::Layout *layout ()
{
return mp_layout;
}
/**
* @brief Gets the layout the shapes are taken from (const version)
* NOTE: this method is provided for testing purposes mainly.
*/
const db::Layout *layout () const
{
return mp_layout;
}
/**
* @brief Gets the cell index of the current cell
* NOTE: this method is provided for testing purposes mainly.
*/
db::cell_index_type cell_index () const
{
return m_cell_index;
}
/**
* @brief Issues an error with the given message
*/
void error (const std::string &msg);
/**
* @brief Issues an error with the given message and error shape
*/
void error (const std::string &msg, const db::DPolygon &poly);
/**
* @brief Issues an error with the given message and error shape
*/
void error (const std::string &msg, const db::Polygon &poly)
{
error (msg, poly.transformed (db::CplxTrans (dbu ())));
}
/**
* @brief Issues an error with the given category name, description and message
*/
void error (const std::string &category_name, const std::string &category_description, const std::string &msg);
/**
* @brief Issues an error with the given category name, description and message and error shape
*/
void error (const std::string &category_name, const std::string &category_description, const std::string &msg, const db::DPolygon &poly);
/**
* @brief Issues an error with the given category name, description and message and error shape
*/
void error (const std::string &category_name, const std::string &category_description, const std::string &msg, const db::Polygon &poly)
{
error (category_name, category_description, msg, poly.transformed (db::CplxTrans (dbu ())));
}
/**
* @brief Gets the name of the current cell
*/
std::string cell_name () const;
/**
* @brief Initializes the extractor
* This method will produce the device classes required for the device extraction.
* It is mainly provided for test purposes. Don't call it directly.
*/
void initialize (db::Netlist *nl);
private:
struct DeviceCellKey
{
DeviceCellKey () { }
bool operator== (const DeviceCellKey &other) const
{
if (geometry != other.geometry) {
return false;
}
if (parameters != other.parameters) {
return false;
}
return true;
}
bool operator< (const DeviceCellKey &other) const
{
if (geometry != other.geometry) {
return geometry < other.geometry;
}
if (parameters != other.parameters) {
return parameters < other.parameters;
}
return false;
}
std::map<size_t, std::map<unsigned int, std::set<db::NetShape> > > geometry;
std::map<size_t, double> parameters;
};
typedef std::map<unsigned int, std::vector<db::NetShape> > geometry_per_layer_type;
typedef std::map<size_t, geometry_per_layer_type> geometry_per_terminal_type;
tl::weak_ptr<db::Netlist> m_netlist;
db::Layout *mp_layout;
db::properties_id_type m_terminal_id_propname_id, m_device_id_propname_id, m_device_class_propname_id;
hier_clusters_type *mp_clusters;
db::cell_index_type m_cell_index;
const std::set<db::cell_index_type> *mp_breakout_cells;
double m_device_scaling;
db::Circuit *mp_circuit;
tl::weak_ptr<db::DeviceClass> mp_device_class;
std::string m_name;
layer_definitions m_layer_definitions;
std::vector<unsigned int> m_layers;
error_list m_errors;
std::map<size_t, std::pair<db::Device *, geometry_per_terminal_type> > m_new_devices;
std::map<DeviceCellKey, std::pair<db::cell_index_type, db::DeviceAbstract *> > m_device_cells;
// no copying
NetlistDeviceExtractor (const NetlistDeviceExtractor &);
NetlistDeviceExtractor &operator= (const NetlistDeviceExtractor &);
void extract_without_initialize (db::Layout &layout, db::Cell &cell, hier_clusters_type &clusters, const std::vector<unsigned int> &layers, double device_scaling, const std::set<cell_index_type> *breakout_cells);
void push_new_devices (const Vector &disp_cache);
void push_cached_devices (const tl::vector<Device *> &cached_devices, const db::Vector &disp_cache, const db::Vector &new_disp);
};
}
#endif