From 271800ab94e1e0ed010d3d981ed9732edcb52302 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 15 May 2025 23:27:03 +0200 Subject: [PATCH 01/10] WIP: first implementation. Builds, but needs testing. --- src/buddies/src/bd/bdReaderOptions.cc | 6 +- .../lefdef/db_plugin/dbLEFDEFImporter.cc | 90 +++++++++++++++---- .../lefdef/db_plugin/dbLEFDEFImporter.h | 56 +++++++++++- .../lefdef/db_plugin/dbLEFDEFPlugin.cc | 84 ++++++++--------- .../lefdef/db_plugin/gsiDeclDbLEFDEF.cc | 4 + .../lefdef/unit_tests/dbLEFDEFImportTests.cc | 4 +- 6 files changed, 177 insertions(+), 67 deletions(-) diff --git a/src/buddies/src/bd/bdReaderOptions.cc b/src/buddies/src/bd/bdReaderOptions.cc index 752d20edd..091412826 100644 --- a/src/buddies/src/bd/bdReaderOptions.cc +++ b/src/buddies/src/bd/bdReaderOptions.cc @@ -846,12 +846,16 @@ static std::vector split_file_list (const std::string &infile) void read_files (db::Layout &layout, const std::string &infile, const db::LoadLayoutOptions &options) { + // enter a LEF caching context for chaining multiple DEF with the same LEF + db::LoadLayoutOptions local_options (options); + local_options.set_option_by_name ("lefdef_config.lef_context_enabled", true); + std::vector files = split_file_list (infile); for (std::vector::const_iterator f = files.begin (); f != files.end (); ++f) { tl::InputStream stream (*f); db::Reader reader (stream); - reader.read (layout, options); + reader.read (layout, local_options); } } diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index d95144c75..c2d8c253e 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -598,7 +598,8 @@ LEFDEFReaderOptions::LEFDEFReaderOptions () m_map_file (), m_macro_resolution_mode (0), m_read_lef_with_def (true), - m_paths_relative_to_cwd (false) + m_paths_relative_to_cwd (false), + m_lef_context_enabled (false) { // .. nothing yet .. } @@ -951,26 +952,32 @@ LEFDEFReaderOptions::special_routing_datatype_str () const return get_datatypes (this, &LEFDEFReaderOptions::special_routing_datatype, &LEFDEFReaderOptions::special_routing_datatype_per_mask, max_mask_number ()); } +void +LEFDEFReaderOptions::set_lef_context_enabled (bool f) +{ + if (f != m_lef_context_enabled) { + mp_reader_state.reset (0); + } +} + +db::LEFDEFReaderState * +LEFDEFReaderOptions::reader_state (db::Layout &layout, const std::string &base_path, const db::LoadLayoutOptions &options) const +{ + if (m_lef_context_enabled && ! mp_reader_state.get ()) { + mp_reader_state.reset (new db::LEFDEFReaderState (this)); + mp_reader_state->init (layout, base_path, options); + } + + return mp_reader_state.get (); +} + // ----------------------------------------------------------------------------------- // LEFDEFLayerDelegate implementation -LEFDEFReaderState::LEFDEFReaderState (const LEFDEFReaderOptions *tc, db::Layout &layout, const std::string &base_path) +LEFDEFReaderState::LEFDEFReaderState (const LEFDEFReaderOptions *tc) : mp_importer (0), m_create_layers (true), m_has_explicit_layer_mapping (false), m_laynum (1), mp_tech_comp (tc) { - if (! tc) { - - // use default options - - } else if (! tc->map_file ().empty ()) { - - read_map_file (tc->map_file (), layout, base_path); - - } else { - - m_layer_map = tc->layer_map (); - m_create_layers = tc->read_all_layers (); - - } + // .. nothing yet .. } LEFDEFReaderState::~LEFDEFReaderState () @@ -988,6 +995,57 @@ LEFDEFReaderState::~LEFDEFReaderState () m_macro_generators.clear (); } +void +LEFDEFReaderState::init (Layout &layout, const std::string &base_path, const LoadLayoutOptions &options) +{ + if (! mp_tech_comp) { + + // use default options + + } else if (! mp_tech_comp->map_file ().empty ()) { + + read_map_file (mp_tech_comp->map_file (), layout, base_path); + + } else { + + m_layer_map = mp_tech_comp->layer_map (); + m_create_layers = mp_tech_comp->read_all_layers (); + + } + + if (mp_tech_comp) { + + m_macro_layouts = mp_tech_comp->macro_layouts (); + + // Additionally read the layouts from the given paths + for (std::vector::const_iterator l = mp_tech_comp->begin_macro_layout_files (); l != mp_tech_comp->end_macro_layout_files (); ++l) { + + auto paths = correct_path (*l, layout, base_path, true); + for (auto lp = paths.begin (); lp != paths.end (); ++lp) { + + tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading LEF macro layout file: ")) + *lp); + + tl::InputStream macro_layout_stream (*lp); + tl::log << tl::to_string (tr ("Reading")) << " " << *lp; + db::Layout *new_layout = new db::Layout (false); + m_macro_layout_object_holder.push_back (new_layout); + m_macro_layouts.push_back (new_layout); + + db::Reader reader (macro_layout_stream); + reader.read (*new_layout, options); + + if (fabs (new_layout->dbu () / layout.dbu () - 1.0) > db::epsilon) { + tl::warn << tl::sprintf (tl::to_string (tr ("DBU of macro layout file '%s' does not match reader DBU (layout DBU is %.12g, reader DBU is set to %.12g)")), + *lp, new_layout->dbu (), layout.dbu ()); + } + + } + + } + + } +} + void LEFDEFReaderState::error (const std::string &msg) { diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h index 2a5736f0e..9fa0e6d04 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h @@ -960,6 +960,25 @@ public: m_macro_layout_files = lf; } + /** + * @brief A hidden attribute to enable a LEF context + * LEF context are used for chaining DEF readers. This method must be + * called on local copy of the importer options. With this attribute + * set to "true", the client code can store a LEFDEFReaderState object + * in this object. + * Initially, this attribute is set to false. + * Note that this attribute is not copied. + */ + void set_lef_context_enabled (bool context); + + bool lef_context_enabled () const + { + return m_lef_context_enabled; + } + + // makes the reader state object if required + db::LEFDEFReaderState *reader_state (db::Layout &layout, const std::string &base_path, const LoadLayoutOptions &options) const; + private: bool m_read_all_layers; db::LayerMap m_layer_map; @@ -1028,6 +1047,8 @@ private: tl::weak_collection m_macro_layouts; std::vector m_macro_layout_files; bool m_paths_relative_to_cwd; + bool m_lef_context_enabled; + mutable std::unique_ptr mp_reader_state; }; /** @@ -1247,13 +1268,18 @@ public: /** * @brief Constructor */ - LEFDEFReaderState (const LEFDEFReaderOptions *tc, db::Layout &layout, const std::string &base_path = std::string ()); + LEFDEFReaderState (const LEFDEFReaderOptions *tc); /** * @brief Destructor */ ~LEFDEFReaderState (); + /** + * @brief Initialize with the layout and base path + */ + void init (db::Layout &layout, const std::string &base_path, const LoadLayoutOptions &options); + /** * @brief Attaches to or detaches from an importer */ @@ -1364,6 +1390,31 @@ public: */ void warn (const std::string &msg, int warn_level = 1); + /** + * @brief Gets a value indicating whether the given LEF file was already read + */ + bool lef_file_already_read (const std::string &fn) + { + return m_lef_files_read.find (fn) != m_lef_files_read.end (); + } + + /** + * @brief Registers a LEF file + * After registration, the same file will report "already_read" + */ + void register_lef_file (const std::string &fn) + { + m_lef_files_read.insert (fn); + } + + /** + * @brief Gets the stored macro layouts + */ + const std::vector ¯o_layouts () const + { + return m_macro_layouts; + } + protected: virtual void common_reader_error (const std::string &msg) { error (msg); } virtual void common_reader_warn (const std::string &msg, int warn_level) { warn (msg, warn_level); } @@ -1456,6 +1507,9 @@ private: std::map > m_macro_cells; std::map m_macro_generators; std::map m_foreign_cells; + std::set m_lef_files_read; + std::vector m_macro_layouts; + tl::shared_collection m_macro_layout_object_holder; std::set open_layer_uncached (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask); db::cell_index_type foreign_cell(Layout &layout, const std::string &name); diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc index 06e42a0c7..0985b0531 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc @@ -113,23 +113,36 @@ LEFDEFReader::read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &opti init (options); const db::LEFDEFReaderOptions *lefdef_options = dynamic_cast (options.get_options (format ())); + db::LEFDEFReaderOptions effective_options; if (lefdef_options) { effective_options = *lefdef_options; } + layout.dbu (effective_options.dbu ()); + std::string base_path; if (! effective_options.paths_relative_to_cwd ()) { base_path = tl::dirname (m_stream.absolute_file_path ()); } - db::LEFDEFReaderState state (&effective_options, layout, base_path); + // If the LEF reader context (LEF caching) is enabled on the options, + // pull the state from there, otherwise create a local state. + db::LEFDEFReaderState local_state (&effective_options); + db::LEFDEFReaderState *state = 0; + if (lefdef_options) { + state = lefdef_options->reader_state (layout, base_path, options); + } + if (! state) { + local_state.init (layout, base_path, options); + state = &local_state; + } + // Configure the conflict resolution mode db::CommonReaderOptions common_options = options.get_options (); - state.set_conflict_resolution_mode (common_options.cell_conflict_resolution); - - layout.dbu (effective_options.dbu ()); + state->set_conflict_resolution_mode (common_options.cell_conflict_resolution); + // Import LEF if (import_lef) { // Always produce LEF geometry when reading LEF @@ -145,13 +158,13 @@ LEFDEFReader::read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &opti for (auto lp = paths.begin (); lp != paths.end (); ++lp) { tl::InputStream lef_stream (*lp); tl::log << tl::to_string (tr ("Reading")) << " " << *lp; - importer.read (lef_stream, layout, state); + importer.read (lef_stream, layout, *state); } } tl::log << tl::to_string (tr ("Reading")) << " " << m_stream.source (); - importer.read (m_stream, layout, state); + importer.read (m_stream, layout, *state); importer.finish_lef (layout); @@ -161,20 +174,21 @@ LEFDEFReader::read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &opti DEFImporter importer (warn_level ()); - std::set lef_files_read; - for (std::vector::const_iterator l = effective_options.begin_lef_files (); l != effective_options.end_lef_files (); ++l) { auto paths = correct_path (*l, layout, base_path, true); for (auto lp = paths.begin (); lp != paths.end (); ++lp) { - if (lef_files_read.insert (tl::normalize_path (*lp)).second) { + std::string norm_lp = tl::normalize_path (*lp); + if (! state->lef_file_already_read (norm_lp)) { tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading LEF file: ")) + *lp); - tl::InputStream lef_stream (*lp); + tl::InputStream lef_stream (norm_lp); tl::log << tl::to_string (tr ("Reading")) << " " << *lp; - importer.read_lef (lef_stream, layout, state); + importer.read_lef (lef_stream, layout, *state); + + state->register_lef_file (norm_lp); } @@ -198,13 +212,16 @@ LEFDEFReader::read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &opti std::string lp = tl::combine_path (input_dir, *e); // skip if already read (issue-1724) - if (lef_files_read.find (tl::normalize_path (lp)) == lef_files_read.end ()) { + std::string norm_lp = tl::normalize_path (lp); + if (! state->lef_file_already_read (norm_lp)) { tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading LEF file: ")) + lp); - tl::InputStream lef_stream (lp); + tl::InputStream lef_stream (norm_lp); tl::log << tl::to_string (tr ("Reading")) << " " << lp; - importer.read_lef (lef_stream, layout, state); + importer.read_lef (lef_stream, layout, *state); + + state->register_lef_file (norm_lp); } @@ -217,43 +234,14 @@ LEFDEFReader::read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &opti } tl::log << tl::to_string (tr ("Reading")) << " " << m_stream.source (); - importer.read (m_stream, layout, state); + importer.read (m_stream, layout, *state); // Resolve unresolved COMPONENT cells - std::map foreign_cells = state.foreign_cells (); + std::map foreign_cells = state->foreign_cells (); db::cell_index_type seen = std::numeric_limits::max (); - std::vector macro_layouts = effective_options.macro_layouts (); - - // Additionally read the layouts from the given paths - tl::shared_collection macro_layout_object_holder; - for (std::vector::const_iterator l = effective_options.begin_macro_layout_files (); l != effective_options.end_macro_layout_files (); ++l) { - - auto paths = correct_path (*l, layout, base_path, true); - for (auto lp = paths.begin (); lp != paths.end (); ++lp) { - - tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading LEF macro layout file: ")) + *lp); - - tl::InputStream macro_layout_stream (*lp); - tl::log << tl::to_string (tr ("Reading")) << " " << *lp; - db::Layout *new_layout = new db::Layout (false); - macro_layout_object_holder.push_back (new_layout); - macro_layouts.push_back (new_layout); - - db::Reader reader (macro_layout_stream); - reader.read (*new_layout, options); - - if (fabs (new_layout->dbu () / layout.dbu () - 1.0) > db::epsilon) { - importer.warn (tl::sprintf (tl::to_string (tr ("DBU of macro layout file '%s' does not match reader DBU (layout DBU is %.12g, reader DBU is set to %.12g)")), - *lp, new_layout->dbu (), layout.dbu ())); - } - - } - - } - - for (std::vector::const_iterator m = macro_layouts.begin (); m != macro_layouts.end (); ++m) { + for (std::vector::const_iterator m = state->macro_layouts ().begin (); m != state->macro_layouts ().end (); ++m) { std::vector target_cells, source_cells; @@ -286,9 +274,9 @@ LEFDEFReader::read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &opti } - state.finish (layout); + state->finish (layout); - m_layer_map = state.layer_map (); + m_layer_map = state->layer_map (); return m_layer_map; } diff --git a/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc b/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc index 032ad31eb..b2dfae449 100644 --- a/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc +++ b/src/plugins/streamers/lefdef/db_plugin/gsiDeclDbLEFDEF.cc @@ -997,6 +997,10 @@ gsi::Class decl_lefdef_config ("db", "LEFDEFReaderConfi "See \\read_lef_with_def for details about this property.\n" "\n" "This property has been added in version 0.27.\n" + ) + + // special attribute to implement LEF caching + gsi::method ("lef_context_enabled=", &db::LEFDEFReaderOptions::set_lef_context_enabled, + "@hide\n" ), "@brief Detailed LEF/DEF reader options\n" "This class is a aggregate belonging to the \\LoadLayoutOptions class. It provides options for the LEF/DEF reader. " diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index 7e128f9c7..a493959b6 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -59,7 +59,9 @@ static db::LayerMap read (db::Layout &layout, const char *lef_dir, const char *f tl::Extractor ex (filename); - db::LEFDEFReaderState ld (&options, layout, fn_path); + db::LoadLayoutOptions other_options; + db::LEFDEFReaderState ld (&options); + ld.init (layout, fn_path, other_options); ld.set_conflict_resolution_mode (cc_mode); db::DEFImporter imp; From 1b98efd7a854af35c89fcbb115867c24189453b7 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 15 May 2025 23:41:23 +0200 Subject: [PATCH 02/10] First bug fixes --- src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index c2d8c253e..bb93be064 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -605,7 +605,8 @@ LEFDEFReaderOptions::LEFDEFReaderOptions () } LEFDEFReaderOptions::LEFDEFReaderOptions (const LEFDEFReaderOptions &d) - : db::FormatSpecificReaderOptions () + : db::FormatSpecificReaderOptions (), + m_lef_context_enabled (false) { operator= (d); } From 5c27fedfe524c743a0e38ae25729e2331f0d0665 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 17 May 2025 00:44:15 +0200 Subject: [PATCH 03/10] Debugging and bug fixes. The 'big example' from issue 2014 now works --- src/db/db/dbCommonReader.cc | 9 ++- src/db/db/dbCommonReader.h | 2 +- .../lefdef/db_plugin/dbDEFImporter.cc | 39 +++------ .../lefdef/db_plugin/dbDEFImporter.h | 16 +--- .../lefdef/db_plugin/dbLEFDEFImporter.cc | 79 ++++++++++++++++++- .../lefdef/db_plugin/dbLEFDEFImporter.h | 31 ++++++++ .../lefdef/db_plugin/dbLEFDEFPlugin.cc | 43 ++-------- .../lefdef/unit_tests/dbLEFDEFImportTests.cc | 7 +- 8 files changed, 139 insertions(+), 87 deletions(-) diff --git a/src/db/db/dbCommonReader.cc b/src/db/db/dbCommonReader.cc index bf21fa5fc..b1becdcfb 100644 --- a/src/db/db/dbCommonReader.cc +++ b/src/db/db/dbCommonReader.cc @@ -314,8 +314,13 @@ CommonReaderBase::merge_cell_without_instances (db::Layout &layout, db::cell_ind } void -CommonReaderBase::init () +CommonReaderBase::start () { + m_id_map.clear (); + m_name_map.clear (); + m_temp_cells.clear (); + m_name_for_id.clear (); + m_layer_map_out.clear (); m_multi_mapping_placeholders.clear (); m_layer_cache.clear (); @@ -621,7 +626,7 @@ void CommonReader::init (const LoadLayoutOptions &options) { ReaderBase::init (options); - CommonReaderBase::init (); + CommonReaderBase::start (); db::CommonReaderOptions common_options = options.get_options (); set_conflict_resolution_mode (common_options.cell_conflict_resolution); diff --git a/src/db/db/dbCommonReader.h b/src/db/db/dbCommonReader.h index 7433cafe3..1a7dafcdf 100644 --- a/src/db/db/dbCommonReader.h +++ b/src/db/db/dbCommonReader.h @@ -207,7 +207,7 @@ public: /** * @brief Re-initialize: clears the tables and caches */ - void init (); + void start (); /** * @brief Sets a value indicating whether to create layers diff --git a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc index b91bd458f..3aa4d79c7 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc @@ -53,24 +53,11 @@ struct DEFImporterGroup }; DEFImporter::DEFImporter (int warn_level) - : LEFDEFImporter (warn_level), - m_lef_importer (warn_level) + : LEFDEFImporter (warn_level) { // .. nothing yet .. } -void -DEFImporter::read_lef (tl::InputStream &stream, db::Layout &layout, LEFDEFReaderState &state) -{ - m_lef_importer.read (stream, layout, state); -} - -void -DEFImporter::finish_lef (db::Layout &layout) -{ - m_lef_importer.finish_lef (layout); -} - void DEFImporter::read_polygon (db::Polygon &poly, double scale) { @@ -112,7 +99,7 @@ DEFImporter::read_rect (db::Polygon &poly, double scale) std::pair DEFImporter::get_wire_width_for_rule (const std::string &rulename, const std::string &ln, double dbu) { - std::pair wxy = m_lef_importer.layer_width (ln, rulename); + std::pair wxy = reader_state ()->lef_importer ().layer_width (ln, rulename); db::Coord wx = db::coord_traits::rounded (wxy.first / dbu); db::Coord wy = db::coord_traits::rounded (wxy.second / dbu); @@ -127,7 +114,7 @@ DEFImporter::get_wire_width_for_rule (const std::string &rulename, const std::st } } - std::pair min_wxy = m_lef_importer.min_layer_width (ln); + std::pair min_wxy = reader_state ()->lef_importer ().min_layer_width (ln); db::Coord min_wx = db::coord_traits::rounded (min_wxy.first / dbu); db::Coord min_wy = db::coord_traits::rounded (min_wxy.second / dbu); @@ -769,7 +756,7 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C unsigned int mask_cut = (mask / 10) % 10; unsigned int mask_bottom = mask % 10; - db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &m_lef_importer); + db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &reader_state ()->lef_importer ()); if (cell) { if (nx <= 1 && ny <= 1) { design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (ft.rot (), db::Vector (pts.back ())))); @@ -953,7 +940,7 @@ DEFImporter::read_nets (db::Layout &layout, db::Cell &design, double scale, bool std::map::const_iterator vd = m_via_desc.find (vn); if (vd != m_via_desc.end ()) { - db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &m_lef_importer); + db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &reader_state ()->lef_importer ()); if (cell) { design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (ft.rot (), pt))); } @@ -1130,7 +1117,7 @@ DEFImporter::read_vias (db::Layout &layout, db::Cell & /*design*/, double scale) std::string ln = get (); - if (m_lef_importer.is_routing_layer (ln)) { + if (reader_state ()->lef_importer ().is_routing_layer (ln)) { if (seen_layers.find (ln) == seen_layers.end ()) { @@ -1145,7 +1132,7 @@ DEFImporter::read_vias (db::Layout &layout, db::Cell & /*design*/, double scale) } - } else if (m_lef_importer.is_cut_layer (ln)) { + } else if (reader_state ()->lef_importer ().is_cut_layer (ln)) { geo_based_vg->set_maskshift_layer (1, ln); has_cut_geometry = true; @@ -1336,7 +1323,7 @@ DEFImporter::read_pins (db::Layout &layout, db::Cell &design, double scale) std::map::const_iterator vd = m_via_desc.find (vn); if (vd != m_via_desc.end ()) { std::string nondefaultrule; - db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &m_lef_importer); + db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &reader_state ()->lef_importer ()); if (cell) { design.insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (pt))); } @@ -1549,7 +1536,7 @@ DEFImporter::read_fills (db::Layout &layout, db::Cell &design, double scale) std::map::const_iterator vd = m_via_desc.find (vn); if (vd != m_via_desc.end ()) { std::string nondefaultrule; - db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &m_lef_importer); + db::Cell *cell = reader_state ()->via_cell (vn, nondefaultrule, layout, mask_bottom, mask_cut, mask_top, &reader_state ()->lef_importer ()); if (cell) { ensure_fill_cell (layout, design, fill_cell).insert (db::CellInstArray (db::CellInst (cell->cell_index ()), db::Trans (pt))); } @@ -1613,8 +1600,8 @@ DEFImporter::read_components (db::Layout &layout, std::list::const_iterator m = m_lef_importer.macros ().find (model); - if (m == m_lef_importer.macros ().end ()) { + std::map::const_iterator m = reader_state ()->lef_importer ().macros ().find (model); + if (m == reader_state ()->lef_importer ().macros ().end ()) { error (tl::to_string (tr ("Macro not found in LEF file: ")) + model); } @@ -1660,7 +1647,7 @@ DEFImporter::read_components (db::Layout &layout, std::list ct = reader_state ()->macro_cell (model, layout, m_component_maskshift, string2masks (maskshift), m->second, &m_lef_importer); + std::pair ct = reader_state ()->macro_cell (model, layout, m_component_maskshift, string2masks (maskshift), m->second, &reader_state ()->lef_importer ()); if (ct.first) { db::CellInstArray inst (db::CellInst (ct.first->cell_index ()), db::Trans (ft.rot (), d) * ct.second); instances.push_back (std::make_pair (inst_name, inst)); @@ -1684,7 +1671,7 @@ DEFImporter::do_read (db::Layout &layout) std::list groups; std::list > instances; - m_via_desc = m_lef_importer.vias (); + m_via_desc = reader_state ()->lef_importer ().vias (); m_styles.clear (); m_design_name.clear (); diff --git a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.h index 0b824e403..56e7568f8 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.h @@ -48,26 +48,12 @@ public: /** * @brief Default constructor */ - DEFImporter (int warn_level = 1); - - /** - * @brief Read the given LEF file prior to the DEF file - * - * This method reads the layout specified into the given layout. - * Multiple LEF files can be read. - */ - void read_lef (tl::InputStream &stream, db::Layout &layout, LEFDEFReaderState &state); - - /** - * @brief Provided for test purposes - */ - void finish_lef (Layout &layout); + DEFImporter (int warn_level); protected: void do_read (db::Layout &layout); private: - LEFImporter m_lef_importer; std::map > m_nondefault_widths; std::map m_via_desc; std::map m_styles; diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index bb93be064..8776f6827 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -22,9 +22,11 @@ #include "dbLEFDEFImporter.h" +#include "dbLEFImporter.h" #include "dbLayoutUtils.h" #include "dbTechnology.h" #include "dbShapeProcessor.h" +#include "dbCellMapping.h" #include "tlStream.h" #include "tlProgress.h" @@ -958,6 +960,7 @@ LEFDEFReaderOptions::set_lef_context_enabled (bool f) { if (f != m_lef_context_enabled) { mp_reader_state.reset (0); + m_lef_context_enabled = f; } } @@ -1036,8 +1039,8 @@ LEFDEFReaderState::init (Layout &layout, const std::string &base_path, const Loa reader.read (*new_layout, options); if (fabs (new_layout->dbu () / layout.dbu () - 1.0) > db::epsilon) { - tl::warn << tl::sprintf (tl::to_string (tr ("DBU of macro layout file '%s' does not match reader DBU (layout DBU is %.12g, reader DBU is set to %.12g)")), - *lp, new_layout->dbu (), layout.dbu ()); + warn (tl::sprintf (tl::to_string (tr ("DBU of macro layout file '%s' does not match reader DBU (layout DBU is %.12g, reader DBU is set to %.12g)")), + *lp, new_layout->dbu (), layout.dbu ())); } } @@ -1063,6 +1066,33 @@ LEFDEFReaderState::warn (const std::string &msg, int warn_level) } } +void +LEFDEFReaderState::ensure_lef_importer (int warn_level) +{ + if (! mp_lef_importer.get ()) { + mp_lef_importer.reset (new db::LEFImporter (warn_level)); + } +} + +db::LEFImporter & +LEFDEFReaderState::lef_importer () +{ + tl_assert (mp_lef_importer.get () != 0); + return *mp_lef_importer; +} + +void +LEFDEFReaderState::read_lef (tl::InputStream &stream, db::Layout &layout) +{ + lef_importer ().read (stream, layout, *this); +} + +void +LEFDEFReaderState::finish_lef (db::Layout &layout) +{ + lef_importer ().finish_lef (layout); +} + void LEFDEFReaderState::register_layer (const std::string &ln) { @@ -1774,11 +1804,56 @@ std::set LEFDEFReaderState::open_layer_uncached(db::Layout &layout } } +void +LEFDEFReaderState::start () +{ + CommonReaderBase::start (); + + m_foreign_cells.clear (); +} + void LEFDEFReaderState::finish (db::Layout &layout) { CommonReaderBase::finish (layout); + // Resolve unresolved COMPONENT cells + + db::cell_index_type seen = std::numeric_limits::max (); + + for (std::vector::const_iterator m = macro_layouts ().begin (); m != macro_layouts ().end (); ++m) { + + std::vector target_cells, source_cells; + + // collect the cells to pull in + for (std::map::iterator f = m_foreign_cells.begin (); f != m_foreign_cells.end (); ++f) { + if (f->second != seen) { + std::pair cp = (*m)->cell_by_name (f->first.c_str ()); + if (cp.first) { + target_cells.push_back (f->second); + source_cells.push_back (cp.second); + layout.cell (f->second).set_ghost_cell (false); + f->second = seen; + } + } + } + + db::CellMapping cm; + cm.create_multi_mapping_full (layout, target_cells, **m, source_cells); + layout.copy_tree_shapes (**m, cm); + + } + + // Warn about cells that could not be resolved + for (std::map::iterator f = m_foreign_cells.begin (); f != m_foreign_cells.end (); ++f) { + if (f->second != seen && layout.cell (f->second).is_ghost_cell ()) { + warn (tl::sprintf (tl::to_string (tr ("Could not find a substitution layout for foreign cell '%s'")), + f->first)); + } + } + + // Create the layers + int lnum = 0; std::set used_numbers; diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h index 9fa0e6d04..fc75c5c63 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h @@ -46,6 +46,7 @@ namespace db class LEFDEFReaderState; class LEFDEFImporter; +class LEFImporter; struct MacroDesc; /** @@ -1325,8 +1326,15 @@ public: */ void register_layer (const std::string &l); + /** + * @brief Start reading a file + * After the file is read, "finish" needs to be called. + */ + void start (); + /** * @brief Finish, i.e. assign GDS layer numbers to the layers + * This is the counterpart for "start". */ void finish (db::Layout &layout); @@ -1390,6 +1398,28 @@ public: */ void warn (const std::string &msg, int warn_level = 1); + /** + * @brief Ensures the LEF importer for DEF reading is available + */ + void ensure_lef_importer (int warn_level); + + /** + * @brief Gets the LEF importer for DEF reading + */ + db::LEFImporter &lef_importer (); + + /** + * @brief Reads a LEF file into the LEF importer + * + * Multiple LEF files can be read. + */ + void read_lef (tl::InputStream &stream, db::Layout &layout); + + /** + * @brief Provided for test purposes + */ + void finish_lef (db::Layout &layout); + /** * @brief Gets a value indicating whether the given LEF file was already read */ @@ -1510,6 +1540,7 @@ private: std::set m_lef_files_read; std::vector m_macro_layouts; tl::shared_collection m_macro_layout_object_holder; + std::unique_ptr mp_lef_importer; std::set open_layer_uncached (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask); db::cell_index_type foreign_cell(Layout &layout, const std::string &name); diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc index 0985b0531..7dad8a35e 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc @@ -138,6 +138,9 @@ LEFDEFReader::read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &opti state = &local_state; } + state->ensure_lef_importer (warn_level ()); + state->start (); + // Configure the conflict resolution mode db::CommonReaderOptions common_options = options.get_options (); state->set_conflict_resolution_mode (common_options.cell_conflict_resolution); @@ -186,7 +189,7 @@ LEFDEFReader::read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &opti tl::InputStream lef_stream (norm_lp); tl::log << tl::to_string (tr ("Reading")) << " " << *lp; - importer.read_lef (lef_stream, layout, *state); + state->read_lef (lef_stream, layout); state->register_lef_file (norm_lp); @@ -219,7 +222,7 @@ LEFDEFReader::read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &opti tl::InputStream lef_stream (norm_lp); tl::log << tl::to_string (tr ("Reading")) << " " << lp; - importer.read_lef (lef_stream, layout, *state); + state->read_lef (lef_stream, layout); state->register_lef_file (norm_lp); @@ -236,42 +239,6 @@ LEFDEFReader::read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &opti tl::log << tl::to_string (tr ("Reading")) << " " << m_stream.source (); importer.read (m_stream, layout, *state); - // Resolve unresolved COMPONENT cells - - std::map foreign_cells = state->foreign_cells (); - db::cell_index_type seen = std::numeric_limits::max (); - - for (std::vector::const_iterator m = state->macro_layouts ().begin (); m != state->macro_layouts ().end (); ++m) { - - std::vector target_cells, source_cells; - - // collect the cells to pull in - for (std::map::iterator f = foreign_cells.begin (); f != foreign_cells.end (); ++f) { - if (f->second != seen) { - std::pair cp = (*m)->cell_by_name (f->first.c_str ()); - if (cp.first) { - target_cells.push_back (f->second); - source_cells.push_back (cp.second); - layout.cell (f->second).set_ghost_cell (false); - f->second = seen; - } - } - } - - db::CellMapping cm; - cm.create_multi_mapping_full (layout, target_cells, **m, source_cells); - layout.copy_tree_shapes (**m, cm); - - } - - // Warn about cells that could not be resolved - for (std::map::iterator f = foreign_cells.begin (); f != foreign_cells.end (); ++f) { - if (f->second != seen && layout.cell (f->second).is_ghost_cell ()) { - importer.warn (tl::sprintf (tl::to_string (tr ("Could not find a substitution layout for foreign cell '%s'")), - f->first)); - } - } - } state->finish (layout); diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index a493959b6..a7448f1e7 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -61,10 +61,11 @@ static db::LayerMap read (db::Layout &layout, const char *lef_dir, const char *f db::LoadLayoutOptions other_options; db::LEFDEFReaderState ld (&options); + ld.ensure_lef_importer (1); ld.init (layout, fn_path, other_options); ld.set_conflict_resolution_mode (cc_mode); - db::DEFImporter imp; + db::DEFImporter imp (1); bool any_def = false; bool any_lef = false; @@ -95,7 +96,7 @@ static db::LayerMap read (db::Layout &layout, const char *lef_dir, const char *f fn += f; tl::InputStream stream (fn); - imp.read_lef (stream, layout, ld); + ld.read_lef (stream, layout); any_lef = true; @@ -136,7 +137,7 @@ static db::LayerMap read (db::Layout &layout, const char *lef_dir, const char *f } if (! any_def && any_lef) { - imp.finish_lef (layout); + ld.finish_lef (layout); } ld.finish (layout); From baed5bd822ae2816e615c388e1a515fcf3202519 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 17 May 2025 00:57:36 +0200 Subject: [PATCH 04/10] Small refactoring --- .../streamers/lefdef/db_plugin/dbLEFDEFImporter.cc | 5 ++++- .../streamers/lefdef/db_plugin/dbLEFDEFImporter.h | 11 +---------- .../streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc | 10 ++-------- .../lefdef/unit_tests/dbLEFDEFImportTests.cc | 3 +-- 4 files changed, 8 insertions(+), 21 deletions(-) diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index 8776f6827..3059105da 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -1082,9 +1082,12 @@ LEFDEFReaderState::lef_importer () } void -LEFDEFReaderState::read_lef (tl::InputStream &stream, db::Layout &layout) +LEFDEFReaderState::read_lef (const std::string &fn, db::Layout &layout) { + tl::InputStream stream (fn); lef_importer ().read (stream, layout, *this); + + m_lef_files_read.insert (fn); } void diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h index fc75c5c63..ddb90415e 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h @@ -1413,7 +1413,7 @@ public: * * Multiple LEF files can be read. */ - void read_lef (tl::InputStream &stream, db::Layout &layout); + void read_lef (const std::string &fn, db::Layout &layout); /** * @brief Provided for test purposes @@ -1428,15 +1428,6 @@ public: return m_lef_files_read.find (fn) != m_lef_files_read.end (); } - /** - * @brief Registers a LEF file - * After registration, the same file will report "already_read" - */ - void register_lef_file (const std::string &fn) - { - m_lef_files_read.insert (fn); - } - /** * @brief Gets the stored macro layouts */ diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc index 7dad8a35e..e4e7dfb80 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFPlugin.cc @@ -187,11 +187,8 @@ LEFDEFReader::read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &opti tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading LEF file: ")) + *lp); - tl::InputStream lef_stream (norm_lp); tl::log << tl::to_string (tr ("Reading")) << " " << *lp; - state->read_lef (lef_stream, layout); - - state->register_lef_file (norm_lp); + state->read_lef (norm_lp, layout); } @@ -220,11 +217,8 @@ LEFDEFReader::read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &opti tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading LEF file: ")) + lp); - tl::InputStream lef_stream (norm_lp); tl::log << tl::to_string (tr ("Reading")) << " " << lp; - state->read_lef (lef_stream, layout); - - state->register_lef_file (norm_lp); + state->read_lef (norm_lp, layout); } diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index a7448f1e7..9ccb295a4 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -95,8 +95,7 @@ static db::LayerMap read (db::Layout &layout, const char *lef_dir, const char *f ex.read_word_or_quoted (f); fn += f; - tl::InputStream stream (fn); - ld.read_lef (stream, layout); + ld.read_lef (fn, layout); any_lef = true; From 4206d7ee634151669af79e85b2970cc0553c8b4e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 17 May 2025 01:00:57 +0200 Subject: [PATCH 05/10] Tried a performance improvement experiment, don't dare to actually use it --- src/buddies/src/bd/bdReaderOptions.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/buddies/src/bd/bdReaderOptions.cc b/src/buddies/src/bd/bdReaderOptions.cc index 091412826..958bdb723 100644 --- a/src/buddies/src/bd/bdReaderOptions.cc +++ b/src/buddies/src/bd/bdReaderOptions.cc @@ -846,6 +846,10 @@ static std::vector split_file_list (const std::string &infile) void read_files (db::Layout &layout, const std::string &infile, const db::LoadLayoutOptions &options) { + // We may do this: + // db::LayoutLocker locker (&layout); + // but there are yet unknown side effects + // enter a LEF caching context for chaining multiple DEF with the same LEF db::LoadLayoutOptions local_options (options); local_options.set_option_by_name ("lefdef_config.lef_context_enabled", true); From 8221923ccbbf6de5ed2ee7506411a4504fc58adb Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 17 May 2025 16:50:47 +0200 Subject: [PATCH 06/10] Added a large (private) testcase for the 'read LEF once' enhancement --- src/buddies/unit_tests/bdConverterTests.cc | 324 +++++++++++++++++++++ 1 file changed, 324 insertions(+) diff --git a/src/buddies/unit_tests/bdConverterTests.cc b/src/buddies/unit_tests/bdConverterTests.cc index eb8eef30d..4dfd7d20e 100644 --- a/src/buddies/unit_tests/bdConverterTests.cc +++ b/src/buddies/unit_tests/bdConverterTests.cc @@ -186,3 +186,327 @@ TEST(6) db::compare_layouts (this, layout, input_au, db::WriteGDS2); } + +// Large LEF/DEF to OAS converter test +TEST(10) +{ + test_is_long_runner (); + + std::string input_dir = tl::testdata_private (); + input_dir += "/lefdef/strm2oas/"; + + std::string lef_dir = input_dir + "/lef"; + std::string def_dir = input_dir + "/def"; + std::string gds_dir = input_dir + "/gds"; + + std::string input_au = input_dir + "/strm2oas_au.oas"; + + std::string output = this->tmp_file ("strm2oas.oas"); + std::string map_arg = "--lefdef-map=" + input_dir + "/sky130.map"; + + const char *lef_files[] = { + "sky130_fd_sc_hd.tlef", + "sky130_fd_sc_hd_merged.lef", + "sky130_fd_sc_hs_merged.lef", + "sky130_ef_sc_hd__decap_20_12.lef", + "sky130_ef_sc_hd__decap_80_12.lef", + "sky130_ef_sc_hd__fill_4.lef", + "sky130_ef_sc_hd__decap_40_12.lef", + "sky130_ef_sc_hd__decap_60_12.lef", + "sky130_ef_io__analog_esd_pad.lef", + "sky130_ef_io__analog_noesd_pad.lef", + "sky130_ef_io__analog_pad.lef", + "sky130_ef_io__bare_pad.lef", + "sky130_ef_io__com_bus_slice_10um.lef", + "sky130_ef_io__com_bus_slice_1um.lef", + "sky130_ef_io__com_bus_slice_20um.lef", + "sky130_ef_io__com_bus_slice_5um.lef", + "sky130_ef_io__connect_vcchib_vccd_and_vswitch_vddio_slice_20um.lef", + "sky130_ef_io__corner_pad.lef", + "sky130_ef_io__disconnect_vccd_slice_5um.lef", + "sky130_ef_io__disconnect_vdda_slice_5um.lef", + "sky130_ef_io__gpiov2_pad.lef", + "sky130_ef_io__gpiov2_pad_wrapped.lef", + "sky130_ef_io__top_power_hvc.lef", + "sky130_ef_io__vccd_hvc_pad.lef", + "sky130_ef_io__vccd_lvc_clamped2_pad.lef", + "sky130_ef_io__vccd_lvc_clamped3_pad.lef", + "sky130_ef_io__vccd_lvc_clamped_pad.lef", + "sky130_ef_io__vccd_lvc_pad.lef", + "sky130_ef_io__vdda_hvc_clamped_pad.lef", + "sky130_ef_io__vdda_hvc_pad.lef", + "sky130_ef_io__vdda_lvc_pad.lef", + "sky130_ef_io__vddio_hvc_clamped_pad.lef", + "sky130_ef_io__vddio_hvc_pad.lef", + "sky130_ef_io__vddio_lvc_pad.lef", + "sky130_ef_io__vssa_hvc_clamped_pad.lef", + "sky130_ef_io__vssa_hvc_pad.lef", + "sky130_ef_io__vssa_lvc_pad.lef", + "sky130_ef_io__vssd_hvc_pad.lef", + "sky130_ef_io__vssd_lvc_clamped2_pad.lef", + "sky130_ef_io__vssd_lvc_clamped3_pad.lef", + "sky130_ef_io__vssd_lvc_clamped_pad.lef", + "sky130_ef_io__vssd_lvc_pad.lef", + "sky130_ef_io__vssio_hvc_clamped_pad.lef", + "sky130_ef_io__vssio_hvc_pad.lef", + "sky130_ef_io__vssio_lvc_pad.lef", + "sky130_fd_io__signal_5_sym_hv_local_5term.lef", + "sky130_fd_io__top_gpiov2.lef", + "sky130_fd_io__top_power_hvc_wpadv2.lef", + "sky130_fd_sc_hvl__a21o_1.lef", + "sky130_fd_sc_hvl__a21oi_1.lef", + "sky130_fd_sc_hvl__a22o_1.lef", + "sky130_fd_sc_hvl__a22oi_1.lef", + "sky130_fd_sc_hvl__and2_1.lef", + "sky130_fd_sc_hvl__and3_1.lef", + "sky130_fd_sc_hvl__buf_1.lef", + "sky130_fd_sc_hvl__buf_16.lef", + "sky130_fd_sc_hvl__buf_2.lef", + "sky130_fd_sc_hvl__buf_32.lef", + "sky130_fd_sc_hvl__buf_4.lef", + "sky130_fd_sc_hvl__buf_8.lef", + "sky130_fd_sc_hvl__conb_1.lef", + "sky130_fd_sc_hvl__decap_4.lef", + "sky130_fd_sc_hvl__decap_8.lef", + "sky130_fd_sc_hvl__dfrbp_1.lef", + "sky130_fd_sc_hvl__dfrtp_1.lef", + "sky130_fd_sc_hvl__dfsbp_1.lef", + "sky130_fd_sc_hvl__dfstp_1.lef", + "sky130_fd_sc_hvl__dfxbp_1.lef", + "sky130_fd_sc_hvl__dfxtp_1.lef", + "sky130_fd_sc_hvl__diode_2.lef", + "sky130_fd_sc_hvl__dlclkp_1.lef", + "sky130_fd_sc_hvl__dlrtp_1.lef", + "sky130_fd_sc_hvl__dlxtp_1.lef", + "sky130_fd_sc_hvl__einvn_1.lef", + "sky130_fd_sc_hvl__einvp_1.lef", + "sky130_fd_sc_hvl__fill_1.lef", + "sky130_fd_sc_hvl__fill_2.lef", + "sky130_fd_sc_hvl__fill_4.lef", + "sky130_fd_sc_hvl__fill_8.lef", + "sky130_fd_sc_hvl__inv_1.lef", + "sky130_fd_sc_hvl__inv_16.lef", + "sky130_fd_sc_hvl__inv_2.lef", + "sky130_fd_sc_hvl__inv_4.lef", + "sky130_fd_sc_hvl__inv_8.lef", + "sky130_fd_sc_hvl__lsbufhv2hv_hl_1.lef", + "sky130_fd_sc_hvl__lsbufhv2hv_lh_1.lef", + "sky130_fd_sc_hvl__lsbufhv2lv_1.lef", + "sky130_fd_sc_hvl__lsbufhv2lv_simple_1.lef", + "sky130_fd_sc_hvl__lsbuflv2hv_1.lef", + "sky130_fd_sc_hvl__lsbuflv2hv_clkiso_hlkg_3.lef", + "sky130_fd_sc_hvl__lsbuflv2hv_isosrchvaon_1.lef", + "sky130_fd_sc_hvl__lsbuflv2hv_symmetric_1.lef", + "sky130_fd_sc_hvl__mux2_1.lef", + "sky130_fd_sc_hvl__mux4_1.lef", + "sky130_fd_sc_hvl__nand2_1.lef", + "sky130_fd_sc_hvl__nand3_1.lef", + "sky130_fd_sc_hvl__nor2_1.lef", + "sky130_fd_sc_hvl__nor3_1.lef", + "sky130_fd_sc_hvl__o21a_1.lef", + "sky130_fd_sc_hvl__o21ai_1.lef", + "sky130_fd_sc_hvl__o22a_1.lef", + "sky130_fd_sc_hvl__o22ai_1.lef", + "sky130_fd_sc_hvl__or2_1.lef", + "sky130_fd_sc_hvl__or3_1.lef", + "sky130_fd_sc_hvl__probe_p_8.lef", + "sky130_fd_sc_hvl__probec_p_8.lef", + "sky130_fd_sc_hvl__schmittbuf_1.lef", + "sky130_fd_sc_hvl__sdfrbp_1.lef", + "sky130_fd_sc_hvl__sdfrtp_1.lef", + "sky130_fd_sc_hvl__sdfsbp_1.lef", + "sky130_fd_sc_hvl__sdfstp_1.lef", + "sky130_fd_sc_hvl__sdfxbp_1.lef", + "sky130_fd_sc_hvl__sdfxtp_1.lef", + "sky130_fd_sc_hvl__sdlclkp_1.lef", + "sky130_fd_sc_hvl__sdlxtp_1.lef", + "sky130_fd_sc_hvl__xnor2_1.lef", + "sky130_fd_sc_hvl__xor2_1.lef", + "caravel.lef", + "caravel_clocking.lef", + "caravel_core.lef", + "gpio_defaults_block.lef", + "gpio_logic_high.lef", + "housekeeping.lef", + "mgmt_protect_hv.lef", + "mprj2_logic_high.lef", + "mprj_io_buffer.lef", + "mprj_logic_high.lef", + "spare_logic_block.lef", + "user_project_wrapper.lef", + "xres_buf.lef", + "caravel_logo-stub.lef", + "caravel_motto-stub.lef", + "chip_io.lef", + "copyright_block-stub.lef", + "empty_macro.lef", + "manual_power_connections.lef", + "open_source-stub.lef", + "simple_por.lef", + "user_id_programming.lef", + "user_id_textblock-stub.lef", + "RAM128.lef" + }; + + std::string lefs_arg = "--lefdef-lefs="; + for (size_t i = 0; i < sizeof (lef_files) / sizeof (lef_files[0]); ++i) { + if (i > 0) { + lefs_arg += ","; + } + lefs_arg += lef_dir + "/" + lef_files[i]; + } + + const char *lefdef_layout_files[] = { + "sky130_fd_sc_hd.gds", + "sky130_fd_sc_hvl__sdlxtp_1.gds", + "sky130_fd_sc_hvl__decap_8.gds", + "sky130_fd_sc_hvl__decap_4.gds", + "sky130_fd_sc_hvl__nand3_1.gds", + "sky130_fd_sc_hvl__sdfxbp_1.gds", + "sky130_fd_sc_hvl__lsbufhv2hv_hl_1.gds", + "sky130_fd_sc_hvl__sdfrbp_1.gds", + "sky130_fd_sc_hvl__a21o_1.gds", + "sky130_fd_sc_hvl__inv_2.gds", + "sky130_fd_sc_hvl__inv_16.gds", + "sky130_fd_sc_hvl__inv_1.gds", + "sky130_fd_sc_hvl__inv_4.gds", + "sky130_fd_sc_hvl__inv_8.gds", + "sky130_fd_sc_hvl__nand2_1.gds", + "sky130_fd_sc_hvl__dfstp_1.gds", + "sky130_fd_sc_hvl__a22o_1.gds", + "sky130_fd_sc_hvl__schmittbuf_1.gds", + "sky130_fd_sc_hvl__a22oi_1.gds", + "sky130_fd_sc_hvl__lsbuflv2hv_1.gds", + "sky130_fd_sc_hvl__fill_4.gds", + "sky130_fd_sc_hvl__fill_1.gds", + "sky130_fd_sc_hvl__fill_2.gds", + "sky130_fd_sc_hvl__fill_8.gds", + "sky130_fd_sc_hvl__sdfrtp_1.gds", + "sky130_fd_sc_hvl__sdfxtp_1.gds", + "sky130_fd_sc_hvl__o22a_1.gds", + "sky130_fd_sc_hvl__dfsbp_1.gds", + "sky130_fd_sc_hvl__o21a_1.gds", + "sky130_fd_sc_hvl__a21oi_1.gds", + "sky130_fd_sc_hvl__buf_1.gds", + "sky130_fd_sc_hvl__buf_2.gds", + "sky130_fd_sc_hvl__buf_4.gds", + "sky130_fd_sc_hvl__buf_32.gds", + "sky130_fd_sc_hvl__buf_16.gds", + "sky130_fd_sc_hvl__buf_8.gds", + "sky130_fd_sc_hvl__einvp_1.gds", + "sky130_fd_sc_hvl__conb_1.gds", + "sky130_fd_sc_hvl__and3_1.gds", + "sky130_fd_sc_hvl__lsbufhv2lv_1.gds", + "sky130_fd_sc_hvl__and2_1.gds", + "sky130_fd_sc_hvl__nor3_1.gds", + "sky130_fd_sc_hvl__dlclkp_1.gds", + "sky130_fd_sc_hvl__lsbuflv2hv_symmetric_1.gds", + "sky130_fd_sc_hvl__sdfstp_1.gds", + "sky130_fd_sc_hvl__dfrbp_1.gds", + "sky130_fd_sc_hvl__dfxbp_1.gds", + "sky130_fd_sc_hvl__nor2_1.gds", + "sky130_fd_sc_hvl__diode_2.gds", + "sky130_fd_sc_hvl__dlrtp_1.gds", + "sky130_fd_sc_hvl__dlxtp_1.gds", + "sky130_fd_sc_hvl__lsbufhv2lv_simple_1.gds", + "sky130_fd_sc_hvl__lsbuflv2hv_clkiso_hlkg_3.gds", + "sky130_fd_sc_hvl__sdlclkp_1.gds", + "sky130_fd_sc_hvl__o22ai_1.gds", + "sky130_fd_sc_hvl__or3_1.gds", + "sky130_fd_sc_hvl__sdfsbp_1.gds", + "sky130_fd_sc_hvl__xor2_1.gds", + "sky130_fd_sc_hvl__mux4_1.gds", + "sky130_fd_sc_hvl__or2_1.gds", + "sky130_fd_sc_hvl__probe_p_8.gds", + "sky130_fd_sc_hvl__dfxtp_1.gds", + "sky130_fd_sc_hvl__mux2_1.gds", + "sky130_fd_sc_hvl__dfrtp_1.gds", + "sky130_fd_sc_hvl__lsbuflv2hv_isosrchvaon_1.gds", + "sky130_fd_sc_hvl__probec_p_8.gds", + "sky130_fd_sc_hvl__xnor2_1.gds", + "sky130_fd_sc_hvl__einvn_1.gds", + "sky130_fd_sc_hvl__o21ai_1.gds", + "sky130_fd_sc_hvl__lsbufhv2hv_lh_1.gds", + "sky130_ef_io__analog.gds", + "sky130_ef_io__bare_pad.gds", + "sky130_ef_io__connect_vcchib_vccd_and_vswitch_vddio_slice_20um.gds", + "sky130_ef_io__disconnect_vccd_slice_5um.gds", + "sky130_ef_io__disconnect_vdda_slice_5um.gds", + "sky130_ef_io__gpiov2_pad_wrapped.gds", + "sky130_ef_sc_hd__decap_12.gds", + "sky130_ef_sc_hd__decap_20_12.gds", + "sky130_ef_sc_hd__decap_40_12.gds", + "sky130_ef_sc_hd__decap_60_12.gds", + "sky130_ef_sc_hd__decap_80_12.gds", + "sky130_ef_sc_hd__fill_12.gds", + "sky130_ef_sc_hd__fill_2.gds", + "sky130_ef_sc_hd__fill_4.gds", + "sky130_ef_sc_hd__fill_8.gds", + "sky130_ef_sc_hvl__fill_8.gds", + "caravel_logo.gds.gz", + "caravel_motto.gds.gz", + "chip_io.gds.gz", + "copyright_block.gds.gz", + "empty_macro.gds.gz", + "manual_power_connections.gds.gz", + "open_source.gds.gz", + "simple_por.gds.gz", + "user_id_programming.gds.gz", + "user_id_textblock.gds.gz", + "RAM128.gds.gz" + }; + + std::string lefdef_layouts_arg = "--lefdef-lef-layouts="; + for (size_t i = 0; i < sizeof (lefdef_layout_files) / sizeof (lefdef_layout_files[0]); ++i) { + if (i > 0) { + lefdef_layouts_arg += ","; + } + lefdef_layouts_arg += gds_dir + "/" + lefdef_layout_files[i]; + } + + const char *def_files[] = { + "caravel.def", + "caravel_clocking.def", + "caravel_core.def.gz", + "gpio_defaults_block.def", + "gpio_logic_high.def", + "housekeeping.def", + "mgmt_protect_hv.def", + "mprj2_logic_high.def", + "mprj_io_buffer.def", + "mprj_logic_high.def", + "spare_logic_block.def", + "user_project_wrapper.def", + "xres_buf.def" + }; + + std::string input; + for (size_t i = 0; i < sizeof (def_files) / sizeof (def_files[0]); ++i) { + if (i > 0) { + input += ","; + } + input += def_dir + "/" + def_files[i]; + } + + const char *argv[] = { "x", + "--lefdef-no-implicit-lef", + map_arg.c_str (), + lefs_arg.c_str (), + lefdef_layouts_arg.c_str (), + input.c_str (), + output.c_str () + }; + + EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0); + + db::Layout layout; + + { + tl::InputStream stream (output); + db::LoadLayoutOptions options; + db::Reader reader (stream); + reader.read (layout, options); + } + + db::compare_layouts (this, layout, input_au, db::WriteOAS); +} From a07d742bee3ee50de74f65b0ac11806b5516e0e5 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 18 May 2025 00:48:10 +0200 Subject: [PATCH 07/10] Fixed a problem with via uniquification - via definitions may be DEF local, so we need to clean them between different DEF reads. --- .../lefdef/db_plugin/dbDEFImporter.cc | 2 ++ .../lefdef/db_plugin/dbLEFDEFImporter.cc | 20 +++++++++++++++++++ .../lefdef/db_plugin/dbLEFDEFImporter.h | 4 +++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc index 3aa4d79c7..a47f99d32 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc @@ -1182,8 +1182,10 @@ DEFImporter::read_vias (db::Layout &layout, db::Cell & /*design*/, double scale) if (rule_based_vg.get () && geo_based_vg.get ()) { error (tl::to_string (tr ("A via can only be defined through a VIARULE or geometry, not both ways"))); } else if (rule_based_vg.get ()) { + rule_based_vg->def_local = true; reader_state ()->register_via_cell (n, std::string (), rule_based_vg.release ()); } else if (geo_based_vg.get ()) { + geo_based_vg->def_local = true; reader_state ()->register_via_cell (n, std::string (), geo_based_vg.release ()); } else { error (tl::to_string (tr ("Too little information to generate a via"))); diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index 3059105da..4d1ecba24 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -1810,9 +1810,29 @@ std::set LEFDEFReaderState::open_layer_uncached(db::Layout &layout void LEFDEFReaderState::start () { + // Start over for a new DEF file - this function is used in LEF context mode + // i.e. when LEFs are cached during multiple DEF reads. It is called when a new DEF is read. + CommonReaderBase::start (); m_foreign_cells.clear (); + + // Remove the via generators that were added by DEF + // TODO: there is no concept for "local LEFs" currently. Even LEFs stored along + // with DEFs are considered "global". + for (auto vg = m_via_generators.begin (); vg != m_via_generators.end (); ) { + auto vg_here = vg; + ++vg; + if (vg_here->second->def_local) { + delete vg_here->second; + m_via_generators.erase (vg_here); + } + } + + // We always create fresh via cells for different DEFs to avoid potential + // content conflicts. Problem is: vias can be generated by both LEF (global) + // and DEF (local) + m_via_cells.clear (); } void diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h index ddb90415e..5c2a2a346 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h @@ -1141,12 +1141,14 @@ public: class DB_PLUGIN_PUBLIC LEFDEFLayoutGenerator { public: - LEFDEFLayoutGenerator () { } + LEFDEFLayoutGenerator () : def_local (false) { } virtual ~LEFDEFLayoutGenerator () { } virtual void create_cell (LEFDEFReaderState &reader, db::Layout &layout, db::Cell &cell, const std::vector *maskshift_layers, const std::vector &masks, const LEFDEFNumberOfMasks *nm) = 0; virtual std::vector maskshift_layers () const = 0; virtual bool is_fixedmask () const = 0; + + bool def_local; }; /** From e27e24ff4f6b727e5c7c8fe0c156ed9dc34e6866 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 18 May 2025 22:00:39 +0200 Subject: [PATCH 08/10] Bugfixing multi-DEF reader with LEF cache, adding a testcase. Making unknown vias an error. --- .../lefdef/db_plugin/dbLEFDEFImporter.cc | 56 ++++++----- .../lefdef/db_plugin/dbLEFDEFImporter.h | 3 +- .../lefdef/unit_tests/dbLEFDEFImportTests.cc | 33 +++++++ testdata/lefdef/multi_def/au.oas | Bin 0 -> 980 bytes testdata/lefdef/multi_def/comp_a.def | 20 ++++ testdata/lefdef/multi_def/comp_a.lef | 12 +++ testdata/lefdef/multi_def/comp_b.def | 20 ++++ testdata/lefdef/multi_def/comp_b.lef | 12 +++ testdata/lefdef/multi_def/comp_c.def | 16 ++++ testdata/lefdef/multi_def/comp_c.lef | 12 +++ testdata/lefdef/multi_def/layers.map | 7 ++ testdata/lefdef/multi_def/main.def | 13 +++ testdata/lefdef/multi_def/out.oas | Bin 0 -> 980 bytes testdata/lefdef/multi_def/tech.lef | 89 ++++++++++++++++++ 14 files changed, 270 insertions(+), 23 deletions(-) create mode 100644 testdata/lefdef/multi_def/au.oas create mode 100644 testdata/lefdef/multi_def/comp_a.def create mode 100644 testdata/lefdef/multi_def/comp_a.lef create mode 100644 testdata/lefdef/multi_def/comp_b.def create mode 100644 testdata/lefdef/multi_def/comp_b.lef create mode 100644 testdata/lefdef/multi_def/comp_c.def create mode 100644 testdata/lefdef/multi_def/comp_c.lef create mode 100644 testdata/lefdef/multi_def/layers.map create mode 100644 testdata/lefdef/multi_def/main.def create mode 100644 testdata/lefdef/multi_def/out.oas create mode 100644 testdata/lefdef/multi_def/tech.lef diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index 4d1ecba24..dbbe55cf1 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -1947,48 +1947,52 @@ LEFDEFReaderState::finish (db::Layout &layout) void LEFDEFReaderState::register_via_cell (const std::string &vn, const std::string &nondefaultrule, LEFDEFLayoutGenerator *generator) { - if (m_via_generators.find (std::make_pair (vn, nondefaultrule)) != m_via_generators.end ()) { - delete m_via_generators [std::make_pair (vn, nondefaultrule)]; - } - m_via_generators [std::make_pair (vn, nondefaultrule)] = generator; + // inserts at the end of the range + m_via_generators.insert (std::make_pair (std::make_pair (vn, nondefaultrule), generator)); } LEFDEFLayoutGenerator * LEFDEFReaderState::via_generator (const std::string &vn, const std::string &nondefaultrule) { - std::map, LEFDEFLayoutGenerator *>::const_iterator g = m_via_generators.find (std::make_pair (vn, nondefaultrule)); - if (g == m_via_generators.end () && ! nondefaultrule.empty ()) { - // default rule is fallback - g = m_via_generators.find (std::make_pair (vn, std::string ())); + return via_generator_and_rule (vn, nondefaultrule).first; +} + +std::pair +LEFDEFReaderState::via_generator_and_rule (const std::string &vn, const std::string &nondefaultrule) +{ + auto key = std::make_pair (vn, nondefaultrule); + + auto g = m_via_generators.upper_bound (key); + if (g != m_via_generators.begin ()) { + --g; } - if (g != m_via_generators.end ()) { - return g->second; + + if (g == m_via_generators.end () || g->first != key) { + if (nondefaultrule.empty ()) { + return std::pair (0, std::string ()); + } else { + // default rule is fallback + return via_generator_and_rule (vn, std::string ()); + } } else { - return 0; + return std::make_pair (g->second, nondefaultrule); } } db::Cell * LEFDEFReaderState::via_cell (const std::string &vn, const std::string &nondefaultrule, db::Layout &layout, unsigned int mask_bottom, unsigned int mask_cut, unsigned int mask_top, const LEFDEFNumberOfMasks *nm) { - ViaKey vk (vn, nondefaultrule, mask_bottom, mask_cut, mask_top); + auto gr = via_generator_and_rule (vn, nondefaultrule); + LEFDEFLayoutGenerator *vg = gr.first; - std::map, LEFDEFLayoutGenerator *>::const_iterator g = m_via_generators.find (std::make_pair (vn, nondefaultrule)); - - if (g == m_via_generators.end () && ! vk.nondefaultrule.empty ()) { - // default rule is fallback - g = m_via_generators.find (std::make_pair (vn, std::string ())); - vk.nondefaultrule.clear (); - } + ViaKey vk (vn, gr.second, mask_bottom, mask_cut, mask_top); std::map::const_iterator i = m_via_cells.find (vk); if (i == m_via_cells.end ()) { db::Cell *cell = 0; - if (g != m_via_generators.end ()) { - - LEFDEFLayoutGenerator *vg = g->second; + if (vg) { std::string n = vn; @@ -2017,6 +2021,14 @@ LEFDEFReaderState::via_cell (const std::string &vn, const std::string &nondefaul vg->create_cell (*this, layout, *cell, 0, masks, nm); + } else { + + std::string details; + if (! nondefaultrule.empty () && nondefaultrule != vk.nondefaultrule) { + details = tl::sprintf (tl::to_string (tr (" (trying with NONDEFAULTRULE '%s' and without)")), nondefaultrule); + } + error (tl::sprintf (tl::to_string (tr ("Could not find a via specification with name '%s'")) + details, vn)); + } m_via_cells[vk] = cell; diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h index 5c2a2a346..d801c04b2 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.h @@ -1526,7 +1526,7 @@ private: std::map m_default_number; const LEFDEFReaderOptions *mp_tech_comp; std::map m_via_cells; - std::map, LEFDEFLayoutGenerator *> m_via_generators; + std::multimap, LEFDEFLayoutGenerator *> m_via_generators; std::map > m_macro_cells; std::map m_macro_generators; std::map m_foreign_cells; @@ -1538,6 +1538,7 @@ private: std::set open_layer_uncached (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask); db::cell_index_type foreign_cell(Layout &layout, const std::string &name); void read_single_map_file (const std::string &path, std::map, std::vector > &layer_map); + std::pair via_generator_and_rule (const std::string &vn, const std::string &nondefaultrule); }; /** diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index 9ccb295a4..fb786413f 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -25,6 +25,7 @@ #include "dbWriter.h" #include "dbDEFImporter.h" #include "dbLEFImporter.h" +#include "dbCommonReader.h" #include "tlUnitTest.h" #include "dbTestSupport.h" @@ -1102,3 +1103,35 @@ TEST(214_issue1877) db::compare_layouts (_this, ly, fn_path + "au.oas", db::WriteOAS); } +// multi-DEF reader support (issue-2014) +TEST(215_multiDEF) +{ + std::string fn_path (tl::testdata ()); + fn_path += "/lefdef/multi_def/"; + + db::Layout ly; + + db::LoadLayoutOptions opt; + // anything else will not make much sense + opt.get_options ().cell_conflict_resolution = db::CellConflictResolution::RenameCell; + + // Test "set_option_by_name" + opt.set_option_by_name ("lefdef_config.lef_context_enabled", true); + opt.set_option_by_name ("lefdef_config.map_file", "layers.map"); + opt.set_option_by_name ("lefdef_config.read_lef_with_def", true); + + const char *files[] = { + "main.def", + "comp_a.def", + "comp_b.def", + "comp_c.def" + }; + + for (const char **fn = files; fn != files + sizeof (files) / sizeof (files[0]); ++fn) { + tl::InputStream is (fn_path + *fn); + db::Reader reader (is); + reader.read (ly, opt); + } + + db::compare_layouts (_this, ly, fn_path + "au.oas", db::WriteOAS); +} diff --git a/testdata/lefdef/multi_def/au.oas b/testdata/lefdef/multi_def/au.oas new file mode 100644 index 0000000000000000000000000000000000000000..3b6e663675cd55e565e8efcce65c6a068de4517d GIT binary patch literal 980 zcmY!lcJ=kt^>+;R4CduxWH!_@V0gjKC?n3q!6L)YEF;ds&!EJR>XUoMnybM;fb~F; z;|1o9>4KX(8~>b$4qRRSKbqrK6n{_8gJqfe+C@(E01b3CypJk0~AJy4vpC7rjNt zSg>0}I6yj2GtY2=h}rZF4LOH(*%^3wM6H<_7@3v`eGu5mF_}};l9iF^ir^K&*Bq}o zL~U6ZnIY2a#PUC1VC$;`;qz}3Ndl%p31V3;>lyTrw#whrK2cnD{pE3r)3(N=X1TQcxkQcnb$RKhUWUUgzWX6Q# zM1MaWFCFi*i4z3VAM7}J=+Lw|^P>gkpWt|u*Hk!phQpma3G5R?JvSWYq@K~qQIHgM<`ejCEj%N8Nzw_+;R4CduxWH!_@V0gjKC?n3q!6L)YEF;ds&!EJR>XUoMnybM;fb~F; z;|1o9>4KX(8~>b$4qRRSKbqrK6n{_8gJqfe+C@(E01b3CypJk0~AJy4vpC7rjNt zSg>0}I6yj2GtY2=h}rZF4LOH(*%^3wM6H<_7@3v`eGu5mF_}};l9iF^ir^K&*Bq}o zL~U6ZnIY2a#PUC1VC$;`;qz}3Ndl%p31V3;>lyTrw#whrK2cnD{pE3r)3(N=X1TQcxkQcnb$RKhUWUUgzWX6Q# zM1MaWFCFi*i4z3VAM7}J=+Lw|^P>gkpWt|u*Hk!phQpma3G5R?JvSWYq@K~qQIHgM<`ejCEj%N8Nzw_ Date: Sun, 18 May 2025 22:16:13 +0200 Subject: [PATCH 09/10] Postpone decision about "invalid vias are errors." --- .../lefdef/db_plugin/dbDEFImporter.cc | 7 +- .../lefdef/unit_tests/dbLEFDEFImportTests.cc | 15 +++ .../lefdef/invalid_via/comp_invalid_via.def | 16 ++++ testdata/lefdef/invalid_via/tech.lef | 89 ++++++++++++++++++ testdata/lefdef/multi_def/au.oas | Bin 980 -> 1054 bytes 5 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 testdata/lefdef/invalid_via/comp_invalid_via.def create mode 100644 testdata/lefdef/invalid_via/tech.lef diff --git a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc index a47f99d32..b07a347b0 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc @@ -749,7 +749,12 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C } std::map::const_iterator vd = m_via_desc.find (vn); - if (vd != m_via_desc.end () && ! pts.empty ()) { + + if (vd == m_via_desc.end ()) { + + warn (tl::to_string (tr ("Invalid via name: ")) + vn); + + } else if (! pts.empty ()) { // For the via, the masks are encoded in a three-digit number ( ) unsigned int mask_top = (mask / 100) % 10; diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index fb786413f..f430e4829 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -898,6 +898,21 @@ TEST(132_issue1307_pin_names) run_test (_this, "issue-1307c", "lef:in.lef+def:in.def", "au.oas", opt, false); } +/* +TODO: need to clarify first, if invalid via specs should be errors +TEST(133_unknown_vias_are_errors) +{ + db::LEFDEFReaderOptions opt = default_options (); + + try { + run_test (_this, "invalid_via", "lef:tech.lef+def:comp_invalid_via.def", "au.oas", opt, false); + EXPECT_EQ (true, false); + } catch (db::LEFDEFReaderException &ex) { + EXPECT_EQ (ex.msg ().find ("Invalid via name"), size_t (0)); + } +} +*/ + TEST(200_lefdef_plugin) { db::Layout ly; diff --git a/testdata/lefdef/invalid_via/comp_invalid_via.def b/testdata/lefdef/invalid_via/comp_invalid_via.def new file mode 100644 index 000000000..1eb475daf --- /dev/null +++ b/testdata/lefdef/invalid_via/comp_invalid_via.def @@ -0,0 +1,16 @@ +VERSION 5.8 ; +DIVIDERCHAR "/" ; +BUSBITCHARS "[]" ; +DESIGN comp_invalid_via ; +UNITS DISTANCE MICRONS 1000 ; +DIEAREA ( 0 0 ) ( 10000 2000 ) ; + +SPECIALNETS 2 ; + - VGND ( PIN VGND ) ( * VNB ) ( * VGND ) + USE GROUND + + ROUTED met1 480 + SHAPE FOLLOWPIN ( 0 1000 ) ( 2000 1000 ) + NEW met1 0 + SHAPE STRIPE ( 2000 1000 ) via1 + + ROUTED met2 480 + SHAPE FOLLOWPIN ( 2000 1000 ) ( 4000 1000 ) + NEW met2 0 + SHAPE STRIPE ( 4000 1000 ) invalid_via ; +END SPECIALNETS +END DESIGN + diff --git a/testdata/lefdef/invalid_via/tech.lef b/testdata/lefdef/invalid_via/tech.lef new file mode 100644 index 000000000..cae5bcd54 --- /dev/null +++ b/testdata/lefdef/invalid_via/tech.lef @@ -0,0 +1,89 @@ + +VERSION 5.7 ; + +BUSBITCHARS "[]" ; +DIVIDERCHAR "/" ; +USEMINSPACING OBS OFF ; + +UNITS + DATABASE MICRONS 1000 ; +END UNITS + +MANUFACTURINGGRID 0.005 ; + +LAYER met1 + TYPE ROUTING ; + DIRECTION HORIZONTAL ; + PITCH 0.34 ; + OFFSET 0.17 ; + WIDTH 0.14 ; +END met1 + +LAYER via + TYPE CUT ; + WIDTH 0.15 ; + SPACING 0.17 ; +END via + +LAYER met2 + TYPE ROUTING ; + DIRECTION VERTICAL ; + PITCH 0.46 ; + OFFSET 0.23 ; + WIDTH 0.14 ; +END met2 + +LAYER via2 + TYPE CUT ; + WIDTH 0.2 ; + SPACING 0.2 ; +END via2 + +LAYER met3 + TYPE ROUTING ; + DIRECTION HORIZONTAL ; + PITCH 0.68 ; + OFFSET 0.34 ; + WIDTH 0.3 ; +END met3 + +VIA via1 DEFAULT + LAYER via ; + RECT -0.075 -0.075 0.075 0.075 ; + LAYER met1 ; + RECT -0.16 -0.24 0.16 0.24 ; + LAYER met2 ; + RECT -0.13 -0.24 0.13 0.24 ; +END via1 + +VIARULE M1M2_PR GENERATE + LAYER met1 ; + ENCLOSURE 0.085 0.055 ; + LAYER met2 ; + ENCLOSURE 0.055 0.085 ; + LAYER via ; + RECT -0.075 -0.075 0.075 0.075 ; + SPACING 0.32 BY 0.32 ; +END M1M2_PR + +VIA via2 DEFAULT + LAYER via2 ; + RECT -0.1 -0.1 0.1 0.1 ; + LAYER met2 ; + RECT -0.14 -0.24 0.14 0.24 ; + LAYER met3 ; + RECT -0.165 -0.165 0.165 0.165 ; +END via2 + +VIARULE M2M3_PR GENERATE + LAYER met2 ; + ENCLOSURE 0.04 0.085 ; + LAYER met3 ; + ENCLOSURE 0.065 0.065 ; + LAYER via2 ; + RECT -0.1 -0.1 0.1 0.1 ; + SPACING 0.4 BY 0.4 ; +END M2M3_PR + +END LIBRARY + diff --git a/testdata/lefdef/multi_def/au.oas b/testdata/lefdef/multi_def/au.oas index 3b6e663675cd55e565e8efcce65c6a068de4517d..4f1002177a8d410edd5fe2bc9136b840a45c8f47 100644 GIT binary patch delta 304 zcmcb@K96HUv62#ly4>Rwe?J{B9q+RbQ#gyi7e7q#K6hTX!@uQ{XMmL?!^E1z$txJ; z8M!B)V3eKg%9uRyt~n#?WKl)~Zf3y`JO}J9@C!cRp8SDPj8{gTk%N(+QB06|fxPTw zZYCvu6cJv=$QTiQ1TQcju!D%P2wq@XATOf`G=y330wV*M#Uye#g<*o962of7 zwB$snOA{vurayR*l$r=}Y6?qX{$_`ro<0iiq$JE|N*?)p`phB0XD=nF@jUKUOyM(14VHWyzh=YNNaWg9; U1EVryG2>Lm$q$%5GBGd!0A&1IEC2ui delta 249 zcmbQoafN+CF()T`a$-?pS!&M2sfm-PF`6@SPd>+JFxi+fdEz&Dc~+5XMur1S510=! zJ!BRMWNu+vgO5b`olj%89{6%%A$AU|1$Nr@fI;$@utpHZP6!e$V>ze3?he97$*2BF-&GmNKW+k)A7>rKASi}F#W-flZOsXn=?OJVEze?M|n+! zlV>>G$&)ajDS4#!(3wL)(`IIz;Cdv}T+nmFVNU89og4*8QD;7Z@7BUIvX>;C;Cv*P w*mO#&uzAPi#7%BC3h#2=_!*cO-?K0>Fe)<^GuALNOg3bGJ=uYom5G4?0HlUf(*OVf From ad444c55525b671700543178768ff36b875caa0f Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 28 May 2025 18:58:28 +0200 Subject: [PATCH 10/10] Don't error out on missing MACRO in LEF, but create a dummy macro with size 0,0 instead and issue a warning. This will place nicely with N, but not with other orientations. --- .../lefdef/db_plugin/dbDEFImporter.cc | 30 ++++++++++++++---- .../lefdef/db_plugin/dbLEFImporter.h | 10 +++++- .../lefdef/unit_tests/dbLEFDEFImportTests.cc | 3 ++ .../lefdef/foreigncell/au_no_macros.oas.gz | Bin 0 -> 1242 bytes testdata/lefdef/foreigncell/macros.gds | Bin 0 -> 3718 bytes 5 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 testdata/lefdef/foreigncell/au_no_macros.oas.gz create mode 100644 testdata/lefdef/foreigncell/macros.gds diff --git a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc index b07a347b0..ed3856e6e 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbDEFImporter.cc @@ -1594,6 +1594,7 @@ DEFImporter::read_styles (double scale) } } + void DEFImporter::read_components (db::Layout &layout, std::list > &instances, double scale) { @@ -1607,9 +1608,26 @@ DEFImporter::read_components (db::Layout &layout, std::list::const_iterator m = reader_state ()->lef_importer ().macros ().find (model); - if (m == reader_state ()->lef_importer ().macros ().end ()) { - error (tl::to_string (tr ("Macro not found in LEF file: ")) + model); + const MacroDesc *m = 0; + + std::map::const_iterator im = reader_state ()->lef_importer ().macros ().find (model); + if (im == reader_state ()->lef_importer ().macros ().end ()) { + + warn (tl::sprintf (tl::to_string (tr ("Macro not found in LEF file: %s - creating dummy macro")), model)); + + // create a dummy macro definition (no FOREIGN, size 0x0 etc.) + GeometryBasedLayoutGenerator *mg = new GeometryBasedLayoutGenerator (); + reader_state ()->register_macro_cell (model, mg); + + MacroDesc macro_desc; + macro_desc.bbox = db::Box (db::Point (), db::Point ()); + + m = reader_state ()->lef_importer ().insert_macro (model, macro_desc); + + } else { + + m = &im->second; + } while (test ("+")) { @@ -1621,7 +1639,7 @@ DEFImporter::read_components (db::Layout &layout, std::listsecond.bbox.transformed (ft).lower_left (); + d = pt - m->bbox.transformed (ft).lower_left (); is_placed = true; } else if (test ("UNPLACED")) { @@ -1633,7 +1651,7 @@ DEFImporter::read_components (db::Layout &layout, std::listsecond.bbox.transformed (ft).lower_left (); + d = pt - m->bbox.transformed (ft).lower_left (); is_placed = true; } @@ -1654,7 +1672,7 @@ DEFImporter::read_components (db::Layout &layout, std::list ct = reader_state ()->macro_cell (model, layout, m_component_maskshift, string2masks (maskshift), m->second, &reader_state ()->lef_importer ()); + std::pair ct = reader_state ()->macro_cell (model, layout, m_component_maskshift, string2masks (maskshift), *m, &reader_state ()->lef_importer ()); if (ct.first) { db::CellInstArray inst (db::CellInst (ct.first->cell_index ()), db::Trans (ft.rot (), d) * ct.second); instances.push_back (std::make_pair (inst_name, inst)); diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h index 94721a5fe..38c953194 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFImporter.h @@ -122,7 +122,7 @@ public: } /** - * @brief Gets the + * @brief Gets the macros map * * The map maps the macro name to the macro description. */ @@ -131,6 +131,14 @@ public: return m_macros; } + /** + * @brief Inserts a macro description for a name + */ + const MacroDesc *insert_macro (const std::string &mn, const MacroDesc &m) + { + return &m_macros.insert (std::make_pair (mn, m)).first->second; + } + /** * @brief Finishes reading a LEF file * diff --git a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc index f430e4829..8f27111a6 100644 --- a/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc +++ b/src/plugins/streamers/lefdef/unit_tests/dbLEFDEFImportTests.cc @@ -521,6 +521,9 @@ TEST(109_foreigncell) 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); + + // no macros -> warning + run_test (_this, "foreigncell", "gds:macros.gds+lef:in_tech.lef+def:in.def", "au_no_macros.oas.gz", options, false); } TEST(110_lefpins) diff --git a/testdata/lefdef/foreigncell/au_no_macros.oas.gz b/testdata/lefdef/foreigncell/au_no_macros.oas.gz new file mode 100644 index 0000000000000000000000000000000000000000..98458d212ca3c5a581a8d6692d4a5d5196e68acb GIT binary patch literal 1242 zcmY!lcJ=kt^>+;R4CduxWH!_@V0gjKC?n3q!6L)YEF;ds&!EIm7M^>?kgLIf$L*n^ z!iwD$Gn0~auPrkXEdBMqp4&D2`TLJ6LVe~4rOcb!YvuZ(D`;uK)^4_=&-^lYX4)p1 z@x>Ind~wRnEGcr^Il9=>}tN-`TE11|qHHhe}yW6K1d% zOx$sCo0XE2xtHj|3;}WG<|z`wyh~P^xX#^fzBN=Jc5boVyYr2+Jc9JT&njHX6Owf5 z(h=RO+FRKL&K>_ZL+a#%<_Bw+EPJ~>ith?%+B1)tSAH{@a6EHzc~j6WoBl)L`6QkN zkrQI0gq}aQTk_6XFN9O9^IT5ZgWVq{E;G#keIjMI#(9nS$-j;SCvRMEs^EuG#KrnN z|NnPOu6*CM*Y{qq?bkJeGM5jP$NW&Scr5;#$9MYb1iR=RC&Xs3B)(YReE;k1)%Tv2 zo^=jaVvrJgoc5ic_v6Pe#i`fQ(jGWIV_@KARAT64ddcW|Zm-wj0EuIT^S__Gg#Z%9HIMFPbo>AH- zXGQ%)x@j@YSQL}f~9!)LUvZrma`|Tx` z&m%5u%Y69g`MUH+GGG25Kc~+NOhGf4-Z8rNZv=W+r0wtdlfBoM%oCfv`zJ$h@ImpF zO0HgotKMI9oMSabK~_ek#akoj6Hm~Rj>-KBvQ5p-6E6ks*?8gH^WQ)A7w-xz{pixE z-@fRn2NUN~wd0qj>@rcABwSqQHqW!7%P{``g702`*SWT7+U-2hl3wwku5aO~kI!ar zOP@FK=j~*^?$cg7!p-%cJlXpBSd7*4+s3&pfd(9lr*Y;t$CqX0t_-#*RDUS4beqSI ziR+90JBPmEU@jKi?juva@5I52LHwbO)>{?Cr!Cxms44A**o_6Rs@1zEg%@NL&o@cz zwtPGL*_40(4T@yG@xtB9O@>c!8M#%wiNt)&^$33;aq9;SR}ZoQ1s{69v;BRGc|kbv42!uU{+dHTv3*vpP|PaQ=eADj^hjrOpMdm85tOr8S5DD NFflSTj4Z&w006azIpqKV literal 0 HcmV?d00001 diff --git a/testdata/lefdef/foreigncell/macros.gds b/testdata/lefdef/foreigncell/macros.gds new file mode 100644 index 0000000000000000000000000000000000000000..6bf27d07297c1d02d47d91344d8d79f537f21f8d GIT binary patch literal 3718 zcmeH~y-!n77{=dwZ@JVe6_uE1hzlfGMJe_Bqb7o2hy;x3K>TWIDT*o8&_-}|GdeiS z(!s=NjEfEo#=$`sCkOuo6E_DZ7kr*`&Z}3f5{(fxp5*X5_x(QS-20MBD84@??VjKK zR+^+;*2*sFj;gCB5gs_p~Khr9D9EE-M%C9J@vVhIcabDw%__N?Ck99A05dJ zjOFq}BZH%OlvqL}zBZ&xR<#DABi!msQj*=_@&19~;jGb9)*|a6+gvNn)>7H7!O;@~ zLq|t4T|(U|X{Bzea6Xmo=tytxHPV&RMrpZvxlo*}Sd|z}LN*#r;c96*l|5A^_wUT~ zWX@Rq3hOypxl)?0mQvY?Lb+Npo^ffX=ftH-Eng{2LDyBSjpzB?Wqq4X?ZyJdq>Wc- zGUoeDfZc`s9w8Gyda{v;Jo%4jc+x@ulMZPGded} zs2UHOLs%_tHQQIHP8LOCYcO#$341f0y+409y}$NucKp8^-c7T7_gjmH_KS+ealb9T zY>_bOi!Y}mUzq*U27wHw@*vi@cu{V~dK0FSYwDF)x?$d#Mfo0>e2mSZF-cC!ImaC< zAmwBSCgsXKSm!aRKjuhZ%E{H3l(RP4k@Tlr<7iw`^;jBz_s%b>|FNlmmPQyPbJZR1 zgRJLTggmD?OtOx-&5?CdPJ8tu)sE*`$J~HPIqN1l>gKOy0_&TYv}ax=mZrYO`zV`z zJf;x_$$h+ukaa!9RI;vDm`diMUdcM>uf)>C{a*eB8ex#|^I{P)FXc+q=dHuD5^^tT z^@jAPUWujgZ=C-L_wVhd5!j7C^dlLUa^}f7o^^5(--eMZagW}p(;sl8KjkFu&7++0 zX-6_HoJc~?ICjYHu|n=W^+Hcz8E?77~75$#CEc?jaW^1i3$w=R`Tr{gET>DJPkiag?;9ob}V6 zd<{}gG7sg<%Xpf<4bSxBdD2darHSv}lO_6S!uC=8|NF9&2EVzJ2J&}z(m?)=P8!Ja zc2dp1T%9zKf2)%Q@@I5Xts~k=*|Fwb=OWn=+2P20AUi7Um6X$t9r9U(+WC}F{a6Q_ rDio(LWfuQZTUc1Qh)^HwZ-u4%sEL9;iZT}cs_@<;*4|HXVlnv$B$a~F literal 0 HcmV?d00001