Merge branch 'wip'

This commit is contained in:
Matthias Koefferlein 2026-05-24 15:26:19 +02:00
commit 0648ee1bd0
4 changed files with 595 additions and 57 deletions

View File

@ -32,6 +32,7 @@
#include "dbLibraryProxy.h"
#include "dbLibraryManager.h"
#include "dbLibrary.h"
#include "dbColdProxy.h"
#include "dbLayout.h"
#include "dbLayoutUtils.h"
#include "dbLayerMapping.h"
@ -949,6 +950,11 @@ static std::vector<db::cell_index_type> caller_cells (const db::Cell *c)
return std::vector<db::cell_index_type> (ids.begin (), ids.end ());
}
static bool is_cold_proxy (const db::Cell *cell)
{
return dynamic_cast<const db::ColdProxy *> (cell) != 0;
}
static bool is_library_cell (const db::Cell *cell)
{
return dynamic_cast<const db::LibraryProxy *> (cell) != 0;
@ -974,6 +980,36 @@ static db::Library *library (const db::Cell *cell)
}
}
static std::string library_name (const db::Cell *cell)
{
const db::ColdProxy *cp = dynamic_cast<const db::ColdProxy *> (cell);
if (cp) {
return cp->context_info ().lib_name;
} else {
const db::Library *l = library (cell);
if (l) {
return l->get_name ();
} else {
return std::string ();
}
}
}
static std::string library_cell_name (const db::Cell *cell)
{
const db::ColdProxy *cp = dynamic_cast<const db::ColdProxy *> (cell);
if (cp) {
return cp->context_info ().cell_name;
} else {
const db::Library *l = library (cell);
if (l) {
return l->layout ().cell_name (library_cell_index (cell));
} else {
return std::string ();
}
}
}
static void change_library_ref (db::Cell *cell, db::lib_id_type lib_id, db::cell_index_type cell_index)
{
db::LibraryProxy *l = dynamic_cast<db::LibraryProxy *> (cell);
@ -1173,13 +1209,25 @@ static const std::vector<tl::Variant> &pcell_parameters (const db::Cell *cell)
static tl::Variant pcell_parameter (const db::Cell *cell, const std::string &name)
{
return cell->layout ()->get_pcell_parameter (cell->cell_index (), name);
const db::ColdProxy *cp = dynamic_cast <const db::ColdProxy *> (cell);
if (cp) {
const auto &pp = cp->context_info ().pcell_parameters;
auto i = pp.find (name);
return i != pp.end () ? i->second : tl::Variant ();
} else {
return cell->layout ()->get_pcell_parameter (cell->cell_index (), name);
}
}
static std::map<std::string, tl::Variant> pcell_parameters_by_name (const db::Cell *cell)
{
tl_assert (cell->layout () != 0);
return cell->layout ()->get_named_pcell_parameters (cell->cell_index ());
const db::ColdProxy *cp = dynamic_cast <const db::ColdProxy *> (cell);
if (cp) {
return cp->context_info ().pcell_parameters;
} else {
tl_assert (cell->layout () != 0);
return cell->layout ()->get_named_pcell_parameters (cell->cell_index ());
}
}
static void refresh (db::Cell *cell)
@ -1203,6 +1251,21 @@ static const db::PCellDeclaration *pcell_declaration (const db::Cell *cell)
}
}
static std::string pcell_name (const db::Cell *cell)
{
const db::ColdProxy *cp = dynamic_cast <const db::ColdProxy *> (cell);
if (cp) {
return cp->context_info ().pcell_name;
} else {
const db::PCellDeclaration *pd = pcell_declaration (cell);
if (pd) {
return pd->name ();
} else {
return std::string ();
}
}
}
static const db::PCellDeclaration *pcell_declaration_of_inst (const db::Cell *cell, const db::Cell::instance_type &ref)
{
tl_assert (cell->layout () != 0);
@ -3193,7 +3256,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
"This method has been introduced in version 0.20.\n"
) +
gsi::method ("is_proxy?", &db::Cell::is_proxy,
"@brief Returns true, if the cell presents some external entity \n"
"@brief Returns true, if the cell presents some external entity\n"
"A cell may represent some data which is imported from some other source, i.e.\n"
"a library. Such cells are called \"proxy cells\". For a library reference, the\n"
"proxy cell is some kind of pointer to the library and the cell within the library.\n"
@ -3201,11 +3264,31 @@ Class<db::Cell> decl_Cell ("db", "Cell",
"For PCells, this data can even be computed through some script.\n"
"A PCell proxy represents all instances with a given set of parameters.\n"
"\n"
"Proxy cells cannot be modified, except that pcell parameters can be modified\n"
"and PCell instances can be recomputed.\n"
"Proxy cells should not be modified directly - i.e. the shapes or instances should not\n"
"be touched. However, you can change PCell parameters (\\change_pcell_parameter, \\change_pcell_parameters)\n"
"or change the library reference (\\change_ref).\n"
"\n"
"This method has been introduced in version 0.22.\n"
) +
gsi::method_ext ("is_cold_proxy?", &is_cold_proxy,
"@brief Returns true, if the cell is a 'cold proxy'\n"
"Cold proxies are cells that refer to a library cell or PCell variant, but can temporarily not be resolved -\n"
"for example, because the library is not installed. Such cells are basically placeholders\n"
"for library references and also carry PCell parameter information needed to establish\n"
"the link to the library PCell, once the library is available again.\n"
"\n"
"You can use \\library_name to obtain the name of the library the proxy points to, "
"\\library_cell_name to obtain the cell name in that library, "
"\\pcell_name to obtain the PCell name if it is a PCell proxy, "
"and \\pcell_parameter or \\pcell_parameters_by_name to obtain the PCell parameters.\n"
"\n"
"Cold proxies cannot be created or modified. Cold proxies are basically error indicators "
"and should be fixed by installing the respective library. Their layout state\n"
"reflects the last version of the layout when the cell was functional and properly\n"
"linked to a library. Still, they can be used in read-only applications.\n"
"\n"
"This method has been introduced in version 0.30.9.\n"
) +
gsi::method_ext ("is_library_cell?", &is_library_cell,
"@brief Returns true, if the cell is a proxy cell pointing to a library cell\n"
"If the cell is imported from some library, this attribute returns true.\n"
@ -3231,10 +3314,32 @@ Class<db::Cell> decl_Cell ("db", "Cell",
) +
gsi::method_ext ("library", &library,
"@brief Returns a reference to the library from which the cell is imported\n"
"if the cell is not imported from a library, this reference is nil.\n"
"If the cell is not imported from a library, this reference is nil.\n"
"\n"
"This method has been introduced in version 0.22.\n"
) +
gsi::method_ext ("library_cell_name", &library_cell_name,
"@brief Returns the cell name inside the library from which the cell is imported\n"
"If the cell is not imported from a library, the return value is an empty string.\n"
"This method is basically a convenience function, equivalent to taking the name\n"
"from \\library and \\library_cell_index.\n"
"Note that for PCells, 'library_cell_name' is the name of the PCell proxy cell inside "
"the library, not the name of the PCell.\n"
"\n"
"However, this method also works for 'cold proxies' (see \\is_cold_proxy?)\n"
"for which it delivers the name of cell inside the (missing) library.\n"
"\n"
"This method has been introduced in version 0.30.8.\n"
) +
gsi::method_ext ("library_name", &library_name,
"@brief Returns the name of the library from which the cell is imported\n"
"If the cell is not imported from a library, the return value is an empty string.\n"
"This method is basically a convenience function, equivalent to taking the name\n"
"from \\library. However, this method also works for 'cold proxies' (see \\is_cold_proxy?)\n"
"for which it delivers the name of the (missing) library.\n"
"\n"
"This method has been introduced in version 0.30.8.\n"
) +
gsi::method_ext ("change_ref", &change_library_ref, gsi::arg ("lib_id"), gsi::arg ("lib_cell_index"),
"@brief Changes the reference to a different library cell\n"
"This method requires a cell that is a library reference (i.e. \\is_library_cell? is true). It will "
@ -3307,6 +3412,9 @@ Class<db::Cell> decl_Cell ("db", "Cell",
"If the cell is not a PCell variant or the name is not a valid PCell parameter name, "
"the return value is nil.\n"
"\n"
"This method also works for 'cold proxies' (see \\is_cold_proxy?)\n"
"for which it delivers the value of the given stored PCell parameter.\n"
"\n"
"This method has been introduced in version 0.25."
) +
gsi::method_ext ("pcell_parameters_by_name", &pcell_parameters_by_name,
@ -3316,8 +3424,20 @@ Class<db::Cell> decl_Cell ("db", "Cell",
"method returns an empty dictionary. This method also returns the PCell parameters if\n"
"the cell is a PCell imported from a library.\n"
"\n"
"This method also works for 'cold proxies' (see \\is_cold_proxy?)\n"
"for which it delivers the names and values of the stored PCell parameters.\n"
"\n"
"This method has been introduced in version 0.24.\n"
) +
gsi::method_ext ("pcell_name", &pcell_name,
"@brief Returns the PCell name if the cell is a PCell variant\n"
"If this cell is not a PCell variant, this method returns an empty string.\n"
"This method is basically a convenience function, equivalent to taking the name\n"
"from \\pcell_declaration. However, this method also works for 'cold proxies' (see \\is_cold_proxy?)\n"
"for which it delivers the name of the (missing) PCell.\n"
"\n"
"This method has been introduced in version 0.30.9.\n"
) +
gsi::method_ext ("pcell_declaration", &pcell_declaration,
"@brief Returns a reference to the PCell declaration\n"
"If this cell is not a PCell variant, this method returns nil.\n"

View File

@ -642,12 +642,22 @@ static tl::Variant get_property_from_id (db::properties_id_type id, const tl::Va
}
static void
delete_cells (db::Layout *layout, const std::vector<db::cell_index_type> &cell_indices)
delete_cells (db::Layout *layout, const std::vector<db::cell_index_type> &cell_indexes)
{
for (auto ci = cell_indices.begin (); ci != cell_indices.end (); ++ci) {
for (auto ci = cell_indexes.begin (); ci != cell_indexes.end (); ++ci) {
check_cell_index (layout, *ci);
}
layout->delete_cells (cell_indices.begin (), cell_indices.end ());
layout->delete_cells (cell_indexes.begin (), cell_indexes.end ());
}
static void
delete_cells_ptr (db::Layout *layout, const std::vector<db::Cell *> &cells)
{
std::set<db::cell_index_type> cell_indexes;
for (auto c = cells.begin (); c != cells.end (); ++c) {
cell_indexes.insert ((*c)->cell_index ());
}
layout->delete_cells (cell_indexes);
}
static void
@ -657,20 +667,76 @@ delete_cell_rec (db::Layout *layout, db::cell_index_type cell_index)
layout->delete_cell_rec (cell_index);
}
static void
static void
delete_cell_rec_ptr (db::Layout *layout, db::Cell *cell)
{
layout->delete_cell_rec (cell->cell_index ());
}
static void
prune_cell (db::Layout *layout, db::cell_index_type cell_index, int levels)
{
check_cell_index (layout, cell_index);
layout->prune_cell (cell_index, levels);
}
static void
static void
prune_cell_ptr (db::Layout *layout, db::Cell *cell, int levels)
{
layout->prune_cell (cell->cell_index (), levels);
}
static void
prune_cells (db::Layout *layout, const std::vector<db::cell_index_type> &cell_indexes, int levels)
{
for (auto ci = cell_indexes.begin (); ci != cell_indexes.end (); ++ci) {
check_cell_index (layout, *ci);
}
layout->prune_cells (cell_indexes.begin (), cell_indexes.end (), levels);
}
static void
prune_cells_ptr (db::Layout *layout, const std::vector<db::Cell *> &cells, int levels)
{
std::set<db::cell_index_type> cell_indexes;
for (auto c = cells.begin (); c != cells.end (); ++c) {
cell_indexes.insert ((*c)->cell_index ());
}
layout->prune_cells (cell_indexes, levels);
}
static void
prune_subcells (db::Layout *layout, db::cell_index_type cell_index, int levels)
{
check_cell_index (layout, cell_index);
layout->prune_subcells (cell_index, levels);
}
static void
prune_subcells_ptr (db::Layout *layout, db::Cell *cell, int levels)
{
layout->prune_subcells (cell->cell_index (), levels);
}
static void
prune_subcells_many (db::Layout *layout, const std::vector<db::cell_index_type> &cell_indexes, int levels)
{
for (auto ci = cell_indexes.begin (); ci != cell_indexes.end (); ++ci) {
check_cell_index (layout, *ci);
}
layout->prune_subcells (cell_indexes.begin (), cell_indexes.end (), levels);
}
static void
prune_subcells_many_ptr (db::Layout *layout, const std::vector<db::Cell *> &cells, int levels)
{
std::set<db::cell_index_type> cell_indexes;
for (auto c = cells.begin (); c != cells.end (); ++c) {
cell_indexes.insert ((*c)->cell_index ());
}
layout->prune_subcells (cell_indexes, levels);
}
static void
flatten (db::Layout *layout, db::cell_index_type cell_index, int levels, bool prune)
{
@ -678,7 +744,16 @@ flatten (db::Layout *layout, db::cell_index_type cell_index, int levels, bool pr
layout->flatten (layout->cell (cell_index), levels, prune);
}
static void
static void
flatten_ptr (db::Layout *layout, db::Cell *cell, int levels, bool prune)
{
if (! cell) {
return;
}
layout->flatten (*cell, levels, prune);
}
static void
flatten_into (db::Layout *layout, db::cell_index_type cell_index, db::cell_index_type target_cell_index, const db::ICplxTrans &t, int levels)
{
check_cell_index (layout, cell_index);
@ -686,7 +761,16 @@ flatten_into (db::Layout *layout, db::cell_index_type cell_index, db::cell_index
layout->flatten (layout->cell (cell_index), layout->cell (target_cell_index), t, levels);
}
static void
static void
flatten_into_ptr (db::Layout *layout, db::Cell *cell, db::Cell *target_cell, const db::ICplxTrans &t, int levels)
{
if (! cell || ! target_cell) {
return;
}
layout->flatten (*cell, *target_cell, t, levels);
}
static void
write_simple (db::Layout *layout, const std::string &filename)
{
db::SaveLayoutOptions options;
@ -866,6 +950,11 @@ static void delete_cell (db::Layout *ly, db::cell_index_type ci)
ly->delete_cell (ci);
}
static void delete_cell_ptr (db::Layout *ly, db::Cell *cell)
{
ly->delete_cell (cell->cell_index ());
}
static void rename_cell (db::Layout *ly, db::cell_index_type ci, const std::string &name)
{
check_cell_index (ly, ci);
@ -1655,6 +1744,20 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"\n"
"This method has been introduced in version 0.20.\n"
) +
gsi::method_ext ("delete_cell", &delete_cell_ptr, gsi::arg ("cell"),
"@brief Deletes a cell\n"
"\n"
"This deletes a cell but not the sub cells of the cell.\n"
"These subcells will likely become new top cells unless they are used\n"
"otherwise.\n"
"All instances of this cell are deleted as well.\n"
"Hint: to delete multiple cells, use \"delete_cells\" which is \n"
"far more efficient in this case.\n"
"\n"
"@param cell The cell to delete\n"
"\n"
"This convenience variant taking a cell object has been introduced in version 0.30.9.\n"
) +
gsi::method_ext ("delete_cells", &delete_cells, gsi::arg ("cell_index_list"),
"@brief Deletes multiple cells\n"
"\n"
@ -1667,19 +1770,73 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"\n"
"This method has been introduced in version 0.20.\n"
) +
gsi::method_ext ("prune_subcells", &prune_subcells, gsi::arg ("cell_index"), gsi::arg ("levels"),
gsi::method_ext ("delete_cells", &delete_cells_ptr, gsi::arg ("cell_list"),
"@brief Deletes multiple cells\n"
"\n"
"This deletes the cells but not the sub cells of these cells.\n"
"These subcells will likely become new top cells unless they are used\n"
"otherwise.\n"
"All instances of these cells are deleted as well.\n"
"\n"
"@param cell_list An list of cells to delete\n"
"\n"
"This convenience variant taking a list of cell objects has been introduced in version 0.30.9.\n"
) +
gsi::method_ext ("prune_subcells", &prune_subcells, gsi::arg ("cell_index"), gsi::arg ("levels", -1),
"@brief Deletes all sub cells of the cell which are not used otherwise down to the specified level of hierarchy\n"
"\n"
"This deletes all sub cells of the cell which are not used otherwise.\n"
"All instances of the deleted cells are deleted as well.\n"
"It is possible to specify how many levels of hierarchy below the given root cell are considered.\n"
"\n"
"A variant exists that takes a list of cell indexes and which is more efficient than calling\n"
"'prune_subcells' multiple times on a single cell.\n"
"\n"
"@param cell_index The root cell from which to delete a sub cells\n"
"@param levels The number of hierarchy levels to consider (-1: all, 0: none, 1: one level etc.)\n"
"\n"
"This method has been introduced in version 0.20.\n"
) +
gsi::method_ext ("prune_cell", &prune_cell, gsi::arg ("cell_index"), gsi::arg ("levels"),
gsi::method_ext ("prune_subcells", &prune_subcells_ptr, gsi::arg ("cell"), gsi::arg ("levels", -1),
"@brief Deletes all sub cells of the cell which are not used otherwise down to the specified level of hierarchy\n"
"\n"
"This deletes all sub cells of the cell which are not used otherwise.\n"
"All instances of the deleted cells are deleted as well.\n"
"It is possible to specify how many levels of hierarchy below the given root cell are considered.\n"
"\n"
"A variant exists that takes a list of cells and which is more efficient than calling\n"
"'prune_subcells' multiple times on a single cell.\n"
"\n"
"@param cell The root cell from which to delete a sub cells\n"
"@param levels The number of hierarchy levels to consider (-1: all, 0: none, 1: one level etc.)\n"
"\n"
"This convenience variant taking a list of cell objects has been introduced in version 0.30.9.\n"
) +
gsi::method_ext ("prune_subcells", &prune_subcells_many, gsi::arg ("cell_index_list"), gsi::arg ("levels", -1),
"@brief Deletes all sub cells of the given cells which are not used otherwise down to the specified level of hierarchy\n"
"\n"
"This deletes all sub cells of the given cells which are not used otherwise.\n"
"All instances of the deleted cells are deleted as well.\n"
"It is possible to specify how many levels of hierarchy below the given root cell are considered.\n"
"\n"
"@param cell_index_list The root cells from which to delete the sub cells\n"
"@param levels The number of hierarchy levels to consider (-1: all, 0: none, 1: one level etc.)\n"
"\n"
"This method has been introduced in version 0.30.9.\n"
) +
gsi::method_ext ("prune_subcells", &prune_subcells_many_ptr, gsi::arg ("cell_list"), gsi::arg ("levels", -1),
"@brief Deletes all sub cells of the given cells which are not used otherwise down to the specified level of hierarchy\n"
"\n"
"This deletes all sub cells of the given cells which are not used otherwise.\n"
"All instances of the deleted cells are deleted as well.\n"
"It is possible to specify how many levels of hierarchy below the given root cell are considered.\n"
"\n"
"@param cell_list The root cells from which to delete the sub cells\n"
"@param levels The number of hierarchy levels to consider (-1: all, 0: none, 1: one level etc.)\n"
"\n"
"This method has been introduced in version 0.30.9.\n"
) +
gsi::method_ext ("prune_cell", &prune_cell, gsi::arg ("cell_index"), gsi::arg ("levels", -1),
"@brief Deletes a cell plus subcells not used otherwise\n"
"\n"
"This deletes a cell and also all sub cells of the cell which are not used otherwise.\n"
@ -1687,10 +1844,53 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"only the direct children of the cell are deleted with the cell itself.\n"
"All instances of this cell are deleted as well.\n"
"\n"
"A version that allows pruning multiple cells in one call is \\prune_cells.\n"
"\n"
"@param cell_index The index of the cell to delete\n"
"@param levels The number of hierarchy levels to consider (-1: all, 0: none, 1: one level etc.)\n"
"\n"
"This method has been introduced in version 0.20.\n"
"This method has been introduced in version 0.20. The 'levels' argument was made optional in version 0.30.9.\n"
) +
gsi::method_ext ("prune_cell", &prune_cell_ptr, gsi::arg ("cell"), gsi::arg ("levels", -1),
"@brief Deletes a cell plus subcells not used otherwise\n"
"\n"
"This deletes a cell and also all sub cells of the cell which are not used otherwise.\n"
"The number of hierarchy levels to consider can be specified as well. One level of hierarchy means that "
"only the direct children of the cell are deleted with the cell itself.\n"
"All instances of this cell are deleted as well.\n"
"\n"
"A version that allows pruning multiple cells in one call is \\prune_cells.\n"
"\n"
"@param cell The cell to delete\n"
"@param levels The number of hierarchy levels to consider (-1: all, 0: none, 1: one level etc.)\n"
"\n"
"This convenience variant taking a cell object has been introduced in version 0.30.9.\n"
) +
gsi::method_ext ("prune_cells", &prune_cells, gsi::arg ("cell_indexes"), gsi::arg ("levels", -1),
"@brief Deletes cells plus subcells not used otherwise\n"
"\n"
"This deletes the given cells and also all sub cells of the cells which are not used otherwise.\n"
"The number of hierarchy levels to consider can be specified as well. One level of hierarchy means that "
"only the direct children of the cell are deleted with the cell itself.\n"
"All instances of the pruned cells are deleted as well.\n"
"\n"
"@param cell_indexes The indexes of the cells to delete\n"
"@param levels The number of hierarchy levels to consider (-1: all, 0: none, 1: one level etc.)\n"
"\n"
"This method has been introduced in version 0.30.9.\n"
) +
gsi::method_ext ("prune_cells", &prune_cells_ptr, gsi::arg ("cells"), gsi::arg ("levels", -1),
"@brief Deletes cells plus subcells not used otherwise\n"
"\n"
"This deletes the given cells and also all sub cells of the cells which are not used otherwise.\n"
"The number of hierarchy levels to consider can be specified as well. One level of hierarchy means that "
"only the direct children of the cell are deleted with the cell itself.\n"
"All instances of the pruned cells are deleted as well.\n"
"\n"
"@param cells The cells to delete\n"
"@param levels The number of hierarchy levels to consider (-1: all, 0: none, 1: one level etc.)\n"
"\n"
"This method has been introduced in version 0.30.9.\n"
) +
gsi::method_ext ("delete_cell_rec", &delete_cell_rec, gsi::arg ("cell_index"),
"@brief Deletes a cell plus all subcells\n"
@ -1702,6 +1902,16 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"\n"
"This method has been introduced in version 0.20.\n"
) +
gsi::method_ext ("delete_cell_rec", &delete_cell_rec_ptr, gsi::arg ("cell"),
"@brief Deletes a cell plus all subcells\n"
"\n"
"This deletes a cell and also all sub cells of the cell.\n"
"In contrast to \\prune_cell, all cells are deleted together with their instances even if they are used otherwise.\n"
"\n"
"@param cell The cell to delete\n"
"\n"
"This convenience variant taking a cell object has been introduced in version 0.30.9.\n"
) +
gsi::method_ext ("insert", &insert_region,
gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"),
"@brief Inserts a region into the given cell and layer\n"
@ -1750,7 +1960,7 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method_ext ("flatten", &flatten, gsi::arg ("cell_index"), gsi::arg ("levels"), gsi::arg ("prune"),
gsi::method_ext ("flatten", &flatten, gsi::arg ("cell_index"), gsi::arg ("levels", -1), gsi::arg ("prune", true),
"@brief Flattens the given cell\n"
"\n"
"This method propagates all shapes and instances from the specified number of hierarchy levels below into the given cell.\n"
@ -1761,9 +1971,22 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"@param levels The number of hierarchy levels to flatten (-1: all, 0: none, 1: one level etc.)\n"
"@param prune Set to true to remove orphan cells.\n"
"\n"
"This method has been introduced in version 0.20.\n"
"This method has been introduced in version 0.20. The 'levels' and 'prune' arguments have been made optional in version 0.30.9.\n"
) +
gsi::method_ext ("flatten_into", &flatten_into, gsi::arg ("source_cell_index"), gsi::arg ("target_cell_index"), gsi::arg ("trans"), gsi::arg ("levels"),
gsi::method_ext ("flatten", &flatten_ptr, gsi::arg ("cell"), gsi::arg ("levels", -1), gsi::arg ("prune", true),
"@brief Flattens the given cell\n"
"\n"
"This method propagates all shapes and instances from the specified number of hierarchy levels below into the given cell.\n"
"It also removes the instances of the cells from which the shapes came from, but does not remove the cells themselves if prune is set to false.\n"
"If prune is set to true, these cells are removed if not used otherwise.\n"
"\n"
"@param cell The cell which should be flattened\n"
"@param levels The number of hierarchy levels to flatten (-1: all, 0: none, 1: one level etc.)\n"
"@param prune Set to true to remove orphan cells.\n"
"\n"
"This convenience variant taking a cell object has been introduced in version 0.30.9.\n"
) +
gsi::method_ext ("flatten_into", &flatten_into, gsi::arg ("source_cell_index"), gsi::arg ("target_cell_index"), gsi::arg ("trans", db::ICplxTrans (), "unity"), gsi::arg ("levels", -1),
"@brief Flattens the given cell into another cell\n"
"\n"
"This method works like 'flatten', but allows specification of a target cell which can be different from the source cell plus "
@ -1776,7 +1999,22 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"@param trans The transformation to apply on the output shapes and instances\n"
"@param levels The number of hierarchy levels to flatten (-1: all, 0: none, 1: one level etc.)\n"
"\n"
"This method has been introduced in version 0.24.\n"
"This method has been introduced in version 0.24. The 'trans' and 'levels' arguments have been made optional is version 0.30.9.\n"
) +
gsi::method_ext ("flatten_into", &flatten_into_ptr, gsi::arg ("source_cell"), gsi::arg ("target_cell"), gsi::arg ("trans", db::ICplxTrans (), "unity"), gsi::arg ("levels", -1),
"@brief Flattens the given cell into another cell\n"
"\n"
"This method works like 'flatten', but allows specification of a target cell which can be different from the source cell plus "
"a transformation which is applied for all shapes and instances in the target cell.\n"
"\n"
"In contrast to the 'flatten' method, the source cell is not modified.\n"
"\n"
"@param source_cell The source cell which should be flattened\n"
"@param target_cell The target cell into which the resulting objects are written\n"
"@param trans The transformation to apply on the output shapes and instances\n"
"@param levels The number of hierarchy levels to flatten (-1: all, 0: none, 1: one level etc.)\n"
"\n"
"This convenience variant taking a cell objects has been introduced in version 0.30.9.\n"
) +
gsi::method ("start_changes", &db::Layout::start_changes,
"@brief Signals the start of an operation bringing the layout into invalid state\n"

View File

@ -335,34 +335,21 @@ class DBLayoutTests1_TestClass < TestBase
c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0))))
assert_equal(c0.is_empty?, false)
c0_index = c0.cell_index
assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)");
c0_index = c0.cell_index
ll = l.dup
assert_equal(l.is_valid_cell_index?(c0_index), true)
l.delete_cell(c0.cell_index)
l.delete_cell(c0_index)
assert_equal(l.is_valid_cell_index?(c0_index), false)
assert_equal(collect_hier(l), "[c1](P=)(C=)/[c2](P=)(C=c3)/[c3](P=c2)(C=)");
assert_equal(c3.is_empty?, true)
l = RBA::Layout.new
l.insert_layer_at(0, RBA::LayerInfo.new(1, 0))
c0 = l.cell(l.add_cell("c0"))
c1 = l.cell(l.add_cell("c1"))
c2 = l.cell(l.add_cell("c2"))
c3 = l.cell(l.add_cell("c3"))
assert_equal(c0.is_empty?, true)
l = ll
ll = l.dup
tt = RBA::Trans.new
c0.insert(RBA::CellInstArray.new(c1.cell_index, tt))
c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100))))
c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1)))
c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0))))
assert_equal(c0.is_empty?, false)
assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)");
c0_index = c0.cell_index
assert_equal(l.is_valid_cell_index?(c0_index), true)
l.cell(c0_index).delete
assert_equal(l.is_valid_cell_index?(c0_index), false)
@ -370,6 +357,16 @@ class DBLayoutTests1_TestClass < TestBase
assert_equal(collect_hier(l), "[c1](P=)(C=)/[c2](P=)(C=c3)/[c3](P=c2)(C=)");
assert_equal(c3.is_empty?, true)
l = ll
ll = l.dup
assert_equal(l.is_valid_cell_index?(c0_index), true)
# with cell object
l.delete_cell(l.cell(c0_index))
assert_equal(l.is_valid_cell_index?(c0_index), false)
assert_equal(collect_hier(l), "[c1](P=)(C=)/[c2](P=)(C=c3)/[c3](P=c2)(C=)");
assert_equal(c3.is_empty?, true)
end
def test_5b
@ -413,10 +410,17 @@ class DBLayoutTests1_TestClass < TestBase
assert_equal(collect_hier(l), "[c1](P=)(C=)/[c3](P=)(C=)");
l = ll
ll = l.dup
# Hint: even though we deleted c0 and c2, their indices are still valid
l.delete_cells([c2_index, c0_index])
assert_equal(collect_hier(l), "[c1](P=)(C=)/[c3](P=)(C=)");
l = ll
ll = l.dup
# with cell objects
l.delete_cells([l.cell(c2_index), l.cell(c0_index)])
assert_equal(collect_hier(l), "[c1](P=)(C=)/[c3](P=)(C=)");
end
def test_5d
@ -487,6 +491,7 @@ class DBLayoutTests1_TestClass < TestBase
c0_index = c0.cell_index
c2_index = c2.cell_index
c3_index = c3.cell_index
ll = l.dup
@ -499,6 +504,42 @@ class DBLayoutTests1_TestClass < TestBase
l.cell(c2_index).prune_cell(-1)
assert_equal(collect_hier(l), "[c0](P=)(C=c1,c3)/[c1](P=c0)(C=)/[c3](P=c0)(C=)");
l = ll
ll = l.dup
# As method of Layout
l.prune_cell(c2_index, -1)
assert_equal(collect_hier(l), "[c0](P=)(C=c1,c3)/[c1](P=c0)(C=)/[c3](P=c0)(C=)");
l = ll
ll = l.dup
# As method of Layout with default argument
l.prune_cell(c2_index)
assert_equal(collect_hier(l), "[c0](P=)(C=c1,c3)/[c1](P=c0)(C=)/[c3](P=c0)(C=)");
l = ll
ll = l.dup
# As method of Layout with cell object
l.prune_cell(l.cell(c2_index), -1)
assert_equal(collect_hier(l), "[c0](P=)(C=c1,c3)/[c1](P=c0)(C=)/[c3](P=c0)(C=)");
l = ll
ll = l.dup
# As method of Layout with cell object and default argument
l.prune_cell(l.cell(c2_index), -1)
assert_equal(collect_hier(l), "[c0](P=)(C=c1,c3)/[c1](P=c0)(C=)/[c3](P=c0)(C=)");
l = ll
ll = l.dup
# prune c2 and c3
l.prune_cells([ c2_index, c3_index ], -1)
assert_equal(collect_hier(l), "[c0](P=)(C=c1)/[c1](P=c0)(C=)");
l = ll
ll = l.dup
# prune c2 and c3 with cell objects
l.prune_cells([ l.cell(c2_index), l.cell(c3_index) ], -1)
assert_equal(collect_hier(l), "[c0](P=)(C=c1)/[c1](P=c0)(C=)");
end
def test_5e
@ -546,6 +587,12 @@ class DBLayoutTests1_TestClass < TestBase
l.delete_cell_rec(c2_index)
assert_equal(collect_hier(l), "[c0](P=)(C=c1)/[c1](P=c0)(C=)");
l = ll
ll = l.dup
# with cell object
l.delete_cell_rec(l.cell(c2_index))
assert_equal(collect_hier(l), "[c0](P=)(C=c1)/[c1](P=c0)(C=)");
end
def test_5f
@ -589,12 +636,38 @@ class DBLayoutTests1_TestClass < TestBase
l = ll
ll = l.dup
l.flatten(c0_index, -1, true)
l.flatten(c0_index)
assert_equal(collect_hier(l), "[c0](P=)(C=)");
ii = l.begin_shapes(c0_index, 0);
assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](1200,0;2200,1100)/[c0](-1200,0;-100,1000)");
l = ll
ll = l.dup
c0flat = l.create_cell("c0flat")
l.flatten_into(c0_index, c0flat.cell_index)
assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)/[c0flat](P=)(C=)");
ii = l.begin_shapes(c0flat, 0);
assert_equal(collect(ii, l), "[c0flat](0,100;1000,1200)/[c0flat](0,100;1000,1200)/[c0flat](100,0;1100,1100)/[c0flat](1200,0;2200,1100)/[c0flat](-1200,0;-100,1000)");
l = ll
ll = l.dup
l.flatten(l.cell(c0_index), -1, true) # with cell object
assert_equal(collect_hier(l), "[c0](P=)(C=)");
ii = l.begin_shapes(c0_index, 0);
assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](1200,0;2200,1100)/[c0](-1200,0;-100,1000)");
l = ll
ll = l.dup
c0flat = l.create_cell("c0flat")
l.flatten_into(l.cell(c0_index), c0flat, RBA::ICplxTrans::new(2.0), -1)
assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)/[c0flat](P=)(C=)");
ii = l.begin_shapes(c0flat, 0);
assert_equal(collect(ii, l), "[c0flat](0,200;2000,2400)/[c0flat](0,200;2000,2400)/[c0flat](200,0;2200,2200)/[c0flat](2400,0;4400,2200)/[c0flat](-2400,0;-200,2000)");
l = ll
ll = l.dup
l.flatten(c0_index, 0, false)
@ -748,10 +821,59 @@ class DBLayoutTests1_TestClass < TestBase
assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=)/[c3](P=c0)(C=)");
l = ll
ll = l.dup
# Hint: even though we deleted c0 and c2, their indices are still valid
l.cell(c0_index).prune_subcells(1)
assert_equal(collect_hier(l), "[c0](P=)(C=)");
l = ll
ll = l.dup
# As method of Layout
l.prune_subcells(c0_index, -1)
assert_equal(collect_hier(l), "[c0](P=)(C=)");
l = ll
ll = l.dup
# As method of Layout with default argument
l.prune_subcells(c0_index)
assert_equal(collect_hier(l), "[c0](P=)(C=)");
l = ll
ll = l.dup
# As method of Layout with Cell object
l.prune_subcells(l.cell(c0_index), -1)
assert_equal(collect_hier(l), "[c0](P=)(C=)");
l = ll
ll = l.dup
# As method of Layout with Cell object and default argument
l.prune_subcells(l.cell(c0_index))
assert_equal(collect_hier(l), "[c0](P=)(C=)");
l = ll
ll = l.dup
# As method of Layout with multiple cells
l.prune_subcells([ c0_index ], -1)
assert_equal(collect_hier(l), "[c0](P=)(C=)");
l = ll
ll = l.dup
# As method of Layout with multiple cells and default argument
l.prune_subcells([ c0_index ])
assert_equal(collect_hier(l), "[c0](P=)(C=)");
l = ll
ll = l.dup
# As method of Layout with multiple cells and Cell object
l.prune_subcells([ l.cell(c0_index) ], -1)
assert_equal(collect_hier(l), "[c0](P=)(C=)");
l = ll
ll = l.dup
# As method of Layout with multiple cells and Cell object and default argument
l.prune_subcells([ l.cell(c0_index) ])
assert_equal(collect_hier(l), "[c0](P=)(C=)");
end
def test_6
@ -2365,7 +2487,7 @@ class DBLayoutTests1_TestClass < TestBase
end
# Properties IDs
def test_issue1549
def test_propertyIDs
ly = RBA::Layout::new

View File

@ -277,7 +277,7 @@ end
class DBPCellAPI_TestClass < TestBase
def _test_1
def test_1
# PCellParameterDeclaration
@ -351,7 +351,7 @@ end
class DBPCell_TestClass < TestBase
def _test_1
def test_1
# instantiate and register the library
tl = PCellTestLib::new
@ -593,7 +593,7 @@ class DBPCell_TestClass < TestBase
end
def _test_2
def test_2
# instantiate and register the library
tl = PCellTestLib::new
@ -632,7 +632,7 @@ class DBPCell_TestClass < TestBase
end
def _test_3
def test_3
# instantiate and register the library
tl = PCellTestLib::new
@ -657,7 +657,7 @@ class DBPCell_TestClass < TestBase
end
def _test_4
def test_4
# instantiate and register the library
tl = PCellTestLib::new
@ -674,7 +674,7 @@ class DBPCell_TestClass < TestBase
end
def _test_5
def test_5
# instantiate and register the library
tl = PCellTestLib::new
@ -691,7 +691,7 @@ class DBPCell_TestClass < TestBase
end
def _test_6
def test_6
# instantiate and register the library
tl = PCellTestLib::new
@ -707,7 +707,7 @@ class DBPCell_TestClass < TestBase
end
def _test_7
def test_7
# instantiate and register the library
tl = PCellTestLib::new
@ -725,7 +725,7 @@ class DBPCell_TestClass < TestBase
end
def _test_8
def test_8
# instantiate and register the library
tl = PCellTestLib::new
@ -747,7 +747,7 @@ class DBPCell_TestClass < TestBase
end
def _test_9
def test_9
layout = RBA::Layout::new
@ -813,7 +813,7 @@ class DBPCell_TestClass < TestBase
end
def _test_10
def test_10
lib = CircleLib1782::new("CircleLib")
@ -864,7 +864,7 @@ class DBPCell_TestClass < TestBase
end
def _test_11
def test_11
lib = CircleLib1782::new("CircleLib")
@ -899,7 +899,7 @@ class DBPCell_TestClass < TestBase
end
def _test_12
def test_12
if !RBA.constants.member?(:PCellDeclarationHelper)
return
@ -924,7 +924,7 @@ class DBPCell_TestClass < TestBase
end
# convert to static cell
def _test_13
def test_13
if !RBA.constants.member?(:PCellDeclarationHelper)
return
@ -954,11 +954,69 @@ class DBPCell_TestClass < TestBase
end
# cold proxies
def test_14
# instantiate and register the library
tl = PCellTestLib::new
ly = RBA::Layout::new(true)
ly.dbu = 0.01
li1 = ly.layer(1, 0)
scell = ly.create_cell("A")
param = { "w" => 4.0, "h" => 8.0, "l" => RBA::LayerInfo::new(1, 0) }
cell = ly.create_cell("Box", "PCellTestLib", param)
cell.name = "B"
assert_equal(scell.is_proxy?, false)
assert_equal(scell.is_library_cell?, false)
assert_equal(scell.is_cold_proxy?, false)
assert_equal(scell.pcell_parameter("h").to_s, "")
assert_equal(scell.pcell_parameter("x").to_s, "")
assert_equal(scell.pcell_parameters_by_name.to_s, "{}")
assert_equal(scell.pcell_name, "")
assert_equal(scell.library_name, "")
assert_equal(scell.library_cell_name, "")
assert_equal(cell.is_proxy?, true)
assert_equal(cell.is_library_cell?, true)
assert_equal(cell.is_cold_proxy?, false)
assert_equal(cell.pcell_parameter("h").to_s, "8.0")
assert_equal(cell.pcell_parameter("x").to_s, "")
assert_equal(cell.pcell_parameters_by_name.to_s, "{\"h\"=>8.0, \"l\"=><1/0>, \"w\"=>4.0}")
assert_equal(cell.pcell_name, "Box")
assert_equal(cell.library_cell_name, "Box_L1d0_W4p000_H8p000") # it's the library's PCell proxy
assert_equal(cell.library_name, "PCellTestLib")
assert_equal(cell.display_title, "PCellTestLib.Box(L=1/0,W=4.000,H=8.000)")
tl._destroy
# the cell got destroyed and replaced by a cold proxy
assert_equal(cell._destroyed?, true)
cell = ly.cell("B")
assert_equal(cell.is_proxy?, true)
assert_equal(cell.is_library_cell?, false)
assert_equal(cell.is_cold_proxy?, true)
assert_equal(cell.pcell_parameter("h").to_s, "8.0")
assert_equal(cell.pcell_parameter("x").to_s, "")
assert_equal(cell.pcell_parameters_by_name.to_s, "{\"h\"=>8.0, \"l\"=><1/0>, \"w\"=>4.0}")
assert_equal(cell.pcell_name, "Box")
assert_equal(cell.library_cell_name, "") # it's not a static library cell
assert_equal(cell.library_name, "PCellTestLib")
assert_equal(cell.display_title, "<defunct>PCellTestLib.Box")
end
end
class DBPCellParameterStates_TestClass < TestBase
def _test_1
def test_1
ps = RBA::PCellParameterState::new