diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 47346293b..65b36ade9 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -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") { diff --git a/src/db/db/dbNetlistExtractor.cc b/src/db/db/dbNetlistExtractor.cc new file mode 100644 index 000000000..47c60afbf --- /dev/null +++ b/src/db/db/dbNetlistExtractor.cc @@ -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 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 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 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 > 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::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 &c2p = pins_per_cluster [*cid]; + + std::map 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::const_iterator j = subcircuits.find (i->inst ()); + if (j == subcircuits.end ()) { + + // make subcircuit if required + + std::map::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 >::const_iterator icc2p = pins_per_cluster.find (ccid); + tl_assert (icc2p != pins_per_cluster.end ()); + std::map::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 ()) { + const db::NetlistProperty *np = &j->second.to_user (); + const db::DeviceTerminalProperty *tp = dynamic_cast (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); + } + + } + + } + + } + + } + + } +} + +} diff --git a/src/db/db/dbNetlistExtractor.h b/src/db/db/dbNetlistExtractor.h new file mode 100644 index 000000000..ba1902b2b --- /dev/null +++ b/src/db/db/dbNetlistExtractor.h @@ -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 hier_clusters_type; + typedef db::connected_clusters connected_clusters_type; + typedef db::local_cluster 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 diff --git a/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc b/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc index 71bdba71f..cd1c652a2 100644 --- a/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc @@ -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 hier_clusters_type; - typedef db::connected_clusters connected_clusters_type; - typedef db::local_cluster 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 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 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 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 > 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::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 &c2p = pins_per_cluster [*cid]; - - std::map 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::const_iterator j = subcircuits.find (i->inst ()); - if (j == subcircuits.end ()) { - - // make subcircuit if required - - std::map::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 >::const_iterator icc2p = pins_per_cluster.find (ccid); - tl_assert (icc2p != pins_per_cluster.end ()); - std::map::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 ()) { - const db::NetlistProperty *np = &j->second.to_user (); - const db::DeviceTerminalProperty *tp = dynamic_cast (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