From 4eb1b3f4b916954983f76dd1a5394aad6eae95a5 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 5 Feb 2024 20:58:01 +0100 Subject: [PATCH] Fixed issue #1609 (Cell.read doesn't read LayoutMetaInfo) This also includes some more functions: - Layout#merge_meta_info, Layout#copy_meta_info - Layout#clear_all_meta_info - Cell#merge_meta_info, Cell#copy_meta_info In addition, meta info is merged when importing a layout from another file (Layout/Import -> Other Layouts into current). --- src/db/db/dbLayout.cc | 41 ++++++++++++ src/db/db/dbLayout.h | 49 ++++++++++++++ src/db/db/dbLayoutUtils.cc | 3 + src/db/db/gsiDeclDbCell.cc | 32 +++++++++ src/db/db/gsiDeclDbLayout.cc | 42 ++++++++++++ testdata/ruby/dbLayoutTests2.rb | 115 ++++++++++++++++++++++++++++++++ 6 files changed, 282 insertions(+) diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index 8ab1e87172..49c2e89eca 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -1904,6 +1904,13 @@ Layout::clear_meta (db::cell_index_type ci) m_meta_info_by_cell.erase (ci); } +void +Layout::clear_all_meta () +{ + m_meta_info.clear (); + m_meta_info_by_cell.clear (); +} + void Layout::add_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id, const MetaInfo &i) { @@ -1945,6 +1952,40 @@ Layout::has_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id) c } } +void +Layout::merge_meta_info (const db::Layout &other) +{ + for (auto mi = other.begin_meta (); mi != other.end_meta (); ++mi) { + add_meta_info (other.meta_info_name (mi->first), mi->second); + } +} + +void +Layout::merge_meta_info (db::cell_index_type into_cell, const db::Layout &other, db::cell_index_type other_cell) +{ + auto mi_begin = other.begin_meta (other_cell); + auto mi_end = other.end_meta (other_cell); + for (auto mi = mi_begin; mi != mi_end; ++mi) { + add_meta_info (into_cell, other.meta_info_name (mi->first), mi->second); + } +} + +void +Layout::merge_meta_info (const db::Layout &other, const db::CellMapping &cm) +{ + for (auto i = cm.begin (); i != cm.end (); ++i) { + merge_meta_info (i->second, other, i->first); + } +} + +void +Layout::copy_meta_info (const db::Layout &other, const db::CellMapping &cm) +{ + for (auto i = cm.begin (); i != cm.end (); ++i) { + copy_meta_info (i->second, other, i->first); + } +} + void Layout::swap_layers (unsigned int a, unsigned int b) { diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index 7d2598da6d..59a4ad19f4 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -1993,6 +1993,11 @@ class DB_PUBLIC Layout */ void clear_meta (db::cell_index_type ci); + /** + * @brief Clears all meta information (cells and layout) + */ + void clear_all_meta (); + /** * @brief Adds meta information for a given cell * The given meta information object is to the meta information list for the given cell. @@ -2021,6 +2026,50 @@ class DB_PUBLIC Layout } } + /** + * @brief Merges meta information from the other layout into self + * This applies to the layout-only meta information. Same keys get overwritten, new ones are added. + */ + void merge_meta_info (const db::Layout &other); + + /** + * @brief Copies meta information from the other layout into self + * This applies to the layout-only meta information. All keys are replaced. + */ + void copy_meta_info (const db::Layout &other) + { + clear_meta (); + merge_meta_info (other); + } + + /** + * @brief Merges meta information from the other cell into the target cell from sel. + * This applies to the cell-specific meta information. Same keys get overwritten, new ones are added. + */ + void merge_meta_info (db::cell_index_type into_cell, const db::Layout &other, db::cell_index_type other_cell); + + /** + * @brief Copies meta information from the other cell into the target cell from sel. + * This applies to the cell-specific meta information. All keys are replaced. + */ + void copy_meta_info (db::cell_index_type into_cell, const db::Layout &other, db::cell_index_type other_cell) + { + clear_meta (into_cell); + merge_meta_info (into_cell, other, other_cell); + } + + /** + * @brief Merges meta information from the other cell into the target cell from sel using the given cell mapping. + * The cell mapping specifies which meta information to merge from which cell into which cell. + */ + void merge_meta_info (const db::Layout &other, const db::CellMapping &cm); + + /** + * @brief Copies meta information from the other cell into the target cell from sel using the given cell mapping. + * The cell mapping specifies which meta information to copy from which cell into which cell. + */ + void copy_meta_info (const db::Layout &other, const db::CellMapping &cm); + /** * @brief Gets a value indicating whether a meta info with the given name is present for the given cell */ diff --git a/src/db/db/dbLayoutUtils.cc b/src/db/db/dbLayoutUtils.cc index 1c4a7e0d10..2fe5174fbb 100644 --- a/src/db/db/dbLayoutUtils.cc +++ b/src/db/db/dbLayoutUtils.cc @@ -252,6 +252,9 @@ merge_layouts (db::Layout &target, const db::Cell &source_cell = source.cell (*c); db::Cell &target_cell = target.cell (target_cell_index); + // merge meta info + target.merge_meta_info (target_cell_index, source, *c); + // NOTE: this implementation employs the safe but cumbersome "local transformation" feature. // This means, all cells are transformed according to the given transformation and their // references are transformed to account for that effect. This will lead to somewhat strange diff --git a/src/db/db/gsiDeclDbCell.cc b/src/db/db/gsiDeclDbCell.cc index 4a65a4a91a..fc32fa381d 100644 --- a/src/db/db/gsiDeclDbCell.cc +++ b/src/db/db/gsiDeclDbCell.cc @@ -1004,6 +1004,22 @@ static void cell_add_meta_info (db::Cell *cell, const MetaInfo &mi) } } +static void cell_merge_meta_info (db::Cell *cell, const db::Cell *source) +{ + if (! source || ! cell->layout () || ! source->layout ()) { + return; + } + cell->layout ()->merge_meta_info (cell->cell_index (), *source->layout (), source->cell_index ()); +} + +static void cell_copy_meta_info (db::Cell *cell, const db::Cell *source) +{ + if (! source || ! cell->layout () || ! source->layout ()) { + return; + } + cell->layout ()->copy_meta_info (cell->cell_index (), *source->layout (), source->cell_index ()); +} + static const tl::Variant &cell_meta_info_value (db::Cell *cell, const std::string &name) { if (! cell->layout ()) { @@ -1755,6 +1771,7 @@ read_options (db::Cell *cell, const std::string &path, const db::LoadLayoutOptio db::CellMapping cm; std::vector new_cells = cm.create_single_mapping_full (*cell->layout (), cell->cell_index (), tmp, *tmp.begin_top_down ()); cell->move_tree_shapes (tmp.cell (*tmp.begin_top_down ()), cm); + cell->layout ()->merge_meta_info (tmp, cm); return new_cells; } @@ -1834,6 +1851,21 @@ Class decl_Cell ("db", "Cell", "\n" "This method has been introduced in version 0.28.8." ) + + gsi::method_ext ("merge_meta_info", &cell_merge_meta_info, gsi::arg ("other"), + "@brief Merges the meta information from the other cell into this cell\n" + "See \\LayoutMetaInfo for details about cells and meta information.\n" + "Existing keys in this cell will be overwritten by the respective values from the other cell.\n" + "New keys will be added.\n" + "\n" + "This method has been introduced in version 0.28.16." + ) + + gsi::method_ext ("copy_meta_info", &cell_copy_meta_info, gsi::arg ("other"), + "@brief Copies the meta information from the other cell into this cell\n" + "See \\LayoutMetaInfo for details about cells and meta information.\n" + "The meta information from this cell will be replaced by the meta information from the other cell.\n" + "\n" + "This method has been introduced in version 0.28.16." + ) + gsi::method_ext ("clear_meta_info", &cell_clear_meta_info, "@brief Clears the meta information of the cell\n" "See \\LayoutMetaInfo for details about cells and meta information.\n" diff --git a/src/db/db/gsiDeclDbLayout.cc b/src/db/db/gsiDeclDbLayout.cc index d85fe36873..db8c78233d 100644 --- a/src/db/db/gsiDeclDbLayout.cc +++ b/src/db/db/gsiDeclDbLayout.cc @@ -1105,12 +1105,54 @@ Class decl_Layout ("db", "Layout", "\n" "This method has been introduced in version 0.25." ) + + gsi::method ("merge_meta_info", static_cast (&db::Layout::merge_meta_info), gsi::arg ("other"), + "@brief Merges the meta information from the other layout into this layout\n" + "See \\LayoutMetaInfo for details about cells and meta information.\n" + "Existing keys in this layout will be overwritten by the respective values from the other layout.\n" + "New keys will be added.\n" + "\n" + "This method has been introduced in version 0.28.16." + ) + + gsi::method ("merge_meta_info", static_cast (&db::Layout::merge_meta_info), gsi::arg ("other"), gsi::arg ("cm"), + "@brief Merges the meta information from the other layout into this layout for the cells given by the cell mapping\n" + "See \\LayoutMetaInfo for details about cells and meta information.\n" + "This method will use the source/target cell pairs from the cell mapping object and merge the meta information " + "from each source cell from the 'other' layout into the mapped cell inside self.\n" + "This method can be used with '\\copy_tree_shapes' and similar to copy meta information in addition to the shapes.\n" + "Existing cell-specific keys in this layout will be overwritten by the respective values from the other layout.\n" + "New keys will be added.\n" + "\n" + "This method has been introduced in version 0.28.16." + ) + + gsi::method ("copy_meta_info", static_cast (&db::Layout::copy_meta_info), gsi::arg ("other"), + "@brief Copies the meta information from the other layout into this layout\n" + "See \\LayoutMetaInfo for details about cells and meta information.\n" + "The meta information from this layout will be replaced by the meta information from the other layout.\n" + "\n" + "This method has been introduced in version 0.28.16." + ) + + gsi::method ("copy_meta_info", static_cast (&db::Layout::copy_meta_info), gsi::arg ("other"), gsi::arg ("cm"), + "@brief Copies the meta information from the other layout into this layout for the cells given by the cell mapping\n" + "See \\LayoutMetaInfo for details about cells and meta information.\n" + "This method will use the source/target cell pairs from the cell mapping object and merge the meta information " + "from each source cell from the 'other' layout into the mapped cell inside self.\n" + "This method can be used with '\\copy_tree_shapes' and similar to copy meta information in addition to the shapes.\n" + "All cell-specific keys in this layout will be replaced by the respective values from the other layout.\n" + "\n" + "This method has been introduced in version 0.28.16." + ) + gsi::method ("clear_meta_info", static_cast (&db::Layout::clear_meta), "@brief Clears the meta information of the layout\n" "See \\LayoutMetaInfo for details about layouts and meta information." "\n" "This method has been introduced in version 0.28.8." ) + + gsi::method ("clear_all_meta_info", static_cast (&db::Layout::clear_all_meta), + "@brief Clears all meta information of the layout (cell specific and global)\n" + "See \\LayoutMetaInfo for details about layouts and meta information." + "\n" + "This method has been introduced in version 0.28.16." + ) + gsi::method ("remove_meta_info", static_cast (&db::Layout::remove_meta_info), gsi::arg ("name"), "@brief Removes meta information from the layout\n" "See \\LayoutMetaInfo for details about layouts and meta information." diff --git a/testdata/ruby/dbLayoutTests2.rb b/testdata/ruby/dbLayoutTests2.rb index b5dbb9a50a..99eca6adbc 100644 --- a/testdata/ruby/dbLayoutTests2.rb +++ b/testdata/ruby/dbLayoutTests2.rb @@ -23,6 +23,10 @@ load("test_prologue.rb") +def mi2s(obj) + obj.each_meta_info.collect { |mi| mi.name + ":" + mi.value.to_s }.sort.join(";") +end + class DBLayoutTests2_TestClass < TestBase # LayerInfo @@ -1253,6 +1257,117 @@ def test_15 end + # Cell#read and meta info (issue #1609) + def test_16 + + tmp = File::join($ut_testtmp, "test16.gds") + + ly1 = RBA::Layout::new + a = ly1.create_cell("A") + b = ly1.create_cell("B") + a.insert(RBA::DCellInstArray::new(b, RBA::Trans::new)) + + a.add_meta_info(RBA::LayoutMetaInfo::new("am1", 42.0, "", true)) + a.add_meta_info(RBA::LayoutMetaInfo::new("am2", "u", "", true)) + assert_equal(mi2s(a), "am1:42.0;am2:u") + + b.add_meta_info(RBA::LayoutMetaInfo::new("bm1", 17, "", true)) + assert_equal(mi2s(b), "bm1:17") + + ly1.add_meta_info(RBA::LayoutMetaInfo::new("lm1", -2.0, "", true)) + ly1.add_meta_info(RBA::LayoutMetaInfo::new("lm2", "v", "", true)) + assert_equal(mi2s(ly1), "lm1:-2.0;lm2:v") + + ly1.write(tmp) + + ly2 = RBA::Layout::new + top = ly2.create_cell("TOP") + a = ly2.create_cell("A") + c = ly2.create_cell("C") + top.insert(RBA::DCellInstArray::new(a, RBA::Trans::new)) + a.insert(RBA::DCellInstArray::new(c, RBA::Trans::new)) + + top.add_meta_info(RBA::LayoutMetaInfo::new("topm1", "abc")) + assert_equal(mi2s(top), "topm1:abc") + a.add_meta_info(RBA::LayoutMetaInfo::new("am1", "a number")) + a.add_meta_info(RBA::LayoutMetaInfo::new("am3", 0)) + assert_equal(mi2s(a), "am1:a number;am3:0") + c.add_meta_info(RBA::LayoutMetaInfo::new("cm1", 3)) + assert_equal(mi2s(c), "cm1:3") + + ly2.add_meta_info(RBA::LayoutMetaInfo::new("lm1", 5)) + assert_equal(mi2s(ly2), "lm1:5") + + a.read(tmp) + # not modified + assert_equal(mi2s(ly2), "lm1:5") + # merged + assert_equal(mi2s(a), "am1:42.0;am2:u;am3:0") + # not modified + assert_equal(mi2s(c), "cm1:3") + + b2 = ly2.cell("B") + # imported + assert_equal(mi2s(b2), "bm1:17") + + puts "done." + + end + + # Layout, meta info diverse + def test_17 + + ly = RBA::Layout::new + a = ly.create_cell("A") + ly.add_meta_info(RBA::LayoutMetaInfo::new("lm1", 17)) + a.add_meta_info(RBA::LayoutMetaInfo::new("am1", "u")) + assert_equal(mi2s(ly), "lm1:17") + assert_equal(mi2s(a), "am1:u") + + ly.clear_all_meta_info + assert_equal(mi2s(ly), "") + assert_equal(mi2s(a), "") + + ly2 = RBA::Layout::new + ly.add_meta_info(RBA::LayoutMetaInfo::new("lm1", 17)) + ly2.add_meta_info(RBA::LayoutMetaInfo::new("lm2", 42)) + assert_equal(mi2s(ly), "lm1:17") + ly.merge_meta_info(ly2) + assert_equal(mi2s(ly), "lm1:17;lm2:42") + ly.copy_meta_info(ly2) + assert_equal(mi2s(ly), "lm2:42") + + a = ly.create_cell("A") + a.add_meta_info(RBA::LayoutMetaInfo::new("am1", "u")) + b = ly2.create_cell("B") + b.add_meta_info(RBA::LayoutMetaInfo::new("bm1", "v")) + + assert_equal(mi2s(a), "am1:u") + a.merge_meta_info(b) + assert_equal(mi2s(a), "am1:u;bm1:v") + a.copy_meta_info(b) + assert_equal(mi2s(a), "bm1:v") + + ly = RBA::Layout::new + ly2 = RBA::Layout::new + + a = ly.create_cell("A") + a.add_meta_info(RBA::LayoutMetaInfo::new("am1", "u")) + ly2.create_cell("X") + b = ly2.create_cell("B") + b.add_meta_info(RBA::LayoutMetaInfo::new("bm1", "v")) + + cm = RBA::CellMapping::new + cm.map(b.cell_index, a.cell_index) + + assert_equal(mi2s(a), "am1:u") + ly.merge_meta_info(ly2, cm) + assert_equal(mi2s(a), "am1:u;bm1:v") + ly.copy_meta_info(ly2, cm) + assert_equal(mi2s(a), "bm1:v") + + end + end load("test_epilogue.rb")