mirror of https://github.com/KLayout/klayout.git
Refactoring (split source code file)
This commit is contained in:
parent
9ab7a5a84f
commit
b9baa24d3a
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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<size_t> pin_set;
|
||||
typedef pin_set::const_iterator pin_iterator;
|
||||
typedef std::map<size_t, int> 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<SoftConnectionClusterInfo> 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<size_t, std::pair<int, const SoftConnectionClusterInfo *> > 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<db::NetShape> &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<db::NetShape> &shape_clusters)
|
||||
{
|
||||
SoftConnectionCircuitInfo &sc_circuit_info = m_scc_per_circuit.insert (std::make_pair (circuit, SoftConnectionCircuitInfo (circuit))).first->second;
|
||||
|
||||
std::set<size_t> 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<size_t> connected;
|
||||
connected.insert (c->id ());
|
||||
seen.insert (c->id ());
|
||||
|
||||
SoftConnectionClusterInfo *sc_cluster_info = 0;
|
||||
|
||||
while (! connected.empty ()) {
|
||||
|
||||
std::set<size_t> 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<size_t> 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<size_t> 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<size_t> &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<size_t> net_connections_through_subcircuits (const db::Net *net, size_t &partial_net_count)
|
||||
{
|
||||
std::set<size_t> 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<const db::Circuit *, SoftConnectionCircuitInfo> m_scc_per_circuit;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void LayoutToNetlist::do_soft_connections ()
|
||||
{
|
||||
SoftConnectionInfo sc_info;
|
||||
|
|
|
|||
|
|
@ -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<db::NetShape> &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<db::NetShape> &shape_clusters)
|
||||
{
|
||||
SoftConnectionCircuitInfo &sc_circuit_info = m_scc_per_circuit.insert (std::make_pair (circuit, SoftConnectionCircuitInfo (circuit))).first->second;
|
||||
|
||||
std::set<size_t> 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<size_t> connected;
|
||||
connected.insert (c->id ());
|
||||
seen.insert (c->id ());
|
||||
|
||||
SoftConnectionClusterInfo *sc_cluster_info = 0;
|
||||
|
||||
while (! connected.empty ()) {
|
||||
|
||||
std::set<size_t> 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<size_t> 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<size_t> 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<size_t> &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<size_t> SoftConnectionInfo::net_connections_through_subcircuits (const db::Net *net, size_t &partial_net_count)
|
||||
{
|
||||
std::set<size_t> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 <set>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <cstddef>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
class Net;
|
||||
class Pin;
|
||||
class Circuit;
|
||||
class Netlist;
|
||||
class SubCircuit;
|
||||
|
||||
template <class T> class hier_clusters;
|
||||
template <class T> 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<size_t> pin_set;
|
||||
typedef pin_set::const_iterator pin_iterator;
|
||||
typedef std::map<size_t, int> 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<SoftConnectionClusterInfo> 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<size_t, std::pair<int, const SoftConnectionClusterInfo *> > 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<db::NetShape> &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<const db::Circuit *, SoftConnectionCircuitInfo> 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<db::NetShape> &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<size_t> &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<size_t> net_connections_through_subcircuits (const db::Net *net, size_t &partial_net_count);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue