This commit is contained in:
Matthias Koefferlein 2024-03-16 18:19:20 +01:00
parent 5e95b32ac4
commit db2ae89521
3 changed files with 388 additions and 10 deletions

View File

@ -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<unsigned int> ());
@ -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<size_t> pin_set;
typedef pin_set::const_iterator pin_iterator;
typedef std::map<size_t, int> 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<SoftConnectionClusterInfo> 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 ()));
}
}
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 ())).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);
// 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 && 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<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 ()
{
// @@@
}
void LayoutToNetlist::do_join_nets ()
{
if (! mp_netlist) {

View File

@ -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<tl::GlobPattern> m_joined_net_names;
std::list<std::pair<tl::GlobPattern, tl::GlobPattern> > m_joined_net_names_per_cell;
std::list<std::set<std::string> > 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<const db::SubCircuit *> &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);

View File

@ -506,6 +506,12 @@ Class<db::LayoutToNetlist> 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"