From 2a3fe08e7b6e31b83d272db2ac354baefa6bfd94 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 29 Aug 2020 22:49:38 +0200 Subject: [PATCH] Provide multi-cell copy/move of shapes (GSI binding) --- src/db/db/dbCellMapping.cc | 11 +++ src/db/db/dbCellMapping.h | 5 ++ src/db/db/gsiDeclDbLayout.cc | 95 ++++++++++++++++++++++ testdata/ruby/dbLayout.rb | 149 +++++++++++++++++++++++++++++++++++ 4 files changed, 260 insertions(+) diff --git a/src/db/db/dbCellMapping.cc b/src/db/db/dbCellMapping.cc index 5c65eb914..19c4fee39 100644 --- a/src/db/db/dbCellMapping.cc +++ b/src/db/db/dbCellMapping.cc @@ -269,6 +269,17 @@ void CellMapping::clear () m_b2a_mapping.clear (); } +std::vector CellMapping::source_cells () const +{ + std::vector s; + s.reserve (m_b2a_mapping.size ()); + for (iterator m = begin (); m != end (); ++m) { + s.push_back (m->first); + } + return s; +} + + void CellMapping::create_single_mapping (const db::Layout & /*layout_a*/, db::cell_index_type cell_index_a, const db::Layout & /*layout_b*/, db::cell_index_type cell_index_b) { diff --git a/src/db/db/dbCellMapping.h b/src/db/db/dbCellMapping.h index 8857ad5c8..761ff31b5 100644 --- a/src/db/db/dbCellMapping.h +++ b/src/db/db/dbCellMapping.h @@ -196,6 +196,11 @@ public: return m_b2a_mapping.end (); } + /** + * @brief Gets the source cells + */ + std::vector source_cells () const; + /** * @brief Access to the mapping table */ diff --git a/src/db/db/gsiDeclDbLayout.cc b/src/db/db/gsiDeclDbLayout.cc index d6d5c9975..e2e358a4c 100644 --- a/src/db/db/gsiDeclDbLayout.cc +++ b/src/db/db/gsiDeclDbLayout.cc @@ -37,6 +37,8 @@ #include "dbEdgePairs.h" #include "dbTexts.h" #include "dbLayoutUtils.h" +#include "dbLayerMapping.h" +#include "dbCellMapping.h" #include "tlStream.h" namespace gsi @@ -822,6 +824,56 @@ static void scale_and_snap2 (db::Layout *layout, db::cell_index_type ci, db::Coo scale_and_snap (*layout, layout->cell (ci), g, m, d); } +static void copy_tree_shapes2 (db::Layout *layout, const db::Layout &source_layout, const db::CellMapping &cm) +{ + if (layout == &source_layout) { + throw tl::Exception (tl::to_string (tr ("Cannot copy shapes within the same layout"))); + } + + db::ICplxTrans trans (source_layout.dbu () / layout->dbu ()); + + db::LayerMapping lm; + lm.create_full (*layout, source_layout); + + db::copy_shapes (*layout, source_layout, trans, cm.source_cells (), cm.table (), lm.table ()); +} + +static void copy_tree_shapes3 (db::Layout *layout, const db::Layout &source_layout, const db::CellMapping &cm, const db::LayerMapping &lm) +{ + if (layout == &source_layout) { + throw tl::Exception (tl::to_string (tr ("Cannot copy shapes within the same layout"))); + } + + db::ICplxTrans trans (source_layout.dbu () / layout->dbu ()); + + db::copy_shapes (*layout, source_layout, trans, cm.source_cells (), cm.table (), lm.table ()); +} + +static void move_tree_shapes2 (db::Layout *layout, db::Layout &source_layout, const db::CellMapping &cm) +{ + if (layout == &source_layout) { + throw tl::Exception (tl::to_string (tr ("Cannot copy shapes within the same layout"))); + } + + db::ICplxTrans trans (source_layout.dbu () / layout->dbu ()); + + db::LayerMapping lm; + lm.create_full (*layout, source_layout); + + db::move_shapes (*layout, source_layout, trans, cm.source_cells (), cm.table (), lm.table ()); +} + +static void move_tree_shapes3 (db::Layout *layout, db::Layout &source_layout, const db::CellMapping &cm, const db::LayerMapping &lm) +{ + if (layout == &source_layout) { + throw tl::Exception (tl::to_string (tr ("Cannot copy shapes within the same layout"))); + } + + db::ICplxTrans trans (source_layout.dbu () / layout->dbu ()); + + db::move_shapes (*layout, source_layout, trans, cm.source_cells (), cm.table (), lm.table ()); +} + Class decl_LayoutMetaInfo ("db", "LayoutMetaInfo", gsi::constructor ("new", &layout_meta_info_ctor, gsi::arg ("name"), gsi::arg ("value"), gsi::arg ("description", std::string ()), "@brief Creates a layout meta info object\n" @@ -1529,6 +1581,49 @@ Class decl_Layout ("db", "Layout", "an index in the range of 0 to layers-1 needs to be a valid layer. These layers can be either valid, " "special or unused. Use \\is_valid_layer? and \\is_special_layer? to test for the first two states.\n" ) + + gsi::method_ext ("copy_tree_shapes", ©_tree_shapes2, gsi::arg ("source_layout"), gsi::arg ("cell_mapping"), + "@brief Copies the shapes for all given mappings in the \\CellMapping object\n" + "@param source_layout The layout where to take the shapes from\n" + "@param cell_mapping The cell mapping object that determines how cells are identified between source and target layout\n" + "\n" + "Provide a \\CellMapping object to specify pairs of cells which are mapped from the source layout to this " + "layout. When constructing such a cell mapping object for example with \\CellMapping#for_multi_cell_full, use self " + "as the target layout. During the cell mapping construction, the cell mapper will usually create a suitable target " + "hierarchy already. After having completed the cell mapping, use \\copy_tree_shapes to copy over the shapes from " + "the source to the target layout.\n" + "\n" + "This method has been added in version 0.27.\n" + ) + + gsi::method_ext ("copy_tree_shapes", ©_tree_shapes3, gsi::arg ("source_layout"), gsi::arg ("cell_mapping"), gsi::arg ("layer_mapping"), + "@brief Copies the shapes for all given mappings in the \\CellMapping object using the given layer mapping\n" + "@param source_layout The layout where to take the shapes from\n" + "@param cell_mapping The cell mapping object that determines how cells are identified between source and target layout\n" + "@param layer_mapping Specifies which layers are copied from the source layout to the target layout\n" + "\n" + "Provide a \\CellMapping object to specify pairs of cells which are mapped from the source layout to this " + "layout. When constructing such a cell mapping object for example with \\CellMapping#for_multi_cell_full, use self " + "as the target layout. During the cell mapping construction, the cell mapper will usually create a suitable target " + "hierarchy already. After having completed the cell mapping, use \\copy_tree_shapes to copy over the shapes from " + "the source to the target layout.\n" + "\n" + "This method has been added in version 0.27.\n" + ) + + gsi::method_ext ("move_tree_shapes", &move_tree_shapes2, gsi::arg ("source_layout"), gsi::arg ("cell_mapping"), + "@brief Moves the shapes for all given mappings in the \\CellMapping object\n" + "\n" + "This method acts like the corresponding \\copy_tree_shapes method, but removes the shapes from the source layout " + "after they have been copied.\n" + "\n" + "This method has been added in version 0.27.\n" + ) + + gsi::method_ext ("move_tree_shapes", &move_tree_shapes3, gsi::arg ("source_layout"), gsi::arg ("cell_mapping"), gsi::arg ("layer_mapping"), + "@brief Moves the shapes for all given mappings in the \\CellMapping object using the given layer mapping\n" + "\n" + "This method acts like the corresponding \\copy_tree_shapes method, but removes the shapes from the source layout " + "after they have been copied.\n" + "\n" + "This method has been added in version 0.27.\n" + ) + gsi::method_ext ("scale_and_snap", &scale_and_snap1, gsi::arg ("cell"), gsi::arg ("grid"), gsi::arg ("mult"), gsi::arg ("div"), "@brief Scales and snaps the layout below a given cell by the given rational factor and snaps to the given grid\n" "\n" diff --git a/testdata/ruby/dbLayout.rb b/testdata/ruby/dbLayout.rb index cdefe938b..ecb2efff1 100644 --- a/testdata/ruby/dbLayout.rb +++ b/testdata/ruby/dbLayout.rb @@ -1994,6 +1994,155 @@ END end + def test_20 + + # copy shapes between cell trees starting from multiple cells + + l = RBA::Layout.new + l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) + l.insert_layer_at(1, RBA::LayerInfo.new(2, 0)) + c0 = l.cell(l.add_cell("c0")) + c9 = l.cell(l.add_cell("c9")) + c1 = l.cell(l.add_cell("c1")) + c2 = l.cell(l.add_cell("c2")) + c3 = l.cell(l.add_cell("c3")) + + b = RBA::Box.new(0, 100, 1000, 1200) + c0.shapes(0).insert(b) + c1.shapes(0).insert(b) + c2.shapes(0).insert(b) + c3.shapes(0).insert(b) + b = RBA::Box.new(1, 101, 1001, 1201) + s = c0.shapes(1).insert(b) + s.set_property("p", 17) + + tt = RBA::Trans.new + s = c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) + s.set_property("p", 18) + 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)))) + c9.insert(RBA::CellInstArray.new(c1.cell_index, tt)) + + assert_equal(collect(c0.begin_shapes_rec(0), l), "[c0](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)") + assert_equal(collect(c0.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") + assert_equal(collect(c9.begin_shapes_rec(0), l), "[c1](0,100;1000,1200)") + assert_equal(collect(c9.begin_shapes_rec(1), l), "") + + lt = RBA::Layout::new + + new_cells = [ c0, c9 ].collect { |c| lt.add_cell(c.name) } + ( c0t, c9t ) = new_cells.collect { |ci| lt.cell(ci) } + org_cells = [ c0, c9 ].collect { |c| c.cell_index } + + cm = RBA::CellMapping::new + cm.for_multi_cells(lt, new_cells, l, org_cells) + + lt.copy_tree_shapes(l, cm) + assert_equal(collect(c0t.begin_shapes_rec(0), lt), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](-1200,0;-100,1000)/[c0](1200,0;2200,1100)") + assert_equal(c0t.begin_shapes_rec(0).shape.property("p"), nil) + assert_equal(collect(c9t.begin_shapes_rec(0), lt), "[c9](0,100;1000,1200)") + assert_equal(collect(c0t.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") + assert_equal(c0t.begin_shapes_rec(1).shape.property("p"), 17) + assert_equal(collect(c9t.begin_shapes_rec(1), l), "") + + lt = RBA::Layout::new + + new_cells = [ c0, c9 ].collect { |c| lt.add_cell(c.name) } + ( c0t, c9t ) = new_cells.collect { |ci| lt.cell(ci) } + org_cells = [ c0, c9 ].collect { |c| c.cell_index } + + cm = RBA::CellMapping::new + cm.for_multi_cells_full(lt, new_cells, l, org_cells) + + lt.copy_tree_shapes(l, cm) + assert_equal(collect(c0t.begin_shapes_rec(0), lt), "[c0](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)") + assert_equal(c0t.begin_shapes_rec(0).shape.property("p"), nil) + assert_equal(collect(c9t.begin_shapes_rec(0), lt), "[c1](0,100;1000,1200)") + assert_equal(collect(c0t.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") + assert_equal(c0t.begin_shapes_rec(1).shape.property("p"), 17) + assert_equal(collect(c9t.begin_shapes_rec(1), l), "") + + lt = RBA::Layout::new + lt.layer + lt.layer + ll = lt.layer + + new_cells = [ c0, c9 ].collect { |c| lt.add_cell(c.name) } + ( c0t, c9t ) = new_cells.collect { |ci| lt.cell(ci) } + org_cells = [ c0, c9 ].collect { |c| c.cell_index } + + cm = RBA::CellMapping::new + cm.for_multi_cells_full(lt, new_cells, l, org_cells) + + lm = RBA::LayerMapping::new + lm.map(0, ll) + + lt.copy_tree_shapes(l, cm, lm) + assert_equal(collect(c0t.begin_shapes_rec(ll), lt), "[c0](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)/[c1](0,100;1000,1200)") + assert_equal(c0t.begin_shapes_rec(ll).shape.property("p"), nil) + assert_equal(collect(c9t.begin_shapes_rec(ll), lt), "[c1](0,100;1000,1200)") + + lt = RBA::Layout::new + ls = l.dup + + assert_equal(ls.cell(c0.cell_index).name, "c0") + assert_equal(ls.cell(c9.cell_index).name, "c9") + + new_cells = [ c0, c9 ].collect { |c| lt.add_cell(c.name) } + ( c0t, c9t ) = new_cells.collect { |ci| lt.cell(ci) } + org_cells = [ c0, c9 ].collect { |c| c.cell_index } + + cm = RBA::CellMapping::new + cm.for_multi_cells(lt, new_cells, ls, org_cells) + + lt.move_tree_shapes(ls, cm) + + assert_equal(collect(ls.cell(c0.cell_index).begin_shapes_rec(0), ls), "") + assert_equal(collect(ls.cell(c0.cell_index).begin_shapes_rec(1), ls), "") + assert_equal(collect(ls.cell(c9.cell_index).begin_shapes_rec(0), ls), "") + assert_equal(collect(ls.cell(c9.cell_index).begin_shapes_rec(1), ls), "") + + assert_equal(collect(c0t.begin_shapes_rec(0), lt), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](-1200,0;-100,1000)/[c0](1200,0;2200,1100)") + assert_equal(c0t.begin_shapes_rec(0).shape.property("p"), nil) + assert_equal(collect(c9t.begin_shapes_rec(0), lt), "[c9](0,100;1000,1200)") + assert_equal(collect(c0t.begin_shapes_rec(1), l), "[c0](1,101;1001,1201)") + assert_equal(c0t.begin_shapes_rec(1).shape.property("p"), 17) + assert_equal(collect(c9t.begin_shapes_rec(1), l), "") + + lt = RBA::Layout::new + lt.layer + lt.layer + ll = lt.layer + + ls = l.dup + + assert_equal(ls.cell(c0.cell_index).name, "c0") + assert_equal(ls.cell(c9.cell_index).name, "c9") + + new_cells = [ c0, c9 ].collect { |c| lt.add_cell(c.name) } + ( c0t, c9t ) = new_cells.collect { |ci| lt.cell(ci) } + org_cells = [ c0, c9 ].collect { |c| c.cell_index } + + cm = RBA::CellMapping::new + cm.for_multi_cells(lt, new_cells, ls, org_cells) + + lm = RBA::LayerMapping::new + lm.map(0, ll) + + lt.move_tree_shapes(ls, cm, lm) + + assert_equal(collect(ls.cell(c0.cell_index).begin_shapes_rec(0), ls), "") + assert_equal(collect(ls.cell(c0.cell_index).begin_shapes_rec(1), ls), "[c0](1,101;1001,1201)") + assert_equal(collect(ls.cell(c9.cell_index).begin_shapes_rec(0), ls), "") + assert_equal(collect(ls.cell(c9.cell_index).begin_shapes_rec(1), ls), "") + + assert_equal(collect(c0t.begin_shapes_rec(ll), lt), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](-1200,0;-100,1000)/[c0](1200,0;2200,1100)") + assert_equal(c0t.begin_shapes_rec(ll).shape.property("p"), nil) + assert_equal(collect(c9t.begin_shapes_rec(ll), lt), "[c9](0,100;1000,1200)") + + end + # Iterating while flatten def test_issue200