From 271800ab94e1e0ed010d3d981ed9732edcb52302 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 15 May 2025 23:27:03 +0200 Subject: [PATCH] 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;