Added multi-cell mapping for transferring multiple cells from one layout to another while including their hierarchy without duplicating cells.

This commit is contained in:
Matthias Koefferlein 2020-08-29 10:07:17 +02:00
parent 213eb9f1e8
commit a425d522cc
6 changed files with 205 additions and 18 deletions

View File

@ -276,6 +276,18 @@ CellMapping::create_single_mapping (const db::Layout & /*layout_a*/, db::cell_in
map (cell_index_b, cell_index_a); map (cell_index_b, cell_index_a);
} }
void
CellMapping::create_multi_mapping (const db::Layout & /*layout_a*/, const std::vector<db::cell_index_type> &cell_index_a, const db::Layout & /*layout_b*/, const std::vector<db::cell_index_type> &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<db::cell_index_type>::const_iterator ia = cell_index_a.begin (), ib = cell_index_b.begin (); ia != cell_index_a.end (); ++ia, ++ib) {
map (*ib, *ia);
}
}
void 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) 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)
{ {
@ -295,31 +307,33 @@ CellMapping::create_from_names (const db::Layout &layout_a, db::cell_index_type
} }
std::vector<db::cell_index_type> std::vector<db::cell_index_type>
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<db::cell_index_type> *exclude_cells, const std::set<db::cell_index_type> *include_cells) CellMapping::create_missing_mapping (db::Layout &layout_a, const db::Layout &layout_b, const std::vector<db::cell_index_type> &cell_index_b, const std::set<db::cell_index_type> *exclude_cells, const std::set<db::cell_index_type> *include_cells)
{ {
std::vector<db::cell_index_type> new_cells; std::vector<db::cell_index_type> 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; return new_cells;
} }
std::vector<std::pair<db::cell_index_type, db::cell_index_type> > std::vector<std::pair<db::cell_index_type, db::cell_index_type> >
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<db::cell_index_type> *exclude_cells, const std::set<db::cell_index_type> *include_cells) CellMapping::create_missing_mapping2 (db::Layout &layout_a, const db::Layout &layout_b, const std::vector<db::cell_index_type> &cell_index_b, const std::set<db::cell_index_type> *exclude_cells, const std::set<db::cell_index_type> *include_cells)
{ {
std::vector<std::pair<db::cell_index_type, db::cell_index_type> > cell_pairs; std::vector<std::pair<db::cell_index_type, db::cell_index_type> > 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; return cell_pairs;
} }
void 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<db::cell_index_type> *exclude_cells, const std::set<db::cell_index_type> *include_cells, std::vector<db::cell_index_type> *new_cells_ptr, std::vector<std::pair<db::cell_index_type, db::cell_index_type> > *mapped_pairs) CellMapping::do_create_missing_mapping (db::Layout &layout_a, const db::Layout &layout_b, const std::vector<db::cell_index_type> &cell_index_b, const std::set<db::cell_index_type> *exclude_cells, const std::set<db::cell_index_type> *include_cells, std::vector<db::cell_index_type> *new_cells_ptr, std::vector<std::pair<db::cell_index_type, db::cell_index_type> > *mapped_pairs)
{ {
std::vector<db::cell_index_type> new_cells_int; std::vector<db::cell_index_type> new_cells_int;
std::vector<db::cell_index_type> &new_cells = *(new_cells_ptr ? new_cells_ptr : &new_cells_int); std::vector<db::cell_index_type> &new_cells = *(new_cells_ptr ? new_cells_ptr : &new_cells_int);
std::vector<db::cell_index_type> new_cells_b; std::vector<db::cell_index_type> new_cells_b;
std::set<db::cell_index_type> called_b; std::set<db::cell_index_type> called_b;
layout_b.cell (cell_index_b).collect_called_cells (called_b); for (std::vector<db::cell_index_type>::const_iterator i = cell_index_b.begin (); i != cell_index_b.end (); ++i) {
called_b.insert (cell_index_b); layout_b.cell (*i).collect_called_cells (called_b);
called_b.insert (*i);
}
for (std::set<db::cell_index_type>::const_iterator b = called_b.begin (); b != called_b.end (); ++b) { for (std::set<db::cell_index_type>::const_iterator b = called_b.begin (); b != called_b.end (); ++b) {
if (m_b2a_mapping.find (*b) == m_b2a_mapping.end () if (m_b2a_mapping.find (*b) == m_b2a_mapping.end ()

View File

@ -81,7 +81,30 @@ public:
std::vector<db::cell_index_type> 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) std::vector<db::cell_index_type> 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); 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<db::cell_index_type> &cell_indexes_a, const db::Layout &layout_b, const std::vector<db::cell_index_type> &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<db::cell_index_type> create_multi_mapping_full (db::Layout &layout_a, const std::vector<db::cell_index_type> &cell_indexes_a, const db::Layout &layout_b, const std::vector<db::cell_index_type> &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<db::cell_index_type> 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) std::vector<db::cell_index_type> 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); 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<db::cell_index_type> 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) std::vector<db::cell_index_type> 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); 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 * @brief Creates mappings for all cells not mapped yet
* *
* When constructing a cell mapping by explicit mapping (map (a, b)), some cells may be * When constructing a cell mapping by explicit mapping (map (a, b)), some child cells of the
* left unmapped. This method allows creating mappings for these missing cells by adding * 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. * new cells and the corresponding instances into the target layout_a.
* *
* If given, "exclude_cells" can specify a list of cells not to map. * 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. * The returned vector lists the new cells.
*/ */
std::vector<db::cell_index_type> 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<db::cell_index_type> *exclude_cells = 0, const std::set<db::cell_index_type> *include_cells = 0); std::vector<db::cell_index_type> create_missing_mapping (db::Layout &layout_a, const db::Layout &layout_b, const std::vector<db::cell_index_type> &cell_index_b, const std::set<db::cell_index_type> *exclude_cells = 0, const std::set<db::cell_index_type> *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<db::cell_index_type> create_missing_mapping (db::Layout &layout_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set<db::cell_index_type> *exclude_cells = 0, const std::set<db::cell_index_type> *include_cells = 0)
{
std::vector<db::cell_index_type> 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 * @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 * 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. * is the new cell in layout_b.
*/ */
std::vector<std::pair<db::cell_index_type, db::cell_index_type> > 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<db::cell_index_type> *exclude_cells = 0, const std::set<db::cell_index_type> *include_cells = 0); std::vector<std::pair<db::cell_index_type, db::cell_index_type> > create_missing_mapping2 (db::Layout &layout_a, const db::Layout &layout_b, const std::vector<db::cell_index_type> &cell_index_b, const std::set<db::cell_index_type> *exclude_cells = 0, const std::set<db::cell_index_type> *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<std::pair<db::cell_index_type, db::cell_index_type> > create_missing_mapping2 (db::Layout &layout_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set<db::cell_index_type> *exclude_cells = 0, const std::set<db::cell_index_type> *include_cells = 0)
{
std::vector<db::cell_index_type> cib;
cib.reserve (1);
cib.push_back (cell_index_b);
return create_missing_mapping2 (layout_a, layout_b, cib, exclude_cells, include_cells);
}
private: private:
void extract_unique (std::map <db::cell_index_type, std::vector<db::cell_index_type> >::const_iterator cand, void extract_unique (std::map <db::cell_index_type, std::vector<db::cell_index_type> >::const_iterator cand,
@ -213,7 +262,7 @@ private:
void dump_mapping (const std::map <db::cell_index_type, std::vector<db::cell_index_type> > &candidates, void dump_mapping (const std::map <db::cell_index_type, std::vector<db::cell_index_type> > &candidates,
const db::Layout &layout_a, const db::Layout &layout_b); 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<db::cell_index_type> *exclude_cells, const std::set<db::cell_index_type> *include_cells, std::vector<db::cell_index_type> *new_cells, std::vector<std::pair<db::cell_index_type, db::cell_index_type> > *mapped_pairs); void do_create_missing_mapping (db::Layout &layout_a, const db::Layout &layout_b, const std::vector<db::cell_index_type> &cell_index_b, const std::set<db::cell_index_type> *exclude_cells, const std::set<db::cell_index_type> *include_cells, std::vector<db::cell_index_type> *new_cells, std::vector<std::pair<db::cell_index_type, db::cell_index_type> > *mapped_pairs);
std::map <db::cell_index_type, db::cell_index_type> m_b2a_mapping; std::map <db::cell_index_type, db::cell_index_type> m_b2a_mapping;
}; };

View File

@ -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 // Add new cells for the variants and (possible) devices which are cells added during the device
// extraction process // extraction process
std::vector<std::pair<db::cell_index_type, db::cell_index_type> > new_pairs = cm->second.create_missing_mapping2 (*into_layout, into_cell, *source_layout, source_top, excluded_cells, included_cells); std::vector<std::pair<db::cell_index_type, db::cell_index_type> > 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 // the variant's originals we are going to delete
std::set<db::cell_index_type> cells_to_delete; std::set<db::cell_index_type> cells_to_delete;

View File

@ -76,10 +76,42 @@ Class<db::CellMapping> decl_CellMapping ("db", "CellMapping",
"The cell mapping is created for cell_b to cell_a in the respective layouts. " "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. " "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 " "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" "\n"
"This method has been introduced in version 0.23." "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"), 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" "@brief Initializes the cell mapping using the geometrical identity in full mapping mode\n"
"\n" "\n"
@ -234,6 +266,26 @@ Class<db::CellMapping> decl_CellMapping ("db", "CellMapping",
"\n" "\n"
"CellMapping objects play a role mainly in the hierarchical copy or move operations of \\Layout. " "CellMapping objects play a role mainly in the hierarchical copy or move operations of \\Layout. "
"However, use is not restricted to these applications.\n" "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"
); );
} }

View File

@ -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:"); 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<db::Layout> 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<db::cell_index_type> 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:");
}

View File

@ -205,6 +205,41 @@ class DBCellMapping_TestClass < TestBase
end 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 end
load("test_epilogue.rb") load("test_epilogue.rb")