mirror of https://github.com/KLayout/klayout.git
964 lines
29 KiB
C++
964 lines
29 KiB
C++
|
|
/*
|
|
|
|
KLayout Layout Viewer
|
|
Copyright (C) 2006-2023 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 "dbLayoutDiff.h"
|
|
#include "dbWriter.h"
|
|
#include "dbDEFImporter.h"
|
|
#include "dbLEFImporter.h"
|
|
|
|
#include "tlUnitTest.h"
|
|
#include "dbTestSupport.h"
|
|
|
|
#include <cstdlib>
|
|
|
|
static db::LEFDEFReaderOptions default_options ()
|
|
{
|
|
db::LEFDEFReaderOptions tc;
|
|
tc.set_via_geometry_datatype (0);
|
|
tc.set_via_geometry_suffix ("");
|
|
tc.set_pins_datatype (2);
|
|
tc.set_pins_suffix (".PIN");
|
|
tc.set_obstructions_datatype (3);
|
|
tc.set_obstructions_suffix (".OBS");
|
|
tc.set_routing_datatype (0);
|
|
tc.set_routing_suffix ("");
|
|
tc.set_labels_datatype (1);
|
|
tc.set_labels_suffix (".LABEL");
|
|
tc.set_blockages_datatype (4);
|
|
tc.set_blockages_suffix (".BLK");
|
|
|
|
return tc;
|
|
}
|
|
|
|
static db::LayerMap read (db::Layout &layout, const char *lef_dir, const char *filename, const db::LEFDEFReaderOptions &options, bool priv = true, db::CellConflictResolution cc_mode = db::RenameCell)
|
|
{
|
|
std::string fn_path (priv ? tl::testdata_private () : tl::testdata ());
|
|
fn_path += "/lefdef/";
|
|
fn_path += lef_dir;
|
|
fn_path += "/";
|
|
|
|
tl::Extractor ex (filename);
|
|
|
|
db::LEFDEFReaderState ld (&options, layout, fn_path);
|
|
ld.set_conflict_resolution_mode (cc_mode);
|
|
|
|
db::DEFImporter imp;
|
|
bool any_def = false;
|
|
bool any_lef = false;
|
|
|
|
while (! ex.at_end ()) {
|
|
|
|
if (ex.test ("map:")) {
|
|
|
|
std::string f;
|
|
ex.read_word_or_quoted (f);
|
|
|
|
ld.read_map_file (f, layout, fn_path);
|
|
|
|
} else if (ex.test ("def:")) {
|
|
|
|
std::string fn = fn_path, f;
|
|
ex.read_word_or_quoted (f);
|
|
fn += f;
|
|
|
|
tl::InputStream stream (fn);
|
|
imp.read (stream, layout, ld);
|
|
|
|
any_def = true;
|
|
|
|
} else if (ex.test ("lef:")) {
|
|
|
|
std::string fn = fn_path, f;
|
|
ex.read_word_or_quoted (f);
|
|
fn += f;
|
|
|
|
tl::InputStream stream (fn);
|
|
imp.read_lef (stream, layout, ld);
|
|
|
|
any_lef = true;
|
|
|
|
} else if (ex.test ("gds:")) {
|
|
|
|
std::string fn = fn_path, f;
|
|
ex.read_word_or_quoted (f);
|
|
fn += f;
|
|
|
|
tl::InputStream stream (fn);
|
|
db::Reader reader (stream);
|
|
reader.read (layout, db::LoadLayoutOptions ());
|
|
|
|
} else if (ex.test("read:")) {
|
|
|
|
std::string fn = fn_path, f;
|
|
ex.read_word_or_quoted (f);
|
|
fn += f;
|
|
|
|
tl::InputStream stream (fn);
|
|
db::Reader reader (stream);
|
|
db::LoadLayoutOptions lo;
|
|
lo.set_options (options);
|
|
reader.read (layout, lo);
|
|
|
|
any_def = true;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (! ex.test("+")) {
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if (! any_def && any_lef) {
|
|
imp.finish_lef (layout);
|
|
}
|
|
|
|
ld.finish (layout);
|
|
|
|
return ld.layer_map ();
|
|
}
|
|
|
|
static db::LayerMap run_test (tl::TestBase *_this, const char *lef_dir, const char *filename, const char *au, const db::LEFDEFReaderOptions &options, bool priv = true, db::CellConflictResolution cc_mode = db::RenameCell)
|
|
{
|
|
db::Manager m (false);
|
|
db::Layout layout (&m), layout2 (&m), layout_au (&m);
|
|
|
|
db::LayerMap lm = read (layout, lef_dir, filename, options, priv, cc_mode);
|
|
|
|
// normalize the layout by writing to OASIS and reading from ..
|
|
|
|
// generate a "unique" name ...
|
|
unsigned int hash = 0;
|
|
if (au) {
|
|
for (const char *cp = au; *cp; ++cp) {
|
|
hash = (hash << 4) ^ (hash >> 4) ^ ((unsigned int) *cp);
|
|
}
|
|
}
|
|
|
|
std::string tmp_file = _this->tmp_file (tl::sprintf ("tmp_%x.oas", hash));
|
|
|
|
{
|
|
tl::OutputStream stream (tmp_file);
|
|
db::SaveLayoutOptions options;
|
|
options.set_format ("OASIS");
|
|
options.set_option_by_name ("oasis_permissive", tl::Variant (true));
|
|
db::Writer writer (options);
|
|
writer.write (layout, stream);
|
|
}
|
|
|
|
{
|
|
tl::InputStream stream (tmp_file);
|
|
db::Reader reader (stream);
|
|
reader.read (layout2);
|
|
}
|
|
|
|
if (au) {
|
|
|
|
std::string fn (priv ? tl::testdata_private () : tl::testdata ());
|
|
fn += "/lefdef/";
|
|
fn += lef_dir;
|
|
fn += "/";
|
|
fn += au;
|
|
|
|
try {
|
|
tl::InputStream stream (fn);
|
|
db::Reader reader (stream);
|
|
reader.read (layout_au);
|
|
} catch (...) {
|
|
_this->raise (tl::sprintf ("Compare failed - see %s vs %s (not existing or not readable)\n", tmp_file, fn));
|
|
throw;
|
|
}
|
|
|
|
bool equal = db::compare_layouts (layout2, layout_au, db::layout_diff::f_verbose | db::layout_diff::f_flatten_array_insts, 0);
|
|
if (! equal) {
|
|
_this->raise (tl::sprintf ("Compare failed - see %s vs %s\n", tmp_file, fn));
|
|
}
|
|
|
|
} else {
|
|
|
|
bool equal = db::compare_layouts (layout2, layout_au, db::layout_diff::f_verbose | db::layout_diff::f_flatten_array_insts, 0);
|
|
if (! equal) {
|
|
_this->raise (tl::sprintf ("Compare failed - see %s vs empty file\n", tmp_file));
|
|
}
|
|
|
|
}
|
|
|
|
return lm;
|
|
}
|
|
|
|
static void run_test2 (tl::TestBase *_this, const char *lef_dir, const char *filename, const char *filename2, const char *au, const db::LEFDEFReaderOptions &options, bool priv = true, db::CellConflictResolution cc_mode = db::RenameCell)
|
|
{
|
|
db::Manager m (false);
|
|
db::Layout layout (&m), layout2 (&m), layout_au (&m);
|
|
|
|
read (layout, lef_dir, filename, options, priv, cc_mode);
|
|
read (layout, lef_dir, filename2, options, priv, cc_mode);
|
|
|
|
// normalize the layout by writing to OASIS and reading from ..
|
|
|
|
// generate a "unique" name ...
|
|
unsigned int hash = 0;
|
|
if (au) {
|
|
for (const char *cp = au; *cp; ++cp) {
|
|
hash = (hash << 4) ^ (hash >> 4) ^ ((unsigned int) *cp);
|
|
}
|
|
}
|
|
|
|
std::string tmp_file = _this->tmp_file (tl::sprintf ("tmp_%x.oas", hash));
|
|
|
|
{
|
|
tl::OutputStream stream (tmp_file);
|
|
db::SaveLayoutOptions options;
|
|
options.set_format ("OASIS");
|
|
options.set_option_by_name ("oasis_permissive", tl::Variant (true));
|
|
db::Writer writer (options);
|
|
writer.write (layout, stream);
|
|
}
|
|
|
|
{
|
|
tl::InputStream stream (tmp_file);
|
|
db::Reader reader (stream);
|
|
reader.read (layout2);
|
|
}
|
|
|
|
if (au) {
|
|
|
|
std::string fn (priv ? tl::testdata_private () : tl::testdata ());
|
|
fn += "/lefdef/";
|
|
fn += lef_dir;
|
|
fn += "/";
|
|
fn += au;
|
|
|
|
try {
|
|
tl::InputStream stream (fn);
|
|
db::Reader reader (stream);
|
|
reader.read (layout_au);
|
|
} catch (...) {
|
|
_this->raise (tl::sprintf ("Compare failed - see %s vs %s (not existing or not readable)\n", tmp_file, fn));
|
|
throw;
|
|
}
|
|
|
|
bool equal = db::compare_layouts (layout2, layout_au, db::layout_diff::f_verbose | db::layout_diff::f_flatten_array_insts, 0);
|
|
if (! equal) {
|
|
_this->raise (tl::sprintf ("Compare failed - see %s vs %s\n", tmp_file, fn));
|
|
}
|
|
|
|
} else {
|
|
|
|
bool equal = db::compare_layouts (layout2, layout_au, db::layout_diff::f_verbose | db::layout_diff::f_flatten_array_insts, 0);
|
|
if (! equal) {
|
|
_this->raise (tl::sprintf ("Compare failed - see %s vs empty file\n", tmp_file));
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
TEST(lef1)
|
|
{
|
|
run_test (_this, "lef1", "lef:in.lef", 0, default_options ());
|
|
}
|
|
|
|
TEST(lef2)
|
|
{
|
|
// Also tests ability of plugin to properly read LEF
|
|
run_test (_this, "lef2", "read:in.lef", "au.oas.gz", default_options ());
|
|
}
|
|
|
|
TEST(lef3)
|
|
{
|
|
db::LEFDEFReaderOptions options = default_options ();
|
|
options.set_cell_outline_layer ("OUTLINE (2/0)");
|
|
run_test (_this, "lef3", "lef:in.lef", "au.oas.gz", options);
|
|
}
|
|
|
|
TEST(lef4)
|
|
{
|
|
run_test (_this, "lef4", "lef:in.lef", 0, default_options ());
|
|
}
|
|
|
|
TEST(lef5)
|
|
{
|
|
run_test (_this, "lef5", "lef:in.lef", 0, default_options ());
|
|
}
|
|
|
|
TEST(lef6)
|
|
{
|
|
run_test (_this, "lef6", "lef:in.lef", 0, default_options ());
|
|
}
|
|
|
|
TEST(lef7)
|
|
{
|
|
db::LEFDEFReaderOptions options = default_options ();
|
|
options.set_cell_outline_layer ("OUTLINE (8/0)");
|
|
run_test (_this, "lef7", "lef:in_tech.lef+lef:in.lef", "au.oas.gz", options);
|
|
}
|
|
|
|
TEST(def1)
|
|
{
|
|
run_test (_this, "def1", "lef:in.lef+def:in.def", "au2.oas.gz", default_options ());
|
|
}
|
|
|
|
TEST(def2)
|
|
{
|
|
db::LEFDEFReaderOptions options = default_options ();
|
|
options.set_cell_outline_layer ("OUTLINE (10/0)");
|
|
run_test (_this, "def2", "lef:0.lef+lef:1.lef+def:in.def.gz", "au.oas.gz", options);
|
|
}
|
|
|
|
TEST(def3)
|
|
{
|
|
db::LEFDEFReaderOptions options = default_options ();
|
|
options.set_cell_outline_layer ("OUTLINE (13/0)");
|
|
run_test (_this, "def3", "lef:in.lef+def:in.def", "au.oas.gz", options);
|
|
}
|
|
|
|
TEST(def4)
|
|
{
|
|
run_test (_this, "def4", "lef:in.lef+def:in.def", "au2.oas.gz", default_options ());
|
|
}
|
|
|
|
TEST(def5)
|
|
{
|
|
run_test (_this, "def5", "lef:in.lef+def:in.def", "au.oas.gz", default_options ());
|
|
}
|
|
|
|
TEST(def6)
|
|
{
|
|
run_test (_this, "def6", "lef:cells.lef+lef:tech.lef+def:in.def.gz", "au-new.oas.gz", default_options ());
|
|
}
|
|
|
|
TEST(def7)
|
|
{
|
|
db::LEFDEFReaderOptions options = default_options ();
|
|
options.set_placement_blockage_layer ("PLACEMENT_BLK (11/0)");
|
|
run_test (_this, "def7", "lef:cells.lef+lef:tech.lef+def:in.def.gz", "au-new.oas.gz", options);
|
|
|
|
options.set_placement_blockage_layer ("PLACEMENT_BLK (60/0)");
|
|
run_test (_this, "def7", "map:in.map+lef:cells.lef+lef:tech.lef+def:in.def.gz", "au2_with_map_file-new.oas.gz", options);
|
|
}
|
|
|
|
TEST(def8)
|
|
{
|
|
run_test (_this, "def8", "lef:tech.lef+def:in.def", "au.oas.gz", default_options ());
|
|
}
|
|
|
|
TEST(def9)
|
|
{
|
|
db::LEFDEFReaderOptions options = default_options ();
|
|
options.set_separate_groups (true);
|
|
run_test (_this, "def9", "lef:tech.lef+lef:cells_modified.lef+def:in.def", "au-new.oas.gz", options);
|
|
|
|
run_test (_this, "def9", "lef:tech.lef+lef:cells_modified.lef+def:in.def", "au_nogroups-new.oas.gz", default_options ());
|
|
}
|
|
|
|
TEST(def10)
|
|
{
|
|
db::LEFDEFReaderOptions opt = default_options ();
|
|
opt.set_cell_outline_layer ("OUTLINE (2/0)");
|
|
run_test (_this, "def10", "def:in.def", "au.oas.gz", opt);
|
|
}
|
|
|
|
TEST(def11)
|
|
{
|
|
db::LEFDEFReaderOptions opt = default_options ();
|
|
opt.set_cell_outline_layer ("OUTLINE (12/0)");
|
|
run_test (_this, "def11", "lef:test.lef+def:test.def", "au.oas.gz", opt);
|
|
}
|
|
|
|
TEST(def12)
|
|
{
|
|
db::LEFDEFReaderOptions opt = default_options ();
|
|
opt.set_cell_outline_layer ("OUTLINE (20/0)");
|
|
run_test (_this, "def12", "lef:test.lef+def:test.def", "au-new.oas.gz", opt);
|
|
}
|
|
|
|
TEST(def13)
|
|
{
|
|
db::LEFDEFReaderOptions opt = default_options ();
|
|
run_test (_this, "def13", "map:test.map+lef:test.lef_5.8+def:top.def.gz", "au2.oas.gz", opt);
|
|
}
|
|
|
|
TEST(def14)
|
|
{
|
|
db::LEFDEFReaderOptions opt = default_options ();
|
|
opt.set_macro_resolution_mode (1);
|
|
run_test (_this, "def14", "map:test.map+lef:tech.lef+lef:stdlib.lef+def:test.def", "au.oas.gz", opt);
|
|
}
|
|
|
|
TEST(def15)
|
|
{
|
|
db::LEFDEFReaderOptions opt = default_options ();
|
|
opt.set_macro_resolution_mode (1);
|
|
run_test (_this, "def15", "map:test.map+lef:tech.lef+def:test.def", "au2.oas.gz", opt);
|
|
}
|
|
|
|
TEST(def16)
|
|
{
|
|
db::LEFDEFReaderOptions opt = default_options ();
|
|
opt.set_macro_resolution_mode (1);
|
|
run_test (_this, "def16", "lef:a.lef+def:a.def", "au.oas.gz", opt);
|
|
}
|
|
|
|
TEST(100)
|
|
{
|
|
run_test (_this, "issue-172", "lef:in.lef+def:in.def", "au.oas.gz", default_options (), false);
|
|
}
|
|
|
|
TEST(101)
|
|
{
|
|
db::LEFDEFReaderOptions opt = default_options ();
|
|
opt.set_produce_pin_names (true);
|
|
opt.set_pin_property_name (2);
|
|
opt.set_cell_outline_layer ("OUTLINE (13/0)");
|
|
run_test (_this, "issue-489", "lef:in.lef+def:in.def", "au.oas", opt, false);
|
|
}
|
|
|
|
TEST(102)
|
|
{
|
|
db::LEFDEFReaderOptions opt = default_options ();
|
|
opt.set_produce_pin_names (true);
|
|
opt.set_pin_property_name (3);
|
|
opt.set_cell_outline_layer ("OUTLINE (8/0)");
|
|
run_test (_this, "issue-489b", "lef:in_tech.lef+lef:in.lef", "au.oas.gz", opt, false);
|
|
}
|
|
|
|
TEST(103)
|
|
{
|
|
db::LEFDEFReaderOptions options = default_options ();
|
|
options.set_cell_outline_layer ("OUTLINE (4/0)");
|
|
run_test (_this, "issue-517", "def:in.def", "au.oas.gz", options, false);
|
|
}
|
|
|
|
TEST(104_doxy_vias)
|
|
{
|
|
db::LEFDEFReaderOptions options = default_options ();
|
|
options.set_cell_outline_layer ("OUTLINE (4/0)");
|
|
run_test (_this, "doxy_vias", "def:test.def", "au.oas.gz", options, false);
|
|
}
|
|
|
|
TEST(105_specialnets_geo)
|
|
{
|
|
run_test (_this, "specialnets_geo", "lef:test.lef+def:test.def", "au.oas.gz", default_options (), false);
|
|
|
|
db::LEFDEFReaderOptions options = default_options ();
|
|
options.set_produce_special_routing (false);
|
|
run_test (_this, "specialnets_geo", "lef:test.lef+def:test.def", "au_no_spnet.oas.gz", options, false);
|
|
|
|
options.set_produce_special_routing (true);
|
|
options.set_special_routing_datatype (10);
|
|
options.set_special_routing_suffix (".SPNET");
|
|
|
|
options.set_via_geometry_datatype (11);
|
|
options.set_via_geometry_suffix (".VIA");
|
|
|
|
run_test (_this, "specialnets_geo", "lef:test.lef+def:test.def", "au_spnet_mapped.oas.gz", options, false);
|
|
}
|
|
|
|
TEST(106_wrongdirection)
|
|
{
|
|
run_test (_this, "wrongdirection", "lef:test.lef+def:test.def", "au.oas.gz", default_options (), false);
|
|
}
|
|
|
|
TEST(107_specialwidths)
|
|
{
|
|
run_test (_this, "specialwidths", "lef:test.lef+def:test.def", "au.oas.gz", default_options (), false);
|
|
}
|
|
|
|
TEST(108_scanchain)
|
|
{
|
|
run_test (_this, "scanchain", "def:test.def", "au.oas.gz", default_options (), false);
|
|
}
|
|
|
|
TEST(109_foreigncell)
|
|
{
|
|
db::LEFDEFReaderOptions options = default_options ();
|
|
options.set_cell_outline_layer ("OUTLINE (43/0)");
|
|
|
|
run_test (_this, "foreigncell", "gds:foreign.gds+lef:in_tech.lef+lef:in.lef+def:in.def", "au.oas.gz", options, false);
|
|
|
|
run_test (_this, "foreigncell", "gds:foreign.gds+lef:in_tech.lef+lef:in2.lef+def:in.def", "au_default.oas.gz", options, false);
|
|
|
|
options.set_macro_resolution_mode (1);
|
|
|
|
run_test (_this, "foreigncell", "gds:foreign.gds+lef:in_tech.lef+lef:in2.lef+def:in.def", "au_ignore_foreign.oas.gz", options, false);
|
|
|
|
options.set_macro_resolution_mode (2);
|
|
|
|
run_test (_this, "foreigncell", "gds:foreign.gds+lef:in_tech.lef+lef:in.lef+def:in.def", "au_always_foreign.oas.gz", options, false);
|
|
}
|
|
|
|
TEST(110_lefpins)
|
|
{
|
|
db::LEFDEFReaderOptions options = default_options ();
|
|
options.set_produce_lef_pins (false);
|
|
options.set_cell_outline_layer ("OUTLINE (8/0)");
|
|
run_test (_this, "lefpins", "lef:in_tech.lef+lef:in.lef+def:in.def", "au_no_lefpins.oas.gz", options, false);
|
|
|
|
options.set_produce_lef_pins (true);
|
|
options.set_lef_pins_datatype (10);
|
|
options.set_lef_pins_suffix (".LEFPIN");
|
|
|
|
run_test (_this, "lefpins", "lef:in_tech.lef+lef:in.lef+def:in.def", "au_lefpins_mapped.oas.gz", options, false);
|
|
}
|
|
|
|
TEST(111_mapfile)
|
|
{
|
|
db::LEFDEFReaderOptions options = default_options ();
|
|
options.set_map_file ("test.map");
|
|
|
|
run_test (_this, "mapfile", "read:in.def", "au.oas.gz", options, false);
|
|
}
|
|
|
|
TEST(112_via_properties)
|
|
{
|
|
db::LEFDEFReaderOptions options = default_options ();
|
|
db::LayerMap lm = db::LayerMap::from_string_file_format ("metal1: 1\nvia1: 2\nmetal2: 3");
|
|
options.set_layer_map (lm);
|
|
|
|
db::LayerMap lm_read = run_test (_this, "via_properties", "lef:in.lef+def:in.def", "au.oas.gz", options, false);
|
|
EXPECT_EQ (lm_read.to_string (),
|
|
"layer_map('OUTLINE : OUTLINE (4/0)';'metal1.VIA : metal1 (1/0)';'metal2.VIA : metal2 (3/0)';'via1.VIA : via1 (2/0)')"
|
|
)
|
|
}
|
|
|
|
TEST(113_masks_1)
|
|
{
|
|
db::LEFDEFReaderOptions options = default_options ();
|
|
options.set_routing_suffix ("");
|
|
options.set_routing_datatype_per_mask (1, 100);
|
|
options.set_routing_datatype_per_mask (2, 200);
|
|
options.set_special_routing_suffix ("");
|
|
options.set_special_routing_datatype_per_mask (1, 101);
|
|
options.set_special_routing_datatype_per_mask (2, 201);
|
|
options.set_via_geometry_suffix ("");
|
|
options.set_via_geometry_datatype_per_mask (1, 102);
|
|
options.set_via_geometry_datatype_per_mask (2, 202);
|
|
options.set_pins_suffix ("");
|
|
options.set_pins_datatype_per_mask (1, 110);
|
|
options.set_pins_datatype_per_mask (2, 210);
|
|
options.set_cell_outline_layer ("OUTLINE (4/0)");
|
|
|
|
db::LayerMap lm = db::LayerMap::from_string_file_format ("M1: 3\nM0PO: 1\nVIA0: 2");
|
|
options.set_layer_map (lm);
|
|
|
|
db::LayerMap lm_read = run_test (_this, "masks-1", "lef:in_tech.lef+def:in.def", "au.oas.gz", options, false);
|
|
|
|
EXPECT_EQ (lm_read.to_string_file_format (),
|
|
"OUTLINE : OUTLINE (4/0)\n"
|
|
"'M0PO.SPNET:1' : M0PO (1/101)\n"
|
|
"'M1.SPNET:2' : M1 (3/201)\n"
|
|
"'M1.SPNET:1' : M1 (3/101)\n"
|
|
"'M0PO.VIA:2' : M0PO (1/202)\n"
|
|
"'M1.VIA:1' : M1 (3/102)\n"
|
|
"'VIA0.VIA:1' : VIA0 (2/102)\n"
|
|
"'M0PO.SPNET:2' : M0PO (1/201)\n"
|
|
"M0PO.PIN : M0PO (1/2)\n"
|
|
"M0PO.LABEL : M0PO.LABEL (1/1)\n"
|
|
"'M0PO.PIN:2' : M0PO (1/210)\n"
|
|
"'M1.PIN:1' : M1 (3/110)\n"
|
|
"M1.LABEL : M1.LABEL (3/1)\n"
|
|
"'M1.NET:1' : M1 (3/100)\n"
|
|
"'M1.NET:2' : M1 (3/200)\n"
|
|
"'M0PO.VIA:1' : M0PO (1/102)\n"
|
|
"'M1.VIA:2' : M1 (3/202)\n"
|
|
"'VIA0.VIA:2' : VIA0 (2/202)\n"
|
|
"'M0PO.NET:1' : M0PO (1/100)\n"
|
|
)
|
|
|
|
options = default_options ();
|
|
lm_read = run_test (_this, "masks-1", "map:in.map+lef:in_tech.lef+def:in.def", "au_map.oas.gz", options, false);
|
|
|
|
EXPECT_EQ (lm_read.to_string_file_format (),
|
|
"OUTLINE : OUTLINE (4/0)\n"
|
|
"'M0PO.NET:1' : 'M0PO.NET:1' (1/100)\n"
|
|
"'M0PO.NET:2' : 'M0PO.NET:2' (1/200)\n"
|
|
"M0PO.PIN : M0PO.PIN (1/2)\n"
|
|
"'M0PO.PIN:1' : 'M0PO.PIN:1' (1/110)\n"
|
|
"'M0PO.PIN:2' : 'M0PO.PIN:2' (1/210)\n"
|
|
"'M0PO.SPNET:1' : 'M0PO.SPNET:1' (1/101)\n"
|
|
"'M0PO.SPNET:2' : 'M0PO.SPNET:2' (1/201)\n"
|
|
"'M0PO.VIA:1' : 'M0PO.VIA:1' (1/102)\n"
|
|
"'M0PO.VIA:2' : 'M0PO.VIA:2' (1/202)\n"
|
|
"M0PO.LABEL;M0PO.LEFLABEL : 'M0PO.LABEL/M0PO.LEFLABEL' (1/1)\n"
|
|
"'M1.NET:1' : 'M1.NET:1' (3/100)\n"
|
|
"'M1.NET:2' : 'M1.NET:2' (3/200)\n"
|
|
"M1.PIN : M1.PIN (3/2)\n"
|
|
"'M1.PIN:1' : 'M1.PIN:1' (3/110)\n"
|
|
"'M1.PIN:2' : 'M1.PIN:2' (3/210)\n"
|
|
"'M1.SPNET:1' : 'M1.SPNET:1' (3/101)\n"
|
|
"'M1.SPNET:2' : 'M1.SPNET:2' (3/201)\n"
|
|
"'M1.VIA:1' : 'M1.VIA:1' (3/102)\n"
|
|
"'M1.VIA:2' : 'M1.VIA:2' (3/202)\n"
|
|
"M1.LABEL;M1.LEFLABEL : 'M1.LABEL/M1.LEFLABEL' (3/1)\n"
|
|
"'VIA0.NET:1' : 'VIA0.NET:1' (2/100)\n"
|
|
"'VIA0.NET:2' : 'VIA0.NET:2' (2/200)\n"
|
|
"VIA0.PIN : VIA0.PIN (2/2)\n"
|
|
"'VIA0.PIN:1' : 'VIA0.PIN:1' (2/110)\n"
|
|
"'VIA0.PIN:2' : 'VIA0.PIN:2' (2/210)\n"
|
|
"'VIA0.SPNET:1' : 'VIA0.SPNET:1' (2/101)\n"
|
|
"'VIA0.SPNET:2' : 'VIA0.SPNET:2' (2/201)\n"
|
|
"'VIA0.VIA:1' : 'VIA0.VIA:1' (2/102)\n"
|
|
"'VIA0.VIA:2' : 'VIA0.VIA:2' (2/202)\n"
|
|
"VIA0.LABEL;VIA0.LEFLABEL : 'VIA0.LABEL/VIA0.LEFLABEL' (2/1)\n"
|
|
)
|
|
}
|
|
|
|
TEST(114_lef_skips_end_library)
|
|
{
|
|
db::LEFDEFReaderOptions opt = default_options ();
|
|
opt.set_produce_pin_names (true);
|
|
opt.set_pin_property_name (2);
|
|
opt.set_cell_outline_layer ("OUTLINE (13/0)");
|
|
run_test (_this, "lef-skips-end-library", "lef:in.lef+def:in.def", "au.oas", opt, false);
|
|
}
|
|
|
|
TEST(115_componentmaskshift)
|
|
{
|
|
db::LEFDEFReaderOptions options = default_options ();
|
|
options.set_map_file ("in.map");
|
|
|
|
run_test (_this, "masks-2", "lef:in_tech.lef+lef:in.lef+def:in.def", "au.oas.gz", options, false);
|
|
}
|
|
|
|
TEST(116_layer_mapping)
|
|
{
|
|
db::LEFDEFReaderOptions options = default_options ();
|
|
db::LayerMap lm = db::LayerMap::from_string_file_format ("metal1: 1\nvia1: 2\nmetal2: 3\nOUTLINE: 42/17");
|
|
options.set_layer_map (lm);
|
|
|
|
{
|
|
db::Layout layout;
|
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
|
EXPECT_EQ (lm_read.to_string (),
|
|
"layer_map('OUTLINE : OUTLINE (42/17)';'metal1.VIA : metal1 (1/0)';'metal2.VIA : metal2 (3/0)';'via1.VIA : via1 (2/0)')"
|
|
)
|
|
}
|
|
|
|
options.set_layer_map (db::LayerMap ());
|
|
|
|
{
|
|
db::Layout layout;
|
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
|
EXPECT_EQ (lm_read.to_string (),
|
|
"layer_map('OUTLINE : OUTLINE (4/0)';'metal1.VIA : metal1 (1/0)';'metal2.VIA : metal2 (3/0)';'via1.VIA : via1 (2/0)')"
|
|
)
|
|
}
|
|
|
|
lm = db::LayerMap::from_string_file_format ("metal1: M1\nmetal1.V: M1_V\nvia1: V1\nmetal2: M2\nOUTLINE: OUTL");
|
|
options.set_layer_map (lm);
|
|
options.set_via_geometry_suffix ("V");
|
|
options.set_via_geometry_datatype (42);
|
|
|
|
{
|
|
db::Layout layout;
|
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
|
EXPECT_EQ (lm_read.to_string (),
|
|
"layer_map('OUTLINE : OUTL (4/0)';'metal1.VIA : M1V (1/42)';'metal2.VIA : M2V (3/42)';'via1.VIA : V1V (2/42)')"
|
|
)
|
|
}
|
|
|
|
lm = db::LayerMap::from_string_file_format ("metal1: M1\nmetal1.V: M1_V\nvia1: V1\nmetal2: M2");
|
|
options.set_layer_map (lm);
|
|
options.set_via_geometry_suffix ("V");
|
|
options.set_via_geometry_datatype (42);
|
|
options.set_read_all_layers (false);
|
|
|
|
{
|
|
db::Layout layout;
|
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
|
EXPECT_EQ (lm_read.to_string (),
|
|
"layer_map('metal1.VIA : M1V (1/42)';'metal2.VIA : M2V (3/42)';'via1.VIA : V1V (2/42)')"
|
|
)
|
|
}
|
|
|
|
lm = db::LayerMap::from_string_file_format ("metal2: M2 (17/1)");
|
|
options.set_layer_map (lm);
|
|
|
|
{
|
|
db::Layout layout;
|
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
|
EXPECT_EQ (lm_read.to_string (),
|
|
"layer_map('metal2.VIA : M2V (17/43)')"
|
|
)
|
|
}
|
|
|
|
options.set_produce_via_geometry (false);
|
|
|
|
{
|
|
db::Layout layout;
|
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
|
EXPECT_EQ (lm_read.to_string (),
|
|
"layer_map()"
|
|
)
|
|
}
|
|
|
|
options.set_produce_via_geometry (true);
|
|
options.set_via_geometry_suffix (".V");
|
|
lm = db::LayerMap::from_string_file_format ("metal2.V: 17/1");
|
|
options.set_layer_map (lm);
|
|
|
|
{
|
|
db::Layout layout;
|
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
|
EXPECT_EQ (lm_read.to_string (),
|
|
"layer_map('metal2.VIA : metal2.V (17/1)')"
|
|
)
|
|
}
|
|
|
|
lm = db::LayerMap::from_string_file_format ("metal2.V: m2v (17/5)");
|
|
options.set_layer_map (lm);
|
|
|
|
{
|
|
db::Layout layout;
|
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
|
EXPECT_EQ (lm_read.to_string (),
|
|
"layer_map('metal2.VIA : m2v (17/5)')"
|
|
)
|
|
}
|
|
|
|
lm = db::LayerMap::from_string_file_format ("OUTLINE: OUTL");
|
|
options.set_layer_map (lm);
|
|
options.set_cell_outline_layer ("OUTLINE (42/17)");
|
|
|
|
{
|
|
db::Layout layout;
|
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
|
EXPECT_EQ (lm_read.to_string (),
|
|
"layer_map('OUTLINE : OUTL (42/17)')"
|
|
)
|
|
}
|
|
|
|
lm = db::LayerMap::from_string_file_format ("OUTLINE: OUTL (18/1)");
|
|
options.set_layer_map (lm);
|
|
options.set_cell_outline_layer ("OUTLINE (42/17)");
|
|
|
|
{
|
|
db::Layout layout;
|
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
|
EXPECT_EQ (lm_read.to_string (),
|
|
"layer_map('OUTLINE : OUTL (18/1)')"
|
|
)
|
|
}
|
|
|
|
options.set_cell_outline_layer ("OUTLINE (42/17)");
|
|
lm = db::LayerMap::from_string_file_format ("42/17: OUTL (18/1)");
|
|
options.set_layer_map (lm);
|
|
|
|
{
|
|
db::Layout layout;
|
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
|
EXPECT_EQ (lm_read.to_string (),
|
|
"layer_map('OUTLINE : OUTL (18/1)')"
|
|
)
|
|
}
|
|
|
|
options.set_cell_outline_layer ("42/17");
|
|
lm = db::LayerMap::from_string_file_format ("42/17: 18/1");
|
|
options.set_layer_map (lm);
|
|
|
|
{
|
|
db::Layout layout;
|
|
db::LayerMap lm_read = read (layout, "via_properties", "lef:in.lef+def:in.def", options, false);
|
|
EXPECT_EQ (lm_read.to_string (),
|
|
"layer_map('OUTLINE : OUTLINE (18/1)')"
|
|
)
|
|
}
|
|
}
|
|
|
|
TEST(117_mapfile_all)
|
|
{
|
|
db::LEFDEFReaderOptions options = default_options ();
|
|
|
|
db::Layout layout;
|
|
db::LayerMap lm_read = read (layout, "mapfile", "lef:in.lef+def:in.def+map:all.map", options, false);
|
|
EXPECT_EQ (lm_read.to_string (),
|
|
"layer_map("
|
|
"'OUTLINE : OUTLINE (1/0)';"
|
|
"'+M1.LEFOBS;M1.LEFPIN;M1.NET;M1.PIN;M1.SPNET;M1.VIA : \\'M1.NET/PIN/SPNET/...\\' (1/5)';"
|
|
"'+M1.NET;M1.SPNET : \\'M1.NET/SPNET\\' (16/0)';"
|
|
"'+M1.NET : M1.NET (18/0)';"
|
|
"'+M1.FILL;M1.FILLOPC;M1.LEFOBS;M1.LEFPIN;M1.NET;M1.PIN;M1.SPNET;M1.VIA : \\'M1.NET/PIN/FILL/...\\' (22/2)';"
|
|
"'+\\'M1.NET:1\\';\\'M1.PIN:1\\';\\'M1.SPNET:1\\';\\'M1.VIA:1\\' : \\'M1.NET:1/PIN:1/...\\' (6/0)';"
|
|
"'+\\'M1.NET:1\\' : \\'M1.NET:1\\' (7/0)';"
|
|
"'+M1.PIN : M1.PIN (3/0)';"
|
|
"'+M1.PIN : M1.PIN (4/0)';"
|
|
"'+M1.FILL : M1.FILL (14/0)';"
|
|
"'+M1.FILL : M1.FILL (15/0)';"
|
|
"'+M1.FILL : M1.FILL (17/0)';"
|
|
"'+M1.FILLOPC : M1.FILLOPC (9/0)';"
|
|
"'\\'M1.FILLOPC:1\\' : \\'M1.FILLOPC:1\\' (10/0)';"
|
|
"'\\'M1.FILLOPC:2\\' : \\'M1.FILLOPC:2\\' (11/0)';"
|
|
"'\\'M1.VIA:SIZE0.05X0.05\\' : \\'M1.VIA:SIZE0.05X0.05\\' (20/0)';"
|
|
"'\\'M1.VIA:SIZE3X3\\' : \\'M1.VIA:SIZE3X3\\' (21/0)';"
|
|
"'M1.LABEL : M1.LABEL (26/0)';"
|
|
// NAME M1/NET not supported: "'+M1.LABEL : M1.LABEL (27/0)';"
|
|
// NAME M1/SPNET not supported: "'+M1.LABEL : M1.LABEL (28/1)';"
|
|
"'M1.BLK : M1.BLK (13/0)';"
|
|
"'M1_TEXT.LABEL;M1_TEXT.LEFLABEL : \\'M1_TEXT.LABEL/M1_TEXT.LEFLABEL\\' (29/0)'"
|
|
")"
|
|
)
|
|
}
|
|
|
|
TEST(118_density)
|
|
{
|
|
run_test (_this, "density", "read:in.lef", "au.oas.gz", default_options (), false);
|
|
}
|
|
|
|
TEST(119_multimapping)
|
|
{
|
|
db::LEFDEFReaderOptions options = default_options ();
|
|
db::LayerMap lm = db::LayerMap::from_string_file_format ("(M1:1/0)\n(M2:3/0)\n+(M1:100/0)\n+(M2:100/0)\n(VIA1:2/0)");
|
|
options.set_layer_map (lm);
|
|
|
|
db::LayerMap lm_read = run_test (_this, "multimap", "def:test.def", "au.oas.gz", options, false);
|
|
EXPECT_EQ (lm_read.to_string (),
|
|
"layer_map("
|
|
"'OUTLINE : OUTLINE (4/0)';"
|
|
"'+M1.VIA : M1 (1/0)';"
|
|
"'+M1.VIA;M2.VIA : \\'M1;M2\\' (100/0)';"
|
|
"'+M2.VIA : M2 (3/0)';"
|
|
"'VIA1.VIA : VIA1 (2/0)'"
|
|
")"
|
|
)
|
|
}
|
|
|
|
TEST(120_simplefill)
|
|
{
|
|
run_test (_this, "fill", "map:simple.map+lef:simple.lef+def:simple.def", "simple_au.oas.gz", default_options (), false);
|
|
}
|
|
|
|
TEST(121_fillwithmask)
|
|
{
|
|
run_test (_this, "fill", "map:with_mask.map+lef:with_mask.lef+def:with_mask.def", "with_mask_au.oas.gz", default_options (), false);
|
|
}
|
|
|
|
TEST(130_viasize)
|
|
{
|
|
run_test (_this, "viasize", "map:test.map+lef:test.lef+def:test.def", "au.oas.gz", default_options (), false);
|
|
}
|
|
|
|
// issue-1065
|
|
TEST(130_viasize2)
|
|
{
|
|
run_test (_this, "viasize2", "map:test_ok.map+lef:test.lef+def:test.def", "au.oas.gz", default_options (), false);
|
|
run_test (_this, "viasize2", "map:test_fail.map+lef:test.lef+def:test.def", "au.oas.gz", default_options (), false);
|
|
}
|
|
|
|
TEST(131_patternname)
|
|
{
|
|
run_test (_this, "patternname", "map:v.map+lef:v.lef+def:v.def", "au.oas.gz", default_options (), false);
|
|
}
|
|
|
|
TEST(200_lefdef_plugin)
|
|
{
|
|
db::Layout ly;
|
|
|
|
std::string fn_path (tl::testdata ());
|
|
fn_path += "/lefdef/masks-1/";
|
|
|
|
db::LEFDEFReaderOptions lefdef_opt = default_options ();
|
|
lefdef_opt.set_map_file ("in.map");
|
|
db::LoadLayoutOptions opt;
|
|
opt.set_options (lefdef_opt);
|
|
|
|
{
|
|
tl::InputStream is (fn_path + "in.def");
|
|
db::Reader reader (is);
|
|
reader.read (ly, opt);
|
|
}
|
|
|
|
db::compare_layouts (_this, ly, fn_path + "au_plugin_def.oas.gz", db::WriteOAS);
|
|
}
|
|
|
|
TEST(201_lefdef_plugin_explicit_lef)
|
|
{
|
|
db::Layout ly;
|
|
|
|
std::string fn_path (tl::testdata ());
|
|
fn_path += "/lefdef/masks-1/";
|
|
|
|
db::LEFDEFReaderOptions lefdef_opt = default_options ();
|
|
lefdef_opt.set_map_file ("in.map");
|
|
std::vector<std::string> lf;
|
|
lf.push_back ("hidden/in_tech.lef");
|
|
lefdef_opt.set_lef_files (lf);
|
|
lefdef_opt.set_read_lef_with_def (false);
|
|
db::LoadLayoutOptions opt;
|
|
opt.set_options (lefdef_opt);
|
|
|
|
{
|
|
tl::InputStream is (fn_path + "in.def");
|
|
db::Reader reader (is);
|
|
reader.read (ly, opt);
|
|
}
|
|
|
|
db::compare_layouts (_this, ly, fn_path + "au_plugin_alt_lef.oas.gz", db::WriteOAS);
|
|
}
|
|
|
|
TEST(202_lefdef_blend_mode)
|
|
{
|
|
db::LEFDEFReaderOptions lefdef_opt = default_options ();
|
|
|
|
run_test2 (_this, "blend_mode", "map:layers.map+lef:sub.lef+def:top.def", "map:layers.map+def:sub.def", "au1.oas.gz", lefdef_opt, false);
|
|
run_test2 (_this, "blend_mode", "map:layers.map+lef:sub.lef+def:top.def", "map:layers.map+def:sub.def", "au2.oas.gz", lefdef_opt, false, db::AddToCell);
|
|
|
|
lefdef_opt.set_macro_resolution_mode (2);
|
|
run_test2 (_this, "blend_mode", "map:layers.map+lef:sub.lef+def:top.def", "map:layers.map+def:sub.def", "au3.oas.gz", lefdef_opt, false);
|
|
}
|
|
|
|
TEST(203_regionsAndMapfileConcat)
|
|
{
|
|
db::LEFDEFReaderOptions lefdef_opt = default_options ();
|
|
|
|
run_test (_this, "map_regions", "map:'test.map,test.add.map'+lef:test.lef+def:test.def", "au.oas.gz", lefdef_opt, false);
|
|
}
|
|
|
|
// issue 1132
|
|
TEST(204_concave_pins)
|
|
{
|
|
db::LEFDEFReaderOptions lefdef_opt = default_options ();
|
|
lefdef_opt.set_lef_pins_datatype (12);
|
|
lefdef_opt.set_lef_pins_suffix (".LEFPIN");
|
|
lefdef_opt.set_lef_labels_datatype (11);
|
|
lefdef_opt.set_lef_labels_suffix (".LEFLABEL");
|
|
|
|
run_test (_this, "issue-1132", "read:test.lef", "au.oas.gz", lefdef_opt, false);
|
|
}
|
|
|
|
// issue 1214
|
|
TEST(205_lef_resistance)
|
|
{
|
|
db::LEFDEFReaderOptions lefdef_opt = default_options ();
|
|
lefdef_opt.set_lef_pins_datatype (12);
|
|
lefdef_opt.set_lef_pins_suffix (".LEFPIN");
|
|
lefdef_opt.set_lef_labels_datatype (11);
|
|
lefdef_opt.set_lef_labels_suffix (".LEFLABEL");
|
|
|
|
run_test (_this, "issue-1214", "read:merged.nom.lef", "au.oas.gz", lefdef_opt, false);
|
|
}
|
|
|