WIP: moved netlist extractor into right place.

This commit is contained in:
Matthias Koefferlein 2018-12-27 10:57:46 +01:00
parent 8b2902c31b
commit d6473b4d84
4 changed files with 287 additions and 175 deletions

View File

@ -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") {

View File

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

View File

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

View File

@ -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 &region)
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