From a3d226d99f44ee2345f806b7d6a96c763488fdf0 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 4 Jun 2024 20:34:45 +0200 Subject: [PATCH 1/8] Fixing the specific problem of issue #1709 --- src/laybasic/laybasic/layRedrawThreadWorker.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/laybasic/laybasic/layRedrawThreadWorker.cc b/src/laybasic/laybasic/layRedrawThreadWorker.cc index fe044faf0..b6046cd72 100644 --- a/src/laybasic/laybasic/layRedrawThreadWorker.cc +++ b/src/laybasic/laybasic/layRedrawThreadWorker.cc @@ -1341,7 +1341,7 @@ RedrawThreadWorker::draw_text_layer (bool drawing_context, db::cell_index_type c } else { - bool text_simplified = m_text_lazy_rendering && (dbbox_tot.width () <= 8.0 || dbbox_tot.height () <= 8.0); + bool text_simplified = m_text_lazy_rendering && dbbox_tot.width () <= 8.0 && dbbox_tot.height () <= 8.0; const db::Shapes &shapes = cell.shapes (m_layer); From 4eeb5be9eaf7254c9668d581ea5f5611a6acfb73 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 2 Jun 2024 23:02:31 +0200 Subject: [PATCH 2/8] More explanation of blend modes in common reader options --- src/db/db/gsiDeclDbCommonStreamOptions.cc | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/db/db/gsiDeclDbCommonStreamOptions.cc b/src/db/db/gsiDeclDbCommonStreamOptions.cc index 1bc0281ef..f3a889dd4 100644 --- a/src/db/db/gsiDeclDbCommonStreamOptions.cc +++ b/src/db/db/gsiDeclDbCommonStreamOptions.cc @@ -191,16 +191,22 @@ gsi::ClassExt common_reader_options ( gsi::EnumIn decl_dbCommonReader_CellConflictResolution ("db", "CellConflictResolution", gsi::enum_const ("AddToCell", db::AddToCell, "@brief Add content to existing cell\n" - "This is the mode use in before version 0.27. Content of new cells is simply added to existing cells with the same name." + "This is the mode use in before version 0.27. Content of new cells is simply added to existing cells with the same name.\n" + "Before version 0.29.2, this mode also merged instances, rendering it difficult to merge two identical cell hierarchies.\n" + "Since version 0.29.2, no instance duplicates are generated. Instead only new instances are added to existing cells.\n" + "With this feature in place, it is safe to merge two identical cell hierarchies stored in different files using AddToCell mode.\n" + "In that application, the shapes and layers of the layouts are combined, but the cell hierarchy stays identical." ) + gsi::enum_const ("OverwriteCell", db::OverwriteCell, - "@brief The old cell is overwritten entirely (including child cells which are not used otherwise)\n" + "@brief The old cell is overwritten entirely (including child cells which are not used otherwise).\n" ) + gsi::enum_const ("SkipNewCell", db::SkipNewCell, - "@brief The new cell is skipped entirely (including child cells which are not used otherwise)\n" + "@brief The new cell is skipped entirely (including child cells which are not used otherwise).\n" ) + gsi::enum_const ("RenameCell", db::RenameCell, - "@brief The new cell will be renamed to become unique\n" + "@brief The new cell will be renamed to become unique.\n" + "In this mode, two files are are combined rendering independent cell hierarchies coming from the original files.\n" + "Cells may be renamed however. Also, new top cells will appear after merging a file into the layout using RenameCell mode.\n" ), "@brief This enum specifies how cell conflicts are handled if a layout read into another layout and a cell name conflict arises.\n" "Until version 0.26.8 and before, the mode was always 'AddToCell'. On reading, a cell was 'reopened' when encountering a cell name " From 09a690f5f6354940a1c3b67eb0a9eea1293b5a2b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 2 Jun 2024 23:04:03 +0200 Subject: [PATCH 3/8] WIP --- src/db/db/dbHierNetworkProcessor.cc | 55 ++++++++++++++++++++++++--- src/db/db/dbHierNetworkProcessor.h | 4 +- src/db/db/dbLayoutToNetlist.cc | 8 ++++ src/db/db/dbLayoutToNetlist.h | 13 +++++++ src/db/db/gsiDeclDbLayoutToNetlist.cc | 16 ++++++++ 5 files changed, 90 insertions(+), 6 deletions(-) diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 7f2acce95..d8ed3d9a9 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -524,8 +524,8 @@ class DB_PUBLIC hnp_interaction_receiver public: typedef typename local_cluster::box_type box_type; - hnp_interaction_receiver (const Connectivity &conn, const db::ICplxTrans &trans) - : mp_conn (&conn), m_any (false), m_soft_mode (0), m_trans (trans) + hnp_interaction_receiver (const Connectivity &conn, const db::ICplxTrans &trans, std::map > *interacting_this, std::map > *interacting_other) + : mp_conn (&conn), m_any (false), m_soft_mode (0), m_trans (trans), mp_interacting_this (interacting_this), mp_interacting_other (interacting_other) { // .. nothing yet .. } @@ -534,9 +534,17 @@ public: { int soft = 0; if (mp_conn->interacts (*s1, l1, *s2, l2, m_trans, soft)) { + if (mp_interacting_this) { + (*mp_interacting_this) [l1].insert (s1); + } + if (mp_interacting_other) { + (*mp_interacting_this) [l2].insert (s2); + } if (soft == 0 || (m_soft_mode != 0 && m_soft_mode != soft)) { m_soft_mode = 0; - m_any = true; + if (! mp_interacting_other && ! mp_interacting_this) { + m_any = true; + } } else { m_soft_mode = soft; } @@ -558,6 +566,7 @@ private: bool m_any; int m_soft_mode; db::ICplxTrans m_trans; + std::map > *mp_interacting_this, *mp_interacting_other; }; template @@ -619,9 +628,31 @@ local_cluster::interacts (const db::Cell &cell, const db::ICplxTrans &trans, return false; } +template +static +void collect_interactions_in_original_order (const std::map::tree_type> &shapes, const std::map > &interacting, std::map > &interacting_out) +{ + for (typename std::map >::const_iterator i = interacting.begin (); i != interacting.end (); ++i) { + + std::vector &t = interacting_out [i->first]; + auto s = shapes.find (i->first); + if (s == shapes.end ()) { + continue; + } + + t.reserve (t.size () + i->second.size ()); + for (auto j = s->second.begin (); j != s->second.end (); ++j) { + if (i->second.find (j.operator-> ()) != i->second.end ()) { + t.push_back (j.operator-> ()); + } + } + + } +} + template bool -local_cluster::interacts (const local_cluster &other, const db::ICplxTrans &trans, const Connectivity &conn, int &soft) const +local_cluster::interacts (const local_cluster &other, const db::ICplxTrans &trans, const Connectivity &conn, int &soft, std::map > *interacting_this, std::map > *interacting_other) const { db::box_convert bc; @@ -679,11 +710,25 @@ local_cluster::interacts (const local_cluster &other, const db::ICplxTrans } } - hnp_interaction_receiver rec (conn, trans); + std::map > is_this, is_other; + std::map > *p_is_this = interacting_this ? &is_this : 0; + std::map > *p_is_other = interacting_other ? &is_other : 0; + + hnp_interaction_receiver rec (conn, trans, p_is_this, p_is_other); if (! scanner.process (rec, 1 /*==touching*/, bc, bc_t) || rec.soft_mode () != 0) { + + if (p_is_this) { + collect_interactions_in_original_order (m_shapes, *p_is_this, *interacting_this); + } + if (p_is_other) { + collect_interactions_in_original_order (other.m_shapes, *p_is_other, *interacting_other); + } + soft = rec.soft_mode (); + return true; + } else { return false; } diff --git a/src/db/db/dbHierNetworkProcessor.h b/src/db/db/dbHierNetworkProcessor.h index ad97c7fad..d035075a1 100644 --- a/src/db/db/dbHierNetworkProcessor.h +++ b/src/db/db/dbHierNetworkProcessor.h @@ -326,8 +326,10 @@ public: * * "trans" is the transformation which is applied to the other cluster before * the test. + * If non-null "interacting_this" will receive all interacting shapes from *this in case of success. + * If non-null "interacting_other" will receive all interacting shapes from other in case of success. */ - bool interacts (const local_cluster &other, const db::ICplxTrans &trans, const Connectivity &conn, int &soft) const; + bool interacts (const local_cluster &other, const db::ICplxTrans &trans, const Connectivity &conn, int &soft, std::map > *interacting_this = 0, std::map > *interacting_other = 0) const; /** * @brief Tests whether this cluster interacts with the given cell diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 86b7d50ab..e503518f9 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -1308,6 +1308,14 @@ static bool deliver_shapes_of_net (bool recursive, const db::Netlist *nl, const return true; } +std::map +LayoutToNetlist::shapes_of_pin (const db::NetSubcircuitPinRef &pin, const db::ICplxTrans &trans) const +{ + + // @@@ + +} + void LayoutToNetlist::shapes_of_net (const db::Net &net, const db::Region &of_layer, bool recursive, db::Shapes &to, db::properties_id_type propid, const ICplxTrans &trans) const { unsigned int lid = layer_of (of_layer); diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index e8c78d217..f1b426392 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -828,6 +828,19 @@ public: return m_net_clusters; } + /** + * @brief Gets the shapes that make the subcircuit pin + * + * This method looks up all shapes from the subcircuit that interact with the shapes of the net + * the subcircuit pin lives in. It will return a map of layer index vs. Region with these + * shapes, transformed into the coordinate space of the net. + * + * Note that this method only considers top-down interactions between the shapes of the net + * and subcircuits, not between subcircuits. It is useful only for certain topologies - i.e. + * digital nets connecting gate cells. + */ + std::map shapes_of_pin (const db::NetSubcircuitPinRef &pin, const db::ICplxTrans &trans = db::ICplxTrans ()) const; + /** * @brief Returns all shapes of a specific net and layer. * diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index e041f5ae9..26b670fc5 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -678,6 +678,22 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", gsi::method ("netlist", &db::LayoutToNetlist::netlist, "@brief gets the netlist extracted (0 if no extraction happened yet)\n" ) + + gsi::method ("shapes_of_pin", &db::LayoutToNetlist::shapes_of_pin, gsi::arg ("pin"), gsi::arg ("trans", db::ICplxTrans (), "unity"), + "@brief Returns all shapes of the given subcircuit pin.\n" + "This will return all shapes from the subcircuit attached by the given pin that interact with the net.\n" + "This method returns a \Region object with the shapes per layer where interactions are found.\n" + "The layers are given as layer indexes.\n" + "\n" + "The returned shapes are already transformed into the coordinate system of the net (see \\shapes_of_net for example).\n" + "An additional transformation can be applied using the optional \\trans argument.\n" + "\n" + "Note, that this method only considers interations between net shapes and subcircuits, not between subcircuits.\n" + "It can be used for example for digital nets connecting gate cells. In the general case however, nets may be formed\n" + "also by touching subcircuits. In that case, the nets do not have shapes of their own and this function cannot detect\n" + "the pin shapes.\n" + "\n" + "This method has been introduced in version 0.29.2." + ) + gsi::factory ("shapes_of_net", (db::Region *(db::LayoutToNetlist::*) (const db::Net &, const db::Region &, bool, const db::ICplxTrans &) const) &db::LayoutToNetlist::shapes_of_net, gsi::arg ("net"), gsi::arg ("of_layer"), gsi::arg ("recursive", true), gsi::arg ("trans", db::ICplxTrans (), "unity"), "@brief Returns all shapes of a specific net and layer.\n" "If 'recursive'' is true, the returned region will contain the shapes of\n" From 7388aa13a6b67afedf679a688e0d60ae56a63ec2 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 5 Jun 2024 23:47:57 +0200 Subject: [PATCH 4/8] debugging pin shape generation - not sure if that solution makes sense. --- src/db/db/dbHierNetworkProcessor.cc | 16 +++++++----- src/db/db/dbLayoutToNetlist.cc | 36 ++++++++++++++++++++++++++- src/db/db/gsiDeclDbLayoutToNetlist.cc | 2 ++ 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index d8ed3d9a9..5d0568a73 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -538,22 +538,25 @@ public: (*mp_interacting_this) [l1].insert (s1); } if (mp_interacting_other) { - (*mp_interacting_this) [l2].insert (s2); + (*mp_interacting_other) [l2].insert (s2); } if (soft == 0 || (m_soft_mode != 0 && m_soft_mode != soft)) { m_soft_mode = 0; - if (! mp_interacting_other && ! mp_interacting_this) { - m_any = true; - } + m_any = true; } else { m_soft_mode = soft; } } } + bool any () const + { + return m_any || m_soft_mode != 0; + } + bool stop () const { - return m_any; + return m_any && ! mp_interacting_other && ! mp_interacting_this; } int soft_mode () const @@ -715,8 +718,9 @@ local_cluster::interacts (const local_cluster &other, const db::ICplxTrans std::map > *p_is_other = interacting_other ? &is_other : 0; hnp_interaction_receiver rec (conn, trans, p_is_this, p_is_other); + scanner.process (rec, 1 /*==touching*/, bc, bc_t); - if (! scanner.process (rec, 1 /*==touching*/, bc, bc_t) || rec.soft_mode () != 0) { + if (rec.any ()) { if (p_is_this) { collect_interactions_in_original_order (m_shapes, *p_is_this, *interacting_this); diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index e503518f9..bc8c2a958 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -1311,9 +1311,43 @@ static bool deliver_shapes_of_net (bool recursive, const db::Netlist *nl, const std::map LayoutToNetlist::shapes_of_pin (const db::NetSubcircuitPinRef &pin, const db::ICplxTrans &trans) const { + std::map result; - // @@@ + const db::Net *net = pin.net (); + if (! net || ! net->circuit () || ! pin.subcircuit () || ! pin.subcircuit ()->circuit_ref ()) { + return result; + } + auto cc = m_net_clusters.clusters_per_cell (net->circuit ()->cell_index ()); + auto c = cc.cluster_by_id (net->cluster_id ()); + + double dbu = internal_layout ()->dbu (); + db::ICplxTrans sc_trans = db::CplxTrans (dbu).inverted () * pin.subcircuit ()->trans () * db::CplxTrans (dbu); + + const db::Net *other_net = pin.subcircuit ()->circuit_ref ()->net_for_pin (pin.pin_id ()); + if (! other_net) { + return result; + } + + auto cc_other = m_net_clusters.clusters_per_cell (pin.subcircuit ()->circuit_ref ()->cell_index ()); + auto c_other = cc_other.cluster_by_id (other_net->cluster_id ()); + + std::map > interacting; + int soft = 0; + if (! c.interacts (c_other, sc_trans, m_conn, soft, 0, &interacting)) { + return result; + } + + auto t = trans * sc_trans; + + for (auto i = interacting.begin (); i != interacting.end (); ++i) { + db::Region &r = result [i->first]; + for (auto s = i->second.begin (); s != i->second.end (); ++s) { + deliver_shape (**s, r, t, 0); + } + } + + return result; } void LayoutToNetlist::shapes_of_net (const db::Net &net, const db::Region &of_layer, bool recursive, db::Shapes &to, db::properties_id_type propid, const ICplxTrans &trans) const diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index 26b670fc5..c6a817149 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -692,6 +692,8 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "also by touching subcircuits. In that case, the nets do not have shapes of their own and this function cannot detect\n" "the pin shapes.\n" "\n" + "The call of this method is not cheap, specificially if large nets are involved.\n" + "\n" "This method has been introduced in version 0.29.2." ) + gsi::factory ("shapes_of_net", (db::Region *(db::LayoutToNetlist::*) (const db::Net &, const db::Region &, bool, const db::ICplxTrans &) const) &db::LayoutToNetlist::shapes_of_net, gsi::arg ("net"), gsi::arg ("of_layer"), gsi::arg ("recursive", true), gsi::arg ("trans", db::ICplxTrans (), "unity"), From c44b8097dd338ed0db83e53de80d0126a9e61b43 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 6 Jun 2024 19:54:56 +0200 Subject: [PATCH 5/8] Deep search for pin shapes, added shapes_of_terminal --- src/db/db/dbLayoutToNetlist.cc | 78 ++++++++++++++++++++++----- src/db/db/dbLayoutToNetlist.h | 18 ++++++- src/db/db/gsiDeclDbLayoutToNetlist.cc | 30 +++++++++-- 3 files changed, 107 insertions(+), 19 deletions(-) diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index bc8c2a958..0fc0f40ad 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -1308,6 +1308,43 @@ static bool deliver_shapes_of_net (bool recursive, const db::Netlist *nl, const return true; } +void +LayoutToNetlist::collect_shapes_of_pin (const local_cluster &c, const db::Net *other_net, const db::ICplxTrans &sc_trans, const db::ICplxTrans &trans, std::map &result) const +{ + if (! other_net || ! other_net->circuit ()) { + return; + } + + auto cc_other = m_net_clusters.clusters_per_cell (other_net->circuit ()->cell_index ()); + auto c_other = cc_other.cluster_by_id (other_net->cluster_id ()); + + std::map > interacting; + int soft = 0; + if (c.interacts (c_other, sc_trans, m_conn, soft, 0, &interacting)) { + + auto t = trans * sc_trans; + + for (auto i = interacting.begin (); i != interacting.end (); ++i) { + db::Region &r = result [i->first]; + for (auto s = i->second.begin (); s != i->second.end (); ++s) { + deliver_shape (**s, r, t, 0); + } + } + + } + + double dbu = internal_layout ()->dbu (); + + for (auto p = other_net->begin_subcircuit_pins (); p != other_net->end_subcircuit_pins (); ++p) { + + db::ICplxTrans sc_trans2 = sc_trans * db::CplxTrans (dbu).inverted () * p->subcircuit ()->trans () * db::CplxTrans (dbu); + const db::Net *other_net2 = p->subcircuit ()->circuit_ref ()->net_for_pin (p->pin_id ()); + + collect_shapes_of_pin (c, other_net2, sc_trans2, trans, result); + + } +} + std::map LayoutToNetlist::shapes_of_pin (const db::NetSubcircuitPinRef &pin, const db::ICplxTrans &trans) const { @@ -1323,28 +1360,45 @@ LayoutToNetlist::shapes_of_pin (const db::NetSubcircuitPinRef &pin, const db::IC double dbu = internal_layout ()->dbu (); db::ICplxTrans sc_trans = db::CplxTrans (dbu).inverted () * pin.subcircuit ()->trans () * db::CplxTrans (dbu); - const db::Net *other_net = pin.subcircuit ()->circuit_ref ()->net_for_pin (pin.pin_id ()); - if (! other_net) { + + collect_shapes_of_pin (c, other_net, sc_trans, trans, result); + + return result; +} + +std::map +LayoutToNetlist::shapes_of_terminal (const db::NetTerminalRef &terminal, const db::ICplxTrans &trans) const +{ + std::map result; + + const db::Net *net = terminal.net (); + if (! net || ! net->circuit () || ! terminal.device () || ! terminal.device ()->device_abstract ()) { return result; } - auto cc_other = m_net_clusters.clusters_per_cell (pin.subcircuit ()->circuit_ref ()->cell_index ()); - auto c_other = cc_other.cluster_by_id (other_net->cluster_id ()); + auto cc = m_net_clusters.clusters_per_cell (net->circuit ()->cell_index ()); + auto c = cc.cluster_by_id (net->cluster_id ()); + + double dbu = internal_layout ()->dbu (); + db::ICplxTrans d_trans = db::CplxTrans (dbu).inverted () * terminal.device ()->trans () * db::CplxTrans (dbu); + + auto cc_other = m_net_clusters.clusters_per_cell (terminal.device ()->device_abstract ()->cell_index ()); + auto c_other = cc_other.cluster_by_id (terminal.device ()->device_abstract ()->cluster_id_for_terminal (terminal.terminal_id ())); std::map > interacting; int soft = 0; - if (! c.interacts (c_other, sc_trans, m_conn, soft, 0, &interacting)) { - return result; - } + if (c.interacts (c_other, d_trans, m_conn, soft, 0, &interacting)) { - auto t = trans * sc_trans; + auto t = trans * d_trans; - for (auto i = interacting.begin (); i != interacting.end (); ++i) { - db::Region &r = result [i->first]; - for (auto s = i->second.begin (); s != i->second.end (); ++s) { - deliver_shape (**s, r, t, 0); + for (auto i = interacting.begin (); i != interacting.end (); ++i) { + db::Region &r = result [i->first]; + for (auto s = i->second.begin (); s != i->second.end (); ++s) { + deliver_shape (**s, r, t, 0); + } } + } return result; diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index f1b426392..4d1d1ef49 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -836,11 +836,24 @@ public: * shapes, transformed into the coordinate space of the net. * * Note that this method only considers top-down interactions between the shapes of the net - * and subcircuits, not between subcircuits. It is useful only for certain topologies - i.e. - * digital nets connecting gate cells. + * and subcircuits on any level below, but not between subcircuits. + * It is useful only for certain topologies - i.e. digital nets connecting gate cells. */ std::map shapes_of_pin (const db::NetSubcircuitPinRef &pin, const db::ICplxTrans &trans = db::ICplxTrans ()) const; + /** + * @brief Gets the shapes that make the device terminal + * + * This method looks up all shapes from the device terminals that interact with the shapes of the net + * the device terminal lives in. It will return a map of layer index vs. Region with these + * shapes, transformed into the coordinate space of the net. + * + * Note that this method only considers top-down interactions between the shapes of the net + * and subcircuits on any level below, but not between subcircuits and devices. + * It is useful for flat-extracted netlists for example. + */ + std::map shapes_of_terminal (const db::NetTerminalRef &terminal, const db::ICplxTrans &trans = db::ICplxTrans ()) const; + /** * @brief Returns all shapes of a specific net and layer. * @@ -1112,6 +1125,7 @@ private: void ensure_layout () const; std::string make_new_name (const std::string &stem = std::string ()); db::CellMapping make_cell_mapping_into (db::Layout &layout, db::Cell &cell, const std::vector *nets, bool with_device_cells); + void collect_shapes_of_pin (const local_cluster &c, const db::Net *other_net, const db::ICplxTrans &sc_trans, const db::ICplxTrans &trans, std::map &result) const; 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); diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index c6a817149..3d11ee518 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -679,20 +679,40 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "@brief gets the netlist extracted (0 if no extraction happened yet)\n" ) + gsi::method ("shapes_of_pin", &db::LayoutToNetlist::shapes_of_pin, gsi::arg ("pin"), gsi::arg ("trans", db::ICplxTrans (), "unity"), - "@brief Returns all shapes of the given subcircuit pin.\n" - "This will return all shapes from the subcircuit attached by the given pin that interact with the net.\n" - "This method returns a \Region object with the shapes per layer where interactions are found.\n" + "@brief Returns all shapes of the given subcircuit pin that make a connection to the net the pin lives in.\n" + "This will return all shapes from the subcircuit attached by the given pin that interact with the net the pin lives in.\n" + "This method returns a \\Region object with the shapes per layer where interactions are found.\n" "The layers are given as layer indexes.\n" "\n" "The returned shapes are already transformed into the coordinate system of the net (see \\shapes_of_net for example).\n" "An additional transformation can be applied using the optional \\trans argument.\n" "\n" - "Note, that this method only considers interations between net shapes and subcircuits, not between subcircuits.\n" + "Note, that this method only considers interations between net shapes and subcircuits on every level below, " + "but not between subcircuits.\n" "It can be used for example for digital nets connecting gate cells. In the general case however, nets may be formed\n" "also by touching subcircuits. In that case, the nets do not have shapes of their own and this function cannot detect\n" "the pin shapes.\n" "\n" - "The call of this method is not cheap, specificially if large nets are involved.\n" + "The call of this method may not be cheap, specificially if large nets are involved.\n" + "\n" + "This method has been introduced in version 0.29.2." + ) + + gsi::method ("shapes_of_terminal", &db::LayoutToNetlist::shapes_of_terminal, gsi::arg ("terminal"), gsi::arg ("trans", db::ICplxTrans (), "unity"), + "@brief Returns all shapes of the given device terminal that make a connection to the net the terminal lives in.\n" + "This will return all shapes from the device attached by the given terminal that interact with the net the terminal lives in.\n" + "This method returns a \\Region object with the shapes per layer where interactions are found.\n" + "The layers are given as layer indexes.\n" + "\n" + "The returned shapes are already transformed into the coordinate system of the net (see \\shapes_of_net for example).\n" + "An additional transformation can be applied using the optional \\trans argument.\n" + "\n" + "Note, that this method only considers interations between net shapes and the device connected by the terminal, " + "but not between subcircuits on the net and the device.\n" + "It can be used for example for flat-extracted, transistor-level netlists. In the general case however, nets may be formed\n" + "also by subcircuits touching devices. In that case, the nets do not have shapes of their own and this function cannot detect\n" + "the terminal shapes.\n" + "\n" + "The call of this method may not be cheap, specificially if large nets are involved.\n" "\n" "This method has been introduced in version 0.29.2." ) + From 3e4775aabb383adcdc31a5ec4932a155525b0620 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 6 Jun 2024 20:20:35 +0200 Subject: [PATCH 6/8] Added tests for shapes_of_pin --- src/drc/unit_tests/drcSimpleTests.cc | 42 +++++++++++++++++++++ testdata/drc/drcSimpleTests_120.drc | 52 ++++++++++++++++++++++++++ testdata/drc/drcSimpleTests_120.gds | Bin 0 -> 1616 bytes testdata/drc/drcSimpleTests_au120.gds | Bin 0 -> 2278 bytes 4 files changed, 94 insertions(+) create mode 100644 testdata/drc/drcSimpleTests_120.drc create mode 100644 testdata/drc/drcSimpleTests_120.gds create mode 100644 testdata/drc/drcSimpleTests_au120.gds diff --git a/src/drc/unit_tests/drcSimpleTests.cc b/src/drc/unit_tests/drcSimpleTests.cc index 6f5e2ddd6..e8bbcef71 100644 --- a/src/drc/unit_tests/drcSimpleTests.cc +++ b/src/drc/unit_tests/drcSimpleTests.cc @@ -1827,3 +1827,45 @@ TEST(112_Waiving) compare_text_files (report, au_report); } + +TEST(120_ShapesOfPin) +{ + std::string rs = tl::testdata (); + rs += "/drc/drcSimpleTests_120.drc"; + + // apart from that it's a variant of 14b ... + + std::string input = tl::testdata (); + input += "/drc/drcSimpleTests_120.gds"; + + std::string au = tl::testdata (); + au += "/drc/drcSimpleTests_au120.gds"; + + std::string output = this->tmp_file ("tmp.gds"); + + { + // Set some variables + lym::Macro config; + config.set_text (tl::sprintf ( + "$drc_test_source = '%s'\n" + "$drc_test_target = '%s'\n" + , input, output) + ); + config.set_interpreter (lym::Macro::Ruby); + EXPECT_EQ (config.run (), 0); + } + + lym::Macro drc; + drc.load_from (rs); + EXPECT_EQ (drc.run (), 0); + + db::Layout layout; + + { + tl::InputStream stream (output); + db::Reader reader (stream); + reader.read (layout); + } + + db::compare_layouts (_this, layout, au, db::NoNormalization); +} diff --git a/testdata/drc/drcSimpleTests_120.drc b/testdata/drc/drcSimpleTests_120.drc new file mode 100644 index 000000000..34bc398a1 --- /dev/null +++ b/testdata/drc/drcSimpleTests_120.drc @@ -0,0 +1,52 @@ + +source $drc_test_source +target $drc_test_target + +deep + +l1 = input(1, 0) +l2 = input(2, 0) +l3 = input(3, 0) + +name(l1, "l1") +name(l2, "l2") +name(l3, "l3") + +connect(l1, l2) +connect(l2, l3) + +netlist + +l1_out = polygons +l2_out = polygons +l3_out = polygons + +output_layers = { + "l1" => l1_out, + "l2" => l2_out, + "l3" => l3_out +} + +[ "A", "B", "C" ].each do |n| + + net = l2n_data.netlist.circuit_by_name("TOP").net_by_name(n) + if net + + net.each_subcircuit_pin do |pin| + shapes = l2n_data.shapes_of_pin(pin) + shapes.keys.each do |li| + output_layers[l2n_data.layer_name(li)].data.insert(shapes[li]) + end + end + + end + +end + +l1.output(1, 0) +l2.output(2, 0) +l3.output(3, 0) +l1_out.output(101, 0) +l2_out.output(102, 0) +l3_out.output(103, 0) + diff --git a/testdata/drc/drcSimpleTests_120.gds b/testdata/drc/drcSimpleTests_120.gds new file mode 100644 index 0000000000000000000000000000000000000000..93675cdcd9d392aebf99dd56eded48636fb2ad82 GIT binary patch literal 1616 zcmcIkD{mV?5dQA9ca81Jj^p^D0|kYZilU|@$~h%bBPGDVG72cF0`db23tCoC)`GH< z!T^Kf-~dB|f&hak3J8j#US@7?b9?rkjdIrLvu5X;*Ul^yYz^eqfuPBgY9XvUfPGyk zNv10z1xgJLk7#-yW92+MpQRsjn0QVZk&)e~D7)4tO7|X^!^Fp$R2Zdm_7UhP>CmG0 zz4||KpUaTF)?M*#pm|HVjlTN=RK{`4So=eL`mj$ z7eMo+V5>v93@G;$wVtpff68|V^lk;inea7gJz>Hx+~~zwq8*oQZC>$?(+gV8PHY?B zX&5irc5j8PY^2!o8*99i#_mZsd0+Wfo*he78nvF@lcoGNy&uf)eh|J!t#7BhPaEO7 FcmM}>DQW-! literal 0 HcmV?d00001 diff --git a/testdata/drc/drcSimpleTests_au120.gds b/testdata/drc/drcSimpleTests_au120.gds new file mode 100644 index 0000000000000000000000000000000000000000..2b853f6a55948165de53f3c03b3813f574b21409 GIT binary patch literal 2278 zcmcIlEo@U!6h3`Fw}rN(Ydf}%ClCvQkRSm=cpHYW0HR`!q0Ro3X zA}Y}6iOGc^2x$l*2ozcN_|7{$d*{CPZHhKGUvuvL&i^?jM?tVoNiC?4$>H0lE}gT# zsS&uf8!JTpFus~TzjX8S``=ftk1oD@voWM3uI4%CQlh9q=ltGat(5@Ay{s@tpWA1E}h7Svmi<7;DRdb5FqwF)EePAxzFHq$`Yd^I9b9HJj zXH}_?8QB77Ob_X(;TSm8hXT_;-lBbbbZuc&fh&YzxTnabWzo@MOF%2#u*&~D%O z)oSG{nKpUFo6~GRGgp!+o<+|1iM!&lqRO!=j^r<3H!y#&DSSnhFZgqP&(1Yx3>D2Y z#}(&{E2_LyagWbC0Tn&m4SvN%UaGj^i{HIvL9R6O6;)oUxZzJ%JX*u@fIp1oiZ?Km z`1kVoo!5x@2c`tr|4!6>QJ~6!Hvg6U_7~wRR`BoJ{MXQ}>?>pZL^@wlzjJ_IzJ>UK?Wgene1R$lTK)s;KldvCmoaMJD5|{FzlQJEf3TTl Q`&-<{g5~;STSpQ71FoHmCIA2c literal 0 HcmV?d00001 From 04caf13d8dedfa50fbca2befb848bbe65400e9b1 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 6 Jun 2024 20:47:55 +0200 Subject: [PATCH 7/8] Added tests for shapes_of_terminal --- src/drc/unit_tests/drcSimpleTests.cc | 42 ++++++++++++ testdata/drc/drcSimpleTests_121.drc | 89 ++++++++++++++++++++++++++ testdata/drc/drcSimpleTests_121.gds | Bin 0 -> 1990 bytes testdata/drc/drcSimpleTests_au121.gds | Bin 0 -> 2944 bytes 4 files changed, 131 insertions(+) create mode 100644 testdata/drc/drcSimpleTests_121.drc create mode 100644 testdata/drc/drcSimpleTests_121.gds create mode 100644 testdata/drc/drcSimpleTests_au121.gds diff --git a/src/drc/unit_tests/drcSimpleTests.cc b/src/drc/unit_tests/drcSimpleTests.cc index e8bbcef71..6cc8d2fb5 100644 --- a/src/drc/unit_tests/drcSimpleTests.cc +++ b/src/drc/unit_tests/drcSimpleTests.cc @@ -1869,3 +1869,45 @@ TEST(120_ShapesOfPin) db::compare_layouts (_this, layout, au, db::NoNormalization); } + +TEST(121_ShapesOfTerminal) +{ + std::string rs = tl::testdata (); + rs += "/drc/drcSimpleTests_121.drc"; + + // apart from that it's a variant of 14b ... + + std::string input = tl::testdata (); + input += "/drc/drcSimpleTests_121.gds"; + + std::string au = tl::testdata (); + au += "/drc/drcSimpleTests_au121.gds"; + + std::string output = this->tmp_file ("tmp.gds"); + + { + // Set some variables + lym::Macro config; + config.set_text (tl::sprintf ( + "$drc_test_source = '%s'\n" + "$drc_test_target = '%s'\n" + , input, output) + ); + config.set_interpreter (lym::Macro::Ruby); + EXPECT_EQ (config.run (), 0); + } + + lym::Macro drc; + drc.load_from (rs); + EXPECT_EQ (drc.run (), 0); + + db::Layout layout; + + { + tl::InputStream stream (output); + db::Reader reader (stream); + reader.read (layout); + } + + db::compare_layouts (_this, layout, au, db::NoNormalization); +} diff --git a/testdata/drc/drcSimpleTests_121.drc b/testdata/drc/drcSimpleTests_121.drc new file mode 100644 index 000000000..6e52ec8b0 --- /dev/null +++ b/testdata/drc/drcSimpleTests_121.drc @@ -0,0 +1,89 @@ + +source $drc_test_source +target $drc_test_target + +# only works flat: +# deep + +l1 = input(1, 0) +l2 = input(2, 0) +l3 = input(3, 0) + +active = input(10, 0) +poly = input(11, 0) +contact = input(12, 0) + +sd = active - poly +gate = active & poly + +name(l1, "l1") +name(l2, "l2") +name(l3, "l3") +name(sd, "sd") +name(poly, "poly") +name(gate, "gate") +name(contact, "contact") + +mos_ex = RBA::DeviceExtractorMOS3Transistor::new("MOS") +extract_devices(mos_ex, { "SD" => sd, "G" => gate, "P" => poly }) + +connect(contact, poly) +connect(contact, sd) +connect(l1, contact) +connect(l1, l2) +connect(l2, l3) + +netlist + +l1_out = polygons +l2_out = polygons +l3_out = polygons +contact_out = polygons +sd_out = polygons +gate_out = polygons +poly_out = polygons + +output_layers = { + "l1" => l1_out, + "l2" => l2_out, + "l3" => l3_out, + "contact" => contact_out, + "poly" => poly_out, + "gate" => gate_out, + "sd" => sd_out +} + +[ "A", "B", "C" ].each do |n| + + net = l2n_data.netlist.circuit_by_name("TOP").net_by_name(n) + if net + + net.each_terminal do |terminal| + shapes = l2n_data.shapes_of_terminal(terminal) + shapes.keys.each do |li| + output_layers[l2n_data.layer_name(li)].data.insert(shapes[li]) + end + end + + end + +end + +l1.output(1, 0) +l2.output(2, 0) +l3.output(3, 0) + +sd.output(10, 0) +poly.output(11, 0) +contact.output(12, 0) +gate.output(13, 0) + +l1_out.output(101, 0) +l2_out.output(102, 0) +l3_out.output(103, 0) + +sd_out.output(110, 0) +poly_out.output(111, 0) +contact_out.output(112, 0) +gate_out.output(113, 0) + diff --git a/testdata/drc/drcSimpleTests_121.gds b/testdata/drc/drcSimpleTests_121.gds new file mode 100644 index 0000000000000000000000000000000000000000..c70c6c2a8be656f0d2509b2aa2b3cd2c95fc1b02 GIT binary patch literal 1990 zcmdUwziSjx5XWctcHeF8Hr|<>9??T1T0}T7ohU(aA&oykixd)4SXzW2!6JpFg@T1e z3PFo21T8EqEK-Q2m4!(Dh!i4e5>_R7erIQgeH-$U+Fh2ODtOclNh@>+^!7NiMGZfO9$K!Mkq1h( z=k(~2_s=AUneA`bnvW$p$7S5-A36MksI?*-TatAs)!te;T0e=};dw585xr9FlgoZR z_c3{jTAWs@ohkYh)1!}K|4wrsHQj&`N;#+aYHpC3$os9+Geh^RMn4cu;7jJ&&)BDj zCDjhPdtK3+w~|}T{YQLOB{}zs@mxP5vDOOz<^o5Yv=D1;OX|SfLZ)5E?&B{YM43IU ztQ6{lD{akSnpeD1{Eys7o$ib%k&*G5kh|&Ld+9bzwa05dJ-XRT{!Yl<95LsAD5lzv m($^EBQ%|4)yPJ~LO0|QY_(jJj#QJkZRVdXC=6dvuD58JdPQSAN literal 0 HcmV?d00001 diff --git a/testdata/drc/drcSimpleTests_au121.gds b/testdata/drc/drcSimpleTests_au121.gds new file mode 100644 index 0000000000000000000000000000000000000000..e562add09327004ccc941b6f23677943b141fe87 GIT binary patch literal 2944 zcmdUxy=xRv6vgk(W@jhnW7l;x2`;)JRzWd^C`yn-Z2SOIqzJ*n(jvqlK~h*+Xd_}J z2*E<&cacsY;2Z9EVc$)h782aYAQIM}w|ryp@{Z5DcH3ssT!8%B%A^yr=Yd7t+y z%Zo_zTEu8^JlCuLzARFjc8;uE*L4^zUYc&LuTQCd;DhRo7OzkF^=oCUFaFbYYz!GK zPO82WkJtJiV*SIOoJ7*eUEoj0f`onHC`yp3b&%exu2&*`xRX5m9(B5z(Bhz1A3k?( z^DPpC+cVs&gcb*5eY<+iH}i-6bR3o7HNPsgxN|N$w{;HHA2y2A?qyaA_0E-+hVhsu zTq!y^?Q~zV(q`pmFKIJ^!0g9S2g4H z`HcUL^!mTOVLsumA;6h>fl}E1baT~sbaJ^m|lO%zv}pgP=BO( zDj6*fdiD8t=<8+p1uKK7Uw1-_gC4ze>!+z#RtBB>f!;A%yp?|Ij_OJ3+^2-p>vdm# z_02by{s$)2ztQ4gOaJ|W`X887|3-_q($gRBBdMc*qs9Gt^=)54#Ut96lpA$8hh|f4oMCv#hl@`a>f_MLzztOAtw`Vl3(c+C>pC0{!2?2jG<1?hu zJWD`}`~6c#|4L5us6qcqi~Id+UikYxsUqa%#3C*3_pj@=I$Pb17Wez7{-4*sD}Dab zEBBDK=U0_|UFlrYUfMDLGWz&y2=jyF{NVgDa(?Lb%>GZO^Y3B)rS$ZxH8kIU@l|*$ SoqrGO&**ov{vuklO@0B{V*Azr literal 0 HcmV?d00001 From 9f7e84d9e7e3cf9393b8ba836b39ae2fe1c73fd7 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 6 Jun 2024 21:01:52 +0200 Subject: [PATCH 8/8] Adding transformation to shapes_of_pin, shapes_of_terminal --- testdata/drc/drcSimpleTests_120.drc | 2 +- testdata/drc/drcSimpleTests_121.drc | 2 +- testdata/drc/drcSimpleTests_au120.gds | Bin 2278 -> 2278 bytes testdata/drc/drcSimpleTests_au121.gds | Bin 2944 -> 2944 bytes 4 files changed, 2 insertions(+), 2 deletions(-) diff --git a/testdata/drc/drcSimpleTests_120.drc b/testdata/drc/drcSimpleTests_120.drc index 34bc398a1..96cb04b97 100644 --- a/testdata/drc/drcSimpleTests_120.drc +++ b/testdata/drc/drcSimpleTests_120.drc @@ -33,7 +33,7 @@ output_layers = { if net net.each_subcircuit_pin do |pin| - shapes = l2n_data.shapes_of_pin(pin) + shapes = l2n_data.shapes_of_pin(pin, RBA::Trans::new(RBA::Vector::new(100, 200))) shapes.keys.each do |li| output_layers[l2n_data.layer_name(li)].data.insert(shapes[li]) end diff --git a/testdata/drc/drcSimpleTests_121.drc b/testdata/drc/drcSimpleTests_121.drc index 6e52ec8b0..8f043e926 100644 --- a/testdata/drc/drcSimpleTests_121.drc +++ b/testdata/drc/drcSimpleTests_121.drc @@ -59,7 +59,7 @@ output_layers = { if net net.each_terminal do |terminal| - shapes = l2n_data.shapes_of_terminal(terminal) + shapes = l2n_data.shapes_of_terminal(terminal, RBA::Trans::new(RBA::Vector::new(100, 200))) shapes.keys.each do |li| output_layers[l2n_data.layer_name(li)].data.insert(shapes[li]) end diff --git a/testdata/drc/drcSimpleTests_au120.gds b/testdata/drc/drcSimpleTests_au120.gds index 2b853f6a55948165de53f3c03b3813f574b21409..16a68283504c78206e2aab556ae99806fcf55ee9 100644 GIT binary patch delta 575 zcmZ9IF-yZx5Xb+0Nt1|aG&b#!mqIB-P+SU~oW$9|vBb^K;3{-*7UXT2#ZhWq96I_b zoVpk~WGYS~#*5{6;SI;{`0?lNxFRgV5gZ6HMbZ-PntBHjPI27qA4W%ehI+|vh3Qlw zu1xoOX?==x3HUQW5Q7_F_f3<%KU0|_(=WiD11+NS2v}=P_V!%mlq`X6SykV}-fEj< zvhS8ErX+2ZRQ2`&&93J#*~_JhU77yUoeN-}*n0*JHk$1Hg_#VVwn=6q`9U+MKs%!C zMCXj|ywhagj#Tc(ht?2CsA>)_=uj#q`(*eZ4X=StAE+6e)Bbx+_MN`UJej@&-UQeo fn!ji7O;qm5apR-$Nmc!<0H*#Z?2s;VscifKr)GG9 delta 575 zcmZ9Iu}Z^W6opUzq)8GDv9xy7?ZZI5>p3I5_qJM09g-66N3W3@+l*!AB7{ zL+IQ|#CSruBxDHR<>QcZ?_c}uSFY}ZAo_fpfRp04CUH0Ak zx%sW)6mT~HTj0HNzGx}l-RR5?<7dDu0fQWTa(-wj-Yj*_;)9(IoG{M0+ZGs;vjUhrwG{7e`$_MsNeVm3+zAqc)pcdf!3`HZ zZYkbc>YVi-K*(hk8S(J?V4?UhWim*{f52$PO-b*T{iiL(k5)PxhVd2PtbskU|MudY bwa$m(S?5KMuB+1_lNl0cN1UlK=m|*??#U2G%!BkRvc=>K2*|Hl-Ng8x7oq7h~g#9)v(UIU;Ghj>6S4dMY9EgS~-7}x>qKu@qR F0001DOIZK_ delta 94 zcmZn=ZxB~vU}IonieQjoWMY2-WV11dFz7NcBeN$eY4W29ZHzMEnry+yJ9##<8e`tX XHTI18lbN_cq!X6~8#@C73kw4PgS`&;