Some enhancements to layer and cell mapping

* Modification of the mapping is possible now
  (#map used to ignore mappings if there was one
  already)
* Added DropCell mapping (also for RBA)
* Added unit tests for cell mapping, layer mapping
  db::merge_layouts, db::copy_shapes and db::move_shapes
This commit is contained in:
Matthias Koefferlein 2017-08-30 01:11:38 +02:00
parent 3499c3856a
commit b28317fb69
24 changed files with 746 additions and 60 deletions

View File

@ -144,7 +144,7 @@ public:
*/ */
void map (db::cell_index_type cell_index_b, db::cell_index_type cell_index_a) void map (db::cell_index_type cell_index_b, db::cell_index_type cell_index_a)
{ {
m_b2a_mapping.insert (std::make_pair (cell_index_b, cell_index_a)); m_b2a_mapping.insert (std::make_pair (cell_index_b, 0)).first->second = cell_index_a;
} }
/** /**

View File

@ -102,7 +102,7 @@ public:
*/ */
void map (unsigned int layer_b, unsigned int layer_a) void map (unsigned int layer_b, unsigned int layer_a)
{ {
m_b2a_mapping.insert (std::make_pair (layer_b, layer_a)); m_b2a_mapping.insert (std::make_pair (layer_b, 0)).first->second = layer_a;
} }
/** /**

View File

@ -126,6 +126,40 @@ PropertyMapper::operator() (db::Layout::properties_id_type source_id)
// ------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------
// merge_layouts implementation // merge_layouts implementation
static void
collect_cells_to_copy (const db::Layout &source,
const std::vector<db::cell_index_type> &source_cells,
const std::map<db::cell_index_type, db::cell_index_type> &cell_mapping,
std::set<db::cell_index_type> &all_top_level_cells,
std::set<db::cell_index_type> &all_cells_to_copy)
{
std::vector<db::cell_index_type> dropped_cells;
for (std::map<db::cell_index_type, db::cell_index_type>::const_iterator m = cell_mapping.begin (); m != cell_mapping.end (); ++m) {
if (m->second == DropCell) {
dropped_cells.push_back (m->first);
}
}
for (std::vector<db::cell_index_type>::const_iterator src = source_cells.begin (); src != source_cells.end (); ++src) {
all_cells_to_copy.insert (*src);
all_top_level_cells.insert (*src);
// feed the excluded cells into the "all_cells_to_copy" cache. This will make "collect_called_cells" not
// dive into their hierarchy. We will later delete them there.
all_cells_to_copy.insert (dropped_cells.begin (), dropped_cells.end ());
source.cell (*src).collect_called_cells (all_cells_to_copy);
for (std::vector<db::cell_index_type>::const_iterator i = dropped_cells.begin (); i != dropped_cells.end (); ++i) {
all_cells_to_copy.erase (*i);
all_top_level_cells.erase (*i);
}
}
}
void void
merge_layouts (db::Layout &target, merge_layouts (db::Layout &target,
const db::Layout &source, const db::Layout &source,
@ -135,19 +169,11 @@ merge_layouts (db::Layout &target,
const std::map<unsigned int, unsigned int> &layer_mapping, const std::map<unsigned int, unsigned int> &layer_mapping,
std::map<db::cell_index_type, db::cell_index_type> *final_cell_mapping) std::map<db::cell_index_type, db::cell_index_type> *final_cell_mapping)
{ {
if (final_cell_mapping) {
final_cell_mapping->insert (cell_mapping.begin (), cell_mapping.end ());
}
// collect all called cells and all top level cells // collect all called cells and all top level cells
std::set<db::cell_index_type> all_top_level_cells; std::set<db::cell_index_type> all_top_level_cells;
std::set<db::cell_index_type> all_cells_to_copy; std::set<db::cell_index_type> all_cells_to_copy;
for (std::vector<db::cell_index_type>::const_iterator src = source_cells.begin (); src != source_cells.end (); ++src) { collect_cells_to_copy (source, source_cells, cell_mapping, all_top_level_cells, all_cells_to_copy);
all_cells_to_copy.insert (*src);
all_top_level_cells.insert (*src);
source.cell (*src).collect_called_cells (all_cells_to_copy);
}
// identify all new cells and create new ones // identify all new cells and create new ones
std::map<db::cell_index_type, db::cell_index_type> new_cell_mapping; std::map<db::cell_index_type, db::cell_index_type> new_cell_mapping;
@ -158,6 +184,11 @@ merge_layouts (db::Layout &target,
} }
if (final_cell_mapping) { if (final_cell_mapping) {
for (std::map<db::cell_index_type, db::cell_index_type>::const_iterator m = cell_mapping.begin (); m != cell_mapping.end (); ++m) {
if (m->second != DropCell) {
final_cell_mapping->insert (*m);
}
}
final_cell_mapping->insert (new_cell_mapping.begin (), new_cell_mapping.end ()); final_cell_mapping->insert (new_cell_mapping.begin (), new_cell_mapping.end ());
} }
@ -248,7 +279,7 @@ copy_or_propagate_shapes (db::Layout &target,
} }
} else { } else if (cm->second != DropCell) {
db::Cell &target_cell = target.cell (cm->second); db::Cell &target_cell = target.cell (cm->second);
target_cell.shapes (target_layer).insert_transformed (source_cell.shapes (source_layer), trans * propagate_trans, pm); target_cell.shapes (target_layer).insert_transformed (source_cell.shapes (source_layer), trans * propagate_trans, pm);
@ -256,23 +287,20 @@ copy_or_propagate_shapes (db::Layout &target,
} }
} }
void static void
copy_shapes (db::Layout &target, copy_or_move_shapes (db::Layout &target,
const db::Layout &source, db::Layout &source,
const db::ICplxTrans &trans, const db::ICplxTrans &trans,
const std::vector<db::cell_index_type> &source_cells, const std::vector<db::cell_index_type> &source_cells,
const std::map<db::cell_index_type, db::cell_index_type> &cell_mapping, const std::map<db::cell_index_type, db::cell_index_type> &cell_mapping,
const std::map<unsigned int, unsigned int> &layer_mapping) const std::map<unsigned int, unsigned int> &layer_mapping,
bool move)
{ {
// collect all called cells and all top level cells // collect all called cells and all top level cells
std::set<db::cell_index_type> all_top_level_cells; std::set<db::cell_index_type> all_top_level_cells;
std::set<db::cell_index_type> all_cells_to_copy; std::set<db::cell_index_type> all_cells_to_copy;
for (std::vector<db::cell_index_type>::const_iterator src = source_cells.begin (); src != source_cells.end (); ++src) { collect_cells_to_copy (source, source_cells, cell_mapping, all_top_level_cells, all_cells_to_copy);
all_cells_to_copy.insert (*src);
all_top_level_cells.insert (*src);
source.cell (*src).collect_called_cells (all_cells_to_copy);
}
// provide the property mapper // provide the property mapper
db::PropertyMapper pm (target, source); db::PropertyMapper pm (target, source);
@ -284,10 +312,24 @@ copy_shapes (db::Layout &target,
for (std::map<unsigned int, unsigned int>::const_iterator lm = layer_mapping.begin (); lm != layer_mapping.end (); ++lm) { for (std::map<unsigned int, unsigned int>::const_iterator lm = layer_mapping.begin (); lm != layer_mapping.end (); ++lm) {
++progress; ++progress;
copy_or_propagate_shapes (target, source, trans, db::ICplxTrans (), pm, *c, *c, lm->second, lm->first, all_cells_to_copy, cell_mapping); copy_or_propagate_shapes (target, source, trans, db::ICplxTrans (), pm, *c, *c, lm->second, lm->first, all_cells_to_copy, cell_mapping);
if (move) {
source.cell (*c).shapes (lm->first).clear ();
}
} }
} }
} }
void
copy_shapes (db::Layout &target,
const db::Layout &source,
const db::ICplxTrans &trans,
const std::vector<db::cell_index_type> &source_cells,
const std::map<db::cell_index_type, db::cell_index_type> &cell_mapping,
const std::map<unsigned int, unsigned int> &layer_mapping)
{
copy_or_move_shapes (target, const_cast<db::Layout &> (source), trans, source_cells, cell_mapping, layer_mapping, false);
}
void void
move_shapes (db::Layout &target, move_shapes (db::Layout &target,
db::Layout &source, db::Layout &source,
@ -296,29 +338,7 @@ move_shapes (db::Layout &target,
const std::map<db::cell_index_type, db::cell_index_type> &cell_mapping, const std::map<db::cell_index_type, db::cell_index_type> &cell_mapping,
const std::map<unsigned int, unsigned int> &layer_mapping) const std::map<unsigned int, unsigned int> &layer_mapping)
{ {
// collect all called cells and all top level cells copy_or_move_shapes (target, source, trans, source_cells, cell_mapping, layer_mapping, true);
std::set<db::cell_index_type> all_top_level_cells;
std::set<db::cell_index_type> all_cells_to_copy;
for (std::vector<db::cell_index_type>::const_iterator src = source_cells.begin (); src != source_cells.end (); ++src) {
all_cells_to_copy.insert (*src);
all_top_level_cells.insert (*src);
source.cell (*src).collect_called_cells (all_cells_to_copy);
}
// provide the property mapper
db::PropertyMapper pm (target, source);
tl::RelativeProgress progress (tl::to_string (QObject::tr ("Merge cells")), all_cells_to_copy.size () * layer_mapping.size (), 1);
// and copy
for (std::set<db::cell_index_type>::const_iterator c = all_cells_to_copy.begin (); c != all_cells_to_copy.end (); ++c) {
for (std::map<unsigned int, unsigned int>::const_iterator lm = layer_mapping.begin (); lm != layer_mapping.end (); ++lm) {
++progress;
copy_or_propagate_shapes (target, source, trans, db::ICplxTrans (), pm, *c, *c, lm->second, lm->first, all_cells_to_copy, cell_mapping);
source.cell (*c).shapes (lm->first).clear ();
}
}
} }
// ------------------------------------------------------------ // ------------------------------------------------------------

View File

@ -32,6 +32,7 @@
#include <map> #include <map>
#include <vector> #include <vector>
#include <limits>
namespace db namespace db
{ {
@ -110,6 +111,14 @@ private:
std::map <db::Layout::properties_id_type, db::Layout::properties_id_type> m_prop_id_map; std::map <db::Layout::properties_id_type, db::Layout::properties_id_type> m_prop_id_map;
}; };
/**
* @brief A constant describing "drop cell" mapping
*
* If used as the target cell index, this constant means "drop the cell".
* This cell and it's children will be dropped unless the children are used by other cells.
*/
const db::cell_index_type DropCell = std::numeric_limits<db::cell_index_type>::max ();
/** /**
* @brief Merge one layout into another * @brief Merge one layout into another
* *

View File

@ -23,6 +23,7 @@
#include "gsiDecl.h" #include "gsiDecl.h"
#include "dbCellMapping.h" #include "dbCellMapping.h"
#include "dbLayoutUtils.h"
#include "dbLayout.h" #include "dbLayout.h"
#include <memory> #include <memory>
@ -30,9 +31,25 @@
namespace gsi namespace gsi
{ {
static db::cell_index_type drop_cell_const ()
{
return db::DropCell;
}
Class<db::CellMapping> decl_CellMapping ("CellMapping", Class<db::CellMapping> decl_CellMapping ("CellMapping",
gsi::method ("DropCell", &drop_cell_const,
"@brief A constant indicating the reques to drop a cell\n"
"\n"
"If used as a pseudo-target for the cell mapping, this index indicates "
"that the cell shall be dropped rather than created on the target side "
"or skipped by flattening. Instead, all shapes of this cell are discarded "
"and it's children are not translated unless explicitly requested or "
"if required are children for other cells.\n"
"\n"
"This constant has been introduced in version 0.25."
) +
gsi::method ("for_single_cell", &db::CellMapping::create_single_mapping, gsi::method ("for_single_cell", &db::CellMapping::create_single_mapping,
"@brief Initialize the cell mapping for top-level identity\n" "@brief Initializes the cell mapping for top-level identity\n"
"\n" "\n"
"@args layout_a, cell_index_a, layout_b, cell_index_b\n" "@args layout_a, cell_index_a, layout_b, cell_index_b\n"
"@param layout_a The target layout.\n" "@param layout_a The target layout.\n"
@ -42,13 +59,15 @@ Class<db::CellMapping> decl_CellMapping ("CellMapping",
"\n" "\n"
"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, this method completes the mapping by adding all the child cells " "If used for \\Cell#copy_tree or \\Cell#move_tree, this cell mapping will essentially "
"of cell_b to layout_a and creating the proper instances. " "flatten the cell.\n"
"\n"
"This method is equivalent to \\clear, followed by \\map(cell_index_a, cell_index_b).\n"
"\n" "\n"
"This method has been introduced in version 0.23." "This method has been introduced in version 0.23."
) + ) +
gsi::method ("for_single_cell_full", &db::CellMapping::create_single_mapping_full, gsi::method ("for_single_cell_full", &db::CellMapping::create_single_mapping_full,
"@brief Initialize the cell mapping for top-level identity\n" "@brief Initializes the cell mapping for top-level identity\n"
"\n" "\n"
"@args layout_a, cell_index_a, layout_b, cell_index_b\n" "@args layout_a, cell_index_a, layout_b, cell_index_b\n"
"@param layout_a The target layout.\n" "@param layout_a The target layout.\n"
@ -58,11 +77,13 @@ Class<db::CellMapping> decl_CellMapping ("CellMapping",
"\n" "\n"
"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 "
"of cell_b to layout_a and creating the proper instances. "
"\n" "\n"
"This method has been introduced in version 0.23." "This method has been introduced in version 0.23."
) + ) +
gsi::method ("from_geometry_full", &db::CellMapping::create_from_geometry_full, gsi::method ("from_geometry_full", &db::CellMapping::create_from_geometry_full,
"@brief Initialize 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"
"@args layout_a, cell_index_a, layout_b, cell_index_b\n" "@args layout_a, cell_index_a, layout_b, cell_index_b\n"
"@param layout_a The target layout.\n" "@param layout_a The target layout.\n"
@ -83,7 +104,7 @@ Class<db::CellMapping> decl_CellMapping ("CellMapping",
"This method has been introduced in version 0.23." "This method has been introduced in version 0.23."
) + ) +
gsi::method ("from_geometry", &db::CellMapping::create_from_geometry, gsi::method ("from_geometry", &db::CellMapping::create_from_geometry,
"@brief Initialize the cell mapping using the geometrical identity\n" "@brief Initializes the cell mapping using the geometrical identity\n"
"\n" "\n"
"@args layout_a, cell_index_a, layout_b, cell_index_b\n" "@args layout_a, cell_index_a, layout_b, cell_index_b\n"
"@param layout_a The target layout.\n" "@param layout_a The target layout.\n"
@ -99,7 +120,7 @@ Class<db::CellMapping> decl_CellMapping ("CellMapping",
"This method has been introduced in version 0.23." "This method has been introduced in version 0.23."
) + ) +
gsi::method ("from_names", &db::CellMapping::create_from_names, gsi::method ("from_names", &db::CellMapping::create_from_names,
"@brief Initialize the cell mapping using the name identity\n" "@brief Initializes the cell mapping using the name identity\n"
"\n" "\n"
"@args layout_a, cell_index_a, layout_b, cell_index_b\n" "@args layout_a, cell_index_a, layout_b, cell_index_b\n"
"@param layout_a The target layout.\n" "@param layout_a The target layout.\n"
@ -114,7 +135,7 @@ Class<db::CellMapping> decl_CellMapping ("CellMapping",
"This method has been introduced in version 0.23." "This method has been introduced in version 0.23."
) + ) +
gsi::method ("from_names_full", &db::CellMapping::create_from_names_full, gsi::method ("from_names_full", &db::CellMapping::create_from_names_full,
"@brief Initialize the cell mapping using the name identity in full mapping mode\n" "@brief Initializes the cell mapping using the name identity in full mapping mode\n"
"\n" "\n"
"@args layout_a, cell_index_a, layout_b, cell_index_b\n" "@args layout_a, cell_index_a, layout_b, cell_index_b\n"
"@param layout_a The target layout.\n" "@param layout_a The target layout.\n"
@ -139,12 +160,12 @@ Class<db::CellMapping> decl_CellMapping ("CellMapping",
"This method has been introduced in version 0.23." "This method has been introduced in version 0.23."
) + ) +
gsi::method ("map", &db::CellMapping::map, gsi::method ("map", &db::CellMapping::map,
"@brief Explicitly specify a mapping.\n" "@brief Explicitly specifies a mapping.\n"
"\n" "\n"
"@args cell_index_b, cell_index_a\n" "@args cell_index_b, cell_index_a\n"
"\n" "\n"
"@param cell_index_b The index of the cell in layout B (the \"source\")\n" "@param cell_index_b The index of the cell in layout B (the \"source\")\n"
"@param cell_index_a The index of the cell in layout A (the \"target\")\n" "@param cell_index_a The index of the cell in layout A (the \"target\") - this index can be \\DropCell\n"
"\n" "\n"
"Beside using the mapping generator algorithms provided through \\from_names and \\from_geometry, " "Beside using the mapping generator algorithms provided through \\from_names and \\from_geometry, "
"it is possible to explicitly specify cell mappings using this method.\n" "it is possible to explicitly specify cell mappings using this method.\n"
@ -152,20 +173,25 @@ Class<db::CellMapping> decl_CellMapping ("CellMapping",
"This method has been introduced in version 0.23." "This method has been introduced in version 0.23."
) + ) +
gsi::method ("has_mapping?", &db::CellMapping::has_mapping, gsi::method ("has_mapping?", &db::CellMapping::has_mapping,
"@brief Determine if a cell of layout_b has a mapping to a layout_a cell.\n" "@brief Returns as value indicating whether a cell of layout_b has a mapping to a layout_a cell.\n"
"\n" "\n"
"@args cell_index_b\n" "@args cell_index_b\n"
"\n" "\n"
"@param cell_index_b The index of the cell in layout_b whose mapping is requested.\n" "@param cell_index_b The index of the cell in layout_b whose mapping is requested.\n"
"@return true, if the cell has a mapping\n" "@return true, if the cell has a mapping\n"
"\n"
"Note that if the cell is supposed to be dropped (see \\DropCell), the respective "
"source cell will also be regarded \"mapped\", so has_mapping? will return true in this case.\n"
) + ) +
gsi::method ("cell_mapping", &db::CellMapping::cell_mapping, gsi::method ("cell_mapping", &db::CellMapping::cell_mapping,
"@brief Determine cell mapping of a layout_b cell to the corresponding layout_a cell.\n" "@brief Determines cell mapping of a layout_b cell to the corresponding layout_a cell.\n"
"\n" "\n"
"@args cell_index_b\n" "@args cell_index_b\n"
"\n" "\n"
"@param cell_index_b The index of the cell in layout_b whose mapping is requested.\n" "@param cell_index_b The index of the cell in layout_b whose mapping is requested.\n"
"@return The cell index in layout_a.\n" "@return The cell index in layout_a.\n"
"\n"
"Note that the returned index can be \\DropCell to indicate the cell shall be dropped."
), ),
"@brief A cell mapping (source to target layout)\n" "@brief A cell mapping (source to target layout)\n"
"\n" "\n"

View File

@ -0,0 +1,616 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2017 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "dbLayoutUtils.h"
#include "dbLayerMapping.h"
#include "dbCellMapping.h"
#include "dbReader.h"
#include "tlString.h"
#include "utHead.h"
unsigned int find_layer (const db::Layout &l, int ly, int dt)
{
for (db::Layout::layer_iterator li = l.begin_layers (); li != l.end_layers (); ++li) {
if ((*li).second->log_equal (db::LayerProperties (ly, dt))) {
return (*li).first;
}
}
tl_assert (false);
}
TEST(1)
{
db::Layout l1;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l1);
}
db::Layout l2;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l2.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l2);
}
db::LayerMapping lm;
lm.create (l2, l1);
unsigned int li1 = find_layer (l1, 1, 0);
unsigned int li2 = find_layer (l1, 2, 0);
unsigned int li3 = find_layer (l1, 3, 0);
EXPECT_EQ (lm.has_mapping (li1), true);
EXPECT_EQ (lm.layer_mapping_pair (li1).first, true);
EXPECT_EQ (l2.get_properties (lm.layer_mapping_pair (li1).second).to_string (), "1/0");
EXPECT_EQ (lm.has_mapping (li2), true);
EXPECT_EQ (lm.layer_mapping_pair (li2).first, true);
EXPECT_EQ (l2.get_properties (lm.layer_mapping_pair (li2).second).to_string (), "2/0");
EXPECT_EQ (lm.has_mapping (li3), false);
EXPECT_EQ (lm.layer_mapping_pair (li3).first, false);
lm.clear ();
EXPECT_EQ (lm.has_mapping (li1), false);
EXPECT_EQ (lm.has_mapping (li2), false);
EXPECT_EQ (lm.has_mapping (li3), false);
lm.create_full (l2, l1);
EXPECT_EQ (lm.has_mapping (li1), true);
EXPECT_EQ (lm.layer_mapping_pair (li1).first, true);
EXPECT_EQ (l2.get_properties (lm.layer_mapping_pair (li1).second).to_string (), "1/0");
EXPECT_EQ (lm.has_mapping (li2), true);
EXPECT_EQ (lm.layer_mapping_pair (li2).first, true);
EXPECT_EQ (l2.get_properties (lm.layer_mapping_pair (li2).second).to_string (), "2/0");
EXPECT_EQ (lm.has_mapping (li3), true);
EXPECT_EQ (lm.layer_mapping_pair (li3).first, true);
EXPECT_EQ (l2.get_properties (lm.layer_mapping_pair (li3).second).to_string (), "3/0");
}
// Tests merge_layout with no specific mapping (plain duplication of the tree)
TEST(2)
{
db::Layout l1;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l1);
}
db::Layout l2;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l2.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l2);
}
unsigned int li1 = find_layer (l1, 1, 0);
unsigned int li2 = find_layer (l1, 2, 0);
unsigned int li3 = find_layer (l1, 3, 0);
db::LayerMapping lm;
lm.map (li1, l2.insert_layer (db::LayerProperties (11, 0)));
lm.map (li2, l2.insert_layer (db::LayerProperties (12, 0)));
lm.map (li3, l2.insert_layer (db::LayerProperties (13, 0)));
db::CellMapping cm;
std::map<db::cell_index_type, db::cell_index_type> fm;
std::vector<db::cell_index_type> src;
src.push_back (l1.cell_by_name ("TOP").second);
db::merge_layouts (l2, l1, db::ICplxTrans (), src, cm.table (), lm.table (), &fm);
CHECKPOINT();
compare_layouts (l2, ut::testsrc () + "/testdata/algo/layout_utils_au2.gds");
EXPECT_EQ (fm.find (l1.cell_by_name ("TOP").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("TOP").second)->second), "TOP$1");
EXPECT_EQ (fm.find (l1.cell_by_name ("A").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("A").second)->second), "A$1");
EXPECT_EQ (fm.find (l1.cell_by_name ("B").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("B").second)->second), "B$1");
EXPECT_EQ (fm.find (l1.cell_by_name ("C").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("C").second)->second), "C$1");
}
// Tests merge_layout with a single mapped cell (the others are mapped automatically)
TEST(3)
{
db::Layout l1;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l1);
}
db::Layout l2;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l2.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l2);
}
unsigned int li1 = find_layer (l1, 1, 0);
unsigned int li2 = find_layer (l1, 2, 0);
unsigned int li3 = find_layer (l1, 3, 0);
db::LayerMapping lm;
lm.map (li1, l2.insert_layer (db::LayerProperties (11, 0)));
lm.map (li2, l2.insert_layer (db::LayerProperties (12, 0)));
lm.map (li3, l2.insert_layer (db::LayerProperties (13, 0)));
db::CellMapping cm;
std::map<db::cell_index_type, db::cell_index_type> fm;
std::vector<db::cell_index_type> src;
src.push_back (l1.cell_by_name ("TOP").second);
cm.map (src.front (), l2.add_cell ("TOPTOP"));
db::merge_layouts (l2, l1, db::ICplxTrans (), src, cm.table (), lm.table (), &fm);
CHECKPOINT();
compare_layouts (l2, ut::testsrc () + "/testdata/algo/layout_utils_au3.gds");
EXPECT_EQ (fm.find (l1.cell_by_name ("TOP").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("TOP").second)->second), "TOPTOP");
EXPECT_EQ (fm.find (l1.cell_by_name ("A").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("A").second)->second), "A$1");
EXPECT_EQ (fm.find (l1.cell_by_name ("B").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("B").second)->second), "B$1");
EXPECT_EQ (fm.find (l1.cell_by_name ("C").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("C").second)->second), "C$1");
}
// Tests merge_layout with a mapped tree (by name)
TEST(4)
{
db::Layout l1;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l1);
}
db::Layout l2;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l2.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l2);
}
unsigned int li1 = find_layer (l1, 1, 0);
unsigned int li2 = find_layer (l1, 2, 0);
unsigned int li3 = find_layer (l1, 3, 0);
db::LayerMapping lm;
lm.map (li1, l2.insert_layer (db::LayerProperties (11, 0)));
lm.map (li2, l2.insert_layer (db::LayerProperties (12, 0)));
lm.map (li3, l2.insert_layer (db::LayerProperties (13, 0)));
db::CellMapping cm;
std::vector<db::cell_index_type> src;
src.push_back (l1.cell_by_name ("TOP").second);
cm.create_from_names_full (l2, l2.cell_by_name ("TOP").second, l1, src.front ());
std::map<db::cell_index_type, db::cell_index_type> fm;
db::merge_layouts (l2, l1, db::ICplxTrans (), src, cm.table (), lm.table (), &fm);
CHECKPOINT();
compare_layouts (l2, ut::testsrc () + "/testdata/algo/layout_utils_au4.gds");
EXPECT_EQ (fm.find (l1.cell_by_name ("TOP").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("TOP").second)->second), "TOP");
EXPECT_EQ (fm.find (l1.cell_by_name ("A").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("A").second)->second), "A");
EXPECT_EQ (fm.find (l1.cell_by_name ("B").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("B").second)->second), "B");
EXPECT_EQ (fm.find (l1.cell_by_name ("C").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("C").second)->second), "C");
}
// Tests merge_layout with a equivalence-mapped tree
TEST(5)
{
db::Layout l1;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l1);
}
db::Layout l2;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l2.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l2);
}
unsigned int li1 = find_layer (l1, 1, 0);
unsigned int li2 = find_layer (l1, 2, 0);
unsigned int li3 = find_layer (l1, 3, 0);
db::LayerMapping lm;
lm.map (li1, l2.insert_layer (db::LayerProperties (11, 0)));
lm.map (li2, l2.insert_layer (db::LayerProperties (12, 0)));
lm.map (li3, l2.insert_layer (db::LayerProperties (13, 0)));
db::CellMapping cm;
std::vector<db::cell_index_type> src;
src.push_back (l1.cell_by_name ("TOP").second);
cm.create_from_geometry_full (l2, l2.cell_by_name ("TOP").second, l1, src.front ());
std::map<db::cell_index_type, db::cell_index_type> fm;
db::merge_layouts (l2, l1, db::ICplxTrans (), src, cm.table (), lm.table (), &fm);
CHECKPOINT();
compare_layouts (l2, ut::testsrc () + "/testdata/algo/layout_utils_au5.gds");
EXPECT_EQ (fm.find (l1.cell_by_name ("TOP").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("TOP").second)->second), "TOP");
EXPECT_EQ (fm.find (l1.cell_by_name ("A").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("A").second)->second), "A");
EXPECT_EQ (fm.find (l1.cell_by_name ("B").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("B").second)->second), "B");
EXPECT_EQ (fm.find (l1.cell_by_name ("C").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("C").second)->second), "C$1");
}
// Tests merge_layout with dropping of cell B
TEST(6)
{
db::Layout l1;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l1);
}
db::Layout l2;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l2.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l2);
}
unsigned int li1 = find_layer (l1, 1, 0);
unsigned int li2 = find_layer (l1, 2, 0);
unsigned int li3 = find_layer (l1, 3, 0);
db::LayerMapping lm;
lm.map (li1, l2.insert_layer (db::LayerProperties (11, 0)));
lm.map (li2, l2.insert_layer (db::LayerProperties (12, 0)));
lm.map (li3, l2.insert_layer (db::LayerProperties (13, 0)));
db::CellMapping cm;
// Drop cell B
cm.map (l1.cell_by_name ("B").second, db::DropCell);
cm.map (l1.cell_by_name ("TOP").second, l2.cell_by_name ("TOP").second);
std::map<db::cell_index_type, db::cell_index_type> fm;
std::vector<db::cell_index_type> src;
src.push_back (l1.cell_by_name ("TOP").second);
db::merge_layouts (l2, l1, db::ICplxTrans (), src, cm.table (), lm.table (), &fm);
CHECKPOINT();
compare_layouts (l2, ut::testsrc () + "/testdata/algo/layout_utils_au6.gds");
EXPECT_EQ (fm.find (l1.cell_by_name ("TOP").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("TOP").second)->second), "TOP");
EXPECT_EQ (fm.find (l1.cell_by_name ("A").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("A").second)->second), "A$1");
EXPECT_EQ (fm.find (l1.cell_by_name ("B").second) != fm.end (), false);
EXPECT_EQ (fm.find (l1.cell_by_name ("C").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("C").second)->second), "C$1");
}
// Tests merge_layout with transformation
TEST(7)
{
db::Layout l1;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l1);
}
db::Layout l2;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l3.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l2);
}
unsigned int li1 = find_layer (l1, 1, 0);
unsigned int li2 = find_layer (l1, 2, 0);
unsigned int li3 = find_layer (l1, 3, 0);
db::LayerMapping lm;
lm.map (li1, l2.insert_layer (db::LayerProperties (11, 0)));
lm.map (li2, l2.insert_layer (db::LayerProperties (12, 0)));
lm.map (li3, l2.insert_layer (db::LayerProperties (13, 0)));
db::Layout l2copy = l2;
db::CellMapping cm;
cm.map (l1.cell_by_name ("TOP").second, l2.cell_by_name ("TOP").second);
std::map<db::cell_index_type, db::cell_index_type> fm;
std::vector<db::cell_index_type> src;
src.push_back (l1.cell_by_name ("TOP").second);
db::merge_layouts (l2, l1, db::ICplxTrans (4.0), src, cm.table (), lm.table (), &fm);
CHECKPOINT();
compare_layouts (l2, ut::testsrc () + "/testdata/algo/layout_utils_au7.gds");
EXPECT_EQ (fm.find (l1.cell_by_name ("TOP").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("TOP").second)->second), "TOP");
EXPECT_EQ (fm.find (l1.cell_by_name ("A").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("A").second)->second), "A$1");
EXPECT_EQ (fm.find (l1.cell_by_name ("B").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("B").second)->second), "B$1");
EXPECT_EQ (fm.find (l1.cell_by_name ("C").second) != fm.end (), true);
EXPECT_EQ (l2.cell_name (fm.find (l1.cell_by_name ("C").second)->second), "C");
// Once with final_mapping = 0 ...
db::merge_layouts (l2copy, l1, db::ICplxTrans (4.0), src, cm.table (), lm.table ());
CHECKPOINT();
compare_layouts (l2copy, ut::testsrc () + "/testdata/algo/layout_utils_au7.gds");
}
// Tests copy_shapes with no specific mapping (flattening)
TEST(12)
{
db::Layout l1;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l1);
}
db::Layout l2;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l2.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l2);
}
unsigned int li1 = find_layer (l1, 1, 0);
unsigned int li2 = find_layer (l1, 2, 0);
unsigned int li3 = find_layer (l1, 3, 0);
db::LayerMapping lm;
lm.map (li1, l2.insert_layer (db::LayerProperties (11, 0)));
lm.map (li2, l2.insert_layer (db::LayerProperties (12, 0)));
lm.map (li3, l2.insert_layer (db::LayerProperties (13, 0)));
db::CellMapping cm;
std::map<db::cell_index_type, db::cell_index_type> fm;
std::vector<db::cell_index_type> src;
src.push_back (l1.cell_by_name ("TOP").second);
cm.map (src.front (), l2.cell_by_name ("TOP").second);
db::copy_shapes (l2, l1, db::ICplxTrans (), src, cm.table (), lm.table ());
CHECKPOINT();
compare_layouts (l2, ut::testsrc () + "/testdata/algo/layout_utils_au12.gds");
}
// Tests copy_shapes with full name mapping
TEST(13)
{
db::Layout l1;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l1);
}
db::Layout l2;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l2.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l2);
}
unsigned int li1 = find_layer (l1, 1, 0);
unsigned int li2 = find_layer (l1, 2, 0);
unsigned int li3 = find_layer (l1, 3, 0);
db::LayerMapping lm;
lm.map (li1, l2.insert_layer (db::LayerProperties (11, 0)));
lm.map (li2, l2.insert_layer (db::LayerProperties (12, 0)));
lm.map (li3, l2.insert_layer (db::LayerProperties (13, 0)));
db::CellMapping cm;
std::vector<db::cell_index_type> src;
src.push_back (l1.cell_by_name ("TOP").second);
cm.create_from_names_full (l2, l2.cell_by_name ("TOP").second, l1, src.front ());
db::copy_shapes (l2, l1, db::ICplxTrans (), src, cm.table (), lm.table ());
CHECKPOINT();
compare_layouts (l2, ut::testsrc () + "/testdata/algo/layout_utils_au13.gds");
}
// Tests copy_shapes with geo mapping
TEST(14)
{
db::Layout l1;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l1);
}
db::Layout l2;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l2.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l2);
}
unsigned int li1 = find_layer (l1, 1, 0);
unsigned int li2 = find_layer (l1, 2, 0);
unsigned int li3 = find_layer (l1, 3, 0);
db::LayerMapping lm;
lm.map (li1, l2.insert_layer (db::LayerProperties (11, 0)));
lm.map (li2, l2.insert_layer (db::LayerProperties (12, 0)));
lm.map (li3, l2.insert_layer (db::LayerProperties (13, 0)));
db::CellMapping cm;
std::vector<db::cell_index_type> src;
src.push_back (l1.cell_by_name ("TOP").second);
cm.create_from_geometry_full (l2, l2.cell_by_name ("TOP").second, l1, src.front ());
db::copy_shapes (l2, l1, db::ICplxTrans (), src, cm.table (), lm.table ());
CHECKPOINT();
compare_layouts (l2, ut::testsrc () + "/testdata/algo/layout_utils_au14.gds");
}
// Tests copy_shapes with flattening minus one cell
TEST(15)
{
db::Layout l1;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l1);
}
db::Layout l2;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l2.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l2);
}
unsigned int li1 = find_layer (l1, 1, 0);
unsigned int li2 = find_layer (l1, 2, 0);
unsigned int li3 = find_layer (l1, 3, 0);
db::LayerMapping lm;
lm.map (li1, l2.insert_layer (db::LayerProperties (11, 0)));
lm.map (li2, l2.insert_layer (db::LayerProperties (12, 0)));
lm.map (li3, l2.insert_layer (db::LayerProperties (13, 0)));
db::CellMapping cm;
std::vector<db::cell_index_type> src;
src.push_back (l1.cell_by_name ("TOP").second);
cm.map (src.front (), l2.cell_by_name ("TOP").second);
cm.map (l1.cell_by_name ("B").second, db::DropCell);
db::copy_shapes (l2, l1, db::ICplxTrans (), src, cm.table (), lm.table ());
CHECKPOINT();
compare_layouts (l2, ut::testsrc () + "/testdata/algo/layout_utils_au15.gds");
}
// Tests copy_shapes/move_shapes with no specific mapping (flattening)
TEST(16)
{
db::Layout l1;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l1);
}
db::Layout l2;
{
std::string fn (ut::testsrc ());
fn += "/testdata/algo/layout_utils_l3.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l2);
}
unsigned int li1 = find_layer (l1, 1, 0);
unsigned int li2 = find_layer (l1, 2, 0);
unsigned int li3 = find_layer (l1, 3, 0);
db::LayerMapping lm;
lm.map (li1, l2.insert_layer (db::LayerProperties (11, 0)));
lm.map (li2, l2.insert_layer (db::LayerProperties (12, 0)));
lm.map (li3, l2.insert_layer (db::LayerProperties (13, 0)));
db::Layout l2copy = l2;
db::CellMapping cm;
std::map<db::cell_index_type, db::cell_index_type> fm;
std::vector<db::cell_index_type> src;
src.push_back (l1.cell_by_name ("TOP").second);
cm.map (src.front (), l2.cell_by_name ("TOP").second);
db::copy_shapes (l2, l1, db::ICplxTrans (4.0), src, cm.table (), lm.table ());
CHECKPOINT();
compare_layouts (l2, ut::testsrc () + "/testdata/algo/layout_utils_au16.gds");
// ... and one test for move:
db::move_shapes (l2copy, l1, db::ICplxTrans (4.0), src, cm.table (), lm.table ());
CHECKPOINT();
compare_layouts (l2copy, ut::testsrc () + "/testdata/algo/layout_utils_au16.gds");
compare_layouts (l1, ut::testsrc () + "/testdata/algo/layout_utils_au16b.gds");
}

View File

@ -31,6 +31,7 @@ SOURCES = \
dbLayerMapping.cc \ dbLayerMapping.cc \
dbLayout.cc \ dbLayout.cc \
dbLayoutDiff.cc \ dbLayoutDiff.cc \
dbLayoutUtils.cc \
dbLayoutQuery.cc \ dbLayoutQuery.cc \
dbLibraries.cc \ dbLibraries.cc \
dbMatrix.cc \ dbMatrix.cc \

BIN
testdata/algo/layout_utils_au12.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/layout_utils_au13.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/layout_utils_au14.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/layout_utils_au15.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/layout_utils_au16.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/layout_utils_au16b.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/layout_utils_au2.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/layout_utils_au3.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/layout_utils_au4.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/layout_utils_au5.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/layout_utils_au6.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/layout_utils_au7.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/layout_utils_l1.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/layout_utils_l2.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/layout_utils_l3.gds vendored Normal file

Binary file not shown.

View File

@ -28,7 +28,12 @@ def mapping_to_s(ly1, ly2, cm)
ly1.each_cell_top_down do |c| ly1.each_cell_top_down do |c|
s = ly1.cell(c).name s = ly1.cell(c).name
if cm.has_mapping?(c) if cm.has_mapping?(c)
s += "=>" + ly2.cell(cm.cell_mapping(c)).name t = cm.cell_mapping(c)
if t == RBA::CellMapping::DropCell
s += "=>(0)"
else
s += "=>" + ly2.cell(t).name
end
end end
r == "" || (r += ";") r == "" || (r += ";")
r += s r += s
@ -50,6 +55,8 @@ class DBCellMapping_TestClass < TestBase
assert_equal(mp.has_mapping?(1), false) assert_equal(mp.has_mapping?(1), false)
mp.map(1, 2) mp.map(1, 2)
assert_equal(mp.cell_mapping(1), 2) assert_equal(mp.cell_mapping(1), 2)
mp.map(1, 3)
assert_equal(mp.cell_mapping(1), 3)
ly = RBA::Layout::new ly = RBA::Layout::new
@ -170,6 +177,11 @@ class DBCellMapping_TestClass < TestBase
assert_equal(mapping_to_s(ly2, ly1dup, mp), "c0;c2=>c2;c1=>c1;c3=>c3$1") assert_equal(mapping_to_s(ly2, ly1dup, mp), "c0;c2=>c2;c1=>c1;c3=>c3$1")
assert_equal(nc.inspect, "[3]") assert_equal(nc.inspect, "[3]")
mp.clear
mp.from_geometry(ly1, top1, ly2, top2)
mp.map(ci2, RBA::CellMapping::DropCell)
assert_equal(mapping_to_s(ly2, ly1, mp), "c0;c2=>(0);c1=>c1;c3")
end end
end end

View File

@ -50,6 +50,8 @@ class DBLayerMapping_TestClass < TestBase
assert_equal(mp.has_mapping?(1), false) assert_equal(mp.has_mapping?(1), false)
mp.map(1, 2) mp.map(1, 2)
assert_equal(mp.layer_mapping(1), 2) assert_equal(mp.layer_mapping(1), 2)
mp.map(1, 3)
assert_equal(mp.layer_mapping(1), 3)
ly1 = RBA::Layout::new ly1 = RBA::Layout::new