mirror of https://github.com/KLayout/klayout.git
WIP: moved netlist extractor into right place.
This commit is contained in:
parent
8b2902c31b
commit
d6473b4d84
|
|
@ -146,7 +146,8 @@ SOURCES = \
|
|||
dbNetlist.cc \
|
||||
gsiDeclDbNetlist.cc \
|
||||
dbNetlistDeviceClasses.cc \
|
||||
dbNetlistDeviceExtractor.cc
|
||||
dbNetlistDeviceExtractor.cc \
|
||||
dbNetlistExtractor.cc
|
||||
|
||||
HEADERS = \
|
||||
dbArray.h \
|
||||
|
|
@ -259,7 +260,8 @@ HEADERS = \
|
|||
dbNetlistProperty.h \
|
||||
dbNetlist.h \
|
||||
dbNetlistDeviceClasses.h \
|
||||
dbNetlistDeviceExtractor.h
|
||||
dbNetlistDeviceExtractor.h \
|
||||
dbNetlistExtractor.h
|
||||
|
||||
!equals(HAVE_QT, "0") {
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,186 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2018 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "dbNetlistExtractor.h"
|
||||
#include "dbDeepShapeStore.h"
|
||||
#include "dbNetlistDeviceExtractor.h"
|
||||
#include "dbNetlistProperty.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
NetlistExtractor::NetlistExtractor ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, const db::Connectivity &conn, db::Netlist *nl)
|
||||
{
|
||||
const db::Layout &layout = dss.const_layout ();
|
||||
const db::Cell &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);
|
||||
if (! dss.text_property_name ().is_nil ()) {
|
||||
text_annot_name_id = 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 ());
|
||||
|
||||
// the big part: actually extract the nets
|
||||
|
||||
m_net_clusters.build (layout, 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 ()));
|
||||
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;
|
||||
|
||||
for (db::Layout::bottom_up_const_iterator cid = layout.begin_bottom_up (); cid != layout.end_bottom_up (); ++cid) {
|
||||
|
||||
const connected_clusters_type &clusters = m_net_clusters.clusters_per_cell (*cid);
|
||||
if (clusters.empty ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// a cell makes a new circuit (or uses an existing one)
|
||||
|
||||
db::Circuit *circuit = 0;
|
||||
|
||||
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));
|
||||
circuit->set_cell_index (*cid);
|
||||
circuits.insert (std::make_pair (*cid, circuit));
|
||||
} else {
|
||||
circuit = k->second;
|
||||
}
|
||||
|
||||
std::map<size_t, size_t> &c2p = pins_per_cluster [*cid];
|
||||
|
||||
std::map<db::InstElement, db::SubCircuit *> subcircuits;
|
||||
|
||||
for (connected_clusters_type::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) {
|
||||
|
||||
db::Net *net = new db::Net ();
|
||||
net->set_cluster_id (*c);
|
||||
circuit->add_net (net);
|
||||
|
||||
if (! clusters.is_root (*c)) {
|
||||
|
||||
// a non-root cluster makes a pin
|
||||
db::Pin pin (net->name ());
|
||||
size_t pin_id = circuit->add_pin (pin).id ();
|
||||
net->add_pin (db::NetPinRef (pin_id));
|
||||
c2p.insert (std::make_pair (*c, pin_id));
|
||||
circuit->connect_pin (pin_id, net);
|
||||
|
||||
}
|
||||
|
||||
const connected_clusters_type::connections_type &connections = clusters.connections_for_cluster (*c);
|
||||
for (connected_clusters_type::connections_type::const_iterator i = connections.begin (); i != connections.end (); ++i) {
|
||||
|
||||
db::SubCircuit *subcircuit = 0;
|
||||
db::cell_index_type ccid = i->inst ().inst_ptr.cell_index ();
|
||||
|
||||
std::map<db::InstElement, db::SubCircuit *>::const_iterator j = subcircuits.find (i->inst ());
|
||||
if (j == subcircuits.end ()) {
|
||||
|
||||
// make subcircuit if required
|
||||
|
||||
std::map<db::cell_index_type, db::Circuit *>::const_iterator k = circuits.find (ccid);
|
||||
tl_assert (k != circuits.end ()); // because we walk bottom-up
|
||||
|
||||
subcircuit = new db::SubCircuit (k->second);
|
||||
db::CplxTrans dbu_trans (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));
|
||||
|
||||
} else {
|
||||
subcircuit = j->second;
|
||||
}
|
||||
|
||||
// create the pin connection to the subcircuit
|
||||
std::map<db::cell_index_type, std::map<size_t, size_t> >::const_iterator icc2p = pins_per_cluster.find (ccid);
|
||||
tl_assert (icc2p != pins_per_cluster.end ());
|
||||
std::map<size_t, size_t>::const_iterator ip = icc2p->second.find (i->id ());
|
||||
tl_assert (ip != icc2p->second.end ());
|
||||
subcircuit->connect_pin (ip->second, 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 (*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) {
|
||||
|
||||
if (j->second.is_user<db::NetlistProperty> ()) {
|
||||
const db::NetlistProperty *np = &j->second.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);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (text_annot_name_id.first && j->first == text_annot_name_id.second) {
|
||||
|
||||
std::string n = j->second.to_string ();
|
||||
if (! n.empty ()) {
|
||||
if (! net->name ().empty ()) {
|
||||
n = net->name () + "," + n;
|
||||
}
|
||||
net->set_name (n);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
|
||||
/*
|
||||
|
||||
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_dbNetlistExtractor
|
||||
#define _HDR_dbNetlistExtractor
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "dbHierNetworkProcessor.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
class DeepShapeStore;
|
||||
class Netlist;
|
||||
|
||||
/**
|
||||
* @brief The Netlist Extractor
|
||||
*
|
||||
* This is the main object responsible for extracting nets from a layout.
|
||||
*
|
||||
* The layout needs to be present as a DeepShapeStore shadow layout. Use hierarchical regions
|
||||
* (db::Region build with a DeepShapeStore) to populate the shape store.
|
||||
*
|
||||
* The extraction requires a connectivity definition through db::Connectivity.
|
||||
*
|
||||
* In addition, the device extraction needs to happen before net extraction.
|
||||
* Device extraction will pre-fill the netlist with circuits and devices and
|
||||
* annotate the layout with terminal shapes, so the net extraction can connect
|
||||
* to the device terminals.
|
||||
*
|
||||
* If the deep shape store has been configured to supply text label annotated
|
||||
* markers (DeepShapeStore::set_text_property_name and DeepShapeStore::set_text_enlargement
|
||||
* to at least 1), texts from layers included in the connectivity will be extracted
|
||||
* as net names. If multiple texts are present, the names will be concatenated using
|
||||
* comma separators.
|
||||
*
|
||||
* Upon extraction, the given netlist is filled with circuits (unless present already),
|
||||
* subcircuits, pins and of course nets. This object also supplies access to the net's
|
||||
* geometries through the clusters() method. This method delivers a hierarchical
|
||||
* cluster object. The nets refer to specific clusters through their "cluster_id"
|
||||
* attribute.
|
||||
*/
|
||||
class DB_PUBLIC NetlistExtractor
|
||||
{
|
||||
public:
|
||||
typedef db::hier_clusters<db::PolygonRef> hier_clusters_type;
|
||||
typedef db::connected_clusters<db::PolygonRef> connected_clusters_type;
|
||||
typedef db::local_cluster<db::PolygonRef> local_cluster_type;
|
||||
|
||||
/**
|
||||
* @brief NetExtractor constructor
|
||||
*/
|
||||
NetlistExtractor ();
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
private:
|
||||
hier_clusters_type m_net_clusters;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -22,8 +22,8 @@
|
|||
|
||||
|
||||
#include "dbNetlistDeviceExtractor.h"
|
||||
#include "dbNetlistExtractor.h"
|
||||
#include "dbNetlistDeviceClasses.h"
|
||||
#include "dbHierNetworkProcessor.h"
|
||||
#include "dbLayout.h"
|
||||
#include "dbDeepShapeStore.h"
|
||||
#include "dbRegion.h"
|
||||
|
|
@ -234,177 +234,6 @@ static unsigned int layer_of (const db::Region ®ion)
|
|||
return db::DeepLayer (region).layer ();
|
||||
}
|
||||
|
||||
// @@@ TODO: move somewhere else
|
||||
class NetExtractor
|
||||
{
|
||||
public:
|
||||
typedef db::hier_clusters<db::PolygonRef> hier_clusters_type;
|
||||
typedef db::connected_clusters<db::PolygonRef> connected_clusters_type;
|
||||
typedef db::local_cluster<db::PolygonRef> local_cluster_type;
|
||||
|
||||
NetExtractor ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void extract_nets (const db::DeepShapeStore &dss, const db::Connectivity &conn, db::Netlist *nl)
|
||||
{
|
||||
const db::Layout &layout = dss.const_layout ();
|
||||
const db::Cell &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);
|
||||
if (! dss.text_property_name ().is_nil ()) {
|
||||
text_annot_name_id = 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 ());
|
||||
|
||||
// the big part: actually extract the nets
|
||||
|
||||
m_net_clusters.build (layout, 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 ()));
|
||||
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;
|
||||
|
||||
for (db::Layout::bottom_up_const_iterator cid = layout.begin_bottom_up (); cid != layout.end_bottom_up (); ++cid) {
|
||||
|
||||
const connected_clusters_type &clusters = m_net_clusters.clusters_per_cell (*cid);
|
||||
if (clusters.empty ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// a cell makes a new circuit (or uses an existing one)
|
||||
|
||||
db::Circuit *circuit = 0;
|
||||
|
||||
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));
|
||||
circuit->set_cell_index (*cid);
|
||||
circuits.insert (std::make_pair (*cid, circuit));
|
||||
} else {
|
||||
circuit = k->second;
|
||||
}
|
||||
|
||||
std::map<size_t, size_t> &c2p = pins_per_cluster [*cid];
|
||||
|
||||
std::map<db::InstElement, db::SubCircuit *> subcircuits;
|
||||
|
||||
for (connected_clusters_type::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) {
|
||||
|
||||
db::Net *net = new db::Net ();
|
||||
net->set_cluster_id (*c);
|
||||
circuit->add_net (net);
|
||||
|
||||
if (! clusters.is_root (*c)) {
|
||||
|
||||
// a non-root cluster makes a pin
|
||||
db::Pin pin (net->name ());
|
||||
size_t pin_id = circuit->add_pin (pin).id ();
|
||||
net->add_pin (db::NetPinRef (pin_id));
|
||||
c2p.insert (std::make_pair (*c, pin_id));
|
||||
circuit->connect_pin (pin_id, net);
|
||||
|
||||
}
|
||||
|
||||
const connected_clusters_type::connections_type &connections = clusters.connections_for_cluster (*c);
|
||||
for (connected_clusters_type::connections_type::const_iterator i = connections.begin (); i != connections.end (); ++i) {
|
||||
|
||||
db::SubCircuit *subcircuit = 0;
|
||||
db::cell_index_type ccid = i->inst ().inst_ptr.cell_index ();
|
||||
|
||||
std::map<db::InstElement, db::SubCircuit *>::const_iterator j = subcircuits.find (i->inst ());
|
||||
if (j == subcircuits.end ()) {
|
||||
|
||||
// make subcircuit if required
|
||||
|
||||
std::map<db::cell_index_type, db::Circuit *>::const_iterator k = circuits.find (ccid);
|
||||
tl_assert (k != circuits.end ()); // because we walk bottom-up
|
||||
|
||||
subcircuit = new db::SubCircuit (k->second);
|
||||
db::CplxTrans dbu_trans (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));
|
||||
|
||||
} else {
|
||||
subcircuit = j->second;
|
||||
}
|
||||
|
||||
// create the pin connection to the subcircuit
|
||||
std::map<db::cell_index_type, std::map<size_t, size_t> >::const_iterator icc2p = pins_per_cluster.find (ccid);
|
||||
tl_assert (icc2p != pins_per_cluster.end ());
|
||||
std::map<size_t, size_t>::const_iterator ip = icc2p->second.find (i->id ());
|
||||
tl_assert (ip != icc2p->second.end ());
|
||||
subcircuit->connect_pin (ip->second, 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 (*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) {
|
||||
|
||||
if (j->second.is_user<db::NetlistProperty> ()) {
|
||||
const db::NetlistProperty *np = &j->second.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);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (text_annot_name_id.first && j->first == text_annot_name_id.second) {
|
||||
|
||||
std::string n = j->second.to_string ();
|
||||
if (! n.empty ()) {
|
||||
if (! net->name ().empty ()) {
|
||||
n = net->name () + "," + n;
|
||||
}
|
||||
net->set_name (n);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const hier_clusters_type clusters () const
|
||||
{
|
||||
return m_net_clusters;
|
||||
}
|
||||
|
||||
private:
|
||||
hier_clusters_type m_net_clusters;
|
||||
};
|
||||
|
||||
static std::string net_name (const db::Net *net)
|
||||
{
|
||||
return net ? net->expanded_name () : "(null)";
|
||||
|
|
@ -614,7 +443,7 @@ TEST(1_DeviceNetExtraction)
|
|||
|
||||
// perform the net extraction
|
||||
|
||||
NetExtractor net_ex;
|
||||
db::NetlistExtractor net_ex;
|
||||
|
||||
db::Connectivity conn;
|
||||
// Intra-layer
|
||||
|
|
|
|||
Loading…
Reference in New Issue