mirror of https://github.com/KLayout/klayout.git
WIP: refactoring - turning devices into cells for better backannotation.
This commit is contained in:
parent
3b0f4b3d78
commit
1af81b74d2
|
|
@ -159,7 +159,9 @@ SOURCES = \
|
|||
dbDeviceClass.cc \
|
||||
dbNet.cc \
|
||||
dbSubCircuit.cc \
|
||||
dbPin.cc
|
||||
dbPin.cc \
|
||||
dbLayoutToNetlistReader.cc \
|
||||
dbLayoutToNetlistWriter.cc
|
||||
|
||||
HEADERS = \
|
||||
dbArray.h \
|
||||
|
|
@ -283,7 +285,9 @@ HEADERS = \
|
|||
dbDevice.h \
|
||||
dbDeviceClass.h \
|
||||
dbPin.h \
|
||||
dbSubCircuit.h
|
||||
dbSubCircuit.h \
|
||||
dbLayoutToNetlistReader.h \
|
||||
dbLayoutToNetlistWriter.h
|
||||
|
||||
!equals(HAVE_QT, "0") {
|
||||
|
||||
|
|
|
|||
|
|
@ -340,7 +340,10 @@ DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator
|
|||
layout_index = (unsigned int) m_layouts.size ();
|
||||
|
||||
m_layouts.push_back (new LayoutHolder ());
|
||||
m_layouts.back ()->layout.dbu (si.layout ()->dbu ());
|
||||
|
||||
db::Layout &layout = m_layouts.back ()->layout;
|
||||
layout.hier_changed_event.add (this, &DeepShapeStore::invalidate_hier);
|
||||
layout.dbu (si.layout ()->dbu ());
|
||||
|
||||
m_layout_map[si] = layout_index;
|
||||
|
||||
|
|
@ -378,6 +381,12 @@ DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator
|
|||
return DeepLayer (this, layout_index, layer_index);
|
||||
}
|
||||
|
||||
void
|
||||
DeepShapeStore::invalidate_hier ()
|
||||
{
|
||||
m_delivery_mapping_cache.clear ();
|
||||
}
|
||||
|
||||
const db::CellMapping &
|
||||
DeepShapeStore::cell_mapping_to_original (size_t layout_index, db::Layout *into_layout, db::cell_index_type into_cell)
|
||||
{
|
||||
|
|
@ -409,8 +418,6 @@ DeepShapeStore::cell_mapping_to_original (size_t layout_index, db::Layout *into_
|
|||
// create from them. We need to consider however, that the hierarchy builder is allowed to create
|
||||
// variants which we cannot map.
|
||||
|
||||
bool any_skipped = false;
|
||||
|
||||
for (HierarchyBuilder::cell_map_type::const_iterator m = original_builder.begin_cell_map (); m != original_builder.end_cell_map (); ++m) {
|
||||
|
||||
HierarchyBuilder::cell_map_type::const_iterator mm = m;
|
||||
|
|
@ -425,16 +432,13 @@ DeepShapeStore::cell_mapping_to_original (size_t layout_index, db::Layout *into_
|
|||
|
||||
if (! skip) {
|
||||
cm->second.map (m->first.first, m->second);
|
||||
} else {
|
||||
any_skipped = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (any_skipped) {
|
||||
// Add new cells for the variants
|
||||
cm->second.create_missing_mapping (*into_layout, into_cell, *source_layout, source_top);
|
||||
}
|
||||
// Add new cells for the variants and (possible) devices which are cells added during the device
|
||||
// extraction process
|
||||
cm->second.create_missing_mapping (*into_layout, into_cell, *source_layout, source_top);
|
||||
|
||||
} else if (into_layout->cells () == 1) {
|
||||
|
||||
|
|
|
|||
|
|
@ -420,6 +420,7 @@ private:
|
|||
|
||||
struct LayoutHolder;
|
||||
|
||||
void invalidate_hier ();
|
||||
void add_ref (unsigned int layout, unsigned int layer);
|
||||
void remove_ref (unsigned int layout, unsigned int layer);
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ namespace db
|
|||
// Device class implementation
|
||||
|
||||
Device::Device ()
|
||||
: mp_device_class (0), m_id (0), mp_circuit (0)
|
||||
: mp_device_class (0), m_cell_index (std::numeric_limits<db::cell_index_type>::max ()), m_id (0), mp_circuit (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -46,13 +46,13 @@ Device::~Device ()
|
|||
}
|
||||
|
||||
Device::Device (DeviceClass *device_class, const std::string &name)
|
||||
: mp_device_class (device_class), m_name (name), m_id (0), mp_circuit (0)
|
||||
: mp_device_class (device_class), m_name (name), m_cell_index (std::numeric_limits<db::cell_index_type>::max ()), m_id (0), mp_circuit (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
Device::Device (const Device &other)
|
||||
: tl::Object (other), mp_device_class (0), m_id (0), mp_circuit (0)
|
||||
: tl::Object (other), mp_device_class (0), m_cell_index (std::numeric_limits<db::cell_index_type>::max ()), m_id (0), mp_circuit (0)
|
||||
{
|
||||
operator= (other);
|
||||
}
|
||||
|
|
@ -61,6 +61,10 @@ Device &Device::operator= (const Device &other)
|
|||
{
|
||||
if (this != &other) {
|
||||
m_name = other.m_name;
|
||||
m_position = other.m_position;
|
||||
m_cell_index = other.m_cell_index;
|
||||
m_terminal_cluster_ids = other.m_terminal_cluster_ids;
|
||||
m_parameters = other.m_parameters;
|
||||
mp_device_class = other.mp_device_class;
|
||||
}
|
||||
return *this;
|
||||
|
|
@ -79,6 +83,29 @@ void Device::set_name (const std::string &n)
|
|||
}
|
||||
}
|
||||
|
||||
void Device::set_position (const db::DPoint &pt)
|
||||
{
|
||||
m_position = pt;
|
||||
}
|
||||
|
||||
void Device::set_cell_index (db::cell_index_type ci)
|
||||
{
|
||||
m_cell_index = ci;
|
||||
}
|
||||
|
||||
size_t Device::cluster_id_for_terminal (size_t terminal_id) const
|
||||
{
|
||||
return terminal_id < m_terminal_cluster_ids.size () ? m_terminal_cluster_ids [terminal_id] : 0;
|
||||
}
|
||||
|
||||
void Device::set_cluster_id_for_terminal (size_t terminal_id, size_t cluster_id)
|
||||
{
|
||||
if (m_terminal_cluster_ids.size () <= terminal_id) {
|
||||
m_terminal_cluster_ids.resize (terminal_id + 1, 0);
|
||||
}
|
||||
m_terminal_cluster_ids [terminal_id] = cluster_id;
|
||||
}
|
||||
|
||||
void Device::set_terminal_ref_for_terminal (size_t terminal_id, Net::terminal_iterator iter)
|
||||
{
|
||||
if (m_terminal_refs.size () < terminal_id + 1) {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "dbCommon.h"
|
||||
#include "dbNet.h"
|
||||
#include "dbPoint.h"
|
||||
|
||||
#include "tlObject.h"
|
||||
|
||||
|
|
@ -127,6 +128,49 @@ public:
|
|||
return m_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the device position
|
||||
* The device position should be the center of the recognition shape or something similar.
|
||||
* Giving the device a position allows combining multiple devices with the same
|
||||
* relative geometry into a single cell.
|
||||
* The position has to be given in micrometer units.
|
||||
*/
|
||||
void set_position (const db::DPoint &pos);
|
||||
|
||||
/**
|
||||
* @brief Gets the device position
|
||||
*/
|
||||
const db::DPoint &position () const
|
||||
{
|
||||
return m_position;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the device cell index
|
||||
* In the layout, a device is represented by a cell. This attribute gives the index of this
|
||||
* cell.
|
||||
*/
|
||||
void set_cell_index (db::cell_index_type ci);
|
||||
|
||||
/**
|
||||
* @brief Gets the device cell index
|
||||
*/
|
||||
db::cell_index_type cell_index () const
|
||||
{
|
||||
return m_cell_index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the cluster ID for a given terminal
|
||||
* This attribute connects the device terminal with a terminal cluster
|
||||
*/
|
||||
size_t cluster_id_for_terminal (size_t terminal_id) const;
|
||||
|
||||
/**
|
||||
* @brief Sets the cluster ID for a given terminal
|
||||
*/
|
||||
void set_cluster_id_for_terminal (size_t terminal_id, size_t cluster_id);
|
||||
|
||||
/**
|
||||
* @brief Gets the net attached to a specific terminal
|
||||
* Returns 0 if no net is attached.
|
||||
|
|
@ -180,7 +224,10 @@ private:
|
|||
|
||||
DeviceClass *mp_device_class;
|
||||
std::string m_name;
|
||||
db::DPoint m_position;
|
||||
db::cell_index_type m_cell_index;
|
||||
std::vector<Net::terminal_iterator> m_terminal_refs;
|
||||
std::vector<size_t> m_terminal_cluster_ids;
|
||||
std::vector<double> m_parameters;
|
||||
size_t m_id;
|
||||
Circuit *mp_circuit;
|
||||
|
|
|
|||
|
|
@ -1664,6 +1664,11 @@ template <class T>
|
|||
void
|
||||
hier_clusters<T>::build_local_cluster (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn)
|
||||
{
|
||||
if (m_per_cell_clusters.find (cell.cell_index ()) != m_per_cell_clusters.end ()) {
|
||||
// skip pre-build clusters (from devices)
|
||||
return;
|
||||
}
|
||||
|
||||
std::string msg = tl::to_string (tr ("Computing local clusters for cell: ")) + std::string (layout.cell_name (cell.cell_index ()));
|
||||
if (tl::verbosity () >= 40) {
|
||||
tl::log << msg;
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ void LayoutToNetlist::extract_devices (db::NetlistDeviceExtractor &extractor, co
|
|||
if (! mp_netlist.get ()) {
|
||||
mp_netlist.reset (new db::Netlist ());
|
||||
}
|
||||
extractor.extract(m_dss, layers, mp_netlist.get ());
|
||||
extractor.extract(m_dss, layers, *mp_netlist, m_net_clusters);
|
||||
}
|
||||
|
||||
void LayoutToNetlist::connect (const db::Region &l)
|
||||
|
|
@ -183,7 +183,12 @@ void LayoutToNetlist::extract_netlist ()
|
|||
if (! mp_netlist.get ()) {
|
||||
mp_netlist.reset (new db::Netlist ());
|
||||
}
|
||||
m_netex.extract_nets(m_dss, m_conn, mp_netlist.get ());
|
||||
|
||||
m_net_clusters.clear ();
|
||||
|
||||
db::NetlistExtractor netex;
|
||||
netex.extract_nets(m_dss, m_conn, *mp_netlist, m_net_clusters);
|
||||
|
||||
m_netlist_extracted = true;
|
||||
}
|
||||
|
||||
|
|
@ -227,14 +232,6 @@ db::Netlist *LayoutToNetlist::netlist () const
|
|||
return mp_netlist.get ();
|
||||
}
|
||||
|
||||
const db::hier_clusters<db::PolygonRef> &LayoutToNetlist::net_clusters () const
|
||||
{
|
||||
if (! m_netlist_extracted) {
|
||||
throw tl::Exception (tl::to_string (tr ("The netlist has not been extracted yet")));
|
||||
}
|
||||
return m_netex.clusters ();
|
||||
}
|
||||
|
||||
template <class Tr>
|
||||
static void deliver_shape (const db::PolygonRef &pr, db::Region ®ion, const Tr &tr)
|
||||
{
|
||||
|
|
@ -261,26 +258,26 @@ static void deliver_shape (const db::PolygonRef &pr, db::Shapes &shapes, const T
|
|||
}
|
||||
|
||||
template <class To>
|
||||
static void deliver_shapes_of_net_recursive (const db::NetlistExtractor &netex, const db::Net &net, unsigned int layer_id, To &to)
|
||||
static void deliver_shapes_of_net_recursive (const db::hier_clusters<db::PolygonRef> &clusters, const db::Net &net, unsigned int layer_id, To &to)
|
||||
{
|
||||
const db::Circuit *circuit = net.circuit ();
|
||||
tl_assert (circuit != 0);
|
||||
|
||||
db::cell_index_type ci = circuit->cell_index ();
|
||||
|
||||
for (db::recursive_cluster_shape_iterator<db::PolygonRef> rci (netex.clusters (), layer_id, ci, net.cluster_id ()); !rci.at_end (); ++rci) {
|
||||
for (db::recursive_cluster_shape_iterator<db::PolygonRef> rci (clusters, layer_id, ci, net.cluster_id ()); !rci.at_end (); ++rci) {
|
||||
deliver_shape (*rci, to, rci.trans ());
|
||||
}
|
||||
}
|
||||
|
||||
template <class To>
|
||||
static void deliver_shapes_of_net_nonrecursive (const db::NetlistExtractor &netex, const db::Net &net, unsigned int layer_id, To &to)
|
||||
static void deliver_shapes_of_net_nonrecursive (const db::hier_clusters<db::PolygonRef> &clusters, const db::Net &net, unsigned int layer_id, To &to)
|
||||
{
|
||||
const db::Circuit *circuit = net.circuit ();
|
||||
tl_assert (circuit != 0);
|
||||
|
||||
db::cell_index_type ci = circuit->cell_index ();
|
||||
const db::local_cluster<db::PolygonRef> &lc = netex.clusters ().clusters_per_cell (ci).cluster_by_id (net.cluster_id ());
|
||||
const db::local_cluster<db::PolygonRef> &lc = clusters.clusters_per_cell (ci).cluster_by_id (net.cluster_id ());
|
||||
|
||||
for (db::local_cluster<db::PolygonRef>::shape_iterator s = lc.begin (layer_id); !s.at_end (); ++s) {
|
||||
deliver_shape (*s, to, db::UnitTrans ());
|
||||
|
|
@ -292,9 +289,9 @@ void LayoutToNetlist::shapes_of_net (const db::Net &net, const db::Region &of_la
|
|||
unsigned int lid = layer_of (of_layer);
|
||||
|
||||
if (! recursive) {
|
||||
deliver_shapes_of_net_nonrecursive (m_netex, net, lid, to);
|
||||
deliver_shapes_of_net_nonrecursive (m_net_clusters, net, lid, to);
|
||||
} else {
|
||||
deliver_shapes_of_net_recursive (m_netex, net, lid, to);
|
||||
deliver_shapes_of_net_recursive (m_net_clusters, net, lid, to);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -304,9 +301,9 @@ db::Region *LayoutToNetlist::shapes_of_net (const db::Net &net, const db::Region
|
|||
std::auto_ptr<db::Region> res (new db::Region ());
|
||||
|
||||
if (! recursive) {
|
||||
deliver_shapes_of_net_nonrecursive (m_netex, net, lid, *res);
|
||||
deliver_shapes_of_net_nonrecursive (m_net_clusters, net, lid, *res);
|
||||
} else {
|
||||
deliver_shapes_of_net_recursive (m_netex, net, lid, *res);
|
||||
deliver_shapes_of_net_recursive (m_net_clusters, net, lid, *res);
|
||||
}
|
||||
|
||||
return res.release ();
|
||||
|
|
@ -326,7 +323,7 @@ LayoutToNetlist::build_net_rec (const db::Net &net, db::Layout &target, db::Cell
|
|||
const db::Circuit *circuit = net.circuit ();
|
||||
tl_assert (circuit != 0);
|
||||
|
||||
const db::connected_clusters<db::PolygonRef> &clusters = m_netex.clusters ().clusters_per_cell (circuit->cell_index ());
|
||||
const db::connected_clusters<db::PolygonRef> &clusters = m_net_clusters.clusters_per_cell (circuit->cell_index ());
|
||||
typedef db::connected_clusters<db::PolygonRef>::connections_type connections_type;
|
||||
const connections_type &connections = clusters.connections_for_cluster (net.cluster_id ());
|
||||
for (connections_type::const_iterator c = connections.begin (); c != connections.end (); ++c) {
|
||||
|
|
@ -390,7 +387,7 @@ LayoutToNetlist::build_all_nets (const db::CellMapping &cmap, db::Layout &target
|
|||
continue;
|
||||
}
|
||||
|
||||
const db::connected_clusters<db::PolygonRef> &ccl = m_netex.clusters ().clusters_per_cell (c->cell_index ());
|
||||
const db::connected_clusters<db::PolygonRef> &ccl = m_net_clusters.clusters_per_cell (c->cell_index ());
|
||||
const db::local_cluster<db::PolygonRef> &cl = ccl.cluster_by_id (n->cluster_id ());
|
||||
|
||||
bool any_connections = ! ccl.connections_for_cluster (n->cluster_id ()).empty ();
|
||||
|
|
|
|||
|
|
@ -197,6 +197,14 @@ public:
|
|||
*/
|
||||
const db::Cell *internal_top_cell () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the connectivity object
|
||||
*/
|
||||
const db::Connectivity &connectivity () const
|
||||
{
|
||||
return m_conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the internal layer for a given extraction layer
|
||||
* This method is required to derive the internal layer index - for example for
|
||||
|
|
@ -227,7 +235,10 @@ public:
|
|||
* NOTE: the layer and cell indexes used inside this structure refer to the
|
||||
* internal layout.
|
||||
*/
|
||||
const db::hier_clusters<db::PolygonRef> &net_clusters () const;
|
||||
const db::hier_clusters<db::PolygonRef> &net_clusters () const
|
||||
{
|
||||
return m_net_clusters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all shapes of a specific net and layer.
|
||||
|
|
@ -327,7 +338,7 @@ private:
|
|||
db::RecursiveShapeIterator m_iter;
|
||||
db::DeepShapeStore m_dss;
|
||||
db::Connectivity m_conn;
|
||||
db::NetlistExtractor m_netex;
|
||||
db::hier_clusters<db::PolygonRef> m_net_clusters;
|
||||
std::auto_ptr<db::Netlist> mp_netlist;
|
||||
std::set<db::DeepLayer> m_dlrefs;
|
||||
bool m_netlist_extracted;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 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 "dbLayoutToNetlistReader.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 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_dbLayoutToNetlistReader
|
||||
#define HDR_dbLayoutToNetlistReader
|
||||
|
||||
#include "dbCommon.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
// ...
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,295 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 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 "dbLayoutToNetlistWriter.h"
|
||||
#include "dbLayoutToNetlist.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// LayoutToNetlistStandardWriter implementation
|
||||
|
||||
/**
|
||||
* Comments are introduced by hash: # ...
|
||||
* Names are words (alphanumerical plus "$", "_", ".") or enclosed in single or double quotes.
|
||||
* Escape character is backslash.
|
||||
* Separator is either , or whitespace. Keywords and names are case sensitive.
|
||||
* Short keys are provided for compacter representation. Short keys can be
|
||||
* non-alpha (e.g. "*") or empty.
|
||||
* Single-valued attributes can be given without brackets.
|
||||
* All dimensions are in units of database unit.
|
||||
*
|
||||
* Global statements:
|
||||
*
|
||||
* description(<text>) - an arbitrary description text
|
||||
* dbu(<dbu>) - specifies the database unit [short key: D]
|
||||
* top(<circuit>) - specifies the name of the top circuit [short key: T]
|
||||
* layer(<name>) - define a layer [short key: L]
|
||||
* connect(<layer1> <name> ...) - connects layer1 with the following layers [short key: C]
|
||||
* global(<layer> <net> ...) - connects a layer with the given global nets [short key: G]
|
||||
* circuit(<name> ...) - defines a circuit (cell) [short key: X]
|
||||
*
|
||||
* Inside the circuit:
|
||||
*
|
||||
* net(<name> ...) - specifies net geometry [short key: N]
|
||||
* device(<name> <class> ...) - defines a device [short key: D]
|
||||
* subcircuit(<name> ...) - defines a subcircuit [short key: X]
|
||||
*
|
||||
* Inside a net:
|
||||
*
|
||||
* polygon(<layer> <x> <y> ...) - defines a polygon [short key: P]
|
||||
* rect(<layer> <left> <bottom> <right> <top>)
|
||||
* - defines a rectangle [short key: R]
|
||||
*
|
||||
* Inside a device:
|
||||
*
|
||||
* param(<name> <value>) - defines a parameter [short key P]
|
||||
* terminal(<terminal-name> <net-name>)
|
||||
* - specifies connection of the terminal with
|
||||
* a net (short key: empty)
|
||||
* location(<x> <y>) - location of the device [short key L]
|
||||
*
|
||||
* Inside a subcircuit:
|
||||
*
|
||||
* location(<x> <y>) - location of the subcircuit [short key L]
|
||||
* rotation(<angle>) - rotation angle [short key O]
|
||||
* mirror - if specified, the instance is mirrored before rotation [short key M]
|
||||
* scale(<mag>) - magnification [short key *]
|
||||
* pin(<pin-name> <net-name>) - specifies connection of the pin with a net
|
||||
*/
|
||||
|
||||
static std::string description_key ("description");
|
||||
static std::string top_key ("top");
|
||||
static std::string dbu_key ("dbu");
|
||||
static std::string layer_key ("layer");
|
||||
static std::string text_key ("text");
|
||||
static std::string connect_key ("connect");
|
||||
static std::string global_key ("global");
|
||||
static std::string circuit_key ("circuit");
|
||||
static std::string net_key ("net");
|
||||
static std::string device_key ("device");
|
||||
static std::string subcircuit_key ("subcircuit");
|
||||
static std::string polygon_key ("polygon");
|
||||
static std::string rect_key ("rect");
|
||||
static std::string terminal_key ("terminal");
|
||||
static std::string label_key ("label");
|
||||
static std::string param_key ("param");
|
||||
static std::string location_key ("location");
|
||||
static std::string rotation_key ("rotation");
|
||||
static std::string mirror_key ("mirror");
|
||||
static std::string scale_key ("scale");
|
||||
static std::string pin_key ("pin");
|
||||
static std::string indent1 (" ");
|
||||
static std::string indent2 (" ");
|
||||
static std::string endl ("\n");
|
||||
|
||||
LayoutToNetlistStandardWriter::LayoutToNetlistStandardWriter (tl::OutputStream &stream)
|
||||
: mp_stream (&stream)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
static std::string name_for_layer (const db::Layout *layout, unsigned int l)
|
||||
{
|
||||
const db::LayerProperties &lp = layout->get_properties (l);
|
||||
if (lp.is_named ()) {
|
||||
return tl::to_word_or_quoted_string (lp.name);
|
||||
} else {
|
||||
return "L" + tl::to_string (l);
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n)
|
||||
{
|
||||
const db::Layout *ly = l2n->internal_layout ();
|
||||
const db::Netlist *nl = l2n->netlist ();
|
||||
|
||||
*mp_stream << top_key << "(" << tl::to_word_or_quoted_string (ly->cell_name (l2n->internal_top_cell ()->cell_index ())) << ")" << endl;
|
||||
*mp_stream << dbu_key << "(" << ly->dbu () << ")" << endl;
|
||||
|
||||
for (db::Connectivity::layer_iterator l = l2n->connectivity ().begin_layers (); l != l2n->connectivity ().end_layers (); ++l) {
|
||||
|
||||
*mp_stream << layer_key << "(" << name_for_layer (ly, *l) << ")" << endl;
|
||||
|
||||
db::Connectivity::layer_iterator ce = l2n->connectivity ().end_connected (*l);
|
||||
db::Connectivity::layer_iterator cb = l2n->connectivity ().begin_connected (*l);
|
||||
if (cb != ce) {
|
||||
*mp_stream << connect_key << "(" << name_for_layer (ly, *l);
|
||||
for (db::Connectivity::layer_iterator c = l2n->connectivity ().begin_connected (*l); c != ce; ++c) {
|
||||
*mp_stream << " " << name_for_layer (ly, *l);
|
||||
}
|
||||
*mp_stream << ")" << endl;
|
||||
}
|
||||
|
||||
db::Connectivity::global_nets_iterator ge = l2n->connectivity ().end_global_connections (*l);
|
||||
db::Connectivity::global_nets_iterator gb = l2n->connectivity ().begin_global_connections (*l);
|
||||
if (gb != ge) {
|
||||
*mp_stream << global_key << "(" << name_for_layer (ly, *l);
|
||||
for (db::Connectivity::global_nets_iterator g = gb; g != ge; ++g) {
|
||||
*mp_stream << " " << tl::to_word_or_quoted_string (l2n->connectivity ().global_net_name (*g));
|
||||
}
|
||||
*mp_stream << ")" << endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (db::Netlist::const_circuit_iterator x = nl->begin_circuits (); x != nl->end_circuits (); ++x) {
|
||||
*mp_stream << circuit_key << "(" << tl::to_word_or_quoted_string (x->name ()) << endl;
|
||||
write (l2n, *x);
|
||||
*mp_stream << ")" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const db::Circuit &circuit)
|
||||
{
|
||||
for (db::Circuit::const_net_iterator n = circuit.begin_nets (); n != circuit.end_nets (); ++n) {
|
||||
write (l2n, *n);
|
||||
}
|
||||
|
||||
for (db::Circuit::const_device_iterator d = circuit.begin_devices (); d != circuit.end_devices (); ++d) {
|
||||
write (l2n, *d);
|
||||
}
|
||||
|
||||
for (db::Circuit::const_subcircuit_iterator x = circuit.begin_subcircuits (); x != circuit.end_subcircuits (); ++x) {
|
||||
write (l2n, *x);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, class Tr>
|
||||
void write_points (tl::OutputStream &stream, const T &poly, const Tr &tr)
|
||||
{
|
||||
for (typename T::polygon_contour_iterator c = poly.begin_hull (); c != poly.end_hull (); ++c) {
|
||||
typename T::point_type pt = tr * *c;
|
||||
stream << " " << pt.x () << " " << pt.y ();
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist *l2n, const db::Net &net)
|
||||
{
|
||||
const db::Layout *ly = l2n->internal_layout ();
|
||||
const db::hier_clusters<db::PolygonRef> &clusters = l2n->net_clusters ();
|
||||
const db::Circuit *circuit = net.circuit ();
|
||||
const db::Connectivity &conn = l2n->connectivity ();
|
||||
|
||||
*mp_stream << indent1 << net_key << "(" << tl::to_word_or_quoted_string (net.expanded_name ()) << endl;
|
||||
|
||||
for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) {
|
||||
|
||||
const db::local_cluster<db::PolygonRef> &lc = clusters.clusters_per_cell (circuit->cell_index ()).cluster_by_id (net.cluster_id ());
|
||||
for (db::local_cluster<db::PolygonRef>::shape_iterator s = lc.begin (*l); ! s.at_end (); ++s) {
|
||||
|
||||
*mp_stream << indent2;
|
||||
|
||||
const db::Polygon &poly = s->obj ();
|
||||
if (poly.is_box ()) {
|
||||
|
||||
db::Box box = s->trans () * poly.box ();
|
||||
*mp_stream << rect_key << "(" << name_for_layer (ly, *l);
|
||||
*mp_stream << " " << box.left () << " " << box.bottom ();
|
||||
*mp_stream << " " << box.right () << " " << box.top ();
|
||||
*mp_stream << ")";
|
||||
|
||||
} else {
|
||||
|
||||
*mp_stream << polygon_key << "(" << name_for_layer (ly, *l);
|
||||
if (poly.holes () > 0) {
|
||||
db::SimplePolygon sp (poly);
|
||||
write_points (*mp_stream, sp, s->trans ());
|
||||
} else {
|
||||
write_points (*mp_stream, poly, s->trans ());
|
||||
}
|
||||
*mp_stream << ")";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
*mp_stream << indent1 << ")" << endl;
|
||||
}
|
||||
|
||||
void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist * /*l2n*/, const db::SubCircuit &subcircuit)
|
||||
{
|
||||
*mp_stream << indent1 << subcircuit_key << "(" << tl::to_word_or_quoted_string (subcircuit.name ());
|
||||
|
||||
const db::DCplxTrans &tr = subcircuit.trans ();
|
||||
if (tr.is_mag ()) {
|
||||
*mp_stream << " " << scale_key << "(" << tr.mag () << ")";
|
||||
}
|
||||
if (tr.is_mirror ()) {
|
||||
*mp_stream << " " << mirror_key;
|
||||
}
|
||||
if (fabs (tr.angle ()) > 1e-6) {
|
||||
*mp_stream << " " << rotation_key << "(" << tr.angle () << ")";
|
||||
}
|
||||
*mp_stream << " " << location_key << "(" << tr.disp ().x () << " " << tr.disp ().y () << ")";
|
||||
|
||||
// each pin in one line for more than 16 pins
|
||||
bool separate_lines = (subcircuit.circuit ()->pin_count () > 16);
|
||||
|
||||
if (separate_lines) {
|
||||
*mp_stream << endl;
|
||||
}
|
||||
|
||||
for (db::Circuit::const_pin_iterator p = subcircuit.circuit ()->begin_pins (); p != subcircuit.circuit ()->end_pins (); ++p) {
|
||||
if (separate_lines) {
|
||||
*mp_stream << indent2;
|
||||
} else {
|
||||
*mp_stream << " ";
|
||||
}
|
||||
*mp_stream << pin_key << "(" << tl::to_word_or_quoted_string (p->name ()) << " " << tl::to_word_or_quoted_string (subcircuit.net_for_pin (p->id ())->expanded_name ()) << ")";
|
||||
if (separate_lines) {
|
||||
*mp_stream << endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (separate_lines) {
|
||||
*mp_stream << indent1;
|
||||
}
|
||||
|
||||
*mp_stream << ")" << endl;
|
||||
}
|
||||
|
||||
void LayoutToNetlistStandardWriter::write (const db::LayoutToNetlist * /*l2n*/, const db::Device &device)
|
||||
{
|
||||
// @@@ TODO: add location
|
||||
|
||||
*mp_stream << indent1 << device_key << "(" << tl::to_word_or_quoted_string (device.name ());
|
||||
*mp_stream << " " << tl::to_word_or_quoted_string (device.device_class ()->name ());
|
||||
|
||||
const std::vector<DeviceParameterDefinition> &pd = device.device_class ()->parameter_definitions ();
|
||||
for (std::vector<DeviceParameterDefinition>::const_iterator i = pd.begin (); i != pd.end (); ++i) {
|
||||
*mp_stream << " " << param_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << device.parameter_value (i->id ()) << ")";
|
||||
}
|
||||
|
||||
const std::vector<DeviceTerminalDefinition> &td = device.device_class ()->terminal_definitions ();
|
||||
for (std::vector<DeviceTerminalDefinition>::const_iterator i = td.begin (); i != td.end (); ++i) {
|
||||
*mp_stream << " " << terminal_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << tl::to_word_or_quoted_string (device.net_for_terminal (i->id ())->expanded_name ()) << ")";
|
||||
}
|
||||
|
||||
*mp_stream << ")" << endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 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_dbLayoutToNetlistWriter
|
||||
#define HDR_dbLayoutToNetlistWriter
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
class LayoutToNetlist;
|
||||
class Net;
|
||||
class Circuit;
|
||||
class SubCircuit;
|
||||
class Device;
|
||||
|
||||
/**
|
||||
* @brief The base class for a LayoutToNetlist writer
|
||||
*/
|
||||
class DB_PUBLIC LayoutToNetlistWriterBase
|
||||
{
|
||||
public:
|
||||
LayoutToNetlistWriterBase () { }
|
||||
virtual ~LayoutToNetlistWriterBase () { }
|
||||
|
||||
virtual void write (const db::LayoutToNetlist *l2n) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The standard writer
|
||||
*/
|
||||
class DB_PUBLIC LayoutToNetlistStandardWriter
|
||||
: public LayoutToNetlistWriterBase
|
||||
{
|
||||
public:
|
||||
LayoutToNetlistStandardWriter (tl::OutputStream &stream);
|
||||
|
||||
void write (const db::LayoutToNetlist *l2n);
|
||||
|
||||
private:
|
||||
tl::OutputStream *mp_stream;
|
||||
|
||||
void write (const db::LayoutToNetlist *l2n, const db::Circuit &circuit);
|
||||
void write (const db::LayoutToNetlist *l2n, const db::Net &net);
|
||||
void write (const db::LayoutToNetlist *l2n, const db::SubCircuit &subcircuit);
|
||||
void write (const db::LayoutToNetlist *l2n, const db::Device &device);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -50,7 +50,9 @@ NetlistDeviceExtractor::NetlistDeviceExtractor (const std::string &name)
|
|||
: mp_layout (0), m_cell_index (0), mp_circuit (0)
|
||||
{
|
||||
m_name = name;
|
||||
m_propname_id = 0;
|
||||
m_terminal_id_propname_id = 0;
|
||||
m_device_class_propname_id = 0;
|
||||
m_device_id_propname_id = 0;
|
||||
}
|
||||
|
||||
NetlistDeviceExtractor::~NetlistDeviceExtractor ()
|
||||
|
|
@ -58,9 +60,21 @@ NetlistDeviceExtractor::~NetlistDeviceExtractor ()
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
const tl::Variant &NetlistDeviceExtractor::terminal_property_name ()
|
||||
const tl::Variant &NetlistDeviceExtractor::terminal_id_property_name ()
|
||||
{
|
||||
static tl::Variant name ("TERMINAL");
|
||||
static tl::Variant name ("TERMINAL_ID");
|
||||
return name;
|
||||
}
|
||||
|
||||
const tl::Variant &NetlistDeviceExtractor::device_id_property_name ()
|
||||
{
|
||||
static tl::Variant name ("DEVICE_ID");
|
||||
return name;
|
||||
}
|
||||
|
||||
const tl::Variant &NetlistDeviceExtractor::device_class_property_name ()
|
||||
{
|
||||
static tl::Variant name ("DEVICE_CLASS");
|
||||
return name;
|
||||
}
|
||||
|
||||
|
|
@ -68,7 +82,9 @@ void NetlistDeviceExtractor::initialize (db::Netlist *nl)
|
|||
{
|
||||
m_layer_definitions.clear ();
|
||||
mp_device_class = 0;
|
||||
m_propname_id = 0;
|
||||
m_terminal_id_propname_id = 0;
|
||||
m_device_id_propname_id = 0;
|
||||
m_device_class_propname_id = 0;
|
||||
m_netlist.reset (nl);
|
||||
|
||||
setup ();
|
||||
|
|
@ -79,9 +95,9 @@ static void insert_into_region (const db::PolygonRef &s, const db::ICplxTrans &t
|
|||
region.insert (s.obj ().transformed (tr * db::ICplxTrans (s.trans ())));
|
||||
}
|
||||
|
||||
void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, const NetlistDeviceExtractor::input_layers &layer_map, db::Netlist *nl)
|
||||
void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, const NetlistDeviceExtractor::input_layers &layer_map, db::Netlist &nl, hier_clusters_type &clusters)
|
||||
{
|
||||
initialize (nl);
|
||||
initialize (&nl);
|
||||
|
||||
std::vector<unsigned int> layers;
|
||||
layers.reserve (m_layer_definitions.size ());
|
||||
|
|
@ -107,16 +123,16 @@ void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, const NetlistDevi
|
|||
|
||||
}
|
||||
|
||||
extract_without_initialize (dss.layout (), dss.initial_cell (), layers);
|
||||
extract_without_initialize (dss.layout (), dss.initial_cell (), clusters, layers);
|
||||
}
|
||||
|
||||
void NetlistDeviceExtractor::extract (db::Layout &layout, db::Cell &cell, const std::vector<unsigned int> &layers, db::Netlist *nl)
|
||||
void NetlistDeviceExtractor::extract (db::Layout &layout, db::Cell &cell, const std::vector<unsigned int> &layers, db::Netlist *nl, hier_clusters_type &clusters)
|
||||
{
|
||||
initialize (nl);
|
||||
extract_without_initialize (layout, cell, layers);
|
||||
extract_without_initialize (layout, cell, clusters, layers);
|
||||
}
|
||||
|
||||
void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db::Cell &cell, const std::vector<unsigned int> &layers)
|
||||
void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db::Cell &cell, hier_clusters_type &clusters, const std::vector<unsigned int> &layers)
|
||||
{
|
||||
tl_assert (layers.size () == m_layer_definitions.size ());
|
||||
|
||||
|
|
@ -125,9 +141,12 @@ void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db:
|
|||
|
||||
mp_layout = &layout;
|
||||
m_layers = layers;
|
||||
mp_clusters = &clusters;
|
||||
|
||||
// terminal properties are kept in a property with the terminal_property_name name
|
||||
m_propname_id = mp_layout->properties_repository ().prop_name_id (terminal_property_name ());
|
||||
m_terminal_id_propname_id = mp_layout->properties_repository ().prop_name_id (terminal_id_property_name ());
|
||||
m_device_id_propname_id = mp_layout->properties_repository ().prop_name_id (device_id_property_name ());
|
||||
m_device_class_propname_id = mp_layout->properties_repository ().prop_name_id (device_class_property_name ());
|
||||
|
||||
tl_assert (m_netlist.get () != 0);
|
||||
|
||||
|
|
@ -150,6 +169,11 @@ void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db:
|
|||
// for each cell investigate the clusters
|
||||
for (std::set<db::cell_index_type>::const_iterator ci = called_cells.begin (); ci != called_cells.end (); ++ci) {
|
||||
|
||||
// skip device cells from previous extractions
|
||||
if (is_device_cell (*ci)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_cell_index = *ci;
|
||||
|
||||
std::map<db::cell_index_type, db::Circuit *>::const_iterator c2c = circuits_by_cell.find (*ci);
|
||||
|
|
@ -192,11 +216,116 @@ void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db:
|
|||
// do the actual device extraction
|
||||
extract_devices (layer_geometry);
|
||||
|
||||
// push the new devices to the layout
|
||||
push_new_devices ();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool NetlistDeviceExtractor::is_device_cell (db::cell_index_type ci) const
|
||||
{
|
||||
db::properties_id_type pi = mp_layout->cell (ci).prop_id ();
|
||||
if (pi == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (pi);
|
||||
for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) {
|
||||
if (j->first == m_device_class_propname_id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void NetlistDeviceExtractor::push_new_devices ()
|
||||
{
|
||||
db::VCplxTrans dbu_inv = db::CplxTrans (mp_layout->dbu ()).inverted ();
|
||||
|
||||
for (std::map<db::Device *, geometry_per_terminal_type>::const_iterator d = m_new_devices.begin (); d != m_new_devices.end (); ++d) {
|
||||
|
||||
db::Vector disp = dbu_inv * d->first->position () - db::Point ();
|
||||
|
||||
DeviceCellKey key;
|
||||
|
||||
for (geometry_per_terminal_type::const_iterator t = d->second.begin (); t != d->second.end (); ++t) {
|
||||
std::map<size_t, std::set<db::PolygonRef> > > = key.geometry [t->first];
|
||||
for (geometry_per_layer_type::const_iterator l = t->second.begin (); l != t->second.end (); ++l) {
|
||||
std::set<db::PolygonRef> &gl = gt [l->first];
|
||||
for (std::vector<db::PolygonRef>::const_iterator p = l->second.begin (); p != l->second.end (); ++p) {
|
||||
db::PolygonRef pr = *p;
|
||||
pr.transform (db::PolygonRef::trans_type (-disp));
|
||||
gl.insert (pr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<db::DeviceParameterDefinition> &pd = mp_device_class->parameter_definitions ();
|
||||
for (std::vector<db::DeviceParameterDefinition>::const_iterator p = pd.begin (); p != pd.end (); ++p) {
|
||||
key.parameters.insert (std::make_pair (p->id (), d->first->parameter_value (p->id ())));
|
||||
}
|
||||
|
||||
db::PropertiesRepository::properties_set ps;
|
||||
|
||||
std::map<DeviceCellKey, db::cell_index_type>::iterator c = m_device_cells.find (key);
|
||||
if (c == m_device_cells.end ()) {
|
||||
|
||||
std::string cell_name = "D$" + mp_device_class->name ();
|
||||
db::Cell &device_cell = mp_layout->cell (mp_layout->add_cell (cell_name.c_str ()));
|
||||
c = m_device_cells.insert (std::make_pair (key, device_cell.cell_index ())).first;
|
||||
|
||||
// attach the device class ID to the cell
|
||||
ps.clear ();
|
||||
ps.insert (std::make_pair (m_device_class_propname_id, tl::Variant (mp_device_class->name ())));
|
||||
device_cell.prop_id (mp_layout->properties_repository ().properties_id (ps));
|
||||
|
||||
db::connected_clusters<db::PolygonRef> &cc = mp_clusters->clusters_per_cell (device_cell.cell_index ());
|
||||
|
||||
for (geometry_per_terminal_type::const_iterator t = d->second.begin (); t != d->second.end (); ++t) {
|
||||
|
||||
// Build a property set for the device terminal ID
|
||||
ps.clear ();
|
||||
ps.insert (std::make_pair (m_terminal_id_propname_id, tl::Variant (t->first)));
|
||||
db::properties_id_type pi = mp_layout->properties_repository ().properties_id (ps);
|
||||
|
||||
// initialize the local cluster (will not be extracted)
|
||||
db::local_cluster<db::PolygonRef> *lc = cc.insert ();
|
||||
lc->add_attr (pi);
|
||||
|
||||
// build the cell shapes and local cluster
|
||||
for (geometry_per_layer_type::const_iterator l = t->second.begin (); l != t->second.end (); ++l) {
|
||||
db::Shapes &shapes = device_cell.shapes (l->first);
|
||||
for (std::vector<db::PolygonRef>::const_iterator s = l->second.begin (); s != l->second.end (); ++s) {
|
||||
db::PolygonRef pr = *s;
|
||||
pr.transform (db::PolygonRef::trans_type (-disp));
|
||||
shapes.insert (db::PolygonRefWithProperties (pr, pi));
|
||||
lc->add (*s, l->first);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// make the cell index known to the device
|
||||
d->first->set_cell_index (c->second);
|
||||
|
||||
// Build a property set for the device ID
|
||||
ps.clear ();
|
||||
ps.insert (std::make_pair (m_device_id_propname_id, tl::Variant (d->first->id ())));
|
||||
db::properties_id_type pi = mp_layout->properties_repository ().properties_id (ps);
|
||||
|
||||
db::CellInstArrayWithProperties inst (db::CellInstArray (db::CellInst (c->second), db::Trans (disp)), pi);
|
||||
mp_layout->cell (m_cell_index).insert (inst);
|
||||
|
||||
}
|
||||
|
||||
m_new_devices.clear ();
|
||||
}
|
||||
|
||||
void NetlistDeviceExtractor::setup ()
|
||||
{
|
||||
// .. the default implementation does nothing ..
|
||||
|
|
@ -253,14 +382,8 @@ void NetlistDeviceExtractor::define_terminal (Device *device, size_t terminal_id
|
|||
tl_assert (geometry_index < m_layers.size ());
|
||||
unsigned int layer_index = m_layers [geometry_index];
|
||||
|
||||
// Build a property set for the DeviceTerminalProperty
|
||||
db::PropertiesRepository::properties_set ps;
|
||||
tl::Variant &v = ps.insert (std::make_pair (m_propname_id, tl::Variant ()))->second;
|
||||
v = tl::Variant (new db::DeviceTerminalProperty (device->id (), terminal_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));
|
||||
m_new_devices[device][terminal_id][layer_index].push_back (pr);
|
||||
}
|
||||
|
||||
void NetlistDeviceExtractor::define_terminal (Device *device, size_t terminal_id, size_t layer_index, const db::Box &box)
|
||||
|
|
|
|||
|
|
@ -194,6 +194,7 @@ public:
|
|||
typedef std::vector<db::NetlistDeviceExtractorLayerDefinition> layer_definitions;
|
||||
typedef layer_definitions::const_iterator layer_definitions_iterator;
|
||||
typedef std::map<std::string, db::Region *> input_layers;
|
||||
typedef db::hier_clusters<db::PolygonRef> hier_clusters_type;
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
|
|
@ -217,11 +218,21 @@ public:
|
|||
|
||||
/**
|
||||
* @brief Gets the property name for the device terminal annotation
|
||||
* Annotation happens through db::DeviceTerminalProperty objects attached to
|
||||
* the terminal shapes.
|
||||
* The name used for the property is the one returned by this function.
|
||||
* This name is used to attach the terminal ID to terminal shapes.
|
||||
*/
|
||||
static const tl::Variant &terminal_property_name ();
|
||||
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
|
||||
|
|
@ -241,7 +252,7 @@ public:
|
|||
*
|
||||
* NOTE: The extractor expects "PolygonRef" type layers.
|
||||
*/
|
||||
void extract (Layout &layout, Cell &cell, const std::vector<unsigned int> &layers, Netlist *netlist);
|
||||
void extract (Layout &layout, Cell &cell, const std::vector<unsigned int> &layers, Netlist *netlist, hier_clusters_type &clusters);
|
||||
|
||||
/**
|
||||
* @brief Extracts the devices from a list of regions
|
||||
|
|
@ -250,7 +261,7 @@ public:
|
|||
* 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, const input_layers &layers, Netlist *netlist);
|
||||
void extract (DeepShapeStore &dss, const input_layers &layers, Netlist &netlist, hier_clusters_type &clusters);
|
||||
|
||||
/**
|
||||
* @brief Gets the error iterator, begin
|
||||
|
|
@ -452,9 +463,43 @@ protected:
|
|||
std::string cell_name () const;
|
||||
|
||||
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<unsigned int, std::map<size_t, std::set<db::PolygonRef> > > geometry;
|
||||
std::map<size_t, double> parameters;
|
||||
};
|
||||
|
||||
typedef std::map<unsigned int, std::vector<db::PolygonRef> > 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_propname_id;
|
||||
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;
|
||||
db::Circuit *mp_circuit;
|
||||
db::DeviceClass *mp_device_class;
|
||||
|
|
@ -462,6 +507,8 @@ private:
|
|||
layer_definitions m_layer_definitions;
|
||||
std::vector<unsigned int> m_layers;
|
||||
error_list m_errors;
|
||||
std::map<db::Device *, geometry_per_terminal_type> m_new_devices;
|
||||
std::map<DeviceCellKey, db::cell_index_type> m_device_cells;
|
||||
|
||||
// no copying
|
||||
NetlistDeviceExtractor (const NetlistDeviceExtractor &);
|
||||
|
|
@ -473,7 +520,9 @@ private:
|
|||
*/
|
||||
void initialize (db::Netlist *nl);
|
||||
|
||||
void extract_without_initialize (db::Layout &layout, db::Cell &cell, const std::vector<unsigned int> &layers);
|
||||
void extract_without_initialize (db::Layout &layout, db::Cell &cell, hier_clusters_type &clusters, const std::vector<unsigned int> &layers);
|
||||
void push_new_devices ();
|
||||
bool is_device_cell (db::cell_index_type ci) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,6 +98,8 @@ void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector<db
|
|||
|
||||
db::Device *device = create_device ();
|
||||
|
||||
device->set_position (db::CplxTrans (dbu ()) * p->box ().center ());
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -29,45 +29,50 @@ namespace db
|
|||
{
|
||||
|
||||
NetlistExtractor::NetlistExtractor ()
|
||||
: mp_clusters (0), mp_layout (0), mp_cell (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, const db::Connectivity &conn, db::Netlist *nl)
|
||||
NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, const db::Connectivity &conn, db::Netlist &nl, hier_clusters_type &clusters)
|
||||
{
|
||||
const db::Layout &layout = dss.const_layout ();
|
||||
const db::Cell &cell = dss.const_initial_cell ();
|
||||
mp_clusters = &clusters;
|
||||
mp_layout = &dss.const_layout ();
|
||||
mp_cell = &dss.const_initial_cell ();
|
||||
|
||||
// gets the text annotation property ID -
|
||||
// this is how the texts are passed for annotating the net names
|
||||
std::pair<bool, db::property_names_id_type> text_annot_name_id (false, 0);
|
||||
m_text_annot_name_id = std::pair<bool, db::property_names_id_type> (false, 0);
|
||||
if (! dss.text_property_name ().is_nil ()) {
|
||||
text_annot_name_id = layout.properties_repository ().get_id_of_name (dss.text_property_name ());
|
||||
m_text_annot_name_id = mp_layout->properties_repository ().get_id_of_name (dss.text_property_name ());
|
||||
}
|
||||
|
||||
// gets the device terminal annotation property ID -
|
||||
// this is how the device extractor conveys terminal shape annotations.
|
||||
std::pair<bool, db::property_names_id_type> terminal_annot_name_id;
|
||||
terminal_annot_name_id = layout.properties_repository ().get_id_of_name (db::NetlistDeviceExtractor::terminal_property_name ());
|
||||
m_terminal_annot_name_id = mp_layout->properties_repository ().get_id_of_name (db::NetlistDeviceExtractor::terminal_id_property_name ());
|
||||
m_device_annot_name_id = mp_layout->properties_repository ().get_id_of_name (db::NetlistDeviceExtractor::device_id_property_name ());
|
||||
m_device_class_annot_name_id = mp_layout->properties_repository ().get_id_of_name (db::NetlistDeviceExtractor::device_class_property_name ());
|
||||
|
||||
// the big part: actually extract the nets
|
||||
|
||||
m_net_clusters.build (layout, cell, db::ShapeIterator::Polygons, conn);
|
||||
mp_clusters->build (*mp_layout, *mp_cell, db::ShapeIterator::Polygons, conn);
|
||||
|
||||
// reverse lookup for Circuit vs. cell index
|
||||
std::map<db::cell_index_type, db::Circuit *> circuits;
|
||||
|
||||
// some circuits may be there because of device extraction
|
||||
for (db::Netlist::circuit_iterator c = nl->begin_circuits (); c != nl->end_circuits (); ++c) {
|
||||
tl_assert (layout.is_valid_cell_index (c->cell_index ()));
|
||||
for (db::Netlist::circuit_iterator c = nl.begin_circuits (); c != nl.end_circuits (); ++c) {
|
||||
tl_assert (mp_layout->is_valid_cell_index (c->cell_index ()));
|
||||
circuits.insert (std::make_pair (c->cell_index (), c.operator-> ()));
|
||||
}
|
||||
|
||||
std::map<db::cell_index_type, std::map<size_t, size_t> > pins_per_cluster_per_cell;
|
||||
for (db::Layout::bottom_up_const_iterator cid = layout.begin_bottom_up (); cid != layout.end_bottom_up (); ++cid) {
|
||||
for (db::Layout::bottom_up_const_iterator cid = mp_layout->begin_bottom_up (); cid != mp_layout->end_bottom_up (); ++cid) {
|
||||
|
||||
const connected_clusters_type &clusters = m_net_clusters.clusters_per_cell (*cid);
|
||||
if (cell_is_device_cell (*cid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const connected_clusters_type &clusters = mp_clusters->clusters_per_cell (*cid);
|
||||
if (clusters.empty ()) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -79,8 +84,8 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, const db::Connect
|
|||
std::map<db::cell_index_type, db::Circuit *>::const_iterator k = circuits.find (*cid);
|
||||
if (k == circuits.end ()) {
|
||||
circuit = new db::Circuit ();
|
||||
nl->add_circuit (circuit);
|
||||
circuit->set_name (layout.cell_name (*cid));
|
||||
nl.add_circuit (circuit);
|
||||
circuit->set_name (mp_layout->cell_name (*cid));
|
||||
circuit->set_cell_index (*cid);
|
||||
circuits.insert (std::make_pair (*cid, circuit));
|
||||
} else {
|
||||
|
|
@ -103,21 +108,13 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, const db::Connect
|
|||
}
|
||||
|
||||
// make subcircuit connections (also make the subcircuits if required) from the connections of the clusters
|
||||
make_and_connect_subcircuits (circuit, clusters, *c, net, subcircuits, circuits, pins_per_cluster_per_cell, layout.dbu ());
|
||||
make_and_connect_subcircuits (circuit, clusters, *c, net, subcircuits, circuits, pins_per_cluster_per_cell);
|
||||
|
||||
// collect the properties - we know that the cluster attributes are property ID's because the
|
||||
// cluster processor converts shape property IDs to attributes
|
||||
const local_cluster_type &lc = clusters.cluster_by_id (*c);
|
||||
for (local_cluster_type::attr_iterator a = lc.begin_attr (); a != lc.end_attr (); ++a) {
|
||||
const db::PropertiesRepository::properties_set &ps = layout.properties_repository ().properties (*a);
|
||||
for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) {
|
||||
if (terminal_annot_name_id.first && j->first == terminal_annot_name_id.second) {
|
||||
make_device_terminal_from_property (j->second, circuit, net);
|
||||
} else if (text_annot_name_id.first && j->first == text_annot_name_id.second) {
|
||||
assign_net_name (j->second.to_string (), net);
|
||||
}
|
||||
}
|
||||
}
|
||||
// connect devices
|
||||
connect_devices (circuit, clusters, *c, net);
|
||||
|
||||
// collect labels to net names
|
||||
collect_labels (clusters, *c, net);
|
||||
|
||||
if (! clusters.is_root (*c)) {
|
||||
// a non-root cluster makes a pin
|
||||
|
|
@ -130,18 +127,137 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, const db::Connect
|
|||
}
|
||||
}
|
||||
|
||||
void NetlistExtractor::collect_labels (const connected_clusters_type &clusters,
|
||||
size_t cid,
|
||||
db::Net *net)
|
||||
{
|
||||
// collect the properties - we know that the cluster attributes are property ID's because the
|
||||
// cluster processor converts shape property IDs to attributes
|
||||
|
||||
const local_cluster_type &lc = clusters.cluster_by_id (cid);
|
||||
for (local_cluster_type::attr_iterator a = lc.begin_attr (); a != lc.end_attr (); ++a) {
|
||||
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (*a);
|
||||
for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) {
|
||||
|
||||
if (m_text_annot_name_id.first && j->first == m_text_annot_name_id.second) {
|
||||
assign_net_name (j->second.to_string (), net);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool NetlistExtractor::cell_is_device_cell (db::cell_index_type ci) const
|
||||
{
|
||||
if (! m_device_class_annot_name_id.first) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const db::Cell &cell = mp_layout->cell (ci);
|
||||
if (cell.prop_id () == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (cell.prop_id ());
|
||||
for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) {
|
||||
if (j->first == m_device_class_annot_name_id.second) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetlistExtractor::instance_is_device (db::properties_id_type prop_id) const
|
||||
{
|
||||
if (! prop_id || ! m_device_annot_name_id.first) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (prop_id);
|
||||
for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) {
|
||||
if (j->first == m_device_annot_name_id.second) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
db::Device *NetlistExtractor::device_from_instance (db::properties_id_type prop_id, db::Circuit *circuit) const
|
||||
{
|
||||
if (! prop_id || ! m_device_annot_name_id.first) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (prop_id);
|
||||
for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) {
|
||||
if (j->first == m_device_annot_name_id.second) {
|
||||
return circuit->device_by_id (j->second.to<size_t> ());
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NetlistExtractor::connect_devices (db::Circuit *circuit,
|
||||
const connected_clusters_type &clusters,
|
||||
size_t cid,
|
||||
db::Net *net)
|
||||
{
|
||||
const connected_clusters_type::connections_type &connections = clusters.connections_for_cluster (cid);
|
||||
for (connected_clusters_type::connections_type::const_iterator i = connections.begin (); i != connections.end (); ++i) {
|
||||
|
||||
const db::Instance &inst = i->inst ().inst_ptr;
|
||||
|
||||
// only consider devices in this pass
|
||||
db::Device *device = device_from_instance (inst.prop_id (), circuit);
|
||||
if (! device) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const db::local_cluster<db::PolygonRef> &dc = mp_clusters->clusters_per_cell (inst.cell_index ()).cluster_by_id (i->id ());
|
||||
|
||||
// connect the net to the terminal of the device: take the terminal ID from the properties on the
|
||||
// device cluster
|
||||
for (local_cluster_type::attr_iterator a = dc.begin_attr (); a != dc.end_attr (); ++a) {
|
||||
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (*a);
|
||||
for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) {
|
||||
|
||||
if (m_terminal_annot_name_id.first && j->first == m_terminal_annot_name_id.second) {
|
||||
|
||||
size_t tid = j->second.to<size_t> ();
|
||||
device->connect_terminal (tid, net);
|
||||
device->set_cluster_id_for_terminal (tid, i->id ());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void NetlistExtractor::make_and_connect_subcircuits (db::Circuit *circuit,
|
||||
const connected_clusters_type &clusters,
|
||||
size_t cid,
|
||||
db::Net *net,
|
||||
std::map<db::InstElement, db::SubCircuit *> &subcircuits,
|
||||
const std::map<db::cell_index_type, db::Circuit *> &circuits,
|
||||
const std::map<db::cell_index_type, std::map<size_t, size_t> > &pins_per_cluster,
|
||||
double dbu)
|
||||
const std::map<db::cell_index_type, std::map<size_t, size_t> > &pins_per_cluster)
|
||||
{
|
||||
const connected_clusters_type::connections_type &connections = clusters.connections_for_cluster (cid);
|
||||
for (connected_clusters_type::connections_type::const_iterator i = connections.begin (); i != connections.end (); ++i) {
|
||||
|
||||
// skip devices in this pass
|
||||
if (instance_is_device (i->inst ().inst_ptr.prop_id ())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
db::SubCircuit *subcircuit = 0;
|
||||
db::cell_index_type ccid = i->inst ().inst_ptr.cell_index ();
|
||||
|
||||
|
|
@ -154,7 +270,7 @@ void NetlistExtractor::make_and_connect_subcircuits (db::Circuit *circuit,
|
|||
tl_assert (k != circuits.end ()); // because we walk bottom-up
|
||||
|
||||
subcircuit = new db::SubCircuit (k->second);
|
||||
db::CplxTrans dbu_trans (dbu);
|
||||
db::CplxTrans dbu_trans (mp_layout->dbu ());
|
||||
subcircuit->set_trans (dbu_trans * i->inst ().complex_trans () * dbu_trans.inverted ());
|
||||
circuit->add_subcircuit (subcircuit);
|
||||
subcircuits.insert (std::make_pair (i->inst (), subcircuit));
|
||||
|
|
@ -183,19 +299,6 @@ size_t NetlistExtractor::make_pin (db::Circuit *circuit, db::Net *net)
|
|||
return pin_id;
|
||||
}
|
||||
|
||||
void NetlistExtractor::make_device_terminal_from_property (const tl::Variant &v, db::Circuit *circuit, db::Net *net)
|
||||
{
|
||||
if (v.is_user<db::NetlistProperty> ()) {
|
||||
const db::NetlistProperty *np = &v.to_user<db::NetlistProperty> ();
|
||||
const db::DeviceTerminalProperty *tp = dynamic_cast<const db::DeviceTerminalProperty *> (np);
|
||||
if (tp) {
|
||||
db::Device *device = circuit->device_by_id (tp->device_id ());
|
||||
tl_assert (device != 0);
|
||||
device->connect_terminal (tp->terminal_id (), net);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetlistExtractor::assign_net_name (const std::string &n, db::Net *net)
|
||||
{
|
||||
std::string nn = n;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ class Netlist;
|
|||
class Circuit;
|
||||
class SubCircuit;
|
||||
class Net;
|
||||
class Device;
|
||||
|
||||
/**
|
||||
* @brief The Netlist Extractor
|
||||
|
|
@ -80,22 +81,21 @@ public:
|
|||
* @brief Extract the nets
|
||||
* See the class description for more details.
|
||||
*/
|
||||
void extract_nets (const db::DeepShapeStore &dss, const db::Connectivity &conn, db::Netlist *nl);
|
||||
|
||||
/**
|
||||
* @brief Gets the shape clusters
|
||||
* See the class description for more details.
|
||||
*/
|
||||
const hier_clusters_type &clusters () const
|
||||
{
|
||||
return m_net_clusters;
|
||||
}
|
||||
void extract_nets (const db::DeepShapeStore &dss, const db::Connectivity &conn, db::Netlist &nl, hier_clusters_type &clusters);
|
||||
|
||||
private:
|
||||
hier_clusters_type m_net_clusters;
|
||||
hier_clusters_type *mp_clusters;
|
||||
const db::Layout *mp_layout;
|
||||
const db::Cell *mp_cell;
|
||||
std::pair<bool, db::property_names_id_type> m_text_annot_name_id;
|
||||
std::pair<bool, db::property_names_id_type> m_device_annot_name_id;
|
||||
std::pair<bool, db::property_names_id_type> m_terminal_annot_name_id;
|
||||
std::pair<bool, db::property_names_id_type> m_device_class_annot_name_id;
|
||||
|
||||
void make_device_terminal_from_property (const tl::Variant &v, db::Circuit *circuit, db::Net *net);
|
||||
void assign_net_name (const std::string &n, db::Net *net);
|
||||
bool instance_is_device (db::properties_id_type prop_id) const;
|
||||
bool cell_is_device_cell (db::cell_index_type ci) const;
|
||||
db::Device *device_from_instance (db::properties_id_type prop_id, db::Circuit *circuit) const;
|
||||
|
||||
/**
|
||||
* @brief Make a pin connection from clusters
|
||||
|
|
@ -120,8 +120,6 @@ private:
|
|||
* - circuits: a lookup table of circuits vs. cell index (reverse lookup)
|
||||
* - pins_per_cluster: a per-cell, reverse lookup table for the pin id per child cell clusters
|
||||
* (used to find the pin ID of a subcircuit from the child cell cluster ID)
|
||||
* - dbu: the database unit (used to compute the micron-unit transformation of the child
|
||||
* cell)
|
||||
* Updates:
|
||||
* - subcircuits: An cell instance to SubCircuit lookup table
|
||||
*/
|
||||
|
|
@ -131,8 +129,30 @@ private:
|
|||
db::Net *net,
|
||||
std::map<db::InstElement, db::SubCircuit *> &subcircuits,
|
||||
const std::map<db::cell_index_type, db::Circuit *> &circuits,
|
||||
const std::map<db::cell_index_type, std::map<size_t, size_t> > &pins_per_cluster,
|
||||
double dbu);
|
||||
const std::map<db::cell_index_type, std::map<size_t, size_t> > &pins_per_cluster);
|
||||
|
||||
/**
|
||||
* @brief Connects the devices
|
||||
*
|
||||
* Devices are identified by special cells. These carry a property with the
|
||||
* device class name. Inside these cells, the terminals are identified by special clusters.
|
||||
* The terminal IDs are coded on these clusters are a property.
|
||||
*/
|
||||
void connect_devices (db::Circuit *circuit,
|
||||
const connected_clusters_type &clusters,
|
||||
size_t cid,
|
||||
db::Net *net);
|
||||
|
||||
/**
|
||||
* @brief Attaches net names from text properties
|
||||
*
|
||||
* Texts (labels) are represented by special shapes. The texts are kept as properties.
|
||||
* This method will collect all these labels and attach them to the nets as (alternative)
|
||||
* names.
|
||||
*/
|
||||
void collect_labels (const connected_clusters_type &clusters,
|
||||
size_t cid,
|
||||
db::Net *net);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,70 +51,6 @@ static unsigned int layer_of (const db::Region ®ion)
|
|||
return dr->deep_layer ().layer ();
|
||||
}
|
||||
|
||||
static std::string device_name (const db::Device &device)
|
||||
{
|
||||
if (device.name ().empty ()) {
|
||||
return "$" + tl::to_string (device.id ());
|
||||
} else {
|
||||
return device.name ();
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class MOSFET3Extractor
|
||||
: public db::NetlistDeviceExtractorMOS3Transistor
|
||||
{
|
||||
public:
|
||||
MOSFET3Extractor (const std::string &name, db::Layout *debug_out)
|
||||
: 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));
|
||||
m_lgate = mp_debug_out->insert_layer (db::LayerProperties (101, 0));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
db::Layout *mp_debug_out;
|
||||
unsigned int m_ldiff, m_lgate;
|
||||
|
||||
void device_out (const db::Device *device, const db::Region &diff, const db::Region &gate)
|
||||
{
|
||||
if (! mp_debug_out) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string cn = layout ()->cell_name (cell_index ());
|
||||
std::pair<bool, db::cell_index_type> target_cp = mp_debug_out->cell_by_name (cn.c_str ());
|
||||
tl_assert (target_cp.first);
|
||||
|
||||
db::cell_index_type dci = mp_debug_out->add_cell ((device->device_class ()->name () + "_" + device->circuit ()->name () + "_" + device_name (*device)).c_str ());
|
||||
mp_debug_out->cell (target_cp.second).insert (db::CellInstArray (db::CellInst (dci), db::Trans ()));
|
||||
|
||||
db::Cell &device_cell = mp_debug_out->cell (dci);
|
||||
for (db::Region::const_iterator p = diff.begin (); ! p.at_end (); ++p) {
|
||||
device_cell.shapes (m_ldiff).insert (*p);
|
||||
}
|
||||
for (db::Region::const_iterator p = gate.begin (); ! p.at_end (); ++p) {
|
||||
device_cell.shapes (m_lgate).insert (*p);
|
||||
}
|
||||
|
||||
std::string ps;
|
||||
const std::vector<db::DeviceParameterDefinition> &pd = device->device_class ()->parameter_definitions ();
|
||||
for (std::vector<db::DeviceParameterDefinition>::const_iterator i = pd.begin (); i != pd.end (); ++i) {
|
||||
if (! ps.empty ()) {
|
||||
ps += ",";
|
||||
}
|
||||
ps += i->name () + "=" + tl::to_string (device->parameter_value (i->id ()));
|
||||
}
|
||||
device_cell.shapes (m_ldiff).insert (db::Text (ps, db::Trans (diff.bbox ().center () - db::Point ())));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static unsigned int define_layer (db::Layout &ly, db::LayerMap &lmap, int gds_layer, int gds_datatype = 0)
|
||||
{
|
||||
unsigned int lid = ly.insert_layer (db::LayerProperties (gds_layer, gds_datatype));
|
||||
|
|
@ -124,6 +60,8 @@ static unsigned int define_layer (db::Layout &ly, db::LayerMap &lmap, int gds_la
|
|||
|
||||
static void dump_nets_to_layout (const db::Netlist &nl, const db::hier_clusters<db::PolygonRef> &clusters, db::Layout &ly, const std::map<unsigned int, unsigned int> &lmap, const db::CellMapping &cmap)
|
||||
{
|
||||
std::set<db::cell_index_type> device_cells_seen;
|
||||
|
||||
for (db::Netlist::const_circuit_iterator c = nl.begin_circuits (); c != nl.end_circuits (); ++c) {
|
||||
|
||||
db::Cell &cell = ly.cell (cmap.cell_mapping (c->cell_index ()));
|
||||
|
|
@ -154,6 +92,40 @@ static void dump_nets_to_layout (const db::Netlist &nl, const db::hier_clusters<
|
|||
|
||||
}
|
||||
|
||||
for (db::Circuit::const_device_iterator d = c->begin_devices (); d != c->end_devices (); ++d) {
|
||||
|
||||
if (device_cells_seen.find (d->cell_index ()) != device_cells_seen.end ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
db::Cell &device_cell = ly.cell (cmap.cell_mapping (d->cell_index ()));
|
||||
device_cells_seen.insert (d->cell_index ());
|
||||
|
||||
std::string ps;
|
||||
const std::vector<db::DeviceParameterDefinition> &pd = d->device_class ()->parameter_definitions ();
|
||||
for (std::vector<db::DeviceParameterDefinition>::const_iterator i = pd.begin (); i != pd.end (); ++i) {
|
||||
if (! ps.empty ()) {
|
||||
ps += ",";
|
||||
}
|
||||
ps += i->name () + "=" + tl::to_string (d->parameter_value (i->id ()));
|
||||
}
|
||||
|
||||
const std::vector<db::DeviceTerminalDefinition> &td = d->device_class ()->terminal_definitions ();
|
||||
for (std::vector<db::DeviceTerminalDefinition>::const_iterator t = td.begin (); t != td.end (); ++t) {
|
||||
|
||||
const db::local_cluster<db::PolygonRef> &dc = clusters.clusters_per_cell (d->cell_index ()).cluster_by_id (d->cluster_id_for_terminal (t->id ()));
|
||||
|
||||
for (std::map<unsigned int, unsigned int>::const_iterator m = lmap.begin (); m != lmap.end (); ++m) {
|
||||
db::Shapes &target = device_cell.shapes (m->second);
|
||||
for (db::local_cluster<db::PolygonRef>::shape_iterator s = dc.begin (m->first); !s.at_end (); ++s) {
|
||||
target.insert (*s);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -235,24 +207,22 @@ TEST(1_DeviceAndNetExtraction)
|
|||
// perform the extraction
|
||||
|
||||
db::Netlist nl;
|
||||
db::hier_clusters<db::PolygonRef> cl;
|
||||
|
||||
// NOTE: the device extractor will add more debug layers for the transistors:
|
||||
// 20/0 -> Diffusion
|
||||
// 21/0 -> Gate
|
||||
MOSFET3Extractor pmos_ex ("PMOS", &ly);
|
||||
MOSFET3Extractor nmos_ex ("NMOS", &ly);
|
||||
db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS");
|
||||
db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS");
|
||||
|
||||
db::NetlistDeviceExtractor::input_layers dl;
|
||||
|
||||
dl["SD"] = &rpsd;
|
||||
dl["G"] = &rpgate;
|
||||
dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes
|
||||
pmos_ex.extract (dss, dl, &nl);
|
||||
pmos_ex.extract (dss, dl, nl, cl);
|
||||
|
||||
dl["SD"] = &rnsd;
|
||||
dl["G"] = &rngate;
|
||||
dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes
|
||||
nmos_ex.extract (dss, dl, &nl);
|
||||
nmos_ex.extract (dss, dl, nl, cl);
|
||||
|
||||
// perform the net extraction
|
||||
|
||||
|
|
@ -282,7 +252,7 @@ TEST(1_DeviceAndNetExtraction)
|
|||
|
||||
// extract the nets
|
||||
|
||||
net_ex.extract_nets (dss, conn, &nl);
|
||||
net_ex.extract_nets (dss, conn, nl, cl);
|
||||
|
||||
// debug layers produced for nets
|
||||
// 202/0 -> Active
|
||||
|
|
@ -306,7 +276,7 @@ TEST(1_DeviceAndNetExtraction)
|
|||
|
||||
// write nets to layout
|
||||
db::CellMapping cm = dss.cell_mapping_to_original (0, &ly, tc.cell_index ());
|
||||
dump_nets_to_layout (nl, net_ex.clusters (), ly, dump_map, cm);
|
||||
dump_nets_to_layout (nl, cl, ly, dump_map, cm);
|
||||
|
||||
// compare netlist as string
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in New Issue