From e8e2858af30692fd6772aa2695af9a565d8f0997 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 25 Oct 2025 00:21:04 +0200 Subject: [PATCH 1/3] Implemented a solution for #2195 A new PCell method cell_name/cell_name_impl that delivers a cell name, which is used for "convert to static cell" and as cell name in general. Needs testing. --- .../pcell_declaration_helper.lym | 30 +++++++++++++++++ .../pcell_declaration_helper.lym | 12 +++++++ src/db/db/dbCell.cc | 6 ++++ src/db/db/dbCell.h | 10 +++++- src/db/db/dbColdProxy.cc | 2 +- src/db/db/dbLayout.cc | 25 ++++++++++++--- src/db/db/dbLayout.h | 13 ++++++-- src/db/db/dbLibraryProxy.cc | 18 ++++++++++- src/db/db/dbLibraryProxy.h | 17 ++++++---- src/db/db/dbPCellDeclaration.h | 12 +++++++ src/db/db/dbPCellVariant.cc | 14 +++++++- src/db/db/dbPCellVariant.h | 32 ++++++++----------- src/db/db/gsiDeclDbLibrary.cc | 23 +++++++++++++ .../klayout/db/pcell_declaration_helper.py | 21 ++++++++++++ 14 files changed, 199 insertions(+), 36 deletions(-) diff --git a/src/db/db/built-in-macros/pcell_declaration_helper.lym b/src/db/db/built-in-macros/pcell_declaration_helper.lym index 6a9c21f9d..1db044b21 100644 --- a/src/db/db/built-in-macros/pcell_declaration_helper.lym +++ b/src/db/db/built-in-macros/pcell_declaration_helper.lym @@ -149,6 +149,18 @@ created as well. This method must be reimplemented in a PCell class to identify the PCell in human-readable form. This text is shown in the cell tree for the PCell for example. +@method cell_name_impl + +@brief Delivers the cell name to be used for the PCell variant + +A PCell variant is represented in the cell tree by a placeholder cell. By +default, the name of this cell is the PCell name. Since multiple variants +may exist, usually a disambiguator is added to the name (e.g. "..$1"). + +This method allows encoding the PCell parameters into that cell name, +so the PCell variant is easier to identify in the cell tree - for example +in the GDS file - instead of the unspecific disambiguator. + @method produce_impl @brief Produces the layout @@ -466,6 +478,19 @@ module RBA text end + # implementation of display_text + def cell_name(parameters) + self._start + @param_values = parameters + text = "" + begin + text = cell_name_impl + ensure + self._finish + end + text + end + # get the parameters def get_parameters @param_decls @@ -568,6 +593,11 @@ module RBA "" end + # default implementation + def cell_name_impl + self.name + end + # default implementation def coerce_parameters_impl end diff --git a/src/db/db/built-in-pymacros/pcell_declaration_helper.lym b/src/db/db/built-in-pymacros/pcell_declaration_helper.lym index 39b4c4807..8b763e6e7 100644 --- a/src/db/db/built-in-pymacros/pcell_declaration_helper.lym +++ b/src/db/db/built-in-pymacros/pcell_declaration_helper.lym @@ -158,6 +158,18 @@ created as well. This method must be reimplemented in a PCell class to identify the PCell in human-readable form. This text is shown in the cell tree for the PCell for example. +@method cell_name_impl + +@brief Delivers the cell name to be used for the PCell variant + +A PCell variant is represented in the cell tree by a placeholder cell. By +default, the name of this cell is the PCell name. Since multiple variants +may exist, usually a disambiguator is added to the name (e.g. "..$1"). + +This method allows encoding the PCell parameters into that cell name, +so the PCell variant is easier to identify in the cell tree - for example +in the GDS file - instead of the unspecific disambiguator. + @method produce_impl @brief Produces the layout diff --git a/src/db/db/dbCell.cc b/src/db/db/dbCell.cc index 629ae4e92..cb56e7354 100644 --- a/src/db/db/dbCell.cc +++ b/src/db/db/dbCell.cc @@ -862,6 +862,12 @@ Cell::get_basic_name () const return layout ()->cell_name (cell_index ()); } +std::string +Cell::get_variant_name () const +{ + return get_basic_name (); +} + std::string Cell::get_qualified_name () const { diff --git a/src/db/db/dbCell.h b/src/db/db/dbCell.h index 2a64cdf23..7ba54fc71 100644 --- a/src/db/db/dbCell.h +++ b/src/db/db/dbCell.h @@ -890,7 +890,7 @@ public: void set_name (const std::string &name); /** - * @brief Get the basic name + * @brief Gets the basic name * * The basic name of the cell is either the cell name or the cell name in the * target library (for library proxies) or the PCell name (for PCell proxies). @@ -898,6 +898,14 @@ public: */ virtual std::string get_basic_name () const; + /** + * @brief Gets the variant name + * + * The variant name is the PCell's "cell_name" - which may encode the PCell parameters + * into a formal name. Usually that is identical to the PCell name. + */ + virtual std::string get_variant_name () const; + /** * @brief Gets the display name * diff --git a/src/db/db/dbColdProxy.cc b/src/db/db/dbColdProxy.cc index 3ccb5806a..e83c712eb 100644 --- a/src/db/db/dbColdProxy.cc +++ b/src/db/db/dbColdProxy.cc @@ -89,7 +89,7 @@ ColdProxy::get_basic_name () const } } -std::string +std::string ColdProxy::get_display_name () const { if (! mp_context_info->lib_name.empty ()) { diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index bf2a84e0e..e7c93b663 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -2462,7 +2462,7 @@ Layout::get_pcell_variant_dict (pcell_id_type pcell_id, const std::mapget_variant (*this, parameters); if (! variant) { - std::string b (header->get_name ()); + std::string b (header->declaration ()->get_cell_name (parameters)); if (m_cell_map.find (b.c_str ()) != m_cell_map.end ()) { b = uniquify_cell_name (b.c_str ()); } @@ -2501,7 +2501,7 @@ Layout::get_pcell_variant (pcell_id_type pcell_id, const std::vectorget_variant (*this, parameters); if (! variant) { - std::string b (header->get_name ()); + std::string b (header->declaration ()->get_cell_name (parameters)); if (m_cell_map.find (b.c_str ()) != m_cell_map.end ()) { b = uniquify_cell_name (b.c_str ()); } @@ -2627,9 +2627,18 @@ Layout::convert_cell_to_static (db::cell_index_type ci) const cell_type &org_cell = cell (ci); - // Note: convert to static cell by explicitly cloning to the db::Cell class - ret_ci = add_cell (org_cell.get_basic_name ().c_str ()); + + std::string vn = org_cell.get_variant_name (); + if (vn == cell_name (ci)) { + // there is a cell name conflict: give priority to the static cell, so it + // will see the variant name + std::string rename_org = uniquify_cell_name (cell_name (ci)); + rename_cell (ci, rename_org.c_str ()); + } + + ret_ci = add_cell (vn.c_str ()); cell_type &new_cell = cell (ret_ci); + // Note: we convert to static cell by explicitly cloning to the db::Cell class new_cell = org_cell; new_cell.set_cell_index (ret_ci); @@ -3126,6 +3135,12 @@ Layout::basic_name (cell_index_type cell_index) const return cell (cell_index).get_basic_name (); } +std::string +Layout::variant_name (cell_index_type cell_index) const +{ + return cell (cell_index).get_variant_name (); +} + void Layout::register_lib_proxy (db::LibraryProxy *lib_proxy) { @@ -3161,7 +3176,7 @@ Layout::get_lib_proxy (Library *lib, cell_index_type cell_index) } else { // create a new unique name - std::string b (lib->layout ().basic_name (cell_index)); + std::string b (lib->layout ().variant_name (cell_index)); if (m_cell_map.find (b.c_str ()) != m_cell_map.end ()) { b = uniquify_cell_name (b.c_str ()); } diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index 4c0d0078a..9104d758d 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -675,7 +675,7 @@ public: std::string display_name (cell_index_type cell_index) const; /** - * @brief Return the basic name for the given cell + * @brief Returns the basic name for the given cell * * This method is forwarded to the respective method of the cell. * The basic name is the "original" cell name within the library or @@ -684,7 +684,16 @@ public: */ std::string basic_name (cell_index_type cell_index) const; - /** + /** + * @brief Returns the variant name for the given cell + * + * The variant name usually is the basic name. For PCells, this name + * can encode PCell parameters, depending on the definition of the + * PCell. + */ + std::string variant_name (cell_index_type cell_index) const; + + /** * @brief Add a cell object with the given ID and name * * This method is basically supposed to be used for "undo" and "redo". diff --git a/src/db/db/dbLibraryProxy.cc b/src/db/db/dbLibraryProxy.cc index 87db31672..c44a319c8 100644 --- a/src/db/db/dbLibraryProxy.cc +++ b/src/db/db/dbLibraryProxy.cc @@ -257,7 +257,23 @@ LibraryProxy::get_basic_name () const } } -std::string +std::string +LibraryProxy::get_variant_name () const +{ + Library *lib = LibraryManager::instance ().lib (lib_id ()); + if (lib) { + if (! lib->layout ().is_valid_cell_index (library_cell_index ())) { + return ""; + } else { + const db::Cell &lib_cell = lib->layout ().cell (library_cell_index ()); + return lib_cell.get_variant_name (); + } + } else { + return Cell::get_variant_name (); + } +} + +std::string LibraryProxy::get_display_name () const { Library *lib = LibraryManager::instance ().lib (lib_id ()); diff --git a/src/db/db/dbLibraryProxy.h b/src/db/db/dbLibraryProxy.h index e1f026ed7..8c72787cc 100644 --- a/src/db/db/dbLibraryProxy.h +++ b/src/db/db/dbLibraryProxy.h @@ -96,25 +96,28 @@ public: /** * @brief Gets the basic name * - * The basic name of the cell is either the cell name or the cell name in the - * target library (for library proxies) or the PCell name (for PCell proxies). - * The actual name may be different by a extension to make it unique. + * This returns the basic name of the proxy target */ virtual std::string get_basic_name () const; + /** + * @brief Gets the variant name + * + * This returns the basic name of the proxy target + */ + virtual std::string get_variant_name () const; + /** * @brief Gets the display name * - * The display name is some "nice" descriptive name of the cell (variant) - * For normal cells this name is equivalent to the normal cell name. + * This returns the basic name of the proxy target */ virtual std::string get_display_name () const; /** * @brief Gets the qualified name * - * The qualified name for a library proxy is made from the library name, a - * dot and the cell's name. + * Gets a combination of the library name and the target cell's qualified name */ virtual std::string get_qualified_name () const; diff --git a/src/db/db/dbPCellDeclaration.h b/src/db/db/dbPCellDeclaration.h index 7db690f4c..a75718d83 100644 --- a/src/db/db/dbPCellDeclaration.h +++ b/src/db/db/dbPCellDeclaration.h @@ -673,6 +673,18 @@ public: return std::string (); } + /** + * @brief Gets a cell name for the PCell, which can depend on the parameters + * + * The actual cell name in the layout may differ by disambiguation. This method + * delivers a proposal for a cell name. + * By default, the PCell name is returned. + */ + virtual std::string get_cell_name (const pcell_parameters_type &) const + { + return m_name; + } + /** * @brief Returns the description text of the PCell * diff --git a/src/db/db/dbPCellVariant.cc b/src/db/db/dbPCellVariant.cc index b401c8471..bebda8921 100644 --- a/src/db/db/dbPCellVariant.cc +++ b/src/db/db/dbPCellVariant.cc @@ -86,7 +86,18 @@ PCellVariant::get_basic_name () const } } -std::string +std::string +PCellVariant::get_variant_name () const +{ + const PCellHeader *header = pcell_header (); + if (header) { + return m_variant_name; + } else { + return Cell::get_basic_name (); + } +} + +std::string PCellVariant::get_display_name () const { const PCellHeader *header = pcell_header (); @@ -172,6 +183,7 @@ PCellVariant::update (ImportLayerMapping *layer_mapping) header->declaration ()->produce (*layout (), layer_ids, plist, *this); m_display_name = header->declaration ()->get_display_name (plist); + m_variant_name = header->declaration ()->get_cell_name (plist); } catch (tl::Exception &ex) { diff --git a/src/db/db/dbPCellVariant.h b/src/db/db/dbPCellVariant.h index b4de1a1f5..c20aafeaf 100644 --- a/src/db/db/dbPCellVariant.h +++ b/src/db/db/dbPCellVariant.h @@ -94,42 +94,37 @@ public: } /** - * @brief Get the basic name - * - * The basic name of the cell is either the cell name or the cell name in the - * target library (for library proxies) or the PCell name (for PCell proxies). - * The actual name may be different by a extension to make it unique. + * @brief Gets the basic name */ virtual std::string get_basic_name () const; /** - * @brief Get the display name - * - * The display name is some "nice" descriptive name of the cell (variant) - * For normal cells this name is equivalent to the normal cell name. + * @brief Gets the variant name + */ + virtual std::string get_variant_name () const; + + /** + * @brief Gets the display name */ virtual std::string get_display_name () const; /** - * @brief Unregister a cell from it's context. + * @brief Unregisters a cell from it's context. */ virtual void unregister (); /** - * @brief Reregister a cell inside it's context. + * @brief Re-registers a cell inside it's context. */ virtual void reregister (); /** - * @brief Update the layout + * @brief Updates the layout */ virtual void update (ImportLayerMapping *layer_mapping = 0); /** - * @brief Tell, if this cell is a proxy cell - * - * Proxy cells are such whose layout represents a snapshot of another entity. - * Such cells can be PCell variants or library references for example. + * @brief Gets a value indicating if this cell is a proxy cell */ virtual bool is_proxy () const { @@ -138,7 +133,7 @@ public: protected: /** - * @brief Get the PCell header for this variant + * @brief Gets the PCell header for this variant */ PCellHeader *pcell_header () { @@ -146,7 +141,7 @@ protected: } /** - * @brief Get the PCell header for this variant + * @brief Gets the PCell header for this variant */ const PCellHeader *pcell_header () const { @@ -156,6 +151,7 @@ protected: private: pcell_parameters_type m_parameters; mutable std::string m_display_name; + mutable std::string m_variant_name; db::pcell_id_type m_pcell_id; bool m_registered; }; diff --git a/src/db/db/gsiDeclDbLibrary.cc b/src/db/db/gsiDeclDbLibrary.cc index d06caba5f..2693b0bb5 100644 --- a/src/db/db/gsiDeclDbLibrary.cc +++ b/src/db/db/gsiDeclDbLibrary.cc @@ -368,6 +368,7 @@ Class decl_PCellDeclaration_Native ("db", "PCellDeclaratio gsi::method ("via_types", &db::PCellDeclaration::via_types) + gsi::method ("description", &db::PCellDeclaration::get_description) + gsi::method ("display_text", &db::PCellDeclaration::get_display_name, gsi::arg ("parameters")) + + gsi::method ("cell_name", &db::PCellDeclaration::get_cell_name, gsi::arg ("parameters")) + gsi::method ("layout", &db::PCellDeclaration::layout, "@brief Gets the Layout object the PCell is registered in or nil if it is not registered yet.\n" "This attribute has been added in version 0.27.5." @@ -659,6 +660,20 @@ public: } } + std::string get_cell_name_fb (const db::pcell_parameters_type ¶meters) const + { + return db::PCellDeclaration::get_cell_name (parameters); + } + + virtual std::string get_cell_name (const db::pcell_parameters_type ¶meters) const + { + if (cb_get_cell_name.can_issue ()) { + return cb_get_cell_name.issue (&db::PCellDeclaration::get_cell_name, parameters); + } else { + return db::PCellDeclaration::get_cell_name (parameters); + } + } + gsi::Callback cb_get_layer_declarations; gsi::Callback cb_get_parameter_declarations; gsi::Callback cb_produce; @@ -669,6 +684,7 @@ public: gsi::Callback cb_coerce_parameters; gsi::Callback cb_callback; gsi::Callback cb_get_display_name; + gsi::Callback cb_get_cell_name; gsi::Callback cb_get_description; gsi::Callback cb_via_types; }; @@ -809,6 +825,13 @@ Class decl_PCellDeclaration (decl_PCellDeclaration_Native, "@brief Returns the display text for this PCell given a certain parameter set\n" "Reimplement this method to create a distinct display text for a PCell variant with \n" "the given parameter set. If this method is not implemented, a default text is created. \n" + ) + + gsi::callback ("cell_name", &PCellDeclarationImpl::get_cell_name, &PCellDeclarationImpl::cb_get_cell_name, gsi::arg ("parameters"), + "@brief Returns a cell name used for the PCell variant\n" + "Reimplement this method to create a cell name the system uses for the PCell variant. By default that is the PCell name.\n" + "This feature allows encoding the PCell parameters into the cell name for easier identification of the PCell variant in a cell tree.\n" + "\n" + "This feature has been added in version 0.30.5.\n" ), "@brief A PCell declaration providing the parameters and code to produce the PCell\n" "\n" diff --git a/src/pymod/distutils_src/klayout/db/pcell_declaration_helper.py b/src/pymod/distutils_src/klayout/db/pcell_declaration_helper.py index 773ff03c7..6a89fc446 100644 --- a/src/pymod/distutils_src/klayout/db/pcell_declaration_helper.py +++ b/src/pymod/distutils_src/klayout/db/pcell_declaration_helper.py @@ -138,6 +138,21 @@ class _PCellDeclarationHelperMixin: self._finish() return text + def cell_name(self, parameters): + """ + Reimplementation of PCellDeclaration.cell_name + + This function delegates the implementation to self.cell_name_impl + after configuring the PCellDeclaration object. + """ + self._start() + self._param_values = parameters + try: + text = self.cell_name_impl() + finally: + self._finish() + return text + def get_parameters(self): """ Reimplementation of PCellDeclaration.get_parameters @@ -333,6 +348,12 @@ class _PCellDeclarationHelperMixin: """ return "" + def cell_name_impl(self): + """ + default implementation + """ + return self.name() + def coerce_parameters_impl(self): """ default implementation From b523f05f8084441712632944218dfc937bb9160a Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 25 Oct 2025 00:33:25 +0200 Subject: [PATCH 2/3] Some typos fixed --- src/db/db/built-in-macros/pcell_declaration_helper.lym | 2 +- src/db/db/dbPCellVariant.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/db/db/built-in-macros/pcell_declaration_helper.lym b/src/db/db/built-in-macros/pcell_declaration_helper.lym index 1db044b21..774a33028 100644 --- a/src/db/db/built-in-macros/pcell_declaration_helper.lym +++ b/src/db/db/built-in-macros/pcell_declaration_helper.lym @@ -478,7 +478,7 @@ module RBA text end - # implementation of display_text + # implementation of cell_name def cell_name(parameters) self._start @param_values = parameters diff --git a/src/db/db/dbPCellVariant.h b/src/db/db/dbPCellVariant.h index c20aafeaf..a949bd0a2 100644 --- a/src/db/db/dbPCellVariant.h +++ b/src/db/db/dbPCellVariant.h @@ -109,12 +109,12 @@ public: virtual std::string get_display_name () const; /** - * @brief Unregisters a cell from it's context. + * @brief Unregisters a cell from its context. */ virtual void unregister (); /** - * @brief Re-registers a cell inside it's context. + * @brief Re-registers a cell inside its context. */ virtual void reregister (); From fc3185165fe329ff60a7a447bda640b2d40d0c10 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 25 Oct 2025 17:16:13 +0200 Subject: [PATCH 3/3] Added some tests --- src/db/db/dbLayout.cc | 10 +-- src/db/db/gsiDeclDbLibrary.cc | 1 + src/db/unit_tests/dbPCellsTests.cc | 118 +++++++++++++++++++++++++++++ testdata/gds/issue_1835_au.gds | Bin 660 -> 658 bytes testdata/gds/pcell_test20.gds | Bin 0 -> 1138 bytes testdata/python/dbPCells.py | 12 +++ testdata/ruby/dbPCells.rb | 46 +++++++++++ 7 files changed, 182 insertions(+), 5 deletions(-) create mode 100644 testdata/gds/pcell_test20.gds diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index e7c93b663..fbf1abf14 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -2627,18 +2627,18 @@ Layout::convert_cell_to_static (db::cell_index_type ci) const cell_type &org_cell = cell (ci); - std::string vn = org_cell.get_variant_name (); - if (vn == cell_name (ci)) { + if (vn == std::string (cell_name (ci), vn.size ())) { // there is a cell name conflict: give priority to the static cell, so it - // will see the variant name - std::string rename_org = uniquify_cell_name (cell_name (ci)); + // will see the variant name or at least the original disambiguated name + std::string rename_org = uniquify_cell_name (vn.c_str ()); + vn = cell_name (ci); rename_cell (ci, rename_org.c_str ()); } ret_ci = add_cell (vn.c_str ()); cell_type &new_cell = cell (ret_ci); - // Note: we convert to static cell by explicitly cloning to the db::Cell class + // Note: we convert to static cell by explicitly converting to the db::Cell class new_cell = org_cell; new_cell.set_cell_index (ret_ci); diff --git a/src/db/db/gsiDeclDbLibrary.cc b/src/db/db/gsiDeclDbLibrary.cc index 2693b0bb5..774e92d40 100644 --- a/src/db/db/gsiDeclDbLibrary.cc +++ b/src/db/db/gsiDeclDbLibrary.cc @@ -698,6 +698,7 @@ Class decl_PCellDeclaration (decl_PCellDeclaration_Native, gsi::method ("parameters_from_shape", &PCellDeclarationImpl::parameters_from_shape_fb, "@hide") + gsi::method ("transformation_from_shape", &PCellDeclarationImpl::transformation_from_shape_fb, "@hide") + gsi::method ("display_text", &PCellDeclarationImpl::get_display_name_fb, "@hide") + + gsi::method ("cell_name", &PCellDeclarationImpl::get_cell_name_fb, "@hide") + gsi::method ("wants_lazy_evaluation", &PCellDeclarationImpl::wants_lazy_evaluation_fb, "@hide") + gsi::method ("description", &PCellDeclarationImpl::get_description_fb, "@hide") + gsi::method ("via_types", &PCellDeclarationImpl::via_types_fb, "@hide") + diff --git a/src/db/unit_tests/dbPCellsTests.cc b/src/db/unit_tests/dbPCellsTests.cc index 9304b9aff..dc41a4c8b 100644 --- a/src/db/unit_tests/dbPCellsTests.cc +++ b/src/db/unit_tests/dbPCellsTests.cc @@ -88,6 +88,13 @@ class PD cell.shapes (l_metal0).insert (db::Box (0, 0, width, height)); } + + virtual std::string get_display_name (const db::pcell_parameters_type ¶meters) const + { + db::Coord width = db::coord_traits::rounded (parameters[0].to_double () * 1000.0); + db::Coord height = db::coord_traits::rounded (parameters[1].to_double () * 1000.0); + return tl::sprintf ("PD(W=%d,H=%d)", width, height); + } }; TEST(0) @@ -252,3 +259,114 @@ TEST(1) } } +// PCell names, convert PCell to static + +class PD2 + : public PD +{ +public: + virtual std::string get_cell_name (const db::pcell_parameters_type ¶meters) const + { + db::Coord width = db::coord_traits::rounded (parameters[0].to_double () * 1000.0); + db::Coord height = db::coord_traits::rounded (parameters[1].to_double () * 1000.0); + return tl::sprintf ("PD_W%d_H%d", width, height); + } +}; + +TEST(2) +{ + db::Manager m (true); + db::Layout layout(&m); + layout.dbu (0.001); + + db::LayerProperties p; + + p.layer = 23; + p.datatype = 0; + unsigned int l_cont = layout.insert_layer (p); + + p.layer = 16; + p.datatype = 0; + unsigned int l_gate = layout.insert_layer (p); + + db::Cell &cell_a = layout.cell (layout.add_cell ("A")); + cell_a.shapes(l_cont).insert(db::Box (50, 50, 150, 150)); + cell_a.shapes(l_gate).insert(db::Box (0, 0, 200, 1000)); + + db::Cell &top = layout.cell (layout.add_cell ("TOP")); + + db::pcell_id_type pd = layout.register_pcell ("PD", new PD2 ()); + + std::vector parameters; + parameters.push_back (tl::Variant ()); + parameters.push_back (tl::Variant ()); + parameters.push_back (tl::Variant ()); + tl::Variant &width = parameters[0]; + tl::Variant &height = parameters[1]; + tl::Variant &orientation = parameters[2]; + + width = 0.5; + height = 1.0; + orientation = long (0); + + db::cell_index_type pd1 = layout.get_pcell_variant (pd, parameters); + top.insert (db::CellInstArray (db::CellInst (pd1), db::Trans (db::Vector (0, 0)))); + + EXPECT_EQ (layout.display_name (pd1), "PD(W=500,H=1000)"); + EXPECT_EQ (layout.cell_name (pd1), "PD_W500_H1000"); + EXPECT_EQ (layout.variant_name (pd1), "PD_W500_H1000"); + + width = 0.4; + height = 0.8; + + db::cell_index_type pd2 = layout.get_pcell_variant (pd, parameters); + top.insert (db::CellInstArray (db::CellInst (pd2), db::Trans (db::Vector (0, 2000)))); + + EXPECT_EQ (layout.display_name (pd2), "PD(W=400,H=800)"); + EXPECT_EQ (layout.cell_name (pd2), "PD_W400_H800"); + EXPECT_EQ (layout.variant_name (pd2), "PD_W400_H800"); + + EXPECT_NE (pd1, pd2); + + width = 0.4; + height = 0.8; + orientation = long (1); + + db::cell_index_type pd3 = layout.get_pcell_variant (pd, parameters); + auto i3 = top.insert (db::CellInstArray (db::CellInst (pd3), db::Trans (db::Vector (2000, 0)))); + + EXPECT_EQ (layout.display_name (pd3), "PD(W=400,H=800)"); + EXPECT_EQ (layout.cell_name (pd3), "PD_W400_H800$1"); + EXPECT_EQ (layout.variant_name (pd3), "PD_W400_H800"); + + EXPECT_NE (pd2, pd3); + + auto pd3_org = pd3; + pd3 = layout.convert_cell_to_static (pd3); + EXPECT_NE (pd3, pd3_org); + + auto ci3 = i3.cell_inst (); + ci3.object ().cell_index (pd3); + top.replace (i3, ci3); + + EXPECT_EQ (layout.cell (pd3_org).is_proxy (), true); + EXPECT_EQ (layout.cell (pd3).is_proxy (), false); + + EXPECT_EQ (layout.display_name (pd3_org), "PD(W=400,H=800)"); + EXPECT_EQ (layout.cell_name (pd3_org), "PD_W400_H800$2"); + EXPECT_EQ (layout.variant_name (pd3_org), "PD_W400_H800"); + + layout.do_cleanup (true); + layout.cleanup (); + + EXPECT_EQ (layout.is_valid_cell_index (pd3_org), false); + + EXPECT_EQ (layout.display_name (pd3), "PD_W400_H800$1"); + EXPECT_EQ (layout.cell_name (pd3), "PD_W400_H800$1"); + EXPECT_EQ (layout.variant_name (pd3), "PD_W400_H800$1"); + + + + CHECKPOINT (); + db::compare_layouts (_this, layout, tl::testdata () + "/gds/pcell_test20.gds", db::NoNormalization); +} diff --git a/testdata/gds/issue_1835_au.gds b/testdata/gds/issue_1835_au.gds index 8770350b017a47331bde24b3dd860fe9c725415c..6d0a52e9a4fbeb98874bc7b34a0367231725382e 100644 GIT binary patch delta 115 zcmbQjI*B!lfsKKQDS|{L4=vr&au{L4=vr&auiN#URPR&tS$Njm&1?U}E#}bYfr-VP>^+>@@d2w)}&o%MSeo zv!g;7WLR9rIjMQ+Fij>53@m~`40MAK#0{n(Hy9cK9YK^U1W;UINRAs! zp>AMjz#DpOY;2A|l^j67@G>!oGqCY70fR^f98yL=77R}VvXL=N+z8@RsD1$y{jjhG z(#$V_#0dnABn1vB0M;{fPWu&H>V36`gUDFN&+pb8Lxxr>E`0RR%7d|Lnj literal 0 HcmV?d00001 diff --git a/testdata/python/dbPCells.py b/testdata/python/dbPCells.py index 41881f415..a7283c9cc 100644 --- a/testdata/python/dbPCells.py +++ b/testdata/python/dbPCells.py @@ -27,6 +27,10 @@ class BoxPCell(pya.PCellDeclaration): # provide a descriptive text for the cell return "Box(L=" + str(parameters[0]) + ",W=" + ('%.3f' % parameters[1]) + ",H=" + ('%.3f' % parameters[2]) + ")" + def cell_name(self, parameters): + # provide a descriptive text for the cell + return "Box_L" + str(parameters[0]).replace("/", "d") + "_W" + ('%.3f' % parameters[1]).replace(".", "p") + "_H" + ('%.3f' % parameters[2]).replace(".", "p") + def get_parameters(self): # prepare a set of parameter declarations @@ -100,6 +104,10 @@ if "PCellDeclarationHelper" in pya.__dict__: # provide a descriptive text for the cell return "Box2(L=" + str(self.layer) + ",W=" + ('%.3f' % self.width) + ",H=" + ('%.3f' % self.height) + ")" + def cell_name_impl(self): + # provide a descriptive text for the cell + return "Box2_L" + str(self.layer).replace("/", "d") + "_W" + ('%.3f' % self.width).replace(".", "p") + "_H" + ('%.3f' % self.height).replace(".", "p") + def wants_lazy_evaluation(self): return True @@ -260,6 +268,8 @@ class DBPCellTests(unittest.TestCase): self.assertEqual(pcell_var.is_pcell_variant(), True) self.assertEqual(pcell_var.display_title(), "PCellTestLib.Box(L=1/0,W=1.000,H=1.000)") self.assertEqual(pcell_var.basic_name(), "Box") + self.assertEqual(pcell_var.qname(), "PCellTestLib.Box") + self.assertEqual(pcell_var.name, "Box_L1d0_W1p000_H1p000") self.assertEqual(pcell_var.pcell_declaration().wants_lazy_evaluation(), False) self.assertEqual(c1.is_pcell_variant(), False) self.assertEqual(c1.is_pcell_variant(pcell_inst), True) @@ -394,6 +404,8 @@ class DBPCellTests(unittest.TestCase): pcell_var = ly.cell(pcell_var_id) pcell_inst = c1.insert(pya.CellInstArray(pcell_var_id, pya.Trans())) self.assertEqual(pcell_var.basic_name(), "Box2") + self.assertEqual(pcell_var.name, "Box2_L1d0_W1p000_H1p000") + self.assertEqual(pcell_var.qname(), "PCellTestLib2.Box2") self.assertEqual(pcell_var.pcell_parameters().__repr__(), "[<1/0>, 1.0, 1.0]") self.assertEqual(pcell_var.display_title(), "PCellTestLib2.Box2(L=1/0,W=1.000,H=1.000)") self.assertEqual(nh(pcell_var.pcell_parameters_by_name()), "{'height': 1.0, 'layer': <1/0>, 'width': 1.0}") diff --git a/testdata/ruby/dbPCells.rb b/testdata/ruby/dbPCells.rb index 61ca6450c..e15989b4b 100644 --- a/testdata/ruby/dbPCells.rb +++ b/testdata/ruby/dbPCells.rb @@ -39,6 +39,11 @@ class BoxPCell < RBA::PCellDeclaration # provide a descriptive text for the cell return "Box(L=#{parameters[0].to_s},W=#{'%.3f' % parameters[1].to_s},H=#{'%.3f' % parameters[2].to_s})" end + + def cell_name(parameters) + # provide a cell name for the PCell + return "Box_L#{parameters[0].to_s.gsub('/','d')}_W#{('%.3f' % parameters[1]).gsub('.','p')}_H#{('%.3f' % parameters[2]).gsub('.','p')}" + end def get_parameters @@ -129,6 +134,11 @@ if RBA.constants.member?(:PCellDeclarationHelper) return "Box2(L=" + layer.to_s + ",W=" + ('%.3f' % width) + ",H=" + ('%.3f' % height) + ")" end + def cell_name_impl + # provide a cell name for the PCell + return "Box2_L" + layer.to_s.gsub('/', 'd') + "_W" + ('%.3f' % width).gsub('.', 'p') + "_H" + ('%.3f' % height).gsub('.', 'p') + end + def produce_impl # fetch the parameters @@ -371,6 +381,9 @@ class DBPCell_TestClass < TestBase param = [ RBA::LayerInfo::new(1, 0) ] # rest is filled with defaults pcell_var_id = ly.add_pcell_variant(lib, pcell_decl_id, param) pcell_var = ly.cell(pcell_var_id) + assert_equal(pcell_var.name, "Box_L1d0_W1p000_H1p000") + assert_equal(pcell_var.qname, "PCellTestLib.Box") + assert_equal(pcell_var.basic_name, "Box") pcell_inst = c1.insert(RBA::CellInstArray::new(pcell_var_id, RBA::Trans::new)) assert_equal(pcell_var.layout.inspect, ly.inspect) assert_equal(pcell_var.library.inspect, lib.inspect) @@ -512,6 +525,8 @@ class DBPCell_TestClass < TestBase pcell_var = ly.cell(pcell_var_id) pcell_inst = c1.insert(RBA::CellInstArray::new(pcell_var_id, RBA::Trans::new)) assert_equal(pcell_var.basic_name, "Box2") + assert_equal(pcell_var.name, "Box2_L1d0_W1p000_H1p000") + assert_equal(pcell_var.qname, "PCellTestLib2.Box2") assert_equal(pcell_var.pcell_parameters().inspect, "[<1/0>, 1.0, 1.0, 0]") assert_equal(pcell_var.display_title(), "PCellTestLib2.Box2(L=1/0,W=1.000,H=1.000)") assert_equal(norm_hash(pcell_var.pcell_parameters_by_name()), "{\"height\"=>1.0, \"layer\"=><1/0>, \"secret\"=>0, \"width\"=>1.0}") @@ -908,6 +923,37 @@ class DBPCell_TestClass < TestBase end + # convert to static cell + def test_13 + + if !RBA.constants.member?(:PCellDeclarationHelper) + return + end + + # instantiate and register the library + tl = PCellTestLib2::new + + ly = RBA::Layout::new(true) + ly.dbu = 0.01 + + ci1 = ly.add_cell("c1") + c1 = ly.cell(ci1) + + lib = RBA::Library.library_by_name("PCellTestLib2") + assert_equal(lib != nil, true) + pcell_decl = lib.layout().pcell_declaration("Box2") + + param = [ RBA::LayerInfo::new(1, 0) ] # rest is filled with defaults + pcell_var_id = ly.add_pcell_variant(lib, pcell_decl.id(), param) + static_id = ly.convert_cell_to_static(pcell_var_id) + static = ly.cell(static_id) + assert_equal(static.basic_name, "Box2_L1d0_W1p000_H1p000") + assert_equal(static.name, "Box2_L1d0_W1p000_H1p000") + assert_equal(static.qname, "Box2_L1d0_W1p000_H1p000") + assert_equal(static.is_proxy?, false) + + end + end class DBPCellParameterStates_TestClass < TestBase