mirror of https://github.com/KLayout/klayout.git
255 lines
8.3 KiB
C++
255 lines
8.3 KiB
C++
|
|
/*
|
|
|
|
KLayout Layout Viewer
|
|
Copyright (C) 2006-2019 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 "dbLayout.h"
|
|
#include "dbPCellHeader.h"
|
|
#include "dbPCellDeclaration.h"
|
|
#include "dbPCellVariant.h"
|
|
#include "dbWriter.h"
|
|
#include "dbReader.h"
|
|
#include "dbLayoutDiff.h"
|
|
#include "dbTestSupport.h"
|
|
#include "tlStream.h"
|
|
#include "tlUnitTest.h"
|
|
|
|
class PD
|
|
: public db::PCellDeclaration
|
|
{
|
|
virtual std::vector<db::PCellLayerDeclaration> get_layer_declarations (const db::pcell_parameters_type &) const
|
|
{
|
|
std::vector<db::PCellLayerDeclaration> layers;
|
|
|
|
layers.push_back(db::PCellLayerDeclaration ());
|
|
layers.back ().symbolic = "gate";
|
|
layers.back ().layer = 16;
|
|
layers.back ().datatype = 0;
|
|
|
|
layers.push_back(db::PCellLayerDeclaration ());
|
|
layers.back ().symbolic = "metal0";
|
|
layers.back ().layer = 24;
|
|
layers.back ().datatype = 0;
|
|
|
|
layers.push_back(db::PCellLayerDeclaration ());
|
|
layers.back ().symbolic = "cont";
|
|
layers.back ().layer = 23;
|
|
layers.back ().datatype = 0;
|
|
|
|
return layers;
|
|
}
|
|
|
|
virtual std::vector<db::PCellParameterDeclaration> get_parameter_declarations () const
|
|
{
|
|
std::vector<db::PCellParameterDeclaration> parameters;
|
|
|
|
parameters.push_back (db::PCellParameterDeclaration ("length"));
|
|
parameters.back ().set_type (db::PCellParameterDeclaration::t_double);
|
|
parameters.push_back (db::PCellParameterDeclaration ("width"));
|
|
parameters.back ().set_type (db::PCellParameterDeclaration::t_double);
|
|
parameters.push_back (db::PCellParameterDeclaration ("orientation"));
|
|
parameters.back ().set_type (db::PCellParameterDeclaration::t_int);
|
|
|
|
return parameters;
|
|
}
|
|
|
|
virtual void produce (const db::Layout &layout, const std::vector<unsigned int> &layer_ids, const db::pcell_parameters_type ¶meters, db::Cell &cell) const
|
|
{
|
|
db::Coord width = db::coord_traits<db::Coord>::rounded (parameters[0].to_double () / layout.dbu ());
|
|
db::Coord height = db::coord_traits<db::Coord>::rounded (parameters[1].to_double () / layout.dbu ());
|
|
|
|
int orientation = parameters[2].to_long ();
|
|
|
|
//unsigned int l_gate = layer_ids[0];
|
|
unsigned int l_metal0 = layer_ids[1];
|
|
//unsigned int l_cont = layer_ids[2];
|
|
|
|
const db::Cell &cell_a = layout.cell (layout.cell_by_name ("A").second);
|
|
|
|
cell.insert (db::CellInstArray (db::CellInst (cell_a.cell_index ()), db::Trans (orientation, db::Vector (width / 2 - 50, height / 2 - 100))));
|
|
|
|
cell.shapes (l_metal0).insert (db::Box (0, 0, width, height));
|
|
}
|
|
};
|
|
|
|
TEST(0)
|
|
{
|
|
db::Manager m;
|
|
db::Layout layout(&m);
|
|
layout.dbu (0.001);
|
|
db::Layout layout_au(&m);
|
|
layout_au.dbu (0.001);
|
|
|
|
// Note: this sample requires the BASIC lib
|
|
|
|
{
|
|
std::string fn (tl::testsrc ());
|
|
fn += "/testdata/gds/pcell_test_0.gds";
|
|
tl::InputStream stream (fn);
|
|
db::Reader reader (stream);
|
|
reader.read (layout);
|
|
}
|
|
|
|
CHECKPOINT ();
|
|
db::compare_layouts (_this, layout, tl::testsrc () + "/testdata/gds/pcell_test_0_au.gds", db::NoNormalization);
|
|
}
|
|
|
|
TEST(1)
|
|
{
|
|
db::Manager m;
|
|
db::Layout layout(&m);
|
|
layout.dbu (0.001);
|
|
|
|
db::LayerProperties p;
|
|
|
|
p.layer = 23;
|
|
p.datatype = 0;
|
|
unsigned int l_cont = layout.insert_layer (p);
|
|
|
|
p.layer = 16;
|
|
p.datatype = 0;
|
|
unsigned int l_gate = layout.insert_layer (p);
|
|
|
|
db::Cell &cell_a = layout.cell (layout.add_cell ("A"));
|
|
cell_a.shapes(l_cont).insert(db::Box (50, 50, 150, 150));
|
|
cell_a.shapes(l_gate).insert(db::Box (0, 0, 200, 1000));
|
|
|
|
db::Cell &top = layout.cell (layout.add_cell ("TOP"));
|
|
|
|
db::pcell_id_type pd = layout.register_pcell ("PD", new PD ());
|
|
|
|
std::vector<tl::Variant> parameters;
|
|
parameters.push_back (tl::Variant ());
|
|
parameters.push_back (tl::Variant ());
|
|
parameters.push_back (tl::Variant ());
|
|
tl::Variant &width = parameters[0];
|
|
tl::Variant &height = parameters[1];
|
|
tl::Variant &orientation = parameters[2];
|
|
|
|
width = 0.5;
|
|
height = 1.0;
|
|
orientation = long (0);
|
|
|
|
db::cell_index_type pd1 = layout.get_pcell_variant (pd, parameters);
|
|
db::Instance i1 = top.insert (db::CellInstArray (db::CellInst (pd1), db::Trans (db::Vector (0, 0))));
|
|
|
|
width = width.to_double () * 0.1;
|
|
width = width.to_double () * 10.0;
|
|
|
|
db::cell_index_type pd2 = layout.get_pcell_variant (pd, parameters);
|
|
db::Instance i2 = top.insert (db::CellInstArray (db::CellInst (pd2), db::Trans (db::Vector (0, 2000))));
|
|
|
|
EXPECT_EQ (pd1, pd2);
|
|
|
|
width = 0.4;
|
|
height = 0.8;
|
|
orientation = long (1);
|
|
|
|
db::cell_index_type pd3 = layout.get_pcell_variant (pd, parameters);
|
|
db::Instance i3 = top.insert (db::CellInstArray (db::CellInst (pd3), db::Trans (db::Vector (2000, 0))));
|
|
|
|
EXPECT_NE (pd2, pd3);
|
|
|
|
EXPECT_EQ (layout.get_properties(0).to_string (), "23/0");
|
|
EXPECT_EQ (layout.get_properties(1).to_string (), "16/0");
|
|
EXPECT_EQ (layout.get_properties(2).to_string (), "24/0");
|
|
|
|
CHECKPOINT ();
|
|
db::compare_layouts (_this, layout, tl::testsrc () + "/testdata/gds/pcell_test.gds", db::NoNormalization);
|
|
|
|
// if not in editable mode, we could have lost the reference to the second instance
|
|
if (db::default_editable_mode ()) {
|
|
|
|
m.transaction ("x");
|
|
|
|
i2 = top.change_pcell_parameters (i2, parameters);
|
|
EXPECT_EQ (i2.cell_index (), pd3);
|
|
EXPECT_NE (i2.cell_index (), pd1);
|
|
|
|
CHECKPOINT ();
|
|
db::compare_layouts (_this, layout, tl::testsrc () + "/testdata/gds/pcell_test2.gds", db::NoNormalization);
|
|
|
|
width = 1.0;
|
|
i1 = top.change_pcell_parameters (i1, parameters);
|
|
EXPECT_NE (i1.cell_index (), pd3);
|
|
EXPECT_NE (i1.cell_index (), pd1);
|
|
|
|
CHECKPOINT ();
|
|
db::compare_layouts (_this, layout, tl::testsrc () + "/testdata/gds/pcell_test3.gds", db::WriteGDS2);
|
|
CHECKPOINT ();
|
|
db::compare_layouts (_this, layout, tl::testsrc () + "/testdata/gds/pcell_test3.gds", db::WriteOAS);
|
|
|
|
m.commit ();
|
|
|
|
m.undo ();
|
|
|
|
CHECKPOINT ();
|
|
db::compare_layouts (_this, layout, tl::testsrc () + "/testdata/gds/pcell_test.gds", db::NoNormalization);
|
|
|
|
m.redo ();
|
|
|
|
CHECKPOINT ();
|
|
db::compare_layouts (_this, layout, tl::testsrc () + "/testdata/gds/pcell_test3.gds", db::WriteGDS2);
|
|
CHECKPOINT ();
|
|
db::compare_layouts (_this, layout, tl::testsrc () + "/testdata/gds/pcell_test3.gds", db::WriteOAS);
|
|
|
|
m.undo (); // test the ability to destroy things stored in the transaction
|
|
|
|
CHECKPOINT ();
|
|
db::compare_layouts (_this, layout, tl::testsrc () + "/testdata/gds/pcell_test.gds", db::NoNormalization);
|
|
|
|
// Test the ability to copy things and change PCell parameters then
|
|
db::Layout copy (layout);
|
|
|
|
CHECKPOINT ();
|
|
db::compare_layouts (_this, copy, tl::testsrc () + "/testdata/gds/pcell_test.gds", db::NoNormalization);
|
|
|
|
db::Cell ©_top = copy.cell (top.cell_index ());
|
|
|
|
db::Instance i1_copy = *(copy_top.begin ());
|
|
const db::PCellVariant *pcv = dynamic_cast<const db::PCellVariant *> (©.cell (i1_copy.cell_index()));
|
|
|
|
EXPECT_EQ (pcv != 0, true);
|
|
EXPECT_EQ (copy_top.is_pcell_instance (i1_copy).first, true);
|
|
|
|
EXPECT_EQ (copy.pcell_by_name ("PD").first, true);
|
|
db::pcell_id_type pd_id_copy = copy.pcell_by_name ("PD").second;
|
|
|
|
EXPECT_EQ (copy_top.is_pcell_instance (i1_copy).second, pd_id_copy);
|
|
|
|
std::vector<tl::Variant> parameters = copy_top.get_pcell_parameters (i1_copy);
|
|
EXPECT_EQ (parameters.size (), size_t (3));
|
|
EXPECT_EQ (std::string (parameters[0].to_string()), "0.4");
|
|
EXPECT_EQ (std::string (parameters[1].to_string()), "0.8");
|
|
EXPECT_EQ (std::string (parameters[2].to_string()), "1");
|
|
|
|
parameters[0] = 1.5;
|
|
i1_copy = copy_top.change_pcell_parameters (i1_copy, parameters);
|
|
|
|
CHECKPOINT ();
|
|
db::compare_layouts (_this, copy, tl::testsrc () + "/testdata/gds/pcell_test4.gds", db::WriteGDS2);
|
|
CHECKPOINT ();
|
|
db::compare_layouts (_this, copy, tl::testsrc () + "/testdata/gds/pcell_test4.gds", db::WriteOAS);
|
|
|
|
}
|
|
}
|
|
|