From a425d522ccb2574da98ef8d0fda5834e58703264 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 29 Aug 2020 10:07:17 +0200 Subject: [PATCH] Added multi-cell mapping for transferring multiple cells from one layout to another while including their hierarchy without duplicating cells. --- src/db/db/dbCellMapping.cc | 30 +++++++++--- src/db/db/dbCellMapping.h | 65 ++++++++++++++++++++++--- src/db/db/dbDeepShapeStore.cc | 2 +- src/db/db/gsiDeclDbCellMapping.cc | 54 +++++++++++++++++++- src/db/unit_tests/dbCellMappingTests.cc | 37 ++++++++++++++ testdata/ruby/dbCellMapping.rb | 35 +++++++++++++ 6 files changed, 205 insertions(+), 18 deletions(-) diff --git a/src/db/db/dbCellMapping.cc b/src/db/db/dbCellMapping.cc index f441e893d..5c65eb914 100644 --- a/src/db/db/dbCellMapping.cc +++ b/src/db/db/dbCellMapping.cc @@ -276,7 +276,19 @@ CellMapping::create_single_mapping (const db::Layout & /*layout_a*/, db::cell_in map (cell_index_b, cell_index_a); } -void +void +CellMapping::create_multi_mapping (const db::Layout & /*layout_a*/, const std::vector &cell_index_a, const db::Layout & /*layout_b*/, const std::vector &cell_index_b) +{ + clear (); + if (cell_index_a.size () != cell_index_b.size ()) { + throw tl::Exception (tl::to_string (tr ("cell index arrays for A and B cells must have same length in 'create_multi_mapping'"))); + } + for (std::vector::const_iterator ia = cell_index_a.begin (), ib = cell_index_b.begin (); ia != cell_index_a.end (); ++ia, ++ib) { + map (*ib, *ia); + } +} + +void CellMapping::create_from_names (const db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b) { clear (); @@ -295,31 +307,33 @@ CellMapping::create_from_names (const db::Layout &layout_a, db::cell_index_type } std::vector -CellMapping::create_missing_mapping (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells, const std::set *include_cells) +CellMapping::create_missing_mapping (db::Layout &layout_a, const db::Layout &layout_b, const std::vector &cell_index_b, const std::set *exclude_cells, const std::set *include_cells) { std::vector new_cells; - do_create_missing_mapping (layout_a, cell_index_a, layout_b, cell_index_b, exclude_cells, include_cells, &new_cells, 0); + do_create_missing_mapping (layout_a, layout_b, cell_index_b, exclude_cells, include_cells, &new_cells, 0); return new_cells; } std::vector > -CellMapping::create_missing_mapping2 (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells, const std::set *include_cells) +CellMapping::create_missing_mapping2 (db::Layout &layout_a, const db::Layout &layout_b, const std::vector &cell_index_b, const std::set *exclude_cells, const std::set *include_cells) { std::vector > cell_pairs; - do_create_missing_mapping (layout_a, cell_index_a, layout_b, cell_index_b, exclude_cells, include_cells, 0, &cell_pairs); + do_create_missing_mapping (layout_a, layout_b, cell_index_b, exclude_cells, include_cells, 0, &cell_pairs); return cell_pairs; } void -CellMapping::do_create_missing_mapping (db::Layout &layout_a, db::cell_index_type /*cell_index_a*/, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells, const std::set *include_cells, std::vector *new_cells_ptr, std::vector > *mapped_pairs) +CellMapping::do_create_missing_mapping (db::Layout &layout_a, const db::Layout &layout_b, const std::vector &cell_index_b, const std::set *exclude_cells, const std::set *include_cells, std::vector *new_cells_ptr, std::vector > *mapped_pairs) { std::vector new_cells_int; std::vector &new_cells = *(new_cells_ptr ? new_cells_ptr : &new_cells_int); std::vector new_cells_b; std::set called_b; - layout_b.cell (cell_index_b).collect_called_cells (called_b); - called_b.insert (cell_index_b); + for (std::vector::const_iterator i = cell_index_b.begin (); i != cell_index_b.end (); ++i) { + layout_b.cell (*i).collect_called_cells (called_b); + called_b.insert (*i); + } for (std::set::const_iterator b = called_b.begin (); b != called_b.end (); ++b) { if (m_b2a_mapping.find (*b) == m_b2a_mapping.end () diff --git a/src/db/db/dbCellMapping.h b/src/db/db/dbCellMapping.h index ae776286e..8857ad5c8 100644 --- a/src/db/db/dbCellMapping.h +++ b/src/db/db/dbCellMapping.h @@ -81,7 +81,30 @@ public: std::vector create_single_mapping_full (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b) { create_single_mapping (layout_a, cell_index_a, layout_b, cell_index_b); - return create_missing_mapping (layout_a, cell_index_a, layout_b, cell_index_b); + return create_missing_mapping (layout_a, layout_b, cell_index_b); + } + + /** + * @brief Create a multi-cell mapping + * + * The mapping created by this function will map the cells of cell_indexes_b to cell_indexes_a. Both arrays need to have + * the same length. + * This cell mapping will not map the child cells. When used for hierarchical copy this will basically + * flatten the cells on copy. + */ + void create_multi_mapping (const db::Layout &layout_a, const std::vector &cell_indexes_a, const db::Layout &layout_b, const std::vector &cell_indexes_b); + + /** + * @brief Create a single cell full mapping + * + * The mapping created by this function will map the cells of cell_indexes_a to cell_indexes_b. Both arrays need to have + * the same length. In addition, new cells for the child cells of all cell_indexes_b cells are created in layout_a and + * included in the mapping. + */ + std::vector create_multi_mapping_full (db::Layout &layout_a, const std::vector &cell_indexes_a, const db::Layout &layout_b, const std::vector &cell_indexes_b) + { + create_multi_mapping (layout_a, cell_indexes_a, layout_b, cell_indexes_b); + return create_missing_mapping (layout_a, layout_b, cell_indexes_b); } /** @@ -100,7 +123,7 @@ public: std::vector create_from_geometry_full (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b) { create_from_geometry (layout_a, cell_index_a, layout_b, cell_index_b); - return create_missing_mapping (layout_a, cell_index_a, layout_b, cell_index_b); + return create_missing_mapping (layout_a, layout_b, cell_index_b); } /** @@ -119,7 +142,7 @@ public: std::vector create_from_names_full (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b) { create_from_names (layout_a, cell_index_a, layout_b, cell_index_b); - return create_missing_mapping (layout_a, cell_index_a, layout_b, cell_index_b); + return create_missing_mapping (layout_a, layout_b, cell_index_b); } /** @@ -184,8 +207,9 @@ public: /** * @brief Creates mappings for all cells not mapped yet * - * When constructing a cell mapping by explicit mapping (map (a, b)), some cells may be - * left unmapped. This method allows creating mappings for these missing cells by adding + * When constructing a cell mapping by explicit mapping (map (a, b)), some child cells of the + * mapped other cells may be left unmapped. + * This method allows creating mappings for these missing cells by adding * new cells and the corresponding instances into the target layout_a. * * If given, "exclude_cells" can specify a list of cells not to map. @@ -195,7 +219,18 @@ public: * * The returned vector lists the new cells. */ - std::vector create_missing_mapping (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells = 0, const std::set *include_cells = 0); + std::vector create_missing_mapping (db::Layout &layout_a, const db::Layout &layout_b, const std::vector &cell_index_b, const std::set *exclude_cells = 0, const std::set *include_cells = 0); + + /** + * @brief A convenience version of create_missing_mappings which takes a single cell for cell_index_a and cell_index_b. + */ + std::vector create_missing_mapping (db::Layout &layout_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells = 0, const std::set *include_cells = 0) + { + std::vector cib; + cib.reserve (1); + cib.push_back (cell_index_b); + return create_missing_mapping (layout_a, layout_b, cib, exclude_cells, include_cells); + } /** * @brief Like create_missing_mapping, but returns the newly mapped pairs @@ -203,7 +238,21 @@ public: * The first cell index of the pair is the old cell in layout_a, the second cell index * is the new cell in layout_b. */ - std::vector > create_missing_mapping2 (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells = 0, const std::set *include_cells = 0); + std::vector > create_missing_mapping2 (db::Layout &layout_a, const db::Layout &layout_b, const std::vector &cell_index_b, const std::set *exclude_cells = 0, const std::set *include_cells = 0); + + /** + * @brief Like create_missing_mapping, but returns the newly mapped pairs (single-cell version) + * + * The first cell index of the pair is the old cell in layout_a, the second cell index + * is the new cell in layout_b. + */ + std::vector > create_missing_mapping2 (db::Layout &layout_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells = 0, const std::set *include_cells = 0) + { + std::vector cib; + cib.reserve (1); + cib.push_back (cell_index_b); + return create_missing_mapping2 (layout_a, layout_b, cib, exclude_cells, include_cells); + } private: void extract_unique (std::map >::const_iterator cand, @@ -213,7 +262,7 @@ private: void dump_mapping (const std::map > &candidates, const db::Layout &layout_a, const db::Layout &layout_b); - void do_create_missing_mapping (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set *exclude_cells, const std::set *include_cells, std::vector *new_cells, std::vector > *mapped_pairs); + void do_create_missing_mapping (db::Layout &layout_a, const db::Layout &layout_b, const std::vector &cell_index_b, const std::set *exclude_cells, const std::set *include_cells, std::vector *new_cells, std::vector > *mapped_pairs); std::map m_b2a_mapping; }; diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index a2e11a840..f95667da2 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -977,7 +977,7 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout // Add new cells for the variants and (possible) devices which are cells added during the device // extraction process - std::vector > new_pairs = cm->second.create_missing_mapping2 (*into_layout, into_cell, *source_layout, source_top, excluded_cells, included_cells); + std::vector > new_pairs = cm->second.create_missing_mapping2 (*into_layout, *source_layout, source_top, excluded_cells, included_cells); // the variant's originals we are going to delete std::set cells_to_delete; diff --git a/src/db/db/gsiDeclDbCellMapping.cc b/src/db/db/gsiDeclDbCellMapping.cc index 3c92720da..14690fac9 100644 --- a/src/db/db/gsiDeclDbCellMapping.cc +++ b/src/db/db/gsiDeclDbCellMapping.cc @@ -76,10 +76,42 @@ Class decl_CellMapping ("db", "CellMapping", "The cell mapping is created for cell_b to cell_a in the respective layouts. " "This method clears the mapping and creates one for the single cell pair. " "In addition and in contrast to \\for_single_cell, this method completes the mapping by adding all the child cells " - "of cell_b to layout_a and creating the proper instances. " + "of cell_b to layout_a and creating the proper instances.\n" "\n" "This method has been introduced in version 0.23." ) + + gsi::method ("for_multi_cells", &db::CellMapping::create_multi_mapping, gsi::arg ("layout_a"), gsi::arg ("cell_indexes_a"), gsi::arg ("layout_b"), gsi::arg ("cell_indexes_b"), + "@brief Initializes the cell mapping for top-level identity\n" + "\n" + "@param layout_a The target layout.\n" + "@param cell_indexes_a A list of cell indexes for the target cells.\n" + "@param layout_b The source layout.\n" + "@param cell_indexes_b A list of cell indexes for the source cells (same number of indexes than \\cell_indexes_a).\n" + "\n" + "The cell mapping is created for cells from cell_indexes_b to cell from cell_indexes_a in the respective layouts. " + "This method clears the mapping and creates one for each cell pair from cell_indexes_b vs. cell_indexes_a. " + "If used for \\Layout#copy_tree or \\Layout#move_tree, this cell mapping will essentially " + "flatten the source cells in the target layout.\n" + "\n" + "This method is equivalent to \\clear, followed by \\map(cell_index_a, cell_index_b) for each cell pair.\n" + "\n" + "This method has been introduced in version 0.27." + ) + + gsi::method ("for_multi_cells_full", &db::CellMapping::create_multi_mapping_full, gsi::arg ("layout_a"), gsi::arg ("cell_indexes_a"), gsi::arg ("layout_b"), gsi::arg ("cell_indexes_b"), + "@brief Initializes the cell mapping for top-level identity\n" + "\n" + "@param layout_a The target layout.\n" + "@param cell_indexes_a A list of cell indexes for the target cells.\n" + "@param layout_b The source layout.\n" + "@param cell_indexes_b A list of cell indexes for the source cells (same number of indexes than \\cell_indexes_a).\n" + "\n" + "The cell mapping is created for cells from cell_indexes_b to cell from cell_indexes_a in the respective layouts. " + "This method clears the mapping and creates one for each cell pair from cell_indexes_b vs. cell_indexes_a. " + "In addition and in contrast to \\for_multi_cells, this method completes the mapping by adding all the child cells " + "of all cells in cell_indexes_b to layout_a and creating the proper instances.\n" + "\n" + "This method has been introduced in version 0.27." + ) + gsi::method ("from_geometry_full", &db::CellMapping::create_from_geometry_full, gsi::arg ("layout_a"), gsi::arg ("cell_index_a"), gsi::arg ("layout_b"), gsi::arg ("cell_index_b"), "@brief Initializes the cell mapping using the geometrical identity in full mapping mode\n" "\n" @@ -234,6 +266,26 @@ Class decl_CellMapping ("db", "CellMapping", "\n" "CellMapping objects play a role mainly in the hierarchical copy or move operations of \\Layout. " "However, use is not restricted to these applications.\n" + "\n" + "Here is one example for using \\CellMapping. It extracts cells 'A', 'B' and 'C' from one layout " + "and copies them to another. It will also copy all shapes and all child cells. Child cells which are " + "shared between the three initial cells will be shared in the target layout too.\n" + "\n" + "@code\n" + "cell_names = [ \"A\", \"B\", \"C\" ]\n" + "\n" + "source = RBA::Layout::new\n" + "source.read(\"input.gds\")\n" + "\n" + "target = RBA::Layout::new\n" + "\n" + "source_cells = cell_names.collect { |n| source.cell_by_name(n).cell_index }\n" + "target_cells = cell_names.collect { |n| target.create_cell(n).cell_index }\n" + "\n" + "cm = RBA::CellMapping::new\n" + "cm.for_multi_cells_full(source, source_cells, target, target_cells)\n" + "target.copy_tree_shapes(source, cm)\n" + "@/code\n" ); } diff --git a/src/db/unit_tests/dbCellMappingTests.cc b/src/db/unit_tests/dbCellMappingTests.cc index 8392d5e25..5559abbe0 100644 --- a/src/db/unit_tests/dbCellMappingTests.cc +++ b/src/db/unit_tests/dbCellMappingTests.cc @@ -453,3 +453,40 @@ TEST(6) EXPECT_EQ (l2s (h), "a0top#0:cell_index=1 r90 0,0 array=(0,10,10,0 5x2),cell_index=2 r90 0,0 array=(0,10,10,0 5x2);a4#1:;a5#2:"); } +// Multi-mapping +TEST(7) +{ + std::auto_ptr g (new db::Layout ()); + db::Cell &a0 (g->cell (g->add_cell ("a0"))); + db::Cell &a1 (g->cell (g->add_cell ("a1"))); + db::Cell &a2 (g->cell (g->add_cell ("a2"))); + db::Cell &a3 (g->cell (g->add_cell ("a3"))); + db::Cell &a4 = g->cell (g->add_cell ("a4")); + db::Cell &a5 = g->cell (g->add_cell ("a5")); + + a3.insert (db::CellInstArray (db::CellInst (a4.cell_index ()), db::Trans ())); + a3.insert (db::CellInstArray (db::CellInst (a5.cell_index ()), db::Trans ())); + + a1.insert (db::CellInstArray (db::CellInst (a4.cell_index ()), db::Trans ())); + a1.insert (db::CellInstArray (db::CellInst (a3.cell_index ()), db::Trans ())); + a2.insert (db::CellInstArray (db::CellInst (a4.cell_index ()), db::Trans ())); + + db::Layout h; + db::Cell &b0 (h.cell (h.add_cell ("b0"))); + db::Cell &b1 (h.cell (h.add_cell ("b1"))); + db::Cell &b2 (h.cell (h.add_cell ("b2"))); + + db::CellMapping cm; + std::vector cib, cia; + cia.push_back (a0.cell_index ()); + cia.push_back (a1.cell_index ()); + cia.push_back (a2.cell_index ()); + cib.push_back (b0.cell_index ()); + cib.push_back (b1.cell_index ()); + cib.push_back (b2.cell_index ()); + cm.create_multi_mapping_full (h, cib, *g, cia); + EXPECT_EQ (m2s (cm, *g, h), "a0->b0;a1->b1;a2->b2;a3->a3;a4->a4;a5->a5"); + + EXPECT_EQ (l2s (h), "b0#0:;b1#1:cell_index=3 r0 0,0,cell_index=4 r0 0,0;b2#2:cell_index=4 r0 0,0;a3#3:cell_index=4 r0 0,0,cell_index=5 r0 0,0;a4#4:;a5#5:"); +} + diff --git a/testdata/ruby/dbCellMapping.rb b/testdata/ruby/dbCellMapping.rb index b15a25ba3..e7ef1496b 100644 --- a/testdata/ruby/dbCellMapping.rb +++ b/testdata/ruby/dbCellMapping.rb @@ -205,6 +205,41 @@ class DBCellMapping_TestClass < TestBase end + def test_2 + + ly = RBA::Layout::new + + a0 = ly.create_cell("a0") + a1 = ly.create_cell("a1") + a2 = ly.create_cell("a2") + a3 = ly.create_cell("a3") + a4 = ly.create_cell("a4") + a5 = ly.create_cell("a5") + + a3.insert(RBA::CellInstArray::new(a4.cell_index, RBA::Trans::new)) + a3.insert(RBA::CellInstArray::new(a5.cell_index, RBA::Trans::new)) + + a1.insert(RBA::CellInstArray::new(a4.cell_index, RBA::Trans::new)) + a1.insert(RBA::CellInstArray::new(a3.cell_index, RBA::Trans::new)) + a2.insert(RBA::CellInstArray::new(a4.cell_index, RBA::Trans::new)) + + ly_target = RBA::Layout::new + b0 = ly_target.create_cell("b0") + b1 = ly_target.create_cell("b1") + b2 = ly_target.create_cell("b2") + + cm = RBA::CellMapping::new + cm.for_multi_cells(ly_target, [ b0, b1, b2 ].collect { |c| c.cell_index }, ly, [ a0, a1, a2 ].collect { |c| c.cell_index }) + + assert_equal(mapping_to_s(ly_target, ly, cm), "b0=>a0;b1=>a1;b2=>a2") + + cm = RBA::CellMapping::new + cm.for_multi_cells_full(ly_target, [ b0, b1, b2 ].collect { |c| c.cell_index }, ly, [ a0, a1, a2 ].collect { |c| c.cell_index }) + + assert_equal(mapping_to_s(ly_target, ly, cm), "b0=>a0;b1=>a1;b2=>a2;a3=>a3;a4=>a4;a5=>a5") + + end + end load("test_epilogue.rb")