From 284a907ffb02ef2c590f27f428e85570c940a743 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 10 Mar 2024 23:35:56 +0100 Subject: [PATCH] First steps: equipping the Connectivity object with soft connections --- src/db/db/dbHierNetworkProcessor.cc | 98 +++++++++++++------ src/db/db/dbHierNetworkProcessor.h | 66 +++++++++++-- src/db/db/dbLayoutToNetlist.cc | 58 ++++++++++- src/db/db/dbLayoutToNetlist.h | 55 +++++++++++ src/db/db/dbLayoutToNetlistFormatDefs.cc | 4 + src/db/db/dbLayoutToNetlistFormatDefs.h | 11 ++- src/db/db/dbLayoutToNetlistReader.cc | 34 ++++++- src/db/db/dbLayoutToNetlistWriter.cc | 60 +++++++++--- .../unit_tests/dbHierNetworkProcessorTests.cc | 88 +++++++++++------ src/layui/layui/layNetInfoDialog.cc | 4 +- src/layui/layui/layNetlistBrowserDialog.cc | 2 +- src/layui/layui/layNetlistBrowserPage.cc | 4 +- 12 files changed, 390 insertions(+), 94 deletions(-) diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 066d8eeb0..8ac6a9581 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -113,11 +113,20 @@ Connectivity::Connectivity (edge_connectivity_type ec) // .. nothing yet .. } +void +Connectivity::soft_connect (unsigned int la, unsigned int lb) +{ + m_connected [la][lb] = -1; + m_connected [lb][la] = 1; + m_all_layers.insert (la); + m_all_layers.insert (lb); +} + void Connectivity::connect (unsigned int la, unsigned int lb) { - m_connected [la].insert (lb); - m_connected [lb].insert (la); + m_connected [la][lb] = 0; + m_connected [lb][la] = 0; m_all_layers.insert (la); m_all_layers.insert (lb); } @@ -125,7 +134,7 @@ Connectivity::connect (unsigned int la, unsigned int lb) void Connectivity::connect (unsigned int l) { - m_connected [l].insert (l); + m_connected [l][l] = 0; m_all_layers.insert (l); } @@ -141,6 +150,12 @@ Connectivity::connect (const db::DeepLayer &la, const db::DeepLayer &lb) connect (la.layer (), lb.layer ()); } +void +Connectivity::soft_connect (const db::DeepLayer &la, const db::DeepLayer &lb) +{ + soft_connect (la.layer (), lb.layer ()); +} + Connectivity::global_nets_type s_empty_global_nets; Connectivity::global_nets_iterator @@ -169,7 +184,16 @@ size_t Connectivity::connect_global (unsigned int l, const std::string &gn) { size_t id = global_net_id (gn); - m_global_connections [l].insert (id); + m_global_connections [l][id] = 0; + m_all_layers.insert (l); + return id; +} + +size_t +Connectivity::soft_connect_global (unsigned int l, const std::string &gn) +{ + size_t id = global_net_id (gn); + m_global_connections [l][id] = -1; m_all_layers.insert (l); return id; } @@ -180,6 +204,12 @@ Connectivity::connect_global (const db::DeepLayer &l, const std::string &gn) return connect_global (l.layer (), gn); } +size_t +Connectivity::soft_connect_global (const db::DeepLayer &l, const std::string &gn) +{ + return soft_connect_global (l.layer (), gn); +} + const std::string & Connectivity::global_net_name (size_t id) const { @@ -208,13 +238,13 @@ Connectivity::global_nets () const return m_global_net_names.size (); } -Connectivity::layer_iterator +Connectivity::all_layer_iterator Connectivity::begin_layers () const { return m_all_layers.begin (); } -Connectivity::layer_iterator +Connectivity::all_layer_iterator Connectivity::end_layers () const { return m_all_layers.end (); @@ -306,13 +336,19 @@ interaction_test (const db::Edge &a, const db::Edge &b, const db::unit_trans } template -bool Connectivity::interacts (const T &a, unsigned int la, const T &b, unsigned int lb, const Trans &trans) const +bool Connectivity::interacts (const T &a, unsigned int la, const T &b, unsigned int lb, const Trans &trans, int &soft) const { std::map::const_iterator i = m_connected.find (la); - if (i == m_connected.end () || i->second.find (lb) == i->second.end ()) { + if (i == m_connected.end ()) { return false; } else { - return interaction_test (a, b, trans, m_ec); + auto t = i->second.find (lb); + if (t == i->second.end () || ! interaction_test (a, b, trans, m_ec)) { + return false; + } else { + soft = t->second; + return true; + } } } @@ -321,7 +357,7 @@ bool Connectivity::interacts (const std::set &la, const std::set::const_iterator i = la.begin (); i != la.end (); ++i) { db::Connectivity::layer_iterator je = end_connected (*i); for (db::Connectivity::layer_iterator j = begin_connected (*i); j != je; ++j) { - if (lb.find (*j) != lb.end ()) { + if (lb.find (j->first) != lb.end ()) { return true; } } @@ -335,7 +371,7 @@ bool Connectivity::interact (const db::Cell &a, const db::Cell &b) const for (std::map::const_iterator i = m_connected.begin (); i != m_connected.end (); ++i) { if (! a.bbox (i->first).empty ()) { for (layers_type::const_iterator j = i->second.begin (); j != i->second.end (); ++j) { - if (! b.bbox (*j).empty ()) { + if (! b.bbox (j->first).empty ()) { return true; } } @@ -353,7 +389,7 @@ bool Connectivity::interact (const db::Cell &a, const T &ta, const db::Cell &b, if (! ba.empty ()) { ba.transform (ta); for (layers_type::const_iterator j = i->second.begin (); j != i->second.end (); ++j) { - db::Box bb = b.bbox (*j); + db::Box bb = b.bbox (j->first); if (! bb.empty () && bb.transformed (tb).touches (ba)) { return true; } @@ -365,12 +401,12 @@ bool Connectivity::interact (const db::Cell &a, const T &ta, const db::Cell &b, } // explicit instantiations -template DB_PUBLIC bool Connectivity::interacts (const db::NetShape &a, unsigned int la, const db::NetShape &b, unsigned int lb, const db::UnitTrans &trans) const; -template DB_PUBLIC bool Connectivity::interacts (const db::NetShape &a, unsigned int la, const db::NetShape &b, unsigned int lb, const db::ICplxTrans &trans) const; -template DB_PUBLIC bool Connectivity::interacts (const db::PolygonRef &a, unsigned int la, const db::PolygonRef &b, unsigned int lb, const db::UnitTrans &trans) const; -template DB_PUBLIC bool Connectivity::interacts (const db::PolygonRef &a, unsigned int la, const db::PolygonRef &b, unsigned int lb, const db::ICplxTrans &trans) const; -template DB_PUBLIC bool Connectivity::interacts (const db::Edge &a, unsigned int la, const db::Edge &b, unsigned int lb, const db::UnitTrans &trans) const; -template DB_PUBLIC bool Connectivity::interacts (const db::Edge &a, unsigned int la, const db::Edge &b, unsigned int lb, const db::ICplxTrans &trans) const; +template DB_PUBLIC bool Connectivity::interacts (const db::NetShape &a, unsigned int la, const db::NetShape &b, unsigned int lb, const db::UnitTrans &trans, int &soft) const; +template DB_PUBLIC bool Connectivity::interacts (const db::NetShape &a, unsigned int la, const db::NetShape &b, unsigned int lb, const db::ICplxTrans &trans, int &soft) const; +template DB_PUBLIC bool Connectivity::interacts (const db::PolygonRef &a, unsigned int la, const db::PolygonRef &b, unsigned int lb, const db::UnitTrans &trans, int &soft) const; +template DB_PUBLIC bool Connectivity::interacts (const db::PolygonRef &a, unsigned int la, const db::PolygonRef &b, unsigned int lb, const db::ICplxTrans &trans, int &soft) const; +template DB_PUBLIC bool Connectivity::interacts (const db::Edge &a, unsigned int la, const db::Edge &b, unsigned int lb, const db::UnitTrans &trans, int &soft) const; +template DB_PUBLIC bool Connectivity::interacts (const db::Edge &a, unsigned int la, const db::Edge &b, unsigned int lb, const db::ICplxTrans &trans, int &soft) const; template DB_PUBLIC bool Connectivity::interact (const db::Cell &a, const db::ICplxTrans &ta, const db::Cell &b, const db::ICplxTrans &tb) const; // ------------------------------------------------------------------------------ @@ -496,7 +532,8 @@ public: void add (const T *s1, unsigned int l1, const T *s2, unsigned int l2) { - if (mp_conn->interacts (*s1, l1, *s2, l2, m_trans)) { + int soft; // @@@ + if (mp_conn->interacts (*s1, l1, *s2, l2, m_trans, soft)) { m_any = true; } } @@ -559,7 +596,7 @@ local_cluster::interacts (const db::Cell &cell, const db::ICplxTrans &trans, Connectivity::layer_iterator le = conn.end_connected (s->first); for (Connectivity::layer_iterator l = conn.begin_connected (s->first); l != le; ++l) { - box += cell.bbox (*l); + box += cell.bbox (l->first); // @@@ soft connections? } if (! box.empty () && ! s->second.begin_touching (box.transformed (trans), bc).at_end ()) { @@ -933,7 +970,8 @@ struct cluster_building_receiver if (m_separate_attributes && p1.second != p2.second) { return; } - if (! mp_conn->interacts (*s1, p1.first, *s2, p2.first)) { + int soft; // @@@ + if (! mp_conn->interacts (*s1, p1.first, *s2, p2.first, soft)) { return; } @@ -996,12 +1034,12 @@ struct cluster_building_receiver db::Connectivity::global_nets_iterator ge = mp_conn->end_global_connections (p.first); for (db::Connectivity::global_nets_iterator g = mp_conn->begin_global_connections (p.first); g != ge; ++g) { - typename std::map::iterator>::iterator icg = m_global_to_clusters.find (*g); + typename std::map::iterator>::iterator icg = m_global_to_clusters.find (g->first); // @@@ soft connections if (icg == m_global_to_clusters.end ()) { - ic->second->second.insert (*g); - m_global_to_clusters.insert (std::make_pair (*g, ic->second)); + ic->second->second.insert (g->first); // @@@ soft connections? + m_global_to_clusters.insert (std::make_pair (g->first, ic->second)); // @@@ soft connections? } else if (ic->second != icg->second) { @@ -1110,7 +1148,7 @@ local_clusters::build_clusters (const db::Cell &cell, const db::Connectivity attr_accessor attr; db::ShapeIterator::flags_type shape_flags = get_shape_flags () (); - for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) { + for (db::Connectivity::all_layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) { const db::Shapes &shapes = cell.shapes (*l); for (db::Shapes::shape_iterator s = shapes.begin (shape_flags); ! s.at_end (); ++s) { bs.insert (heap (*s), std::make_pair (*l, attr (*s))); @@ -1643,13 +1681,13 @@ private: // reject the pair bool any = false; - for (db::Connectivity::layer_iterator la = mp_conn->begin_layers (); la != mp_conn->end_layers () && ! any; ++la) { + for (db::Connectivity::all_layer_iterator la = mp_conn->begin_layers (); la != mp_conn->end_layers () && ! any; ++la) { db::box_convert bca (*mp_layout, *la); box_type bb1 = i1.cell_inst ().bbox (bca).transformed (t1); if (! bb1.empty ()) { db::Connectivity::layer_iterator lbe = mp_conn->end_connected (*la); for (db::Connectivity::layer_iterator lb = mp_conn->begin_connected (*la); lb != lbe && ! any; ++lb) { - db::box_convert bcb (*mp_layout, *lb); + db::box_convert bcb (*mp_layout, lb->first); // @@@ soft connections? box_type bb2 = i2.cell_inst ().bbox (bcb).transformed (t2); any = bb1.touches (bb2); } @@ -2186,6 +2224,10 @@ hier_clusters::propagate_cluster_inst (const db::Layout &layout, const db::Ce if (child_cc.is_root (id)) { std::set > seen; // to avoid duplicate connections + if (! with_self) { + // don't include the instance we came up with initially + seen.insert (std::make_pair (cell.cell_index (), ci)); + } const db::Cell &child_cell = layout.cell (ci.inst_cell_index ()); for (db::Cell::parent_inst_iterator pi = child_cell.begin_parent_insts (); ! pi.at_end (); ++pi) { @@ -2196,7 +2238,7 @@ hier_clusters::propagate_cluster_inst (const db::Layout &layout, const db::Ce for (db::CellInstArray::iterator pii = child_inst.begin (); ! pii.at_end (); ++pii) { ClusterInstance ci2 (id, child_inst.cell_index (), child_inst.complex_trans (*pii), child_inst.prop_id ()); - if ((with_self || cell.cell_index () != pi->parent_cell_index () || ci != ci2) && seen.find (std::make_pair (pi->parent_cell_index (), ci2)) == seen.end ()) { + if (seen.find (std::make_pair (pi->parent_cell_index (), ci2)) == seen.end ()) { size_t id_dummy; diff --git a/src/db/db/dbHierNetworkProcessor.h b/src/db/db/dbHierNetworkProcessor.h index 13c557d64..72bb54302 100644 --- a/src/db/db/dbHierNetworkProcessor.h +++ b/src/db/db/dbHierNetworkProcessor.h @@ -60,9 +60,11 @@ class DeepLayer; class DB_PUBLIC Connectivity { public: - typedef std::set layers_type; + typedef std::set all_layers_type; + typedef all_layers_type::const_iterator all_layer_iterator; + typedef std::map layers_type; typedef layers_type::const_iterator layer_iterator; - typedef std::set global_nets_type; + typedef std::map global_nets_type; typedef global_nets_type::const_iterator global_nets_iterator; /** @@ -101,11 +103,26 @@ public: */ void connect (unsigned int la, unsigned int lb); + /** + * @brief Adds inter-layer connectivity of the soft type + * + * Soft connections are directed and are reported during "interacts" + * by the "soft" output argument. "la" is the "upper" layer and "lb" is the lower layer. + */ + void soft_connect (unsigned int la, unsigned int lb); + /** * @brief Adds a connection to a global net */ size_t connect_global (unsigned int l, const std::string &gn); + /** + * @brief Adds a soft connection to a global net + * + * The global net is always the "lower" layer. + */ + size_t soft_connect_global (unsigned int l, const std::string &gn); + /** * @brief Adds intra-layer connectivity for layer l * This is a convenience method that takes a db::DeepLayer object. @@ -120,11 +137,28 @@ public: */ void connect (const db::DeepLayer &la, const db::DeepLayer &lb); + /** + * @brief Adds inter-layer connectivity + * This is a convenience method that takes a db::DeepLayer object. + * It is assumed that all those layers originate from the same deep shape store. + * + * Soft connections are directed and are reported during "interacts" + * by the "soft" output argument. "la" is the "upper" layer and "lb" is the lower layer. + */ + void soft_connect (const db::DeepLayer &la, const db::DeepLayer &lb); + /** * @brief Adds a connection to a global net */ size_t connect_global (const db::DeepLayer &la, const std::string &gn); + /** + * @brief Adds a soft connection to a global net + * + * The global net is always the "lower" layer. + */ + size_t soft_connect_global (const db::DeepLayer &la, const std::string &gn); + /** * @brief Gets the global net name per ID */ @@ -143,15 +177,19 @@ public: /** * @brief Begin iterator for the layers involved */ - layer_iterator begin_layers () const; + all_layer_iterator begin_layers () const; /** * @brief End iterator for the layers involved */ - layer_iterator end_layers () const; + all_layer_iterator end_layers () const; /** * @brief Begin iterator for the layers connected to a specific layer + * + * The iterator returned is over a map of target layers and soft mode + * (an int, being 0 for a hard connection, +1 for an upward soft connection + * and -1 for a downward soft connection). */ layer_iterator begin_connected (unsigned int layer) const; @@ -162,6 +200,10 @@ public: /** * @brief Begin iterator for the global connections for a specific layer + * + * The iterator returned is over a map of global net ID and soft mode + * (an int, being 0 for a hard connection, +1 for an upward soft connection + * and -1 for a downward soft connection). */ global_nets_iterator begin_global_connections (unsigned int layer) const; @@ -175,17 +217,21 @@ public: * * This method accepts a transformation. This transformation is applied * to the b shape before checking against a. + * + * The "soft" output argument will deliver the soft mode that applies + * to the connection - 0: hard connection, -1: a is the lower layer, +1: a is + * the upper layer. */ template - bool interacts (const T &a, unsigned int la, const T &b, unsigned int lb, const Trans &trans) const; + bool interacts (const T &a, unsigned int la, const T &b, unsigned int lb, const Trans &trans, int &soft) const; /** * @brief Returns true, if the given shapes on the given layers interact */ template - bool interacts (const T &a, unsigned int la, const T &b, unsigned int lb) const + bool interacts (const T &a, unsigned int la, const T &b, unsigned int lb, int &soft) const { - return interacts (a, la, b, lb, UnitTrans ()); + return interacts (a, la, b, lb, UnitTrans (), soft); } /** @@ -195,17 +241,21 @@ public: /** * @brief Returns true, if two cells basically (without considering transformation) interact + * + * This is a pretty basic check based on the cell's bounding boxes */ bool interact (const db::Cell &a, const db::Cell &b) const; /** * @brief Returns true, if two cells with the given transformations interact + * + * This is a pretty basic check based on the cell's bounding boxes */ template bool interact (const db::Cell &a, const T &ta, const db::Cell &b, const T &tb) const; private: - layers_type m_all_layers; + all_layers_type m_all_layers; std::map m_connected; std::vector m_global_net_names; std::map m_global_connections; diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 62d2dc287..117c831af 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -298,6 +298,26 @@ void LayoutToNetlist::connect_impl (const db::ShapeCollection &a, const db::Shap m_conn.connect (dla.layer (), dlb.layer ()); } +void LayoutToNetlist::soft_connect_impl (const db::ShapeCollection &a, const db::ShapeCollection &b) +{ + reset_extracted (); + + if (! is_persisted (a)) { + register_layer (a); + } + if (! is_persisted (b)) { + register_layer (b); + } + + // we need to keep a reference, so we can safely delete the region + db::DeepLayer dla = deep_layer_of (a); + db::DeepLayer dlb = deep_layer_of (b); + m_dlrefs.insert (dla); + m_dlrefs.insert (dlb); + + m_conn.soft_connect (dla.layer (), dlb.layer ()); +} + size_t LayoutToNetlist::connect_global_impl (const db::ShapeCollection &l, const std::string &gn) { reset_extracted (); @@ -313,6 +333,21 @@ size_t LayoutToNetlist::connect_global_impl (const db::ShapeCollection &l, const return m_conn.connect_global (dl.layer (), gn); } +size_t LayoutToNetlist::soft_connect_global_impl (const db::ShapeCollection &l, const std::string &gn) +{ + reset_extracted (); + + if (! is_persisted (l)) { + register_layer (l); + } + + // we need to keep a reference, so we can safely delete the region + db::DeepLayer dl = deep_layer_of (l); + m_dlrefs.insert (dl); + + return m_conn.soft_connect_global (dl.layer (), gn); +} + const std::string &LayoutToNetlist::global_net_name (size_t id) const { return m_conn.global_net_name (id); @@ -360,6 +395,24 @@ void LayoutToNetlist::join_nets (const tl::GlobPattern &cell, const std::setbegin_circuits (); c != netlist->end_circuits (); ++c) { + const db::Circuit &circuit = *c; + for (auto n = circuit.begin_nets (); n != circuit.end_nets (); ++n) { + const db::Net &net = *n; + if (net.pin_count () > 1) { + ok = false; + tl::error << "Many pins on net " << net.expanded_name () << " in circuit " << circuit.name (); + } + } + } + return ok; +} +// @@@ + void LayoutToNetlist::extract_netlist () { if (m_netlist_extracted) { @@ -371,7 +424,10 @@ void LayoutToNetlist::extract_netlist () netex.set_include_floating_subcircuits (m_include_floating_subcircuits); netex.extract_nets (dss (), m_layout_index, m_conn, *mp_netlist, m_net_clusters); + // @@@ NOTE: can we have multiple pins on a net? Will this happen later maybe? + // @@@ do_soft_connections () do_join_nets (); + tl_assert (check_many_pins (mp_netlist.get ())); // @@@ if (tl::verbosity () >= 41) { MemStatisticsCollector m (false); @@ -870,7 +926,7 @@ LayoutToNetlist::create_layermap (db::Layout &target_layout, int ln) const std::set layers_to_copy; const db::Connectivity &conn = connectivity (); - for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) { + for (db::Connectivity::all_layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) { layers_to_copy.insert (*layer); } diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 493450194..4996f6cbf 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -494,6 +494,39 @@ public: connect_impl (b, a); } + /** + * @brief Defines an inter-layer soft connection for the given layers. + * The conditions mentioned with intra-layer "connect" apply for this method too. + * The "a" layer is the "upper" and the "b" layer the "lower" layer of the + * soft connection. + */ + void soft_connect (const db::Region &a, const db::Region &b) + { + soft_connect_impl (a, b); + } + + /** + * @brief Defines an inter-layer connection for the given layers. + * As one layer is a texts layer, this connection will basically add net labels. + * The "a" layer is the "upper" and the "b" layer the "lower" layer of the + * soft connection. + */ + void soft_connect (const db::Region &a, const db::Texts &b) + { + soft_connect_impl (a, b); + } + + /** + * @brief Defines an inter-layer connection for the given layers. + * As one layer is a texts layer, this connection will basically add net labels. + * The "a" layer is the "upper" and the "b" layer the "lower" layer of the + * soft connection. + */ + void soft_connect (const db::Texts &a, const db::Region &b) + { + soft_connect_impl (b, a); + } + /** * @brief Connects the given layer with a global net with the given name * Returns the global net ID @@ -512,6 +545,26 @@ public: return connect_global_impl (l, gn); } + /** + * @brief Soft-connects the given layer with a global net with the given name + * Returns the global net ID. + * The global layer is the "lower" layer of the soft connection. + */ + size_t soft_connect_global (const db::Region &l, const std::string &gn) + { + return soft_connect_global_impl (l, gn); + } + + /** + * @brief Soft-connects the given text layer with a global net with the given name + * Returns the global net ID. + * The global layer is the "lower" layer of the soft connection. + */ + size_t soft_connect_global (const db::Texts &l, const std::string &gn) + { + return soft_connect_global_impl (l, gn); + } + /** * @brief Gets the global net name for a given global net ID */ @@ -1035,6 +1088,8 @@ private: db::CellMapping make_cell_mapping_into (db::Layout &layout, db::Cell &cell, const std::vector *nets, bool with_device_cells); void connect_impl (const db::ShapeCollection &a, const db::ShapeCollection &b); size_t connect_global_impl (const db::ShapeCollection &l, const std::string &gn); + void soft_connect_impl (const db::ShapeCollection &a, const db::ShapeCollection &b); + size_t soft_connect_global_impl (const db::ShapeCollection &l, const std::string &gn); bool is_persisted_impl (const db::ShapeCollection &coll) const; void do_join_nets (db::Circuit &c, const std::vector &nets); void do_join_nets (); diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.cc b/src/db/db/dbLayoutToNetlistFormatDefs.cc index 87be9c00f..67eba13c5 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.cc +++ b/src/db/db/dbLayoutToNetlistFormatDefs.cc @@ -39,7 +39,9 @@ namespace l2n_std_format DB_PUBLIC std::string LongKeys::layer_key ("layer"); DB_PUBLIC std::string LongKeys::class_key ("class"); DB_PUBLIC std::string LongKeys::connect_key ("connect"); + DB_PUBLIC std::string LongKeys::softconnect_key ("softconnect"); DB_PUBLIC std::string LongKeys::global_key ("global"); + DB_PUBLIC std::string LongKeys::softglobal_key ("softglobal"); DB_PUBLIC std::string LongKeys::circuit_key ("circuit"); DB_PUBLIC std::string LongKeys::net_key ("net"); DB_PUBLIC std::string LongKeys::name_key ("name"); @@ -72,7 +74,9 @@ namespace l2n_std_format DB_PUBLIC std::string ShortKeys::layer_key ("L"); DB_PUBLIC std::string ShortKeys::class_key ("K"); DB_PUBLIC std::string ShortKeys::connect_key ("C"); + DB_PUBLIC std::string ShortKeys::softconnect_key ("CS"); DB_PUBLIC std::string ShortKeys::global_key ("G"); + DB_PUBLIC std::string ShortKeys::softglobal_key ("GS"); DB_PUBLIC std::string ShortKeys::circuit_key ("X"); DB_PUBLIC std::string ShortKeys::net_key ("N"); DB_PUBLIC std::string ShortKeys::name_key ("I"); diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.h b/src/db/db/dbLayoutToNetlistFormatDefs.h index 35c41f630..6496ff2f2 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.h +++ b/src/db/db/dbLayoutToNetlistFormatDefs.h @@ -66,11 +66,14 @@ namespace db * * [connect]: * connect( ...) - connects layer1 with the following layers [short key: C] + * softconnect( ...) + * - specifies soft connection between lower and upper layer [short key: CS] * * [global]: * global( ...) - * - connects the shapes of the layer with the given global - * nets [short key: G] + * - connects the shapes of the layer with the given global nets [short key: G] + * softglobal( ...) + * - soft-connects the shapes of the layer with the given global net [shoft key: GS] * * [circuit]: * circuit( [circuit-def]) - circuit (cell) [short key: X] @@ -222,7 +225,9 @@ namespace l2n_std_format static std::string layer_key; static std::string class_key; static std::string connect_key; + static std::string softconnect_key; static std::string global_key; + static std::string softglobal_key; static std::string circuit_key; static std::string net_key; static std::string name_key; @@ -261,7 +266,9 @@ namespace l2n_std_format static std::string layer_key; static std::string class_key; static std::string connect_key; + static std::string softconnect_key; static std::string global_key; + static std::string softglobal_key; static std::string circuit_key; static std::string net_key; static std::string name_key; diff --git a/src/db/db/dbLayoutToNetlistReader.cc b/src/db/db/dbLayoutToNetlistReader.cc index 369cad536..1f310c806 100644 --- a/src/db/db/dbLayoutToNetlistReader.cc +++ b/src/db/db/dbLayoutToNetlistReader.cc @@ -462,12 +462,17 @@ void LayoutToNetlistStandardReader::read_netlist (db::Netlist *netlist, db::Layo } br.done (); - } else if (l2n && (test (skeys::message_key) || test (lkeys::message_key))) { + } else if (l2n && (test (skeys::softconnect_key) || test (lkeys::softconnect_key))) { - db::LogEntryData data; - read_message_entry (data); - - l2n->log_entry (data); + Brace br (this); + std::string l1; + read_word_or_quoted (l1); + while (br) { + std::string l2; + read_word_or_quoted (l2); + l2n->soft_connect (layer_by_name (l2n, l1), layer_by_name (l2n, l2)); + } + br.done (); } else if (l2n && (test (skeys::global_key) || test (lkeys::global_key))) { @@ -481,6 +486,25 @@ void LayoutToNetlistStandardReader::read_netlist (db::Netlist *netlist, db::Layo } br.done (); + } else if (l2n && (test (skeys::softglobal_key) || test (lkeys::softglobal_key))) { + + Brace br (this); + std::string l1; + read_word_or_quoted (l1); + while (br) { + std::string g; + read_word_or_quoted (g); + l2n->soft_connect_global (layer_by_name (l2n, l1), g); + } + br.done (); + + } else if (l2n && (test (skeys::message_key) || test (lkeys::message_key))) { + + db::LogEntryData data; + read_message_entry (data); + + l2n->log_entry (data); + } else if (test (skeys::circuit_key) || test (lkeys::circuit_key)) { Brace br (this); diff --git a/src/db/db/dbLayoutToNetlistWriter.cc b/src/db/db/dbLayoutToNetlistWriter.cc index 86cbba3cb..39caaa1ce 100644 --- a/src/db/db/dbLayoutToNetlistWriter.cc +++ b/src/db/db/dbLayoutToNetlistWriter.cc @@ -351,7 +351,7 @@ void std_writer_impl::write (bool nested, TokenizedOutput &stream, std::ma if (! Keys::is_short ()) { stream << endl << "# Mask layers" << endl; } - for (db::Connectivity::layer_iterator l = mp_l2n->connectivity ().begin_layers (); l != mp_l2n->connectivity ().end_layers (); ++l) { + for (db::Connectivity::all_layer_iterator l = mp_l2n->connectivity ().begin_layers (); l != mp_l2n->connectivity ().end_layers (); ++l) { TokenizedOutput out (stream, Keys::layer_key); out << name_for_layer (mp_l2n, *l); db::LayerProperties lp = ly->get_properties (*l); @@ -364,15 +364,32 @@ void std_writer_impl::write (bool nested, TokenizedOutput &stream, std::ma if (! Keys::is_short ()) { stream << endl << "# Mask layer connectivity" << endl; } - for (db::Connectivity::layer_iterator l = mp_l2n->connectivity ().begin_layers (); l != mp_l2n->connectivity ().end_layers (); ++l) { + for (db::Connectivity::all_layer_iterator l = mp_l2n->connectivity ().begin_layers (); l != mp_l2n->connectivity ().end_layers (); ++l) { db::Connectivity::layer_iterator ce = mp_l2n->connectivity ().end_connected (*l); db::Connectivity::layer_iterator cb = mp_l2n->connectivity ().begin_connected (*l); if (cb != ce) { - TokenizedOutput out (stream, Keys::connect_key); - out << name_for_layer (mp_l2n, *l); - for (db::Connectivity::layer_iterator c = mp_l2n->connectivity ().begin_connected (*l); c != ce; ++c) { - out << name_for_layer (mp_l2n, *c); + bool any_soft = false; + { + TokenizedOutput out (stream, Keys::connect_key); + out << name_for_layer (mp_l2n, *l); + for (db::Connectivity::layer_iterator c = mp_l2n->connectivity ().begin_connected (*l); c != ce; ++c) { + if (c->second < 0) { + any_soft = true; + } + out << name_for_layer (mp_l2n, c->first); + } + } + // add soft connections in addition and as overrides to stay backward compatible with older versions + // (these will ignore these statements) + if (any_soft) { + TokenizedOutput out (stream, Keys::softconnect_key); + out << name_for_layer (mp_l2n, *l); + for (db::Connectivity::layer_iterator c = mp_l2n->connectivity ().begin_connected (*l); c != ce; ++c) { + if (c->second < 0) { + out << name_for_layer (mp_l2n, c->first); + } + } } m_progress.set (mp_stream->pos ()); } @@ -380,7 +397,7 @@ void std_writer_impl::write (bool nested, TokenizedOutput &stream, std::ma } any = false; - for (db::Connectivity::layer_iterator l = mp_l2n->connectivity ().begin_layers (); l != mp_l2n->connectivity ().end_layers (); ++l) { + for (db::Connectivity::all_layer_iterator l = mp_l2n->connectivity ().begin_layers (); l != mp_l2n->connectivity ().end_layers (); ++l) { db::Connectivity::global_nets_iterator ge = mp_l2n->connectivity ().end_global_connections (*l); db::Connectivity::global_nets_iterator gb = mp_l2n->connectivity ().begin_global_connections (*l); @@ -391,10 +408,27 @@ void std_writer_impl::write (bool nested, TokenizedOutput &stream, std::ma } any = true; } - TokenizedOutput out (stream, Keys::global_key); - out << name_for_layer (mp_l2n, *l); - for (db::Connectivity::global_nets_iterator g = gb; g != ge; ++g) { - out << tl::to_word_or_quoted_string (mp_l2n->connectivity ().global_net_name (*g)); + bool any_soft = false; + { + TokenizedOutput out (stream, Keys::global_key); + out << name_for_layer (mp_l2n, *l); + for (db::Connectivity::global_nets_iterator g = gb; g != ge; ++g) { + if (g->second < 0) { + any_soft = true; + } + out << tl::to_word_or_quoted_string (mp_l2n->connectivity ().global_net_name (g->first)); + } + } + // add soft connections in addition and as overrides to stay backward compatible with older versions + // (these will ignore these statements) + if (any_soft) { + TokenizedOutput out (stream, Keys::softglobal_key); + out << name_for_layer (mp_l2n, *l); + for (db::Connectivity::global_nets_iterator g = gb; g != ge; ++g) { + if (g->second < 0) { + out << tl::to_word_or_quoted_string (mp_l2n->connectivity ().global_net_name (g->first)); + } + } } m_progress.set (mp_stream->pos ()); } @@ -634,7 +668,7 @@ void std_writer_impl::write (TokenizedOutput &stream, const db::Net &net, reset_geometry_ref (); - for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) { + for (db::Connectivity::all_layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) { db::cell_index_type cci = circuit->cell_index (); db::cell_index_type prev_ci = cci; @@ -757,7 +791,7 @@ void std_writer_impl::write (TokenizedOutput &stream, const db::DeviceAbst bool any = false; - for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) { + for (db::Connectivity::all_layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) { size_t cid = device_abstract.cluster_id_for_terminal (t->id ()); if (cid == 0) { diff --git a/src/db/unit_tests/dbHierNetworkProcessorTests.cc b/src/db/unit_tests/dbHierNetworkProcessorTests.cc index 7ad05b9a3..d4024b97b 100644 --- a/src/db/unit_tests/dbHierNetworkProcessorTests.cc +++ b/src/db/unit_tests/dbHierNetworkProcessorTests.cc @@ -36,6 +36,23 @@ static std::string l2s (db::Connectivity::layer_iterator b, db::Connectivity::la { std::string s; for (db::Connectivity::layer_iterator i = b; i != e; ++i) { + if (! s.empty ()) { + s += ","; + } + s += tl::to_string (i->first); + if (i->second < 0) { + s += "-S"; + } else if (i->second > 0) { + s += "+S"; + } + } + return s; +} + +static std::string al2s (db::Connectivity::all_layer_iterator b, db::Connectivity::all_layer_iterator e) +{ + std::string s; + for (db::Connectivity::all_layer_iterator i = b; i != e; ++i) { if (! s.empty ()) { s += ","; } @@ -51,7 +68,12 @@ static std::string gn2s (db::Connectivity::global_nets_iterator b, db::Connectiv if (! s.empty ()) { s += ","; } - s += tl::to_string (*i); + s += tl::to_string (i->first); + if (i->second < 0) { + s += "-S"; + } else if (i->second > 0) { + s += "+S"; + } } return s; } @@ -60,15 +82,15 @@ TEST(1_Connectivity) { db::Connectivity conn; - EXPECT_EQ (l2s (conn.begin_layers (), conn.end_layers ()), ""); + EXPECT_EQ (al2s (conn.begin_layers (), conn.end_layers ()), ""); conn.connect (0); - EXPECT_EQ (l2s (conn.begin_layers (), conn.end_layers ()), "0"); + EXPECT_EQ (al2s (conn.begin_layers (), conn.end_layers ()), "0"); EXPECT_EQ (l2s (conn.begin_connected (0), conn.end_connected (0)), "0"); EXPECT_EQ (l2s (conn.begin_connected (1), conn.end_connected (1)), ""); conn.connect (0, 1); - EXPECT_EQ (l2s (conn.begin_layers (), conn.end_layers ()), "0,1"); + EXPECT_EQ (al2s (conn.begin_layers (), conn.end_layers ()), "0,1"); EXPECT_EQ (l2s (conn.begin_connected (0), conn.end_connected (0)), "0,1"); EXPECT_EQ (l2s (conn.begin_connected (1), conn.end_connected (1)), "0"); @@ -121,18 +143,19 @@ TEST(2_ShapeInteractions) db::ICplxTrans t3 (db::Trans (db::Vector (0, 2000))); db::PolygonRef ref3 (poly.transformed (t3), repo); - EXPECT_EQ (conn.interacts (ref1, 0, ref2, 0), true); - EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t2), true); // t2*ref1 == ref2 - EXPECT_EQ (conn.interacts (ref1, 0, ref2, 1), true); - EXPECT_EQ (conn.interacts (ref1, 0, ref1, 1, t2), true); - EXPECT_EQ (conn.interacts (ref1, 1, ref2, 0), true); - EXPECT_EQ (conn.interacts (ref1, 1, ref1, 0, t2), true); - EXPECT_EQ (conn.interacts (ref1, 0, ref3, 0), false); - EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t3), false); // t3*ref1 == ref3 - EXPECT_EQ (conn.interacts (ref1, 0, ref3, 1), false); - EXPECT_EQ (conn.interacts (ref1, 0, ref1, 1, t3), false); - EXPECT_EQ (conn.interacts (ref1, 1, ref2, 2), false); - EXPECT_EQ (conn.interacts (ref1, 1, ref1, 2, t2), false); + int soft = std::numeric_limits::max (); + EXPECT_EQ (conn.interacts (ref1, 0, ref2, 0, soft), true); + EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t2, soft), true); // t2*ref1 == ref2 + EXPECT_EQ (conn.interacts (ref1, 0, ref2, 1, soft), true); + EXPECT_EQ (conn.interacts (ref1, 0, ref1, 1, t2, soft), true); + EXPECT_EQ (conn.interacts (ref1, 1, ref2, 0, soft), true); + EXPECT_EQ (conn.interacts (ref1, 1, ref1, 0, t2, soft), true); + EXPECT_EQ (conn.interacts (ref1, 0, ref3, 0, soft), false); + EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t3, soft), false); // t3*ref1 == ref3 + EXPECT_EQ (conn.interacts (ref1, 0, ref3, 1, soft), false); + EXPECT_EQ (conn.interacts (ref1, 0, ref1, 1, t3, soft), false); + EXPECT_EQ (conn.interacts (ref1, 1, ref2, 2, soft), false); + EXPECT_EQ (conn.interacts (ref1, 1, ref1, 2, t2, soft), false); } TEST(2_ShapeInteractionsRealPolygon) @@ -154,20 +177,21 @@ TEST(2_ShapeInteractionsRealPolygon) db::ICplxTrans t4 (db::Trans (db::Vector (0, 1500))); db::PolygonRef ref4 (poly.transformed (t4), repo); - EXPECT_EQ (conn.interacts (ref1, 0, ref2, 0), true); - EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t2), true); // t2*ref1 == ref2 - EXPECT_EQ (conn.interacts (ref1, 0, ref2, 1), true); - EXPECT_EQ (conn.interacts (ref1, 0, ref1, 1, t2), true); - EXPECT_EQ (conn.interacts (ref1, 1, ref2, 0), true); - EXPECT_EQ (conn.interacts (ref1, 1, ref1, 0, t2), true); - EXPECT_EQ (conn.interacts (ref1, 0, ref3, 0), false); - EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t3), false); - EXPECT_EQ (conn.interacts (ref1, 0, ref4, 0), true); - EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t4), true); - EXPECT_EQ (conn.interacts (ref1, 0, ref3, 1), false); - EXPECT_EQ (conn.interacts (ref1, 0, ref1, 1, t3), false); - EXPECT_EQ (conn.interacts (ref1, 1, ref2, 2), false); - EXPECT_EQ (conn.interacts (ref1, 1, ref1, 2, t2), false); + int soft = std::numeric_limits::max (); + EXPECT_EQ (conn.interacts (ref1, 0, ref2, 0, soft), true); + EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t2, soft), true); // t2*ref1 == ref2 + EXPECT_EQ (conn.interacts (ref1, 0, ref2, 1, soft), true); + EXPECT_EQ (conn.interacts (ref1, 0, ref1, 1, t2, soft), true); + EXPECT_EQ (conn.interacts (ref1, 1, ref2, 0, soft), true); + EXPECT_EQ (conn.interacts (ref1, 1, ref1, 0, t2, soft), true); + EXPECT_EQ (conn.interacts (ref1, 0, ref3, 0, soft), false); + EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t3, soft), false); + EXPECT_EQ (conn.interacts (ref1, 0, ref4, 0, soft), true); + EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t4, soft), true); + EXPECT_EQ (conn.interacts (ref1, 0, ref3, 1, soft), false); + EXPECT_EQ (conn.interacts (ref1, 0, ref1, 1, t3, soft), false); + EXPECT_EQ (conn.interacts (ref1, 1, ref2, 2, soft), false); + EXPECT_EQ (conn.interacts (ref1, 1, ref1, 2, t2, soft), false); } TEST(10_LocalClusterBasic) @@ -286,7 +310,7 @@ template static std::string local_cluster_to_string (const db::local_cluster &cluster, const db::Connectivity &conn) { std::string res; - for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) { + for (db::Connectivity::all_layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) { for (typename db::local_cluster::shape_iterator s = cluster.begin (*l); ! s.at_end (); ++s) { if (! res.empty ()) { res += ";"; @@ -920,7 +944,7 @@ static void copy_cluster_shapes (const std::string *&attrs, db::Shapes &out, db: const db::local_cluster &lc = clusters.cluster_by_id (cluster_id); // copy the shapes from this cell - for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) { + for (db::Connectivity::all_layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) { for (db::local_cluster::shape_iterator s = lc.begin (*l); ! s.at_end (); ++s) { db::Polygon poly = s->obj ().transformed (trans * db::ICplxTrans (s->trans ())); out.insert (db::PolygonWithProperties (poly, cell_and_attr_pid > 0 ? cell_and_attr_pid : cell_pid)); diff --git a/src/layui/layui/layNetInfoDialog.cc b/src/layui/layui/layNetInfoDialog.cc index 8ab5ff6ff..be7fdb467 100644 --- a/src/layui/layui/layNetInfoDialog.cc +++ b/src/layui/layui/layNetInfoDialog.cc @@ -100,7 +100,7 @@ size_t count_shapes (db::LayoutToNetlist *l2ndb, db::Net *net) size_t n = 0; const db::Connectivity &conn = l2ndb->connectivity (); - for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) { + for (db::Connectivity::all_layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) { n += count_shapes (l2ndb, net, *layer); } @@ -276,7 +276,7 @@ void NetInfoDialog::update_info_text () bool incomplete = false; const db::Connectivity &conn = mp_l2ndb->connectivity (); - for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) { + for (db::Connectivity::all_layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) { std::string l = layer_string (mp_l2ndb.get (), *layer); diff --git a/src/layui/layui/layNetlistBrowserDialog.cc b/src/layui/layui/layNetlistBrowserDialog.cc index eb860859a..d8eeeded6 100644 --- a/src/layui/layui/layNetlistBrowserDialog.cc +++ b/src/layui/layui/layNetlistBrowserDialog.cc @@ -306,7 +306,7 @@ NetlistBrowserDialog::probe_net (const db::DPoint &p, bool trace_path) std::vector regions; const db::Connectivity &conn = l2ndb->connectivity (); - for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) { + for (db::Connectivity::all_layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) { db::LayerProperties lp = l2ndb->internal_layout ()->get_properties (*layer); if (! lp.is_null ()) { db::Region *region = l2ndb->layer_by_index (*layer); diff --git a/src/layui/layui/layNetlistBrowserPage.cc b/src/layui/layui/layNetlistBrowserPage.cc index d8a27bcf8..66cbdec49 100644 --- a/src/layui/layui/layNetlistBrowserPage.cc +++ b/src/layui/layui/layNetlistBrowserPage.cc @@ -1421,7 +1421,7 @@ NetlistBrowserPage::adjust_view () size_t cluster_id = net->cluster_id (); const db::Connectivity &conn = mp_database->connectivity (); - for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) { + for (db::Connectivity::all_layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) { db::Box layer_bbox; db::recursive_cluster_shape_iterator shapes (mp_database->net_clusters (), *layer, cell_index, cluster_id); @@ -1580,7 +1580,7 @@ NetlistBrowserPage::produce_highlights_for_net (const db::Net *net, size_t &n_ma tl::Color fallback_color = make_valid_color (m_colorizer.marker_color ()); const db::Connectivity &conn = mp_database->connectivity (); - for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) { + for (db::Connectivity::all_layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) { db::LayerProperties lp = layout->get_properties (*layer); std::map::const_iterator display = display_by_lp.find (lp);