Soft connection analysis, first algorithm

This commit is contained in:
Matthias Koefferlein 2024-03-16 21:38:35 +01:00
parent db2ae89521
commit 9ab7a5a84f
2 changed files with 171 additions and 11 deletions

View File

@ -430,7 +430,7 @@ void LayoutToNetlist::extract_netlist ()
// treat soft connections
if (m_make_soft_connection_diodes) {
make_soft_connection_diodes ();
do_make_soft_connection_diodes ();
} else {
do_soft_connections ();
}
@ -651,7 +651,7 @@ void LayoutToNetlist::check_must_connect_impl (const db::Circuit &c, const db::N
}
}
void LayoutToNetlist::make_soft_connection_diodes ()
void LayoutToNetlist::do_make_soft_connection_diodes ()
{
db::DeviceClassDiode *soft_diode = 0;
@ -702,6 +702,7 @@ namespace
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)
@ -719,10 +720,12 @@ namespace
*/
void add (const db::Net *net, int dir, const db::Pin *pin, size_t partial_net_count)
{
m_partial_net_count += 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 && ! net->is_floating ()) {
if (! pin && dir < 0) {
m_partial_net_count += 1;
}
@ -752,7 +755,7 @@ namespace
/**
* @brief Gets the pins on the cluster (begin iterator)
*
* The iterator delivers Pin IDs
* The iterator delivers Pin IDs of pins leading outside the circuit this cluster lives in.
*/
pin_iterator begin_pins () const
{
@ -767,6 +770,22 @@ namespace
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;
@ -782,6 +801,26 @@ namespace
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
*/
@ -831,8 +870,25 @@ namespace
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:
std::list<SoftConnectionClusterInfo> m_cluster_info;
const db::Circuit *mp_circuit;
cluster_list m_cluster_info;
std::map<size_t, std::pair<int, const SoftConnectionClusterInfo *> > m_pin_info;
};
@ -855,7 +911,100 @@ namespace
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:
@ -871,7 +1020,7 @@ namespace
*/
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 ())).first->second;
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) {
@ -894,7 +1043,10 @@ namespace
for (auto cc = connected.begin (); cc != connected.end (); ++cc) {
const db::Net *net = circuit->net_by_cluster_id (*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:
@ -929,7 +1081,7 @@ namespace
// is this net associated with a pin?
const db::Pin *pin = 0;
if (net && net->begin_pins () != net->end_pins ()) {
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 ();
@ -939,7 +1091,10 @@ namespace
sc_cluster_info = &sc_circuit_info.make_cluster ();
}
sc_cluster_info->add (net, dir, pin, sc_partial_net_count);
// 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);
@ -1033,9 +1188,14 @@ namespace
void LayoutToNetlist::do_soft_connections ()
{
SoftConnectionInfo sc_info;
sc_info.build (*netlist (), net_clusters ());
// @@@
sc_info.print_errors (*netlist ());
// @@@
sc_info.join_soft_connections (*netlist ());
}
void LayoutToNetlist::do_join_nets ()

View File

@ -1113,7 +1113,7 @@ private:
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<const db::SubCircuit *> &path);
// for debugging and testing
void make_soft_connection_diodes ();
void do_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);