diff --git a/src/buddies/src/bd/bdReaderOptions.cc b/src/buddies/src/bd/bdReaderOptions.cc index f0a090310..11faf2573 100644 --- a/src/buddies/src/bd/bdReaderOptions.cc +++ b/src/buddies/src/bd/bdReaderOptions.cc @@ -112,6 +112,7 @@ GenericReaderOptions::GenericReaderOptions () m_lefdef_produce_special_routing = load_options.get_option_by_name ("lefdef_config.produce_special_routing").to_bool (); m_lefdef_special_routing_suffix = load_options.get_option_by_name ("lefdef_config.special_routing_suffix_str").to_string (); m_lefdef_special_routing_datatype = load_options.get_option_by_name ("lefdef_config.special_routing_datatype_str").to_string (); + m_lefdef_skip_duplicate_macros = load_options.get_option_by_name ("lefdef_config.skip_duplicate_macros").to_bool (); tl::Variant lef_files = load_options.get_option_by_name ("lefdef_config.lef_files"); for (tl::Variant::const_iterator i = lef_files.begin (); i != lef_files.end (); ++i) { @@ -653,9 +654,9 @@ GenericReaderOptions::add_options (tl::CommandLineOptions &cmd) "\n" "The following values are accepted for this option:\n" "\n" - "* 0: produce LEF geometry unless a FOREIGN cell is specified (the default)\n" + "* 0: produce LEF geometry unless a FOREIGN cell is specified\n" "* 1: produce LEF geometry always and ignore FOREIGN\n" - "* 2: Never produce LEF geometry and assume FOREIGN always\n" + "* 2: Never produce LEF geometry and assume FOREIGN always (the default)\n" "\n" "In case of FOREIGN macros in mode 0 or always in mode 2, the '--" + m_long_prefix + "lefdef-lef-layouts' option is available to specify " "external layout files for providing the LEF macro layouts.\n" @@ -686,6 +687,15 @@ GenericReaderOptions::add_options (tl::CommandLineOptions &cmd) "See also '--" + m_long_prefix + "lefdef-read-lef-with-def' for an option to implicitly read all LEF files in the same " "place than the DEF file.\n" ) + << tl::arg (group + + "#--" + m_long_prefix + "lefdef-skip-duplicate-macros", &m_lefdef_skip_duplicate_macros, "Skip duplicate LEF macros", + "This option applies when reading DEF files.\n" + "\n" + "If this option is present, having the same macro in different LEF files is a warning rather than being an error. " + "In that case, the first occurance is used. Use this option with care, as it may render invalid layouts when " + "the versions of the macro are defined differently. It is intended for cases, when macros with the same name are guaranteed " + "to be identical. KLayout does not check, if that is actually the case." + ) ; } @@ -814,6 +824,7 @@ GenericReaderOptions::configure (db::LoadLayoutOptions &load_options) load_options.set_option_by_name ("lefdef_config.macro_resolution_mode", m_lefdef_macro_resolution_mode); load_options.set_option_by_name ("lefdef_config.macro_resolution_mode", m_lefdef_macro_resolution_mode); load_options.set_option_by_name ("lefdef_config.paths_relative_to_cwd", true); + load_options.set_option_by_name ("lefdef_config.skip_duplicate_macros", m_lefdef_skip_duplicate_macros); tl::Variant lef_layout_files = tl::Variant::empty_list (); for (std::vector::const_iterator l = m_lefdef_lef_layout_files.begin (); l != m_lefdef_lef_layout_files.end (); ++l) { diff --git a/src/buddies/src/bd/bdReaderOptions.h b/src/buddies/src/bd/bdReaderOptions.h index 1bffd06fd..727778f6f 100644 --- a/src/buddies/src/bd/bdReaderOptions.h +++ b/src/buddies/src/bd/bdReaderOptions.h @@ -189,6 +189,7 @@ class BD_PUBLIC GenericReaderOptions std::vector m_lefdef_map_files; int m_lefdef_macro_resolution_mode; std::vector m_lefdef_lef_layout_files; + bool m_lefdef_skip_duplicate_macros; }; /** diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index 299a24252..8657d3596 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -597,6 +597,7 @@ LEFDEFReaderOptions::LEFDEFReaderOptions () m_special_routing_datatype (0), m_separate_groups (false), m_joined_paths (false), + m_skip_duplicate_macros (false), m_macro_resolution_mode (0), m_read_lef_with_def (true), m_paths_relative_to_cwd (false), @@ -682,6 +683,7 @@ LEFDEFReaderOptions &LEFDEFReaderOptions::operator= (const LEFDEFReaderOptions & m_macro_layout_files = d.m_macro_layout_files; m_read_lef_with_def = d.m_read_lef_with_def; m_paths_relative_to_cwd = d.m_paths_relative_to_cwd; + m_skip_duplicate_macros = d.m_skip_duplicate_macros; set_macro_layouts (d.macro_layouts ()); } return *this; @@ -1070,6 +1072,9 @@ LEFDEFReaderState::ensure_lef_importer (int warn_level) { if (! mp_lef_importer.get ()) { mp_lef_importer.reset (new db::LEFImporter (warn_level)); + if (mp_tech_comp) { + mp_lef_importer->set_skip_duplicate_macros (mp_tech_comp->skip_duplicate_macros ()); + } } } diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h index 743612e68..25e8e058f 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h @@ -896,6 +896,16 @@ class DB_PLUGIN_PUBLIC LEFDEFReaderOptions m_map_files = f; } + bool skip_duplicate_macros () const + { + return m_skip_duplicate_macros; + } + + void set_skip_duplicate_macros (bool v) + { + m_skip_duplicate_macros = v; + } + std::string single_map_file () const { return m_map_files.empty () ? std::string () : m_map_files.front (); @@ -1055,6 +1065,7 @@ class DB_PLUGIN_PUBLIC LEFDEFReaderOptions bool m_separate_groups; bool m_joined_paths; std::vector m_map_files; + bool m_skip_duplicate_macros; unsigned int m_macro_resolution_mode; bool m_read_lef_with_def; std::vector m_lef_files; diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc index ff4ceb531..4fb7de9d0 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc @@ -34,7 +34,8 @@ namespace db // LEFImporter implementation LEFImporter::LEFImporter (int warn_level) - : LEFDEFImporter (warn_level) + : LEFDEFImporter (warn_level), + m_skip_duplicate_macros (false) { // .. nothing yet .. } @@ -884,16 +885,21 @@ void LEFImporter::read_macro (Layout &layout) { std::string mn = get (); + set_cellname (mn); + + GeometryBasedLayoutGenerator *mg = 0; if (m_macros.find (mn) != m_macros.end ()) { - error (tl::to_string (tr ("Duplicate MACRO name: ")) + mn); + if (m_skip_duplicate_macros) { + warn (tl::to_string (tr ("Skipping duplicate MACRO: : ")) + mn + tl::to_string (tr (" (skip option is enabled by user)"))); + } else { + error (tl::to_string (tr ("Duplicate MACRO name: ")) + mn); + } + } else { + mg = new GeometryBasedLayoutGenerator (); + reader_state ()->register_macro_cell (mn, mg); } - set_cellname (mn); - - GeometryBasedLayoutGenerator *mg = new GeometryBasedLayoutGenerator (); - reader_state ()->register_macro_cell (mn, mg); - db::Trans foreign_trans; std::string foreign_name; @@ -965,7 +971,7 @@ LEFImporter::read_macro (Layout &layout) read_geometries (mg, layout.dbu (), LEFPins, &boxes_for_labels, prop_id); for (std::map ::const_iterator b = boxes_for_labels.begin (); b != boxes_for_labels.end (); ++b) { - if (! b->second.empty ()) { + if (mg && ! b->second.empty ()) { mg->add_text (b->first, LEFLabel, db::Text (label.c_str (), db::Trans (b->second.center () - db::Point ())), 0, 0); } } @@ -1052,7 +1058,9 @@ LEFImporter::read_macro (Layout &layout) } else if (test ("FIXEDMASK")) { - mg->set_fixedmask (true); + if (mg) { + mg->set_fixedmask (true); + } expect (";"); } else { @@ -1075,8 +1083,10 @@ LEFImporter::read_macro (Layout &layout) } - mg->add_box (std::string (), Outline, db::Box (-origin, -origin + size), 0, 0); - mg->subtract_overlap_from_outline (m_overlap_layers); + if (mg) { + mg->add_box (std::string (), Outline, db::Box (-origin, -origin + size), 0, 0); + mg->subtract_overlap_from_outline (m_overlap_layers); + } MacroDesc macro_desc; macro_desc.foreign_name = foreign_name; diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h index 176648099..c3d04efdc 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h @@ -147,6 +147,31 @@ class DB_PLUGIN_PUBLIC LEFImporter */ void finish_lef (db::Layout &layout); + /** + * @brief Sets a flag indicating whether to skip duplicate macros + * + * With this flag set to true, macros are ignored when there already + * is a macro with the same name. Use this option with caution, as + * skipping is only permitted if both macros are identical. The + * LEF reader does not check this condition. + * + * The default is "false" (raise an error on duplicate macros). + */ + void set_skip_duplicate_macros (bool f) + { + m_skip_duplicate_macros = f; + } + + /** + * @brief Gets a flag indicating whether to skip duplicate macros + * + * See set_skip_duplicate_macros for an explanation of this flag. + */ + bool skip_duplicate_macros () const + { + return m_skip_duplicate_macros; + } + protected: void do_read (db::Layout &layout); @@ -159,6 +184,7 @@ class DB_PLUGIN_PUBLIC LEFImporter std::map m_vias; std::set m_routing_layers, m_cut_layers, m_overlap_layers; std::map m_num_masks; + bool m_skip_duplicate_macros; std::vector get_iteration (double dbu); void read_geometries (GeometryBasedLayoutGenerator *lg, double dbu, LayerPurpose purpose, std::map *collect_bboxes = 0, properties_id_type prop_id = 0); diff --git a/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc b/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc index 0d1efba6b..a726396eb 100644 --- a/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc +++ b/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc @@ -967,6 +967,24 @@ gsi::Class decl_lefdef_config ("db", "LEFDEFReaderConfi "\n" "This property has been added in version 0.27. The ability to supply multiple files has been added in version 0.30.6.\n" ) + + gsi::method ("skip_duplicate_macros", &db::LEFDEFReaderOptions::skip_duplicate_macros, + "@brief Gets a value indicating wether to skip duplicate LEF Macro definitions.\n" + "If this property is 'true', having the same macro in different LEF files is a warning rather than being an error. " + "In that case, the first occurance is used. Use this option with care, as it may render invalid layouts when " + "the versions of the macro are defined differently. It is intended for cases, when macros with the same name are guaranteed " + "to be identical. KLayout does not check, if that is actually the case." + "\n" + "The default is 'false' (duplicate macro names are an error).\n" + "\n" + "This property has been added in version 0.30.x.\n" + ) + + gsi::method ("skip_duplicate_macros=", &db::LEFDEFReaderOptions::set_skip_duplicate_macros, gsi::arg ("skip_duplicate_macros"), + "@brief Sets a value indicating wether to skip duplicate LEF Macro definitions.\n" + "\n" + "See \\skip_duplicate_macros for a description of this property.\n" + "\n" + "This property has been added in version 0.30.11.\n" + ) + gsi::method ("macro_resolution_mode", &db::LEFDEFReaderOptions::macro_resolution_mode, "@brief Gets the macro resolution mode (LEF macros into DEF).\n" "This property describes the way LEF macros are turned into layout cells when reading DEF. There " diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index e5552338c..81c790077 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -1199,3 +1199,54 @@ TEST(216_line_extensions) run_test (_this, "issue-2075", "map:test.map+lef:test.lef+def:test.def", "au.oas", default_options (), false); } +// issue-2374 (skip duplicate LEF macro option) +TEST(217_skip_duplicate_macro) +{ + std::string fn_path (tl::testdata ()); + fn_path += "/lefdef/issue-2374/"; + + db::LEFDEFReaderOptions lefdef_opt = default_options (); + lefdef_opt.set_single_map_file ("tech.map"); + std::vector lf; + lf.push_back ("tech.lef"); + lf.push_back ("lib1.lef"); // macros a,b + lf.push_back ("lib2.lef"); // macros b,c + lefdef_opt.set_lef_files (lf); + lefdef_opt.set_read_lef_with_def (false); + + db::Layout ly; + + try { + + db::LoadLayoutOptions opt; + opt.set_options (lefdef_opt); + EXPECT_EQ (lefdef_opt.skip_duplicate_macros (), false); + + tl::InputStream is (fn_path + "top.def"); + db::Reader reader (is); + reader.read (ly, opt); + + // must throw an exception because of duplicate macros + EXPECT_EQ (1, 0); + + } catch (...) { } + + ly = db::Layout (); + + { + + db::LEFDEFReaderOptions lo = lefdef_opt; + lo.set_skip_duplicate_macros (true); + EXPECT_EQ (lo.skip_duplicate_macros (), true); + db::LoadLayoutOptions opt; + opt.set_options (lo); + + tl::InputStream is (fn_path + "top.def"); + db::Reader reader (is); + reader.read (ly, opt); + + } + + db::compare_layouts (_this, ly, fn_path + "au.oas", db::WriteOAS); +} + diff --git a/testdata/lefdef/issue-2374/au.oas b/testdata/lefdef/issue-2374/au.oas new file mode 100644 index 000000000..02bb44686 Binary files /dev/null and b/testdata/lefdef/issue-2374/au.oas differ diff --git a/testdata/lefdef/issue-2374/lib1.lef b/testdata/lefdef/issue-2374/lib1.lef new file mode 100644 index 000000000..88d2463d7 --- /dev/null +++ b/testdata/lefdef/issue-2374/lib1.lef @@ -0,0 +1,20 @@ +VERSION 5.8 ; + +MACRO a + ORIGIN 0 0 ; + SIZE 600 BY 600 ; + OBS + LAYER M1 ; + RECT 10 10 590 590 ; + END +END a + +MACRO b + ORIGIN -600 0 ; + SIZE 400 BY 500 ; + OBS + LAYER M1 ; + RECT 610 10 990 490 ; + END +END b + diff --git a/testdata/lefdef/issue-2374/lib2.lef b/testdata/lefdef/issue-2374/lib2.lef new file mode 100644 index 000000000..659694c36 --- /dev/null +++ b/testdata/lefdef/issue-2374/lib2.lef @@ -0,0 +1,22 @@ +VERSION 5.8 ; + +MACRO b + ORIGIN -600 0 ; + SIZE 400 BY 500 ; + OBS + LAYER M1 ; + RECT 610 10 990 590 ; + END +END b + +MACRO c + ORIGIN -500 -500 ; + SIZE 500 BY 500 ; + OBS + LAYER M1 ; + POLYGON 510 610 610 610 610 510 990 510 990 990 510 990 ; + LAYER overlap ; + RECT 500 700 1000 1000 ; + POLYGON 500 600 600 600 600 500 1000 500 1000 700 500 700 ; + END +END c diff --git a/testdata/lefdef/issue-2374/tech.lef b/testdata/lefdef/issue-2374/tech.lef new file mode 100644 index 000000000..606730c96 --- /dev/null +++ b/testdata/lefdef/issue-2374/tech.lef @@ -0,0 +1,12 @@ +VERSION 5.8 ; + +LAYER M1 + TYPE ROUTING ; + DIRECTION HORIZONTAL ; + WIDTH 0.1 ; + PITCH 0.1 ; +END M1 + +LAYER overlap + TYPE OVERLAP ; +END overlap diff --git a/testdata/lefdef/issue-2374/tech.map b/testdata/lefdef/issue-2374/tech.map new file mode 100644 index 000000000..e848325a6 --- /dev/null +++ b/testdata/lefdef/issue-2374/tech.map @@ -0,0 +1,6 @@ +DIEAREA ALL 1 0 +#BOUNDARY DIEAREA 1 0 +BOUNDARY MACRO 1 0 +#M1 LEFOBS 2 0 +M1 LEFOBS 3 0 +M1 BLOCKAGE 3 0 diff --git a/testdata/lefdef/issue-2374/top.def b/testdata/lefdef/issue-2374/top.def new file mode 100644 index 000000000..1e1cd5c32 --- /dev/null +++ b/testdata/lefdef/issue-2374/top.def @@ -0,0 +1,10 @@ +VERSION 5.8 ; +DESIGN top ; +UNITS DISTANCE MICRONS 1000 ; +DIEAREA ( 0 0 ) ( 1000000 1000000 ) ; +COMPONENTS 3 ; +- a a + PLACED ( 0 0 ) N ; +- b b + PLACED ( 600000 0 ) N ; +- c c + PLACED ( 500000 500000 ) N ; +END COMPONENTS +END DESIGN diff --git a/testdata/ruby/dbReaders.rb b/testdata/ruby/dbReaders.rb index 9a787d25f..e01e03696 100644 --- a/testdata/ruby/dbReaders.rb +++ b/testdata/ruby/dbReaders.rb @@ -392,6 +392,10 @@ def test_lefdef_options conf.read_lef_with_def = false assert_equal(conf.read_lef_with_def, false) + assert_equal(conf.skip_duplicate_macros, false) + conf.skip_duplicate_macros = true + assert_equal(conf.skip_duplicate_macros, true) + end # MAG Options