From 592d65f9f6f7e02861ae0c1c3fe8911d3813910c Mon Sep 17 00:00:00 2001 From: Andreas Wiener Date: Fri, 12 Jun 2026 13:31:41 +0200 Subject: [PATCH 1/4] added option to skip duplicate defined LEF MACROS during lef import --- .../lefdef/db_plugin/dbLEFDEFImporter.cc | 2 +- .../lefdef/db_plugin/dbLEFDEFImporter.h | 11 ++++ .../lefdef/db_plugin/dbLEFDEFPlugin.cc | 2 +- .../lefdef/db_plugin/dbLEFImporter.cc | 58 ++++++++++++++++++- .../lefdef/db_plugin/dbLEFImporter.h | 4 +- .../lefdef/db_plugin/gsiDeclDbLEFDEF.cc | 13 +++++ 6 files changed, 84 insertions(+), 6 deletions(-) diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index 299a24252..eb572ec5a 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -1069,7 +1069,7 @@ void LEFDEFReaderState::ensure_lef_importer (int warn_level) { if (! mp_lef_importer.get ()) { - mp_lef_importer.reset (new db::LEFImporter (warn_level)); + mp_lef_importer.reset (new db::LEFImporter (warn_level, true)); } } 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/dbLEFDEFPlugin.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc index 8d3519cda..45a9daab0 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc @@ -142,7 +142,7 @@ LEFDEFReader::read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &opti tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading LEF file"))); - db::LEFImporter importer (warn_level ()); + db::LEFImporter importer (warn_level (), effective_options.skip_duplicate_macros ()); for (std::vector::const_iterator l = effective_options.begin_lef_files (); l != effective_options.end_lef_files (); ++l) { diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc index ff4ceb531..03f41f115 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc @@ -33,8 +33,9 @@ namespace db // ----------------------------------------------------------------------------------- // LEFImporter implementation -LEFImporter::LEFImporter (int warn_level) - : LEFDEFImporter (warn_level) +LEFImporter::LEFImporter (int warn_level, bool skip_duplicate_macros) + : LEFDEFImporter (warn_level), + m_skip_duplicate_macros (skip_duplicate_macros) { // .. nothing yet .. } @@ -886,7 +887,58 @@ LEFImporter::read_macro (Layout &layout) std::string mn = get (); if (m_macros.find (mn) != m_macros.end ()) { - error (tl::to_string (tr ("Duplicate MACRO name: ")) + mn); + if (m_skip_duplicate_macros) { + // 1. Change error to warning + warn (tl::to_string (tr ("Duplicate MACRO name: ")) + mn + tl::to_string (tr (" (Skipping duplicate)"))); + + // Safe LEF block skipping + while (! at_end ()) { + + if (test ("END")) { + expect (mn); + break; + } else if (test ("PIN")) { + std::string pn = get (); // PIN always has a pin-name -> skip it + //tl::info << tl::to_string (tr ("Found PIN : ")) + pn; + while (! at_end ()) { + if (test ("PORT")) { + //tl::info << tl::to_string (tr ("Found PORT within ")) + pn; + while (! at_end ()) { + if (test ("END")) { + //tl::info << tl::to_string (tr ("Found PORT END within ")) + pn; + break; + } else { + skip_entry (); + } + } + } else if (test ("END")) { + std::string pn = get (); // PIN always has a pin-name -> skip it + //tl::info << tl::to_string (tr ("Found PIN END : ")) + pn; + break; + } else { + skip_entry (); + } + } + } else if (test ("OBS")) { + //tl::info << tl::to_string (tr ("Found OBS")); + while (! at_end ()) { + if (test ("END")) { + //tl::info << tl::to_string (tr ("Found END OBS")); + break; + } else { + skip_entry (); + } + } + } else { + skip_entry (); + } + } + tl::info << tl::to_string (tr ("Successfully skipped duplicate MACRO: ")) + mn; + + return; // Exit early so we don't register or process this duplicate + } else { + error (tl::to_string (tr ("Duplicate MACRO name: ")) + mn); + } } set_cellname (mn); diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h index 176648099..4d994e504 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h @@ -50,7 +50,7 @@ class DB_PLUGIN_PUBLIC LEFImporter /** * @brief Default constructor */ - LEFImporter (int warn_level); + LEFImporter (int warn_level, bool skip_duplicate_macros); /** * @brief Destructor @@ -169,6 +169,8 @@ class DB_PLUGIN_PUBLIC LEFImporter void read_layer (Layout &layout); void read_macro (Layout &layout); void skip_entry (); + + bool m_skip_duplicate_macros; }; } diff --git a/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc b/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc index 0d1efba6b..04061b6ef 100644 --- a/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc +++ b/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc @@ -967,6 +967,19 @@ 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 Get the setting for wether to skip douplicate LEF Macro definitions.\n" + "This property describes what to do when while reading LEF files douplicate MACRO definitions are " + "discovered. Normally an error is issued and the import fails. When setting this flag to true a" + "warning is issued and the macro definition is skipped. So always the first definition of MACRO is used.\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 mode how to handle douplicate MARCO definitions.\n" + "\n" + "This property has been added in version 0.30.x.\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 " From a654c707b3b00d8bd39d14de8346f3eed073a2d7 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 5 Aug 2026 17:57:45 +0200 Subject: [PATCH 2/4] Refining solution - Properly handling copy constructor and initialization - Simplify code - Added test --- .../lefdef/db_plugin/dbLEFDEFImporter.cc | 7 +- .../lefdef/db_plugin/dbLEFDEFPlugin.cc | 2 +- .../lefdef/db_plugin/dbLEFImporter.cc | 76 ++++-------------- .../lefdef/db_plugin/dbLEFImporter.h | 30 ++++++- .../lefdef/unit_tests/dbLEFDEFImportTests.cc | 51 ++++++++++++ testdata/lefdef/issue-2374/au.oas | Bin 0 -> 574 bytes testdata/lefdef/issue-2374/lib1.lef | 20 +++++ testdata/lefdef/issue-2374/lib2.lef | 22 +++++ testdata/lefdef/issue-2374/tech.lef | 12 +++ testdata/lefdef/issue-2374/tech.map | 6 ++ testdata/lefdef/issue-2374/top.def | 10 +++ 11 files changed, 172 insertions(+), 64 deletions(-) create mode 100644 testdata/lefdef/issue-2374/au.oas create mode 100644 testdata/lefdef/issue-2374/lib1.lef create mode 100644 testdata/lefdef/issue-2374/lib2.lef create mode 100644 testdata/lefdef/issue-2374/tech.lef create mode 100644 testdata/lefdef/issue-2374/tech.map create mode 100644 testdata/lefdef/issue-2374/top.def diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index eb572ec5a..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; @@ -1069,7 +1071,10 @@ void LEFDEFReaderState::ensure_lef_importer (int warn_level) { if (! mp_lef_importer.get ()) { - mp_lef_importer.reset (new db::LEFImporter (warn_level, true)); + 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/dbLEFDEFPlugin.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc index 45a9daab0..8d3519cda 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc @@ -142,7 +142,7 @@ LEFDEFReader::read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &opti tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading LEF file"))); - db::LEFImporter importer (warn_level (), effective_options.skip_duplicate_macros ()); + db::LEFImporter importer (warn_level ()); for (std::vector::const_iterator l = effective_options.begin_lef_files (); l != effective_options.end_lef_files (); ++l) { diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc index 03f41f115..4fb7de9d0 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.cc @@ -33,9 +33,9 @@ namespace db // ----------------------------------------------------------------------------------- // LEFImporter implementation -LEFImporter::LEFImporter (int warn_level, bool skip_duplicate_macros) +LEFImporter::LEFImporter (int warn_level) : LEFDEFImporter (warn_level), - m_skip_duplicate_macros (skip_duplicate_macros) + m_skip_duplicate_macros (false) { // .. nothing yet .. } @@ -885,67 +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 ()) { if (m_skip_duplicate_macros) { - // 1. Change error to warning - warn (tl::to_string (tr ("Duplicate MACRO name: ")) + mn + tl::to_string (tr (" (Skipping duplicate)"))); - - // Safe LEF block skipping - while (! at_end ()) { - - if (test ("END")) { - expect (mn); - break; - } else if (test ("PIN")) { - std::string pn = get (); // PIN always has a pin-name -> skip it - //tl::info << tl::to_string (tr ("Found PIN : ")) + pn; - while (! at_end ()) { - if (test ("PORT")) { - //tl::info << tl::to_string (tr ("Found PORT within ")) + pn; - while (! at_end ()) { - if (test ("END")) { - //tl::info << tl::to_string (tr ("Found PORT END within ")) + pn; - break; - } else { - skip_entry (); - } - } - } else if (test ("END")) { - std::string pn = get (); // PIN always has a pin-name -> skip it - //tl::info << tl::to_string (tr ("Found PIN END : ")) + pn; - break; - } else { - skip_entry (); - } - } - } else if (test ("OBS")) { - //tl::info << tl::to_string (tr ("Found OBS")); - while (! at_end ()) { - if (test ("END")) { - //tl::info << tl::to_string (tr ("Found END OBS")); - break; - } else { - skip_entry (); - } - } - } else { - skip_entry (); - } - } - tl::info << tl::to_string (tr ("Successfully skipped duplicate MACRO: ")) + mn; - - return; // Exit early so we don't register or process this duplicate + 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; @@ -1017,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); } } @@ -1104,7 +1058,9 @@ LEFImporter::read_macro (Layout &layout) } else if (test ("FIXEDMASK")) { - mg->set_fixedmask (true); + if (mg) { + mg->set_fixedmask (true); + } expect (";"); } else { @@ -1127,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 4d994e504..c3d04efdc 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h @@ -50,7 +50,7 @@ class DB_PLUGIN_PUBLIC LEFImporter /** * @brief Default constructor */ - LEFImporter (int warn_level, bool skip_duplicate_macros); + LEFImporter (int warn_level); /** * @brief Destructor @@ -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); @@ -169,8 +195,6 @@ class DB_PLUGIN_PUBLIC LEFImporter void read_layer (Layout &layout); void read_macro (Layout &layout); void skip_entry (); - - bool m_skip_duplicate_macros; }; } 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 0000000000000000000000000000000000000000..02bb446865b5da48a048da26c2f367b86d5e9830 GIT binary patch literal 574 zcmY!lcJ=kt^>+;R4CduxWH!_@V0gjKC?n3q!6L)YEF;ds&!EJR>XUoMnybM;fb~F; z;|1o9>4KX(8~>b$4qRRSKbqrK6n{_8gJqfNT9PTCm&e!2&y8CXr%BhK8*Y3l7Nv6^c|cKbRrjuuK*xyI>9@FQdp|Mur3DRYYzw zFW9UM6afh`2p(XTQD@{}F=Hbm(7KTY7#INc{pia8 literal 0 HcmV?d00001 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 From 52a96a618ccefa8c2c9e2ed9ba9a6656bd7e68cd Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 5 Aug 2026 18:29:23 +0200 Subject: [PATCH 3/4] Refinement * Option added to buddy tools ("lefdef-skip-duplicate-macros") * Properly adding to GSI * Tests for GSI binding in LoadLayoutOptions --- src/buddies/src/bd/bdReaderOptions.cc | 11 +++++++++++ src/buddies/src/bd/bdReaderOptions.h | 1 + .../lefdef/db_plugin/gsiDeclDbLEFDEF.cc | 17 +++++++++++------ testdata/ruby/dbReaders.rb | 4 ++++ 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/buddies/src/bd/bdReaderOptions.cc b/src/buddies/src/bd/bdReaderOptions.cc index f0a090310..5dbd4016a 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) { @@ -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/gsiDeclDbLEFDEF.cc b/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc index 04061b6ef..a726396eb 100644 --- a/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc +++ b/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc @@ -968,17 +968,22 @@ gsi::Class decl_lefdef_config ("db", "LEFDEFReaderConfi "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 Get the setting for wether to skip douplicate LEF Macro definitions.\n" - "This property describes what to do when while reading LEF files douplicate MACRO definitions are " - "discovered. Normally an error is issued and the import fails. When setting this flag to true a" - "warning is issued and the macro definition is skipped. So always the first definition of MACRO is used.\n" + "@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 mode how to handle douplicate MARCO definitions.\n" + "@brief Sets a value indicating wether to skip duplicate LEF Macro definitions.\n" "\n" - "This property has been added in version 0.30.x.\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" 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 From f8daa76b1a54c40aa33750db0190c9040237cb4b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 5 Aug 2026 18:30:33 +0200 Subject: [PATCH 4/4] [consider merging] Fixed documentation --- src/buddies/src/bd/bdReaderOptions.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/buddies/src/bd/bdReaderOptions.cc b/src/buddies/src/bd/bdReaderOptions.cc index 5dbd4016a..11faf2573 100644 --- a/src/buddies/src/bd/bdReaderOptions.cc +++ b/src/buddies/src/bd/bdReaderOptions.cc @@ -654,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"