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)
{
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)
{
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
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
merge_layouts (db::Layout &target,
const db::Layout &source,
@ -135,19 +169,11 @@ merge_layouts (db::Layout &target,
const std::map<unsigned int, unsigned int> &layer_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
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);
}
collect_cells_to_copy (source, source_cells, cell_mapping, all_top_level_cells, all_cells_to_copy);
// identify all new cells and create new ones
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) {
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 ());
}
@ -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);
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
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)
static void
copy_or_move_shapes (db::Layout &target,
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,
bool move)
{
// 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_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);
}
collect_cells_to_copy (source, source_cells, cell_mapping, all_top_level_cells, all_cells_to_copy);
// provide the property mapper
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) {
++progress;
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
move_shapes (db::Layout &target,
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<unsigned int, unsigned int> &layer_mapping)
{
// 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_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 ();
}
}
copy_or_move_shapes (target, source, trans, source_cells, cell_mapping, layer_mapping, true);
}
// ------------------------------------------------------------

View File

@ -32,6 +32,7 @@
#include <map>
#include <vector>
#include <limits>
namespace db
{
@ -110,6 +111,14 @@ private:
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
*

View File

@ -23,6 +23,7 @@
#include "gsiDecl.h"
#include "dbCellMapping.h"
#include "dbLayoutUtils.h"
#include "dbLayout.h"
#include <memory>
@ -30,9 +31,25 @@
namespace gsi
{
static db::cell_index_type drop_cell_const ()
{
return db::DropCell;
}
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,
"@brief Initialize the cell mapping for top-level identity\n"
"@brief Initializes the cell mapping for top-level identity\n"
"\n"
"@args layout_a, cell_index_a, layout_b, cell_index_b\n"
"@param layout_a The target layout.\n"
@ -42,13 +59,15 @@ Class<db::CellMapping> decl_CellMapping ("CellMapping",
"\n"
"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, this method completes the mapping by adding all the child cells "
"of cell_b to layout_a and creating the proper instances. "
"If used for \\Cell#copy_tree or \\Cell#move_tree, this cell mapping will essentially "
"flatten the cell.\n"
"\n"
"This method is equivalent to \\clear, followed by \\map(cell_index_a, cell_index_b).\n"
"\n"
"This method has been introduced in version 0.23."
) +
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"
"@args layout_a, cell_index_a, layout_b, cell_index_b\n"
"@param layout_a The target layout.\n"
@ -58,11 +77,13 @@ Class<db::CellMapping> decl_CellMapping ("CellMapping",
"\n"
"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. "
"\n"
"This method has been introduced in version 0.23."
) +
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"
"@args layout_a, cell_index_a, layout_b, cell_index_b\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."
) +
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"
"@args layout_a, cell_index_a, layout_b, cell_index_b\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."
) +
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"
"@args layout_a, cell_index_a, layout_b, cell_index_b\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."
) +
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"
"@args layout_a, cell_index_a, layout_b, cell_index_b\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."
) +
gsi::method ("map", &db::CellMapping::map,
"@brief Explicitly specify a mapping.\n"
"@brief Explicitly specifies a mapping.\n"
"\n"
"@args cell_index_b, cell_index_a\n"
"\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"
"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"
@ -152,20 +173,25 @@ Class<db::CellMapping> decl_CellMapping ("CellMapping",
"This method has been introduced in version 0.23."
) +
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"
"@args cell_index_b\n"
"\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"
"\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,
"@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"
"@args cell_index_b\n"
"\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"
"\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"
"\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 \
dbLayout.cc \
dbLayoutDiff.cc \
dbLayoutUtils.cc \
dbLayoutQuery.cc \
dbLibraries.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|
s = ly1.cell(c).name
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
r == "" || (r += ";")
r += s
@ -50,6 +55,8 @@ class DBCellMapping_TestClass < TestBase
assert_equal(mp.has_mapping?(1), false)
mp.map(1, 2)
assert_equal(mp.cell_mapping(1), 2)
mp.map(1, 3)
assert_equal(mp.cell_mapping(1), 3)
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(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

View File

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