From db2ae89521422a9fc58916ebfeb5671bc12824d0 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 16 Mar 2024 18:19:20 +0100 Subject: [PATCH] WIP --- src/db/db/dbLayoutToNetlist.cc | 376 +++++++++++++++++++++++++- src/db/db/dbLayoutToNetlist.h | 16 ++ src/db/db/gsiDeclDbLayoutToNetlist.cc | 6 + 3 files changed, 388 insertions(+), 10 deletions(-) diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index cf70d975a..aff06cb31 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -46,7 +46,7 @@ namespace db // Note: the iterator provides the hierarchical selection (enabling/disabling cells etc.) LayoutToNetlist::LayoutToNetlist (const db::RecursiveShapeIterator &iter) - : m_iter (iter), m_layout_index (0), m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false), m_top_level_mode (false) + : m_iter (iter), m_layout_index (0), m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false), m_top_level_mode (false), m_make_soft_connection_diodes (false) { // check the iterator if (iter.has_complex_region () || iter.region () != db::Box::world ()) { @@ -66,7 +66,7 @@ LayoutToNetlist::LayoutToNetlist (const db::RecursiveShapeIterator &iter) } LayoutToNetlist::LayoutToNetlist (db::DeepShapeStore *dss, unsigned int layout_index) - : mp_dss (dss), m_layout_index (layout_index), m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false), m_top_level_mode (false) + : mp_dss (dss), m_layout_index (layout_index), m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false), m_top_level_mode (false), m_make_soft_connection_diodes (false) { if (dss->is_valid_layout_index (m_layout_index)) { m_iter = db::RecursiveShapeIterator (dss->layout (m_layout_index), dss->initial_cell (m_layout_index), std::set ()); @@ -74,7 +74,7 @@ LayoutToNetlist::LayoutToNetlist (db::DeepShapeStore *dss, unsigned int layout_i } LayoutToNetlist::LayoutToNetlist (const std::string &topcell_name, double dbu) - : m_iter (), m_netlist_extracted (false), m_is_flat (true), m_device_scaling (1.0), m_include_floating_subcircuits (false), m_top_level_mode (false) + : m_iter (), m_netlist_extracted (false), m_is_flat (true), m_device_scaling (1.0), m_include_floating_subcircuits (false), m_top_level_mode (false), m_make_soft_connection_diodes (false) { mp_internal_dss.reset (new db::DeepShapeStore (topcell_name, dbu)); mp_dss.reset (mp_internal_dss.get ()); @@ -85,7 +85,7 @@ LayoutToNetlist::LayoutToNetlist (const std::string &topcell_name, double dbu) LayoutToNetlist::LayoutToNetlist () : m_iter (), mp_internal_dss (new db::DeepShapeStore ()), mp_dss (mp_internal_dss.get ()), m_layout_index (0), - m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false), m_top_level_mode (false) + m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false), m_top_level_mode (false), m_make_soft_connection_diodes (false) { init (); } @@ -427,8 +427,16 @@ void LayoutToNetlist::extract_netlist () // @@@ NOTE: can we have multiple pins on a net? Will this happen later maybe? tl_assert (check_many_pins (mp_netlist.get ())); // @@@ - do_soft_connections (); + + // treat soft connections + if (m_make_soft_connection_diodes) { + make_soft_connection_diodes (); + } else { + do_soft_connections (); + } + tl_assert (check_many_pins (mp_netlist.get ())); // @@@ + // implement the "join_nets" (aka "must connect") feature do_join_nets (); tl_assert (check_many_pins (mp_netlist.get ())); // @@@ @@ -643,16 +651,12 @@ void LayoutToNetlist::check_must_connect_impl (const db::Circuit &c, const db::N } } -void LayoutToNetlist::do_soft_connections () +void LayoutToNetlist::make_soft_connection_diodes () { - // @@@ NetlistLocker locked_netlist (mp_netlist.get ()); - db::DeviceClassDiode *soft_diode = 0; for (auto c = mp_netlist->begin_bottom_up (); c != mp_netlist->end_bottom_up (); ++c) { - // @@@ create diodes as of now - auto clusters = net_clusters ().clusters_per_cell (c->cell_index ()); for (auto n = c->begin_nets (); n != c->end_nets (); ++n) { @@ -682,6 +686,358 @@ void LayoutToNetlist::do_soft_connections () } } +namespace +{ + + /** + * @brief Describes a soft-connected cluster + * + * Such a cluster is a collection of nets/shape clusters that are connected via + * soft connections. + * There is also some information about the count of "down-only" nets. + */ + class SoftConnectionClusterInfo + { + public: + typedef std::set pin_set; + typedef pin_set::const_iterator pin_iterator; + typedef std::map dir_map; + + SoftConnectionClusterInfo () + : m_partial_net_count (0) + { + // .. nothing yet .. + } + + /** + * @brief Enters information about a specific net + * + * @param net The Net for which we are entering information + * @param dir The direction code of the net (0: no soft connection or both directions, +1: up-only, -1: down-only) + * @param pin A pin that might leading outside our current circuit from this net (0 if there is none) + * @param partial_net_count The partial net count of nets attached to this net inside subcircuits + */ + void add (const db::Net *net, int dir, const db::Pin *pin, size_t partial_net_count) + { + m_partial_net_count += partial_net_count; + + // this is where we make the decision about the partial nets ... + if (! pin && dir < 0 && ! net->is_floating ()) { + m_partial_net_count += 1; + } + + if (pin) { + m_pin_ids.insert (pin->id ()); + } + + m_cluster_dir.insert (std::make_pair (net->cluster_id (), dir)); + } + + /** + * @brief Gets the partial net count + * + * The partial net count is the number of nets definitely isolated. + * This is the count of "down-only" connected nets on the cluster. + * This may also involve nets from subcircuits. + * Only non-trivial (floating) nets are counted. + * + * A partial net count of more than one indicates a soft connection + * between nets. + */ + size_t partial_net_count () const + { + return m_partial_net_count; + } + + /** + * @brief Gets the pins on the cluster (begin iterator) + * + * The iterator delivers Pin IDs + */ + pin_iterator begin_pins () const + { + return m_pin_ids.begin (); + } + + /** + * @brief Gets the pins on the cluster (end iterator) + */ + pin_iterator end_pins () const + { + return m_pin_ids.end (); + } + + private: + pin_set m_pin_ids; + size_t m_partial_net_count; + dir_map m_cluster_dir; + }; + + /** + * @brief Provides temporary soft connection information for a circuit + * + * Soft connection information is the soft-connected-clusters that are formed inside + * the circuit and how these clusters connect to pins. + */ + class SoftConnectionCircuitInfo + { + public: + /** + * @brief Creates a new cluster info object + */ + SoftConnectionClusterInfo &make_cluster () + { + m_cluster_info.push_back (SoftConnectionClusterInfo ()); + return m_cluster_info.back (); + } + + /** + * @brief Adds information about a pin + * + * @param pin The pin + * @param dir The nature of connections from the pin: 0 if no soft connections / both directions, +1 to "up only" and -1 for "down only" + * @param sc_cluster_info The soft-connected net cluster info object + */ + void add_pin_info (const db::Pin *pin, int dir, SoftConnectionClusterInfo *sc_cluster_info) + { + if (pin) { + m_pin_info.insert (std::make_pair (pin->id (), std::make_pair (dir, sc_cluster_info))); + } + } + + /** + * @brief Gets the direction attribute of the pin + */ + int direction_per_pin (const db::Pin *pin) const + { + if (! pin) { + return 0; + } + + auto p = m_pin_info.find (pin->id ()); + return p != m_pin_info.end () ? p->second.first : 0; + } + + /** + * @brief Gets the soft-connected net cluster info object the pin connects to + */ + const SoftConnectionClusterInfo *get_cluster_info_per_pin (const db::Pin *pin) const + { + if (! pin) { + return 0; + } + + auto p = m_pin_info.find (pin->id ()); + return p != m_pin_info.end () ? p->second.second : 0; + } + + private: + std::list m_cluster_info; + std::map > m_pin_info; + }; + + /** + * @brief Provides temporary soft connection information for a netlist + */ + class SoftConnectionInfo + { + public: + SoftConnectionInfo () + { + // .. nothing yet .. + } + + /** + * @brief Builds the soft connection information for the given netlist and net clusters + */ + void build (const db::Netlist &netlist, const db::hier_clusters &net_clusters) + { + for (auto c = netlist.begin_bottom_up (); c != netlist.end_bottom_up (); ++c) { + build_clusters_for_circuit (c.operator-> (), net_clusters.clusters_per_cell (c->cell_index ())); + } + + } + + private: + /** + * @brief Builds the per-circuit cluster information + * + * First of all, this method creates a SoftConnectionCircuitInfo object for the circuit. + * + * Inside this per-circuit object, it will create a number of SoftConnectionClusterInfo objects - each one + * for a cluster of soft-connected nets. + * + * Call this method bottom-up as it needs SoftConnectionCircuitInfo objects for called circuits. + */ + void build_clusters_for_circuit (const db::Circuit *circuit, const db::connected_clusters &shape_clusters) + { + SoftConnectionCircuitInfo &sc_circuit_info = m_scc_per_circuit.insert (std::make_pair (circuit, SoftConnectionCircuitInfo ())).first->second; + + std::set seen; + for (auto c = shape_clusters.begin (); c != shape_clusters.end (); ++c) { + + if (seen.find (c->id ()) != seen.end ()) { + continue; + } + + // incrementally collect further connected nets (shape clusters) + + std::set connected; + connected.insert (c->id ()); + seen.insert (c->id ()); + + SoftConnectionClusterInfo *sc_cluster_info = 0; + + while (! connected.empty ()) { + + std::set next_connected; + + for (auto cc = connected.begin (); cc != connected.end (); ++cc) { + + const db::Net *net = circuit->net_by_cluster_id (*cc); + + // the direction of a net is 0 for "no connections" or "both up and down" + // and -1 for "down-only" connections and +1 for "up-only" connections: + + int dir = 0; + + // direct soft connections to other nets + + for (int up = 0; up < 2; ++up) { + std::set next = up ? shape_clusters.upward_soft_connections (*cc) : shape_clusters.downward_soft_connections (*cc); + if (! next.empty () || net_has_up_or_down_subcircuit_connections (net, up)) { + dir += up ? 1 : -1; + } + for (auto i = next.begin (); i != next.end (); ++i) { + if (seen.insert (*i).second) { + next_connected.insert (*i); + } + } + } + + // collect soft connections via subcircuits + + size_t sc_partial_net_count = 0; + std::set next = net_connections_through_subcircuits (net, sc_partial_net_count); + + for (auto i = next.begin (); i != next.end (); ++i) { + if (seen.insert (*i).second) { + next_connected.insert (*i); + } + } + + // is this net associated with a pin? + + const db::Pin *pin = 0; + if (net && net->begin_pins () != net->end_pins ()) { + // TODO: multiple pins per net need to be supported? + tl_assert (net->pin_count () == 1); + pin = net->begin_pins ()->pin (); + } + + if (! sc_cluster_info) { + sc_cluster_info = &sc_circuit_info.make_cluster (); + } + + sc_cluster_info->add (net, dir, pin, sc_partial_net_count); + + sc_circuit_info.add_pin_info (pin, dir, sc_cluster_info); + + } + + connected.swap (next_connected); + + } + + } + + } + + /** + * @brief Gets a value indicating whether the given net connects to subcircuits with up or down connections inside + */ + bool net_has_up_or_down_subcircuit_connections (const db::Net *net, bool up) + { + int look_for_dir = up ? 1 : -1; + + for (auto sc = net->begin_subcircuit_pins (); sc != net->end_subcircuit_pins (); ++sc) { + const db::Pin *pin = sc->pin (); + const db::Circuit *ref = sc->subcircuit ()->circuit_ref (); + auto scc_ref = m_scc_per_circuit.find (ref); + if (scc_ref != m_scc_per_circuit.end ()) { + int dir = scc_ref->second.direction_per_pin (pin); + if (dir == look_for_dir) { + return true; + } + } + } + + return false; + } + + /** + * @brief Gets connections to other nets / shape clusters through the given subcircuit from the given pin + * + * As a side effect, this method will also collect the partial net count - that is the number + * of defintively disconnected (down-only) nets. + * More that one such a net will render an error. + */ + void get_net_connections_through_subcircuit (const db::SubCircuit *subcircuit, const db::Pin *pin, std::set &ids, size_t &partial_net_count) + { + auto scc = m_scc_per_circuit.find (subcircuit->circuit_ref ()); + if (scc != m_scc_per_circuit.end ()) { + + const SoftConnectionCircuitInfo &sci = scc->second; + + const SoftConnectionClusterInfo *scci = sci.get_cluster_info_per_pin (pin); + if (scci) { + + partial_net_count += scci->partial_net_count (); + + for (auto p = scci->begin_pins (); p != scci->end_pins (); ++p) { + if (*p != pin->id ()) { + const NetSubcircuitPinRef *netref = subcircuit->netref_for_pin (*p); + if (netref && netref->net ()) { + ids.insert (netref->net ()->cluster_id ()); + } + } + } + + } + + } + } + + /** + * @brief Gets connections to other nets / shape clusters through the subcircuits on the net + * + * As a side effect, this method will also collect the partial net count - that is the number + * of defintively disconnected (down-only) nets. + * More that one such a net will render an error. + * + * The return value is a set of nets shape cluster IDs. + */ + std::set net_connections_through_subcircuits (const db::Net *net, size_t &partial_net_count) + { + std::set ids; + for (auto sc = net->begin_subcircuit_pins (); sc != net->end_subcircuit_pins (); ++sc) { + get_net_connections_through_subcircuit (sc->subcircuit (), sc->pin (), ids, partial_net_count); + } + return ids; + } + + std::map m_scc_per_circuit; + }; + +} + +void LayoutToNetlist::do_soft_connections () +{ + + // @@@ + +} + void LayoutToNetlist::do_join_nets () { if (! mp_netlist) { diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 01f945e97..c6630d13b 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -1045,6 +1045,18 @@ public: */ void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const; + // for debugging and testing + bool make_soft_connection_diodes () const + { + return m_make_soft_connection_diodes; + } + + // for debugging and testing + void set_make_soft_connection_diodes (bool f) + { + m_make_soft_connection_diodes = f; + } + private: // no copying LayoutToNetlist (const db::LayoutToNetlist &other); @@ -1074,6 +1086,7 @@ private: std::string m_generator; bool m_include_floating_subcircuits; bool m_top_level_mode; + bool m_make_soft_connection_diodes; std::list m_joined_net_names; std::list > m_joined_net_names_per_cell; std::list > m_joined_nets; @@ -1099,6 +1112,9 @@ private: void check_must_connect (const db::Circuit &c, const db::Net &a, const db::Net &b); void check_must_connect_impl (const db::Circuit &c, const db::Net &a, const db::Net &b, const db::Circuit &c_org, const db::Net &a_org, const db::Net &b_org, std::vector &path); + // for debugging and testing + void make_soft_connection_diodes (); + // implementation of NetlistManipulationCallbacks virtual size_t link_net_to_parent_circuit (const Net *subcircuit_net, Circuit *parent_circuit, const DCplxTrans &trans); virtual void link_nets (const db::Net *net, const db::Net *with); diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index e8f12cddf..a9c06d59d 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -506,6 +506,12 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "\n" "This attribute has been introduced in version 0.27.\n" ) + + gsi::method ("make_soft_connection_diodes=", &db::LayoutToNetlist::set_make_soft_connection_diodes, gsi::arg ("flag"), + "@hide" + ) + + gsi::method ("make_soft_connection_diodes", &db::LayoutToNetlist::make_soft_connection_diodes, + "@hide" + ) + gsi::method ("top_level_mode=", &db::LayoutToNetlist::set_top_level_mode, gsi::arg ("flag"), "@brief Sets a flag indicating whether top level mode is enabled.\n" "\n"