From 99ea1a283bd8e82b674fc72c849c44b13213f55b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 14 Jul 2024 16:16:18 +0200 Subject: [PATCH] WIP --- src/db/db/dbNetlistDeviceExtractor.cc | 211 +++++++++++-------- src/db/db/dbNetlistDeviceExtractor.h | 31 ++- src/db/db/gsiDeclDbNetlistDeviceExtractor.cc | 17 ++ 3 files changed, 165 insertions(+), 94 deletions(-) diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc index 00cbe62a5..c37edbe70 100644 --- a/src/db/db/dbNetlistDeviceExtractor.cc +++ b/src/db/db/dbNetlistDeviceExtractor.cc @@ -28,6 +28,7 @@ #include "tlProgress.h" #include "tlTimer.h" #include "tlInternational.h" +#include "tlEnv.h" namespace db { @@ -38,10 +39,24 @@ namespace db NetlistDeviceExtractor::NetlistDeviceExtractor (const std::string &name) : mp_layout (0), m_cell_index (0), mp_breakout_cells (0), m_device_scaling (1.0), mp_circuit (0) { + // inspects the KLAYOUT_SMART_DEVICE_PROPAGATION environment variable (if set) + // to derive the default value for m_smart_device_propagation. + static bool s_is_sdp_default_set = false; + static bool s_sdp_default = false; + if (! s_is_sdp_default_set) { + int v = 0; + std::string ve = tl::get_env ("KLAYOUT_SMART_DEVICE_PROPAGATION", "0"); + tl::Extractor (ve.c_str ()).try_read (v); + s_sdp_default = (v != 0); + s_is_sdp_default_set = true; + } + m_name = name; m_terminal_id_propname_id = 0; m_device_class_propname_id = 0; m_device_id_propname_id = 0; + m_smart_device_propagation = s_sdp_default; + m_pre_extract = false; } NetlistDeviceExtractor::~NetlistDeviceExtractor () @@ -167,12 +182,17 @@ struct ExtractorCacheValueType { } +void NetlistDeviceExtractor::pre_extract_for_device_propagation (const db::hier_clusters &device_clusters, const std::set &called_cells, std::set::id_type> > &to_extract) +{ + + // @@@ + +} + void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db::Cell &cell, hier_clusters_type &clusters, const std::vector &layers, double device_scaling, const std::set *breakout_cells) { tl_assert (layers.size () == m_layer_definitions.size ()); - typedef db::NetShape shape_type; - mp_layout = &layout; m_layers = layers; mp_clusters = &clusters; @@ -212,31 +232,49 @@ void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db: db::hier_clusters device_clusters; device_clusters.build (layout, cell, device_conn, 0, breakout_cells); + // in "smart device propagation" mode, do a pre-extraction a determine the devices + // that need propagation + + std::set::id_type> > to_extract; + + if (m_smart_device_propagation) { + + pre_extract_for_device_propagation (device_clusters, called_cells, to_extract); + + } else { + + // in stupid mode, extract all root clusters + for (std::set::const_iterator ci = called_cells.begin (); ci != called_cells.end (); ++ci) { + db::connected_clusters cc = device_clusters.clusters_per_cell (*ci); + for (db::connected_clusters::all_iterator c = cc.begin_all (); !c.at_end(); ++c) { + if (cc.is_root (*c)) { + to_extract.insert (std::make_pair (*ci, *c)); + } + } + + } + + } + + m_pre_extract = false; + tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Extracting devices"))); // count effort and make a progress reporter - size_t n = 0; - for (std::set::const_iterator ci = called_cells.begin (); ci != called_cells.end (); ++ci) { - db::connected_clusters cc = device_clusters.clusters_per_cell (*ci); - for (db::connected_clusters::all_iterator c = cc.begin_all (); !c.at_end(); ++c) { - if (cc.is_root (*c)) { - ++n; - } - } - } - - tl::RelativeProgress progress (tl::to_string (tr ("Extracting devices")), n, 1); + tl::RelativeProgress progress (tl::to_string (tr ("Extracting devices")), to_extract.size (), 1); typedef std::map, ExtractorCacheValueType> extractor_cache_type; extractor_cache_type extractor_cache; - // for each cell investigate the clusters - for (std::set::const_iterator ci = called_cells.begin (); ci != called_cells.end (); ++ci) { + // extract clusters to devices + for (auto e = to_extract.begin (); e != to_extract.end (); ++e) { - m_cell_index = *ci; + ++progress; - std::map::const_iterator c2c = circuits_by_cell.find (*ci); + m_cell_index = e->first; + + std::map::const_iterator c2c = circuits_by_cell.find (m_cell_index); if (c2c != circuits_by_cell.end ()) { // reuse existing circuit @@ -245,87 +283,78 @@ void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db: } else { // create a new circuit for this cell - mp_circuit = new db::Circuit (layout, *ci); + mp_circuit = new db::Circuit (layout, m_cell_index); m_netlist->add_circuit (mp_circuit); + circuits_by_cell.insert (std::make_pair (m_cell_index, mp_circuit)); } // investigate each cluster - db::connected_clusters cc = device_clusters.clusters_per_cell (*ci); - for (db::connected_clusters::all_iterator c = cc.begin_all (); !c.at_end(); ++c) { + db::connected_clusters::id_type c = e->second; - // take only root clusters - others have upward connections and are not "whole" - if (! cc.is_root (*c)) { - continue; + // build layer geometry from the cluster found + + std::vector layer_geometry; + layer_geometry.resize (layers.size ()); + + for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { + db::Region &r = layer_geometry [l - layers.begin ()]; + for (db::recursive_cluster_shape_iterator si (device_clusters, *l, m_cell_index, c); ! si.at_end(); ++si) { + insert_into_region (*si, si.trans (), r); } + r.set_base_verbosity (50); + } - ++progress; + db::Box box; + for (std::vector::const_iterator g = layer_geometry.begin (); g != layer_geometry.end (); ++g) { + box += g->bbox (); + } - // build layer geometry from the cluster found + db::Vector disp = box.p1 () - db::Point (); + for (std::vector::iterator g = layer_geometry.begin (); g != layer_geometry.end (); ++g) { + g->transform (db::Disp (-disp)); + } - std::vector layer_geometry; - layer_geometry.resize (layers.size ()); + extractor_cache_type::const_iterator ec = extractor_cache.find (layer_geometry); + if (ec == extractor_cache.end ()) { - for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { - db::Region &r = layer_geometry [l - layers.begin ()]; - for (db::recursive_cluster_shape_iterator si (device_clusters, *l, *ci, *c); ! si.at_end(); ++si) { - insert_into_region (*si, si.trans (), r); + log_entry_list log_entries; + m_log_entries.swap (log_entries); + + // do the actual device extraction + extract_devices (layer_geometry); + + // push the new devices to the layout + push_new_devices (disp); + + if (m_log_entries.empty ()) { + + // cache unless log entries are produced + ExtractorCacheValueType &ecv = extractor_cache [layer_geometry]; + ecv.disp = disp; + + for (std::map >::const_iterator d = m_new_devices.begin (); d != m_new_devices.end (); ++d) { + ecv.devices.push_back (d->second.first); } - r.set_base_verbosity (50); - } - - db::Box box; - for (std::vector::const_iterator g = layer_geometry.begin (); g != layer_geometry.end (); ++g) { - box += g->bbox (); - } - - db::Vector disp = box.p1 () - db::Point (); - for (std::vector::iterator g = layer_geometry.begin (); g != layer_geometry.end (); ++g) { - g->transform (db::Disp (-disp)); - } - - extractor_cache_type::const_iterator ec = extractor_cache.find (layer_geometry); - if (ec == extractor_cache.end ()) { - - log_entry_list log_entries; - m_log_entries.swap (log_entries); - - // do the actual device extraction - extract_devices (layer_geometry); - - // push the new devices to the layout - push_new_devices (disp); - - if (m_log_entries.empty ()) { - - // cache unless log entries are produced - ExtractorCacheValueType &ecv = extractor_cache [layer_geometry]; - ecv.disp = disp; - - for (std::map >::const_iterator d = m_new_devices.begin (); d != m_new_devices.end (); ++d) { - ecv.devices.push_back (d->second.first); - } - - } else { - - // transform the marker geometries from the log entries to match the device - db::DVector disp_dbu = db::CplxTrans (dbu ()) * disp; - for (auto l = m_log_entries.begin (); l != m_log_entries.end (); ++l) { - l->set_geometry (l->geometry ().moved (disp_dbu)); - } - - } - - m_log_entries.splice (m_log_entries.begin (), log_entries); - - m_new_devices.clear (); } else { - push_cached_devices (ec->second.devices, ec->second.disp, disp); + // transform the marker geometries from the log entries to match the device + db::DVector disp_dbu = db::CplxTrans (dbu ()) * disp; + for (auto l = m_log_entries.begin (); l != m_log_entries.end (); ++l) { + l->set_geometry (l->geometry ().moved (disp_dbu)); + } } + m_log_entries.splice (m_log_entries.begin (), log_entries); + + m_new_devices.clear (); + + } else { + + push_cached_devices (ec->second.devices, ec->second.disp, disp); + } } @@ -346,12 +375,12 @@ void NetlistDeviceExtractor::push_new_devices (const db::Vector &disp_cache) DeviceCellKey key; for (geometry_per_terminal_type::const_iterator t = d->second.second.begin (); t != d->second.second.end (); ++t) { - std::map > > = key.geometry [t->first]; + std::map > > = key.geometry [t->first]; for (geometry_per_layer_type::const_iterator l = t->second.begin (); l != t->second.end (); ++l) { - std::set &gl = gt [l->first]; - for (std::vector::const_iterator p = l->second.begin (); p != l->second.end (); ++p) { - db::NetShape pr = *p; - pr.transform (db::NetShape::trans_type (-disp)); + std::set &gl = gt [l->first]; + for (std::vector::const_iterator p = l->second.begin (); p != l->second.end (); ++p) { + shape_type pr = *p; + pr.transform (shape_type::trans_type (-disp)); gl.insert (pr); } } @@ -392,9 +421,9 @@ void NetlistDeviceExtractor::push_new_devices (const db::Vector &disp_cache) 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::const_iterator s = l->second.begin (); s != l->second.end (); ++s) { - db::NetShape pr = *s; - pr.transform (db::NetShape::trans_type (-disp)); + for (std::vector::const_iterator s = l->second.begin (); s != l->second.end (); ++s) { + shape_type pr = *s; + pr.transform (shape_type::trans_type (-disp)); pr.insert_into (shapes, pi); } @@ -523,10 +552,10 @@ void NetlistDeviceExtractor::define_terminal (Device *device, size_t terminal_id std::pair &dd = m_new_devices[device->id ()]; dd.first = device; - std::vector &geo = dd.second[terminal_id][layer_index]; + std::vector &geo = dd.second[terminal_id][layer_index]; for (db::Region::const_iterator p = region.begin_merged (); !p.at_end (); ++p) { - geo.push_back (db::NetShape (*p, mp_layout->shape_repository ())); + geo.push_back (shape_type (*p, mp_layout->shape_repository ())); } } @@ -536,7 +565,7 @@ 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]; - db::NetShape pr (polygon, mp_layout->shape_repository ()); + shape_type pr (polygon, mp_layout->shape_repository ()); std::pair &dd = m_new_devices[device->id ()]; dd.first = device; dd.second[terminal_id][layer_index].push_back (pr); diff --git a/src/db/db/dbNetlistDeviceExtractor.h b/src/db/db/dbNetlistDeviceExtractor.h index d5648319b..fd30495de 100644 --- a/src/db/db/dbNetlistDeviceExtractor.h +++ b/src/db/db/dbNetlistDeviceExtractor.h @@ -87,12 +87,13 @@ class DB_PUBLIC NetlistDeviceExtractor : public gsi::ObjectBase, public tl::Object { public: + typedef db::NetShape shape_type; typedef std::list log_entry_list; typedef log_entry_list::const_iterator log_entry_iterator; typedef std::vector layer_definitions; typedef layer_definitions::const_iterator layer_definitions_iterator; typedef std::map input_layers; - typedef db::hier_clusters hier_clusters_type; + typedef db::hier_clusters hier_clusters_type; /** * @brief Constructor @@ -124,6 +125,26 @@ public: */ static const tl::Variant &device_class_property_name (); + /** + * @brief Sets a flag indicating whether to use "smart device propagation" + * If set to true, the extractor will run a pre-extraction pass to determine which devices + * need to be propagated up in the hierarchy. This may reduce the need for hierarchy cheats + * for overlapping devices. + */ + void set_smart_device_propagation (bool f) + { + m_smart_device_propagation = f; + } + + /** + * @brief Sets a flag indicating whether to use "smart device propagation" + * See set_smart_device_propagation for a description of that flag. + */ + bool smart_device_propagation () const + { + return m_smart_device_propagation; + } + /** * @brief Performs the extraction * @@ -459,11 +480,11 @@ private: return false; } - std::map > > geometry; + std::map > > geometry; std::map parameters; }; - typedef std::map > geometry_per_layer_type; + typedef std::map > geometry_per_layer_type; typedef std::map geometry_per_terminal_type; tl::weak_ptr m_netlist; @@ -479,14 +500,18 @@ private: layer_definitions m_layer_definitions; std::vector m_layers; log_entry_list m_log_entries; + bool m_smart_device_propagation; + bool m_pre_extract; std::map > m_new_devices; std::map > m_device_cells; + std::vector m_new_devices_pre_extracted; // no copying NetlistDeviceExtractor (const NetlistDeviceExtractor &); NetlistDeviceExtractor &operator= (const NetlistDeviceExtractor &); void extract_without_initialize (db::Layout &layout, db::Cell &cell, hier_clusters_type &clusters, const std::vector &layers, double device_scaling, const std::set *breakout_cells); + void pre_extract_for_device_propagation (const hier_clusters_type &device_clusters, const std::set &called_cells, std::set::id_type> > &to_extract); void push_new_devices (const Vector &disp_cache); void push_cached_devices (const tl::vector &cached_devices, const db::Vector &disp_cache, const db::Vector &new_disp); }; diff --git a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc index 3429c2823..90af5c12d 100644 --- a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc +++ b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc @@ -218,6 +218,23 @@ Class decl_dbNetlistDeviceExtractor ("db", "DeviceEx "\n" "This method has been added in version 0.27.3.\n" ) + + gsi::method ("smart_device_propagation=", &db::NetlistDeviceExtractor::set_smart_device_propagation, gsi::arg ("flag"), + "@brief Sets a flag indicating whether to use 'smart device propagation'\n" + "If set to true, the extractor will run a pre-extraction pass to determine which devices\n" + "need to be propagated up in the hierarchy. This may reduce the need for hierarchy cheats\n" + "for overlapping devices.\n" + "\n" + "The default value is 'false', but can be changed by setting the 'KLAYOUT_SMART_DEVICE_PROPAGATION' environment " + "variable to '1'.\n" + "\n" + "This attribute has been introduced in version 0.29.5." + ) + + gsi::method ("smart_device_propagation", &db::NetlistDeviceExtractor::smart_device_propagation, + "@brief Gets a flag indicating whether to use 'smart device propagation'\n" + "See \\smart_device_propagation= for a description of that mode.\n" + "\n" + "This attribute has been introduced in version 0.29.5." + ) + gsi::method_ext ("test_initialize", &test_initialize, gsi::arg ("netlist"), "@hide") + // for test only gsi::iterator ("each_layer_definition", &db::NetlistDeviceExtractor::begin_layer_definitions, &db::NetlistDeviceExtractor::end_layer_definitions, "@brief Iterates over all layer definitions."