diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 8f0e76770..b6aac64f3 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -45,6 +45,7 @@ SOURCES = \ dbLayoutDiff.cc \ dbLayoutQuery.cc \ dbLayoutStateModel.cc \ + dbLayoutToNetlistSoftConnections.cc \ dbLayoutUtils.cc \ dbLibrary.cc \ dbLibraryManager.cc \ @@ -270,6 +271,7 @@ HEADERS = \ dbLayoutQuery.h \ dbLayoutStateModel.h \ dbLayoutToNetlistEnums.h \ + dbLayoutToNetlistSoftConnections.h \ dbLayoutUtils.h \ dbLibrary.h \ dbLibraryManager.h \ diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index f80f1e7d2..0b2ab5c55 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -32,6 +32,7 @@ #include "dbLayoutVsSchematic.h" #include "dbLayoutToNetlistFormatDefs.h" #include "dbLayoutVsSchematicFormatDefs.h" +#include "dbLayoutToNetlistSoftConnections.h" #include "dbShapeProcessor.h" #include "dbNetlistDeviceClasses.h" #include "dbLog.h" @@ -686,506 +687,6 @@ void LayoutToNetlist::do_make_soft_connection_diodes () } } -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; - typedef dir_map::const_iterator dir_map_iterator; - - 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) - { - // limiting the partial net count to 1 means we report errors only once in the - // hierarchy, not on every level - m_partial_net_count += std::min (size_t (1), partial_net_count); - - // this is where we make the decision about the partial nets ... - if (! pin && dir < 0) { - 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 of pins leading outside the circuit this cluster lives in. - */ - 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 (); - } - - /** - * @brief Gets the shape clusters + dir information (begin iterator) - */ - dir_map_iterator begin_clusters () const - { - return m_cluster_dir.begin (); - } - - /** - * @brief Gets the shape clusters + dir information (end iterator) - */ - dir_map_iterator end_clusters () const - { - return m_cluster_dir.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: - typedef std::list cluster_list; - typedef cluster_list::const_iterator cluster_list_iterator; - - /** - * @brief Constructor - */ - SoftConnectionCircuitInfo (const db::Circuit *circuit) - : mp_circuit (circuit) - { - // .. nothing yet .. - } - - /** - * @brief Gets the circuit for this info object - */ - const db::Circuit *circuit () const - { - return mp_circuit; - } - - /** - * @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; - } - - /** - * @brief List of per-circui info objects, begin iterator - */ - cluster_list_iterator begin () const - { - return m_cluster_info.begin (); - } - - /** - * @brief List of per-circui info objects, end iterator - */ - cluster_list_iterator end () const - { - return m_cluster_info.end (); - } - - private: - const db::Circuit *mp_circuit; - cluster_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 ())); - } - } - - /** - * @brief Joins nets connected by soft connections - * - * This method will clear the information from this object - * as the clusters will no longer be valid. - */ - void join_soft_connections (db::Netlist &netlist) - { - if (tl::verbosity () >= 20) { - tl::info << "Joining soft-connected net clusters .."; - } - - size_t nclusters_tot = 0; - size_t npartial_tot = 0; - - for (auto c = netlist.begin_top_down (); c != netlist.end_top_down (); ++c) { - - size_t nclusters = 0; - size_t npartial = 0; - - auto scc = m_scc_per_circuit.find (c.operator-> ()); - if (scc == m_scc_per_circuit.end ()) { - continue; - } - - const SoftConnectionCircuitInfo &sc_info = scc->second; - - for (auto sc = sc_info.begin (); sc != sc_info.end (); ++sc) { - - auto cc = sc->begin_clusters (); - if (cc != sc->end_clusters ()) { - db::Net *net0 = c->net_by_cluster_id (cc->first); - tl_assert (net0 != 0); - ++nclusters; - while (++cc != sc->end_clusters ()) { - // TODO: logging? - c->join_nets (net0, c->net_by_cluster_id (cc->first)); - ++npartial; - } - } - - } - - nclusters_tot += nclusters; - npartial_tot += npartial; - - if (nclusters > 0 && tl::verbosity () >= 30) { - tl::info << "Circuit " << c->name () << ": joined " << nclusters << " soft-connected net clusters with " << npartial << " partial nets."; - } - - } - - if (tl::verbosity () >= 20) { - tl::info << "Joined " << nclusters_tot << " soft-connected net clusters with " << npartial_tot << " partial nets in total."; - } - - m_scc_per_circuit.clear (); - } - - void print_errors (const db::Netlist &netlist) - { - for (auto c = netlist.begin_bottom_up (); c != netlist.end_bottom_up (); ++c) { - - auto scc = m_scc_per_circuit.find (c.operator-> ()); - if (scc == m_scc_per_circuit.end ()) { - continue; - } - - const SoftConnectionCircuitInfo &sc_info = scc->second; - - bool first = true; - for (auto sc = sc_info.begin (); sc != sc_info.end (); ++sc) { - - if (sc->partial_net_count () < 2) { - continue; - } - - if (first) { - tl::info << "Circuit " << c->name () << ":"; - first = false; - } - - tl::info << " Partial nets on soft-connect cluster:"; - for (auto cc = sc->begin_clusters (); cc != sc->end_clusters (); ++cc) { - if (cc->second < 0) { - tl::info << " " << c->net_by_cluster_id (cc->first)->expanded_name (); - } - } - - } - - } - } - - 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 (circuit))).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); - if (! net) { - continue; - } - - // 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->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 (); - } - - // we do not count floating nets as they cannot make a functional connection - if (! net->is_floating ()) { - 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 () { SoftConnectionInfo sc_info; diff --git a/src/db/db/dbLayoutToNetlistSoftConnections.cc b/src/db/db/dbLayoutToNetlistSoftConnections.cc new file mode 100644 index 000000000..0380d4dca --- /dev/null +++ b/src/db/db/dbLayoutToNetlistSoftConnections.cc @@ -0,0 +1,348 @@ + + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2024 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 "dbCommon.h" +#include "dbLayoutToNetlistSoftConnections.h" +#include "dbLayoutToNetlist.h" +#include "dbNetlist.h" + +namespace db +{ + +// ------------------------------------------------------------------------------- +// SoftConnectionClusterInfo implementation + +SoftConnectionClusterInfo::SoftConnectionClusterInfo () + : m_partial_net_count (0) +{ + // .. nothing yet .. +} + +void SoftConnectionClusterInfo::add (const db::Net *net, int dir, const db::Pin *pin, size_t partial_net_count) +{ + // limiting the partial net count to 1 means we report errors only once in the + // hierarchy, not on every level + m_partial_net_count += std::min (size_t (1), partial_net_count); + + // this is where we make the decision about the partial nets ... + if (! pin && dir < 0) { + m_partial_net_count += 1; + } + + if (pin) { + m_pin_ids.insert (pin->id ()); + } + + m_cluster_dir.insert (std::make_pair (net->cluster_id (), dir)); +} + +// ------------------------------------------------------------------------------- +// SoftConnectionCircuitInfo implementation + +SoftConnectionCircuitInfo::SoftConnectionCircuitInfo (const db::Circuit *circuit) + : mp_circuit (circuit) +{ + // .. nothing yet .. +} + +SoftConnectionClusterInfo &SoftConnectionCircuitInfo::make_cluster () +{ + m_cluster_info.push_back (SoftConnectionClusterInfo ()); + return m_cluster_info.back (); +} + +void SoftConnectionCircuitInfo::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))); + } +} + +int SoftConnectionCircuitInfo::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; +} + +const SoftConnectionClusterInfo *SoftConnectionCircuitInfo::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; +} + +// ------------------------------------------------------------------------------- +// SoftConnectionInfo implementation + +SoftConnectionInfo::SoftConnectionInfo () +{ + // .. nothing yet .. +} + +void SoftConnectionInfo::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 ())); + } +} + +void SoftConnectionInfo::join_soft_connections (db::Netlist &netlist) +{ + if (tl::verbosity () >= 20) { + tl::info << "Joining soft-connected net clusters .."; + } + + size_t nclusters_tot = 0; + size_t npartial_tot = 0; + + for (auto c = netlist.begin_top_down (); c != netlist.end_top_down (); ++c) { + + size_t nclusters = 0; + size_t npartial = 0; + + auto scc = m_scc_per_circuit.find (c.operator-> ()); + if (scc == m_scc_per_circuit.end ()) { + continue; + } + + const SoftConnectionCircuitInfo &sc_info = scc->second; + + for (auto sc = sc_info.begin (); sc != sc_info.end (); ++sc) { + + auto cc = sc->begin_clusters (); + if (cc != sc->end_clusters ()) { + db::Net *net0 = c->net_by_cluster_id (cc->first); + tl_assert (net0 != 0); + ++nclusters; + while (++cc != sc->end_clusters ()) { + // TODO: logging? + c->join_nets (net0, c->net_by_cluster_id (cc->first)); + ++npartial; + } + } + + } + + nclusters_tot += nclusters; + npartial_tot += npartial; + + if (nclusters > 0 && tl::verbosity () >= 30) { + tl::info << "Circuit " << c->name () << ": joined " << nclusters << " soft-connected net clusters with " << npartial << " partial nets."; + } + + } + + if (tl::verbosity () >= 20) { + tl::info << "Joined " << nclusters_tot << " soft-connected net clusters with " << npartial_tot << " partial nets in total."; + } + + m_scc_per_circuit.clear (); +} + +void SoftConnectionInfo::print_errors (const db::Netlist &netlist) +{ + for (auto c = netlist.begin_bottom_up (); c != netlist.end_bottom_up (); ++c) { + + auto scc = m_scc_per_circuit.find (c.operator-> ()); + if (scc == m_scc_per_circuit.end ()) { + continue; + } + + const SoftConnectionCircuitInfo &sc_info = scc->second; + + bool first = true; + for (auto sc = sc_info.begin (); sc != sc_info.end (); ++sc) { + + if (sc->partial_net_count () < 2) { + continue; + } + + if (first) { + tl::info << "Circuit " << c->name () << ":"; + first = false; + } + + tl::info << " Partial nets on soft-connect cluster:"; + for (auto cc = sc->begin_clusters (); cc != sc->end_clusters (); ++cc) { + if (cc->second < 0) { + tl::info << " " << c->net_by_cluster_id (cc->first)->expanded_name (); + } + } + + } + + } +} + +void SoftConnectionInfo::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 (circuit))).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); + if (! net) { + continue; + } + + // 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->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 (); + } + + // we do not count floating nets as they cannot make a functional connection + if (! net->is_floating ()) { + 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); + + } + + } + +} + +bool SoftConnectionInfo::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; +} + +void SoftConnectionInfo::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 ()); + } + } + } + + } + + } +} + +std::set SoftConnectionInfo::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; +} + +} diff --git a/src/db/db/dbLayoutToNetlistSoftConnections.h b/src/db/db/dbLayoutToNetlistSoftConnections.h new file mode 100644 index 000000000..9c2bad69d --- /dev/null +++ b/src/db/db/dbLayoutToNetlistSoftConnections.h @@ -0,0 +1,269 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2024 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_dbLayoutToNetlistSoftConnections +#define _HDR_dbLayoutToNetlistSoftConnections + +#include "dbCommon.h" + +#include +#include +#include +#include + +namespace db +{ + +class Net; +class Pin; +class Circuit; +class Netlist; +class SubCircuit; + +template class hier_clusters; +template class connected_clusters; +class NetShape; + +/** + * @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 DB_PUBLIC SoftConnectionClusterInfo +{ +public: + typedef std::set pin_set; + typedef pin_set::const_iterator pin_iterator; + typedef std::map dir_map; + typedef dir_map::const_iterator dir_map_iterator; + + SoftConnectionClusterInfo (); + + /** + * @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); + + /** + * @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 of pins leading outside the circuit this cluster lives in. + */ + 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 (); + } + + /** + * @brief Gets the shape clusters + dir information (begin iterator) + */ + dir_map_iterator begin_clusters () const + { + return m_cluster_dir.begin (); + } + + /** + * @brief Gets the shape clusters + dir information (end iterator) + */ + dir_map_iterator end_clusters () const + { + return m_cluster_dir.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 DB_PUBLIC SoftConnectionCircuitInfo +{ +public: + typedef std::list cluster_list; + typedef cluster_list::const_iterator cluster_list_iterator; + + /** + * @brief Constructor + */ + SoftConnectionCircuitInfo (const db::Circuit *circuit); + + /** + * @brief Gets the circuit for this info object + */ + const db::Circuit *circuit () const + { + return mp_circuit; + } + + /** + * @brief Creates a new cluster info object + */ + SoftConnectionClusterInfo &make_cluster (); + + /** + * @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); + + /** + * @brief Gets the direction attribute of the pin + */ + int direction_per_pin (const db::Pin *pin) const; + + /** + * @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; + + /** + * @brief List of per-circui info objects, begin iterator + */ + cluster_list_iterator begin () const + { + return m_cluster_info.begin (); + } + + /** + * @brief List of per-circui info objects, end iterator + */ + cluster_list_iterator end () const + { + return m_cluster_info.end (); + } + +private: + const db::Circuit *mp_circuit; + cluster_list m_cluster_info; + std::map > m_pin_info; +}; + +/** + * @brief Provides temporary soft connection information for a netlist + */ +class DB_PUBLIC SoftConnectionInfo +{ +public: + SoftConnectionInfo (); + + /** + * @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); + + /** + * @brief Joins nets connected by soft connections + * + * This method will clear the information from this object + * as the clusters will no longer be valid. + */ + void join_soft_connections (db::Netlist &netlist); + + /** + * @brief For debugging + */ + void print_errors (const db::Netlist &netlist); + +private: + std::map m_scc_per_circuit; + + /** + * @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); + + /** + * @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); + + /** + * @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); + + /** + * @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); +}; + +} + +#endif