/* 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 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 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); }