From 78695f9c233686d25558b53ee60a43ac2c50d6ee Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 13 Dec 2020 12:13:21 +0100 Subject: [PATCH 1/8] WIP: new technology management scheme, libraries can be tech specific, update of technology in layout updates library references --- src/db/db/dbLayout.cc | 151 +++++++++++- src/db/db/dbLayout.h | 23 +- src/db/db/dbLayoutContextHandler.cc | 2 +- src/db/db/dbLibrary.cc | 3 + src/db/db/dbLibraryManager.cc | 46 +++- src/db/db/dbLibraryManager.h | 67 ++++- src/db/db/dbPCellDeclaration.h | 4 +- src/db/db/gsiDeclDbLayout.cc | 20 +- src/db/db/gsiDeclDbLibrary.cc | 45 +++- src/db/unit_tests/dbLibrariesTests.cc | 40 +++ src/edt/edt/edtEditorOptionsPages.cc | 78 +++--- src/edt/edt/edtEditorOptionsPages.h | 15 +- src/edt/edt/edtPCellParametersPage.cc | 231 +++++++++--------- src/edt/edt/edtPCellParametersPage.h | 4 +- src/edt/edt/edtPlugin.cc | 12 +- src/edt/edt/edtRecentConfigurationPage.cc | 26 +- src/edt/edt/edtRecentConfigurationPage.h | 7 +- src/edt/edt/edtServiceImpl.cc | 4 +- src/lay/lay/layLibraryController.cc | 35 ++- src/lay/lay/layLibraryController.h | 10 +- src/lay/lay/layMainWindow.cc | 2 +- src/laybasic/laybasic/layCellView.cc | 26 +- src/laybasic/laybasic/layCellView.h | 6 +- src/laybasic/laybasic/layEditorOptionsPage.cc | 31 ++- src/laybasic/laybasic/layEditorOptionsPage.h | 21 +- .../lefdef/db_plugin/dbLEFDEFImporter.cc | 6 +- .../streamers/magic/db_plugin/dbMAGReader.cc | 6 +- .../streamers/magic/db_plugin/dbMAGReader.h | 2 +- .../streamers/magic/db_plugin/dbMAGWriter.cc | 4 +- 29 files changed, 682 insertions(+), 245 deletions(-) diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index 2e767684e..e73be99d4 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -24,6 +24,7 @@ #include "dbLayout.h" #include "dbMemStatistics.h" #include "dbTrans.h" +#include "dbTechnology.h" #include "dbShapeRepository.h" #include "dbPCellHeader.h" #include "dbPCellVariant.h" @@ -442,6 +443,152 @@ Layout::operator= (const Layout &d) return *this; } +const db::Technology * +Layout::technology () const +{ + return db::Technologies::instance ()->technology_by_name (m_tech_name); +} + +void +Layout::set_technology_name (const std::string &tech) +{ + if (tech == m_tech_name) { + return; + } + + // determine which library to map to what + std::map mapping; + std::set seen; + + for (db::Layout::iterator c = begin (); c != end (); ++c) { + + db::LibraryProxy *lib_proxy = dynamic_cast (&*c); + if (lib_proxy && seen.find (lib_proxy->lib_id ()) == seen.end ()) { + + seen.insert (lib_proxy->lib_id ()); + + std::pair new_id (false, 0); + const db::Library *l = db::LibraryManager::instance ().lib (lib_proxy->lib_id ()); + if (l) { + new_id = db::LibraryManager::instance ().lib_by_name (l->get_name (), tech); + } + + if (new_id.first && new_id.second != l->get_id ()) { + mapping.insert (std::make_pair (l->get_id (), new_id.second)); + } + + } + + } + + if (mapping.empty ()) { + + bool needs_cleanup = false; + + std::vector > pcells_to_map; + std::vector lib_cells_to_map; + + for (db::Layout::iterator c = begin (); c != end (); ++c) { + + std::map::const_iterator m; + + db::LibraryProxy *lib_proxy = dynamic_cast (&*c); + if (lib_proxy && (m = mapping.find (lib_proxy->lib_id ())) != mapping.end ()) { + + db::Cell *lib_cell = &cell (lib_proxy->library_cell_index ()); + db::PCellVariant *lib_pcell = dynamic_cast (lib_cell); + if (lib_pcell) { + pcells_to_map.push_back (std::make_pair (lib_proxy, lib_pcell)); + } else { + lib_cells_to_map.push_back (lib_proxy); + } + + needs_cleanup = true; + + } + + } + + // We do PCell resolution before the library proxy resolution. The reason is that + // PCells may generate library proxies in their instantiation. Hence we must instantiate + // the PCells before we can resolve them. + for (std::vector >::const_iterator lp = pcells_to_map.begin (); lp != pcells_to_map.end (); ++lp) { + + db::cell_index_type ci = lp->first->Cell::cell_index (); + db::PCellVariant *lib_pcell = lp->second; + + std::pair pn = lib_pcell->layout ()->pcell_by_name (lp->first->get_basic_name ().c_str ()); + + if (! pn.first) { + + // substitute by static layout cell + // @@@ TODO: keep reference so we don't loose the connection immediately. + std::string name = cell_name (ci); + db::Cell *old_cell = take_cell (ci); + insert_cell (ci, name, new db::Cell (*old_cell)); + delete old_cell; + + } else { + + db::Library *new_lib = db::LibraryManager::instance ().lib (mapping [lp->first->lib_id ()]); + + const db::PCellDeclaration *old_pcell_decl = lib_pcell->layout ()->pcell_declaration (lib_pcell->pcell_id ()); + const db::PCellDeclaration *new_pcell_decl = new_lib->layout ().pcell_declaration (pn.second); + if (! old_pcell_decl || ! new_pcell_decl) { + + // substitute by static layout cell + // @@@ TODO: keep reference so we don't loose the connection immediately. + std::string name = cell_name (ci); + db::Cell *old_cell = take_cell (ci); + insert_cell (ci, name, new db::Cell (*old_cell)); + delete old_cell; + + } else { + + // map pcell parameters by name + std::map param_by_name = lib_pcell->parameters_by_name (); + lp->first->remap (new_lib->get_id (), new_lib->layout ().get_pcell_variant (pn.second, new_pcell_decl->map_parameters (param_by_name))); + + } + + } + + } + + for (std::vector::const_iterator lp = lib_cells_to_map.begin (); lp != lib_cells_to_map.end (); ++lp) { + + db::Library *new_lib = db::LibraryManager::instance ().lib (mapping [(*lp)->lib_id ()]); + + db::cell_index_type ci = (*lp)->Cell::cell_index (); + + std::pair cn = new_lib->layout ().cell_by_name ((*lp)->get_basic_name ().c_str ()); + + if (! cn.first) { + + // unlink this proxy: substitute by static layout cell + // @@@ TODO: keep reference so we don't loose the connection immediately. + std::string name = cell_name (ci); + db::Cell *old_cell = take_cell (ci); + insert_cell (ci, name, new db::Cell (*old_cell)); + delete old_cell; + + } else { + + (*lp)->remap (new_lib->get_id (), cn.second); + + } + + } + + if (needs_cleanup) { + cleanup (); + } + + } + + m_tech_name = tech; +} + void Layout::mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const { @@ -2224,7 +2371,7 @@ Layout::recover_proxy_as (cell_index_type cell_index, std::vector : if (ex.test ("LIB=")) { std::string lib_name = ex.skip (); - Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (lib_name); + Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (lib_name, m_tech_name); if (! lib) { return false; } @@ -2284,7 +2431,7 @@ Layout::recover_proxy (std::vector ::const_iterator from, std::vect if (ex.test ("LIB=")) { std::string lib_name = ex.skip (); - Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (lib_name); + Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (lib_name, m_tech_name); if (! lib) { return 0; } diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index f1555cb61..c79629567 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -67,6 +67,7 @@ class Region; class Edges; class EdgePairs; class Texts; +class Technology; class CellMapping; class LayerMapping; @@ -555,10 +556,29 @@ public: } /** - * @brief Clear the layout + * @brief Clears the layout */ void clear (); + /** + * @brief Gets the technology name the layout is associated with + */ + const std::string &technology_name () const + { + return m_tech_name; + } + + /** + * @brief Gets the technology object the layout is associated with or null if no valid technology is associated + */ + const db::Technology *technology () const; + + /** + * @brief Changes the technology, the layout is associated with + * Changing the layout may re-assess all the library references as libraries can be technology specific + */ + void set_technology_name (const std::string &tech); + /** * @brief Accessor to the array repository */ @@ -1779,6 +1799,7 @@ private: bool m_do_cleanup; bool m_editable; meta_info m_meta_info; + std::string m_tech_name; tl::Mutex m_lock; /** diff --git a/src/db/db/dbLayoutContextHandler.cc b/src/db/db/dbLayoutContextHandler.cc index 5c6bf49fb..90cff6c50 100644 --- a/src/db/db/dbLayoutContextHandler.cc +++ b/src/db/db/dbLayoutContextHandler.cc @@ -80,7 +80,7 @@ tl::Variant LayoutContextHandler::eval_double_bracket (const std::string &s) con std::string tail = cp + 1; - db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname); + db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname, mp_layout->technology_name ()); if (! lib) { throw tl::Exception (tl::to_string (tr ("Not a valid library name: ")) + libname); } diff --git a/src/db/db/dbLibrary.cc b/src/db/db/dbLibrary.cc index 0e10fe3e9..3103f0c56 100644 --- a/src/db/db/dbLibrary.cc +++ b/src/db/db/dbLibrary.cc @@ -192,6 +192,7 @@ Library::remap_to (db::Library *other) if (! pn.first) { // substitute by static layout cell + // @@@ TODO: keep reference so we don't loose the connection immediately. std::string name = r->first->cell_name (ci); db::Cell *old_cell = r->first->take_cell (ci); r->first->insert_cell (ci, name, new db::Cell (*old_cell)); @@ -204,6 +205,7 @@ Library::remap_to (db::Library *other) if (! old_pcell_decl || ! new_pcell_decl) { // substitute by static layout cell + // @@@ TODO: keep reference so we don't loose the connection immediately. std::string name = r->first->cell_name (ci); db::Cell *old_cell = r->first->take_cell (ci); r->first->insert_cell (ci, name, new db::Cell (*old_cell)); @@ -233,6 +235,7 @@ Library::remap_to (db::Library *other) if (! cn.first) { // unlink this proxy: substitute by static layout cell + // @@@ TODO: keep reference so we don't loose the connection immediately. std::string name = r->first->cell_name (ci); db::Cell *old_cell = r->first->take_cell (ci); r->first->insert_cell (ci, name, new db::Cell (*old_cell)); diff --git a/src/db/db/dbLibraryManager.cc b/src/db/db/dbLibraryManager.cc index ba8f2b685..8a8a0ff9e 100644 --- a/src/db/db/dbLibraryManager.cc +++ b/src/db/db/dbLibraryManager.cc @@ -66,14 +66,24 @@ LibraryManager::~LibraryManager () } std::pair -LibraryManager::lib_by_name (const std::string &name) const +LibraryManager::lib_by_name (const std::string &name, const std::set &for_technologies) const { iterator l = m_lib_by_name.find (name); - if (l == m_lib_by_name.end ()) { - return std::make_pair (false, lib_id_type (0)); - } else { - return std::make_pair (true, l->second); + while (l != m_lib_by_name.end () && l->first == name) { + bool found = true; + for (std::set::const_iterator t = for_technologies.begin (); t != for_technologies.end (); ++t) { + if (! lib (l->second)->is_for_technology (*t)) { + found = false; + break; + } + } + if (found) { + return std::make_pair (true, l->second); + } + ++l; } + + return std::make_pair (false, lib_id_type (0)); } void @@ -116,14 +126,28 @@ LibraryManager::register_lib (Library *library) library->set_id (id); // if the new library replaces the old one, remap existing library proxies before deleting the library - lib_name_map::iterator ln = m_lib_by_name.find (library->get_name ()); - if (ln != m_lib_by_name.end () && m_libs [ln->second]) { - m_libs [ln->second]->remap_to (library); - delete m_libs [ln->second]; - m_libs [ln->second] = 0; + // (replacement is done only when all technologies are substituted) + lib_name_map::iterator l = m_lib_by_name.find (library->get_name ()); + bool found = false; + while (l != m_lib_by_name.end () && l->first == library->get_name ()) { + if (m_libs [l->second] && m_libs [l->second]->get_technologies () == library->get_technologies ()) { + found = true; + break; + } + ++l; } - m_lib_by_name.insert (std::make_pair (library->get_name (), id)).first->second = id; + if (found) { + // substitute + m_libs [l->second]->remap_to (library); + delete m_libs [l->second]; + m_libs [l->second] = 0; + m_lib_by_name.erase (l); + } + + // insert new lib as first of this name + l = m_lib_by_name.find (library->get_name ()); + m_lib_by_name.insert (l, std::make_pair (library->get_name (), id)); changed_event (); diff --git a/src/db/db/dbLibraryManager.h b/src/db/db/dbLibraryManager.h index 48cf5e0a1..34d9e4428 100644 --- a/src/db/db/dbLibraryManager.h +++ b/src/db/db/dbLibraryManager.h @@ -33,6 +33,7 @@ #include #include #include +#include namespace db { @@ -50,7 +51,7 @@ class Library; class DB_PUBLIC LibraryManager { public: - typedef std::map lib_name_map; + typedef std::multimap lib_name_map; typedef lib_name_map::const_iterator iterator; /** @@ -90,11 +91,41 @@ public: } /** - * @brief Get the library by name + * @brief Get the library by name which is valid for all given technologies + * + * This method looks up a library which is valid for all technologies listed in "for_technologies". It may be + * responsible for more than that too. * * @return A pair, the boolean is true, if the name is valid. The second member is the library id. */ - std::pair lib_by_name (const std::string &name) const; + std::pair lib_by_name (const std::string &name, const std::set &for_technologies) const; + + /** + * @brief Get the library by name which is valid for the given technology + * + * This method looks up a library which is valid for the given technology. It may be + * responsible for more than that too. + * + * @return A pair, the boolean is true, if the name is valid. The second member is the library id. + */ + std::pair lib_by_name (const std::string &name, const std::string &for_technology) const + { + std::set techs; + if (! for_technology.empty ()) { + techs.insert (for_technology); + } + return lib_by_name (name, techs); + } + + /** + * @brief Get the library by name for any technology + * + * @return A pair, the boolean is true, if the name is valid. The second member is the library id. + */ + std::pair lib_by_name (const std::string &name) const + { + return lib_by_name (name, std::set ()); + } /** * @brief Get the library by name @@ -111,6 +142,36 @@ public: } } + /** + * @brief Get the library by name and technology + * + * @return The pointer to the library or 0, if there is no library with that name. + */ + Library *lib_ptr_by_name (const std::string &name, const std::string &for_technology) const + { + std::pair ll = lib_by_name (name, for_technology); + if (ll.first) { + return lib (ll.second); + } else { + return 0; + } + } + + /** + * @brief Get the library by name and technology + * + * @return The pointer to the library or 0, if there is no library with that name. + */ + Library *lib_ptr_by_name (const std::string &name, const std::set &for_technologies) const + { + std::pair ll = lib_by_name (name, for_technologies); + if (ll.first) { + return lib (ll.second); + } else { + return 0; + } + } + /** * @brief Register a library under the given name and associate a id * diff --git a/src/db/db/dbPCellDeclaration.h b/src/db/db/dbPCellDeclaration.h index 540efa369..e27ad00b0 100644 --- a/src/db/db/dbPCellDeclaration.h +++ b/src/db/db/dbPCellDeclaration.h @@ -29,6 +29,7 @@ #include "gsiObject.h" #include "dbLayout.h" #include "tlVariant.h" +#include "tlObject.h" namespace db { @@ -327,7 +328,8 @@ public: * @brief A declaration for a PCell */ class DB_PUBLIC PCellDeclaration - : public gsi::ObjectBase + : public gsi::ObjectBase, + public tl::Object { public: /** diff --git a/src/db/db/gsiDeclDbLayout.cc b/src/db/db/gsiDeclDbLayout.cc index 2e85264b4..e9539343d 100644 --- a/src/db/db/gsiDeclDbLayout.cc +++ b/src/db/db/gsiDeclDbLayout.cc @@ -39,6 +39,7 @@ #include "dbLayoutUtils.h" #include "dbLayerMapping.h" #include "dbCellMapping.h" +#include "dbTechnology.h" #include "tlStream.h" namespace gsi @@ -750,7 +751,7 @@ static db::Cell *create_cell2 (db::Layout *layout, const std::string &name, cons static db::Cell *create_cell3 (db::Layout *layout, const std::string &name, const std::string &libname) { - db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname); + db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname, layout->technology_name ()); if (! lib) { return 0; } @@ -765,7 +766,7 @@ static db::Cell *create_cell3 (db::Layout *layout, const std::string &name, cons static db::Cell *create_cell4 (db::Layout *layout, const std::string &name, const std::string &libname, const std::map ¶ms) { - db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname); + db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (libname, layout->technology_name ()); if (! lib) { return 0; } @@ -988,6 +989,21 @@ Class decl_Layout ("db", "Layout", "\n" "This method has been introduced in version 0.25." ) + + gsi::method ("technology_name", &db::Layout::technology_name, + "@brief Gets the name of the technology this layout is associated with\n" + "This method has been introduced in version 0.27. Before that, the technology has been kept in the 'technology' meta data element." + ) + + gsi::method ("technology", &db::Layout::technology, + "@brief Gets the \\Technology object of the technology this layout is associated with or nil if the layout is not associated with a technology\n" + "This method has been introduced in version 0.27. Before that, the technology has been kept in the 'technology' meta data element." + ) + + gsi::method ("technology_name=", &db::Layout::set_technology_name, gsi::arg ("name"), + "@brief Sets the name of the technology this layout is associated with\n" + "Changing the technology name will re-assess all library references because libraries can be technology specified. " + "Cell layouts may be substituted during this re-assessment.\n" + "\n" + "This method has been introduced in version 0.27." + ) + gsi::method ("is_editable?", &db::Layout::is_editable, "@brief Returns a value indicating whether the layout is editable.\n" "@return True, if the layout is editable.\n" diff --git a/src/db/db/gsiDeclDbLibrary.cc b/src/db/db/gsiDeclDbLibrary.cc index 0476a5087..a156b6375 100644 --- a/src/db/db/gsiDeclDbLibrary.cc +++ b/src/db/db/gsiDeclDbLibrary.cc @@ -43,9 +43,14 @@ static db::Library *new_lib () return new db::Library (); } -static db::Library *library_by_name (const std::string &name) +static db::Library *library_by_name (const std::string &name, const std::string &for_technology) { - return db::LibraryManager::instance ().lib_ptr_by_name (name); + return db::LibraryManager::instance ().lib_ptr_by_name (name, for_technology); +} + +static db::Library *library_by_id (db::lib_id_type id) +{ + return db::LibraryManager::instance ().lib (id); } static std::vector library_names () @@ -57,6 +62,15 @@ static std::vector library_names () return r; } +static std::vector library_ids () +{ + std::vector r; + for (db::LibraryManager::iterator l = db::LibraryManager::instance ().begin (); l != db::LibraryManager::instance ().end (); ++l) { + r.push_back (l->second); + } + return r; +} + static void register_lib (db::Library *lib, const std::string &name) { lib->set_name (name); @@ -110,22 +124,45 @@ LibraryClass decl_Library ("db", "Library", gsi::constructor ("new", &new_lib, "@brief Creates a new, empty library" ) + - gsi::method ("library_by_name", &library_by_name, gsi::arg ("name"), + gsi::method ("library_by_name", &library_by_name, gsi::arg ("name"), gsi::arg ("for_technology", std::string (), "unspecific"), "@brief Gets a library by name\n" "Returns the library object for the given name. If the name is not a valid\n" "library name, nil is returned.\n" + "\n" + "Different libraries can be registered under the same names for different technologies. When a technology name is given in 'for_technologies', " + "the first library matching this technology is returned. If no technology is given, the first library is returned.\n" + "\n" + "The technology selector has been introduced in version 0.27." + ) + + gsi::method ("library_by_id", &library_by_id, gsi::arg ("id"), + "@brief Gets the library object for the given ID\n" + "If the ID is not valid, nil is returned.\n" + "\n" + "This method has been introduced in version 0.27." ) + gsi::method ("library_names", &library_names, "@brief Returns a list of the names of all libraries registered in the system.\n" + "\n" + "NOTE: starting with version 0.27, the name of a library does not need to be unique if libraries are associated with specific technologies. " + "This method will only return the names and it's not possible not unambiguously derive the library object. It is recommended to use " + "\\library_ids and \\library_by_id to obtain the library unambiguously." + ) + + gsi::method ("library_ids", &library_ids, + "@brief Returns a list of valid library IDs.\n" + "See \\library_names for the reasoning behind this method." + "\n" + "This method has been introduced in version 0.27." ) + gsi::method_ext ("register", ®ister_lib, gsi::arg ("name"), "@brief Registers the library with the given name\n" "\n" "This method can be called in the constructor to register the library after \n" "the layout object has been filled with content. If a library with that name\n" - "already exists, it will be replaced with this library. \n" + "already exists for the same technologies, it will be replaced with this library. \n" "\n" "This method will set the libraries' name.\n" + "\n" + "The technology specific bahvior has been introduced in version 0.27." ) + gsi::method_ext ("delete", &delete_lib, "@brief Deletes the library\n" diff --git a/src/db/unit_tests/dbLibrariesTests.cc b/src/db/unit_tests/dbLibrariesTests.cc index 1be0d58f6..5e81a819c 100644 --- a/src/db/unit_tests/dbLibrariesTests.cc +++ b/src/db/unit_tests/dbLibrariesTests.cc @@ -617,3 +617,43 @@ TEST(3) } } +TEST(4) +{ + LIBT_A *lib_a1 = new LIBT_A (); + lib_a1->add_technology ("X"); + db::LibraryManager::instance ().register_lib (lib_a1); + + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a1->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a1->get_id ()); + + LIBT_A *lib_a2 = new LIBT_A (); + lib_a2->add_technology ("Y"); + db::LibraryManager::instance ().register_lib (lib_a2); + + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a2->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a1->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ()); + + LIBT_A *lib_a3 = new LIBT_A (); + lib_a3->add_technology ("X"); + db::LibraryManager::instance ().register_lib (lib_a3); + + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a3->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a3->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ()); +} + diff --git a/src/edt/edt/edtEditorOptionsPages.cc b/src/edt/edt/edtEditorOptionsPages.cc index 5cf86b819..b8c944587 100644 --- a/src/edt/edt/edtEditorOptionsPages.cc +++ b/src/edt/edt/edtEditorOptionsPages.cc @@ -69,8 +69,8 @@ static void configure_from_line_edit (lay::Dispatcher *dispatcher, QLineEdit *le // ------------------------------------------------------------------ // EditorOptionsGeneric implementation -EditorOptionsGeneric::EditorOptionsGeneric (lay::Dispatcher *dispatcher) - : EditorOptionsPage (dispatcher) +EditorOptionsGeneric::EditorOptionsGeneric (lay::LayoutView *view, lay::Dispatcher *dispatcher) + : EditorOptionsPage (view, dispatcher) { mp_ui = new Ui::EditorOptionsGeneric (); mp_ui->setupUi (this); @@ -206,8 +206,8 @@ EditorOptionsGeneric::setup (lay::Dispatcher *root) // ------------------------------------------------------------------ // EditorOptionsText implementation -EditorOptionsText::EditorOptionsText (lay::Dispatcher *dispatcher) - : lay::EditorOptionsPage (dispatcher) +EditorOptionsText::EditorOptionsText (lay::LayoutView *view, lay::Dispatcher *dispatcher) + : lay::EditorOptionsPage (view, dispatcher) { mp_ui = new Ui::EditorOptionsText (); mp_ui->setupUi (this); @@ -284,8 +284,8 @@ EditorOptionsText::setup (lay::Dispatcher *root) // ------------------------------------------------------------------ // EditorOptionsPath implementation -EditorOptionsPath::EditorOptionsPath (lay::Dispatcher *dispatcher) - : lay::EditorOptionsPage (dispatcher) +EditorOptionsPath::EditorOptionsPath (lay::LayoutView *view, lay::Dispatcher *dispatcher) + : lay::EditorOptionsPage (view, dispatcher) { mp_ui = new Ui::EditorOptionsPath (); mp_ui->setupUi (this); @@ -385,8 +385,8 @@ EditorOptionsPath::setup (lay::Dispatcher *root) // ------------------------------------------------------------------ // EditorOptionsInst implementation -EditorOptionsInst::EditorOptionsInst (lay::Dispatcher *dispatcher) - : lay::EditorOptionsPage (dispatcher) +EditorOptionsInst::EditorOptionsInst (lay::LayoutView *view, lay::Dispatcher *dispatcher) + : lay::EditorOptionsPage (view, dispatcher) { mp_ui = new Ui::EditorOptionsInst (); mp_ui->setupUi (this); @@ -579,21 +579,35 @@ EditorOptionsInst::apply (lay::Dispatcher *root) root->config_set (cfg_edit_inst_place_origin, tl::to_string (place_origin)); } -void +void +EditorOptionsInst::technology_changed (const std::string &) +{ + // The layout's technology has changed + setup (dispatcher ()); +} + +void +EditorOptionsInst::active_cellview_changed () +{ + // The active cellview has changed + setup (dispatcher ()); +} + +void EditorOptionsInst::setup (lay::Dispatcher *root) { - m_cv_index = -1; - if (lay::LayoutView::current ()) { - m_cv_index = lay::LayoutView::current ()->active_cellview_index (); - } + m_cv_index = view ()->active_cellview_index (); try { mp_ui->lib_cbx->blockSignals (true); + std::string techname; + mp_ui->lib_cbx->update_list (); if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) { - mp_ui->lib_cbx->set_technology_filter (lay::LayoutView::current ()->cellview (m_cv_index)->tech_name (), true); + techname = lay::LayoutView::current ()->cellview (m_cv_index)->tech_name (); + mp_ui->lib_cbx->set_technology_filter (techname, true); } else { mp_ui->lib_cbx->set_technology_filter (std::string (), false); } @@ -606,7 +620,7 @@ EditorOptionsInst::setup (lay::Dispatcher *root) // library std::string l; root->config_get (cfg_edit_inst_lib_name, l); - mp_ui->lib_cbx->set_current_library (db::LibraryManager::instance ().lib_ptr_by_name (l)); + mp_ui->lib_cbx->set_current_library (db::LibraryManager::instance ().lib_ptr_by_name (l, techname)); mp_ui->lib_cbx->blockSignals (false); update_cell_edits (); @@ -667,8 +681,8 @@ EditorOptionsInst::setup (lay::Dispatcher *root) // ------------------------------------------------------------------ // EditorOptionsInstPCellParam implementation -EditorOptionsInstPCellParam::EditorOptionsInstPCellParam (lay::Dispatcher *dispatcher) - : lay::EditorOptionsPage (dispatcher), mp_pcell_parameters (0), mp_placeholder_label (0) +EditorOptionsInstPCellParam::EditorOptionsInstPCellParam (lay::LayoutView *view, lay::Dispatcher *dispatcher) + : lay::EditorOptionsPage (view, dispatcher), mp_pcell_parameters (0), mp_placeholder_label (0) { mp_ui = new Ui::EditorOptionsInstPCellParam (); mp_ui->setupUi (this); @@ -693,7 +707,7 @@ EditorOptionsInstPCellParam::apply (lay::Dispatcher *root) std::string param; db::Layout *layout = 0; - db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name); + db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, view ()->active_cellview_ref ()->tech_name ()); if (lib) { layout = &lib->layout (); } else if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) { @@ -717,13 +731,16 @@ EditorOptionsInstPCellParam::apply (lay::Dispatcher *root) } } +void +EditorOptionsInstPCellParam::technology_changed (const std::string &) +{ + setup (dispatcher ()); +} + void EditorOptionsInstPCellParam::setup (lay::Dispatcher *root) { - m_cv_index = -1; - if (lay::LayoutView::current ()) { - m_cv_index = lay::LayoutView::current ()->active_cellview_index (); - } + m_cv_index = view ()->active_cellview_index (); bool needs_update = (mp_pcell_parameters == 0); @@ -743,7 +760,7 @@ EditorOptionsInstPCellParam::setup (lay::Dispatcher *root) needs_update = true; } - db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name); + db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, view ()->active_cellview_ref ()->tech_name ()); // pcell parameters std::string param; @@ -752,8 +769,8 @@ EditorOptionsInstPCellParam::setup (lay::Dispatcher *root) db::Layout *layout = 0; if (lib) { layout = &lib->layout (); - } else if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) { - layout = &lay::LayoutView::current ()->cellview (m_cv_index)->layout (); + } else if (m_cv_index >= 0 && view ()->cellview (m_cv_index).is_valid ()) { + layout = &view ()->cellview (m_cv_index)->layout (); } std::vector pv; @@ -820,15 +837,14 @@ void EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector ¶meters) { db::Layout *layout = 0; - lay::LayoutView *view = lay::LayoutView::current (); // find the layout the cell has to be looked up: that is either the layout of the current instance or // the library selected - db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name); + db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, view ()->active_cellview_ref ()->tech_name ()); if (lib) { layout = &lib->layout (); - } else if (view) { - const lay::CellView &cv = view->cellview (m_cv_index); + } else { + const lay::CellView &cv = view ()->cellview (m_cv_index); if (cv.is_valid ()) { layout = &cv->layout (); } @@ -856,10 +872,10 @@ EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector pcell_declaration (pc.second) && view && view->cellview (m_cv_index).is_valid ()) { + if (pc.first && layout->pcell_declaration (pc.second) && view ()->cellview (m_cv_index).is_valid ()) { mp_pcell_parameters = new PCellParametersPage (this, true /*dense*/); - mp_pcell_parameters->setup (&view->cellview (m_cv_index)->layout (), view, m_cv_index, layout->pcell_declaration (pc.second), parameters); + mp_pcell_parameters->setup (&view ()->cellview (m_cv_index)->layout (), view (), m_cv_index, layout->pcell_declaration (pc.second), parameters); this->layout ()->addWidget (mp_pcell_parameters); mp_pcell_parameters->set_state (pcp_state); diff --git a/src/edt/edt/edtEditorOptionsPages.h b/src/edt/edt/edtEditorOptionsPages.h index 3b639c5d8..92b697198 100644 --- a/src/edt/edt/edtEditorOptionsPages.h +++ b/src/edt/edt/edtEditorOptionsPages.h @@ -51,6 +51,7 @@ namespace lay { class PluginDeclaration; class Dispatcher; + class LayoutView; class Plugin; } @@ -68,7 +69,7 @@ class EditorOptionsGeneric Q_OBJECT public: - EditorOptionsGeneric (lay::Dispatcher *dispatcher); + EditorOptionsGeneric (lay::LayoutView *view, lay::Dispatcher *dispatcher); ~EditorOptionsGeneric (); virtual std::string title () const; @@ -91,7 +92,7 @@ class EditorOptionsText : public lay::EditorOptionsPage { public: - EditorOptionsText (lay::Dispatcher *dispatcher); + EditorOptionsText (lay::LayoutView *view, lay::Dispatcher *dispatcher); ~EditorOptionsText (); virtual std::string title () const; @@ -112,7 +113,7 @@ class EditorOptionsPath Q_OBJECT public: - EditorOptionsPath (lay::Dispatcher *dispatcher); + EditorOptionsPath (lay::LayoutView *view, lay::Dispatcher *dispatcher); ~EditorOptionsPath (); virtual std::string title () const; @@ -136,7 +137,7 @@ class EditorOptionsInst Q_OBJECT public: - EditorOptionsInst (lay::Dispatcher *root); + EditorOptionsInst (lay::LayoutView *view, lay::Dispatcher *root); ~EditorOptionsInst (); virtual std::string title () const; @@ -154,6 +155,9 @@ private: Ui::EditorOptionsInst *mp_ui; edt::PCellParametersPage *mp_pcell_parameters; int m_cv_index; + + virtual void technology_changed (const std::string &); + virtual void active_cellview_changed (); }; /** @@ -165,7 +169,7 @@ class EditorOptionsInstPCellParam Q_OBJECT public: - EditorOptionsInstPCellParam (lay::Dispatcher *root); + EditorOptionsInstPCellParam (lay::LayoutView *view, lay::Dispatcher *root); ~EditorOptionsInstPCellParam (); virtual std::string title () const; @@ -184,6 +188,7 @@ private: std::string m_lib_name, m_cell_name; void update_pcell_parameters (const std::vector ¶meters); + virtual void technology_changed (const std::string &); }; } diff --git a/src/edt/edt/edtPCellParametersPage.cc b/src/edt/edt/edtPCellParametersPage.cc index 01b667002..5908c8d36 100644 --- a/src/edt/edt/edtPCellParametersPage.cc +++ b/src/edt/edt/edtPCellParametersPage.cc @@ -153,7 +153,7 @@ PCellParametersPage::PCellParametersPage (QWidget *parent, bool dense) void PCellParametersPage::init () { - mp_pcell_decl = 0; + mp_pcell_decl.reset (0); mp_layout = 0; mp_view = 0; m_cv_index = 0; @@ -185,7 +185,7 @@ PCellParametersPage::init () void PCellParametersPage::setup (const db::Layout *layout, lay::LayoutView *view, int cv_index, const db::PCellDeclaration *pcell_decl, const db::pcell_parameters_type ¶meters) { - mp_pcell_decl = pcell_decl; + mp_pcell_decl.reset (const_cast (pcell_decl)); // no const weak_ptr ... mp_layout = layout; mp_view = view; m_cv_index = cv_index; @@ -457,131 +457,136 @@ std::vector PCellParametersPage::get_parameters (bool *ok) { std::vector parameters; - bool edit_error = true; - int r = 0; - const std::vector &pcp = mp_pcell_decl->parameter_declarations (); - for (std::vector::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++r) { + try { - if (p->is_hidden () || p->get_type () == db::PCellParameterDeclaration::t_shape) { + if (! mp_pcell_decl) { + throw tl::Exception (tl::to_string (tr ("PCell no longer valid."))); + } - if (r < (int) m_parameters.size ()) { - parameters.push_back (m_parameters [r]); - } else { - parameters.push_back (p->get_default ()); - } + bool edit_error = true; - } else { + int r = 0; + const std::vector &pcp = mp_pcell_decl->parameter_declarations (); + for (std::vector::const_iterator p = pcp.begin (); p != pcp.end (); ++p, ++r) { - parameters.push_back (tl::Variant ()); + if (p->is_hidden () || p->get_type () == db::PCellParameterDeclaration::t_shape) { - if (p->get_choices ().empty ()) { - - switch (p->get_type ()) { - - case db::PCellParameterDeclaration::t_int: - { - QLineEdit *le = dynamic_cast (m_widgets [r]); - if (le) { - - try { - - int v = 0; - tl::from_string (tl::to_string (le->text ()), v); - - parameters.back () = tl::Variant (v); - lay::indicate_error (le, 0); - - } catch (tl::Exception &ex) { - - lay::indicate_error (le, &ex); - edit_error = false; - - } - - } - } - break; - - case db::PCellParameterDeclaration::t_double: - { - QLineEdit *le = dynamic_cast (m_widgets [r]); - if (le) { - - try { - - double v = 0; - tl::from_string (tl::to_string (le->text ()), v); - - parameters.back () = tl::Variant (v); - lay::indicate_error (le, 0); - - } catch (tl::Exception &ex) { - - lay::indicate_error (le, &ex); - edit_error = false; - - } - - } - } - break; - - case db::PCellParameterDeclaration::t_string: - { - QLineEdit *le = dynamic_cast (m_widgets [r]); - if (le) { - parameters.back () = tl::Variant (tl::to_string (le->text ())); - } - } - break; - - case db::PCellParameterDeclaration::t_list: - { - QLineEdit *le = dynamic_cast (m_widgets [r]); - if (le) { - std::vector values = tl::split (tl::to_string (le->text ()), ","); - parameters.back () = tl::Variant (values.begin (), values.end ()); - } - } - break; - - case db::PCellParameterDeclaration::t_layer: - { - lay::LayerSelectionComboBox *ly = dynamic_cast (m_widgets [r]); - if (ly) { - parameters.back () = tl::Variant (ly->current_layer_props ()); - } - } - break; - case db::PCellParameterDeclaration::t_boolean: - { - QCheckBox *cbx = dynamic_cast (m_widgets [r]); - if (cbx) { - parameters.back () = tl::Variant (cbx->isChecked ()); - } - } - break; - - default: - break; + if (r < (int) m_parameters.size ()) { + parameters.push_back (m_parameters [r]); + } else { + parameters.push_back (p->get_default ()); } } else { - QComboBox *cb = dynamic_cast (m_widgets [r]); - if (cb && cb->currentIndex () >= 0 && cb->currentIndex () < int (p->get_choices ().size ())) { - parameters.back () = p->get_choices () [cb->currentIndex ()]; + parameters.push_back (tl::Variant ()); + + if (p->get_choices ().empty ()) { + + switch (p->get_type ()) { + + case db::PCellParameterDeclaration::t_int: + { + QLineEdit *le = dynamic_cast (m_widgets [r]); + if (le) { + + try { + + int v = 0; + tl::from_string (tl::to_string (le->text ()), v); + + parameters.back () = tl::Variant (v); + lay::indicate_error (le, 0); + + } catch (tl::Exception &ex) { + + lay::indicate_error (le, &ex); + edit_error = false; + + } + + } + } + break; + + case db::PCellParameterDeclaration::t_double: + { + QLineEdit *le = dynamic_cast (m_widgets [r]); + if (le) { + + try { + + double v = 0; + tl::from_string (tl::to_string (le->text ()), v); + + parameters.back () = tl::Variant (v); + lay::indicate_error (le, 0); + + } catch (tl::Exception &ex) { + + lay::indicate_error (le, &ex); + edit_error = false; + + } + + } + } + break; + + case db::PCellParameterDeclaration::t_string: + { + QLineEdit *le = dynamic_cast (m_widgets [r]); + if (le) { + parameters.back () = tl::Variant (tl::to_string (le->text ())); + } + } + break; + + case db::PCellParameterDeclaration::t_list: + { + QLineEdit *le = dynamic_cast (m_widgets [r]); + if (le) { + std::vector values = tl::split (tl::to_string (le->text ()), ","); + parameters.back () = tl::Variant (values.begin (), values.end ()); + } + } + break; + + case db::PCellParameterDeclaration::t_layer: + { + lay::LayerSelectionComboBox *ly = dynamic_cast (m_widgets [r]); + if (ly) { + parameters.back () = tl::Variant (ly->current_layer_props ()); + } + } + break; + case db::PCellParameterDeclaration::t_boolean: + { + QCheckBox *cbx = dynamic_cast (m_widgets [r]); + if (cbx) { + parameters.back () = tl::Variant (cbx->isChecked ()); + } + } + break; + + default: + break; + } + + } else { + + QComboBox *cb = dynamic_cast (m_widgets [r]); + if (cb && cb->currentIndex () >= 0 && cb->currentIndex () < int (p->get_choices ().size ())) { + parameters.back () = p->get_choices () [cb->currentIndex ()]; + } + } } } - } - - try { - if (! edit_error) { throw tl::Exception (tl::to_string (tr ("There are errors. See the highlighted edit fields for details."))); } @@ -628,6 +633,10 @@ PCellParametersPage::get_parameters (bool *ok) void PCellParametersPage::set_parameters (const std::vector ¶meters) { + if (! mp_pcell_decl) { + return; + } + // write the changed value back size_t r = 0; const std::vector &pcp = mp_pcell_decl->parameter_declarations (); diff --git a/src/edt/edt/edtPCellParametersPage.h b/src/edt/edt/edtPCellParametersPage.h index 9786a2c8b..158a3cb07 100644 --- a/src/edt/edt/edtPCellParametersPage.h +++ b/src/edt/edt/edtPCellParametersPage.h @@ -104,7 +104,7 @@ public: */ const db::PCellDeclaration *pcell_decl () const { - return mp_pcell_decl; + return mp_pcell_decl.get (); } /** @@ -122,7 +122,7 @@ private: QScrollArea *mp_parameters_area; QLabel *mp_error_label; QLabel *mp_error_icon; - const db::PCellDeclaration *mp_pcell_decl; + tl::weak_ptr mp_pcell_decl; std::vector m_widgets; const db::Layout *mp_layout; lay::LayoutView *mp_view; diff --git a/src/edt/edt/edtPlugin.cc b/src/edt/edt/edtPlugin.cc index 1cf07b535..8f7aa14c2 100644 --- a/src/edt/edt/edtPlugin.cc +++ b/src/edt/edt/edtPlugin.cc @@ -75,7 +75,7 @@ void get_text_editor_options_pages (std::vector &ret, ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-text-param", &text_cfg_descriptors[0], &text_cfg_descriptors[sizeof (text_cfg_descriptors) / sizeof (text_cfg_descriptors[0])])); - ret.push_back (new edt::EditorOptionsText (dispatcher)); + ret.push_back (new edt::EditorOptionsText (view, dispatcher)); } static @@ -101,7 +101,7 @@ void get_path_editor_options_pages (std::vector &ret, ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-path-param", &path_cfg_descriptors[0], &path_cfg_descriptors[sizeof (path_cfg_descriptors) / sizeof (path_cfg_descriptors[0])])); - ret.push_back (new EditorOptionsPath (dispatcher)); + ret.push_back (new EditorOptionsPath (view, dispatcher)); } static @@ -145,8 +145,8 @@ void get_inst_editor_options_pages (std::vector &ret, ret.push_back (new RecentConfigurationPage (view, dispatcher, "edit-recent-inst-param", &inst_cfg_descriptors[0], &inst_cfg_descriptors[sizeof (inst_cfg_descriptors) / sizeof (inst_cfg_descriptors[0])])); - ret.push_back (new EditorOptionsInstPCellParam (dispatcher)); - ret.push_back (new EditorOptionsInst (dispatcher)); + ret.push_back (new EditorOptionsInstPCellParam (view, dispatcher)); + ret.push_back (new EditorOptionsInst (view, dispatcher)); } template @@ -327,10 +327,10 @@ public: return false; } - virtual void get_editor_options_pages (std::vector &pages, lay::LayoutView * /*view*/, lay::Dispatcher *dispatcher) const + virtual void get_editor_options_pages (std::vector &pages, lay::LayoutView *view, lay::Dispatcher *dispatcher) const { // NOTE: we do not set plugin_declaration which makes the page unspecific - EditorOptionsGeneric *generic_opt = new EditorOptionsGeneric (dispatcher); + EditorOptionsGeneric *generic_opt = new EditorOptionsGeneric (view, dispatcher); pages.push_back (generic_opt); } diff --git a/src/edt/edt/edtRecentConfigurationPage.cc b/src/edt/edt/edtRecentConfigurationPage.cc index 554f85be0..4c5726b8f 100644 --- a/src/edt/edt/edtRecentConfigurationPage.cc +++ b/src/edt/edt/edtRecentConfigurationPage.cc @@ -55,7 +55,7 @@ RecentConfigurationPage::init () ly->addWidget (mp_tree_widget); connect (mp_tree_widget, SIGNAL (itemClicked (QTreeWidgetItem *, int)), this, SLOT (item_clicked (QTreeWidgetItem *))); - mp_view->layer_list_changed_event.add (this, &RecentConfigurationPage::layers_changed); + view ()->layer_list_changed_event.add (this, &RecentConfigurationPage::layers_changed); mp_tree_widget->setColumnCount (int (m_cfg.size ())); @@ -166,10 +166,10 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std case RecentConfigurationPage::Layer: { - int icon_size = mp_view->style ()->pixelMetric (QStyle::PM_ButtonIconSize); - lay::LayerPropertiesConstIterator l = lp_iter_from_string (mp_view, values [column]); + int icon_size = view ()->style ()->pixelMetric (QStyle::PM_ButtonIconSize); + lay::LayerPropertiesConstIterator l = lp_iter_from_string (view (), values [column]); if (! l.is_null () && ! l.at_end ()) { - item->setIcon (column, lay::LayerTreeModel::icon_for_layer (l, mp_view, icon_size, icon_size, 0, true)); + item->setIcon (column, lay::LayerTreeModel::icon_for_layer (l, view (), icon_size, icon_size, 0, true)); item->setText (column, tl::to_qstring (values [column])); } else { item->setIcon (column, QIcon ()); @@ -219,7 +219,7 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std const db::Library *lib = 0; for (std::list::const_iterator c = m_cfg.begin (); c != m_cfg.end (); ++c, ++libname_column) { if (c->rendering == RecentConfigurationPage::CellLibraryName) { - lib = db::LibraryManager::instance ().lib_ptr_by_name (values [libname_column]); + lib = db::LibraryManager::instance ().lib_ptr_by_name (values [libname_column], view ()->active_cellview_ref ()->tech_name ()); break; } } @@ -278,6 +278,12 @@ RecentConfigurationPage::layers_changed (int) update_list (get_stored_values ()); } +void +RecentConfigurationPage::technology_changed (const std::string &) +{ + update_list (get_stored_values ()); +} + void RecentConfigurationPage::update_list (const std::list > &stored_values) { @@ -327,7 +333,7 @@ RecentConfigurationPage::item_clicked (QTreeWidgetItem *item) ex.read (cv_index); } - mp_view->set_or_request_current_layer (cv_index, lp); + view ()->set_or_request_current_layer (cv_index, lp); } else { dispatcher ()->config_set (c->cfg_name, v); @@ -349,11 +355,11 @@ RecentConfigurationPage::commit_recent (lay::Dispatcher *root) std::string s; - if (!(mp_view->current_layer ().is_null () || mp_view->current_layer ().at_end ()) && mp_view->current_layer ()->is_visual ()) { + if (!(view ()->current_layer ().is_null () || view ()->current_layer ().at_end ()) && view ()->current_layer ()->is_visual ()) { - int cv_index = mp_view->current_layer ()->cellview_index (); - const lay::CellView &cv = mp_view->cellview (cv_index); - int li = mp_view->current_layer ()->layer_index (); + int cv_index = view ()->current_layer ()->cellview_index (); + const lay::CellView &cv = view ()->cellview (cv_index); + int li = view ()->current_layer ()->layer_index (); if (cv.is_valid () && cv->layout ().is_valid_layer (li)) { s = cv->layout ().get_properties (li).to_string (); if (cv_index > 0) { diff --git a/src/edt/edt/edtRecentConfigurationPage.h b/src/edt/edt/edtRecentConfigurationPage.h index a177be7fb..56b542950 100644 --- a/src/edt/edt/edtRecentConfigurationPage.h +++ b/src/edt/edt/edtRecentConfigurationPage.h @@ -46,8 +46,7 @@ class EditorOptionsPages; * @brief The base class for a object properties page */ class RecentConfigurationPage - : public lay::EditorOptionsPage, - public tl::Object + : public lay::EditorOptionsPage { Q_OBJECT @@ -79,7 +78,7 @@ public: template RecentConfigurationPage (lay::LayoutView *view, lay::Dispatcher *dispatcher, const std::string &recent_cfg_name, Iter begin_cfg, Iter end_cfg) - : EditorOptionsPage (dispatcher), mp_view (view), m_recent_cfg_name (recent_cfg_name), m_cfg (begin_cfg, end_cfg) + : EditorOptionsPage (view, dispatcher), m_recent_cfg_name (recent_cfg_name), m_cfg (begin_cfg, end_cfg) { init (); } @@ -96,7 +95,6 @@ private slots: void item_clicked (QTreeWidgetItem *item); private: - lay::LayoutView *mp_view; std::string m_recent_cfg_name; std::list m_cfg; QTreeWidget *mp_tree_widget; @@ -107,6 +105,7 @@ private: void set_stored_values (const std::list > &values) const; void render_to (QTreeWidgetItem *item, int column, const std::vector &values, RecentConfigurationPage::ConfigurationRendering rendering); void layers_changed (int); + virtual void technology_changed (const std::string &); }; } diff --git a/src/edt/edt/edtServiceImpl.cc b/src/edt/edt/edtServiceImpl.cc index c15bc6106..8f9e048be 100644 --- a/src/edt/edt/edtServiceImpl.cc +++ b/src/edt/edt/edtServiceImpl.cc @@ -1414,7 +1414,7 @@ InstService::make_cell (const lay::CellView &cv) lay::LayerState layer_state = view ()->layer_snapshot (); - db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name); + db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, cv->tech_name ()); // find the layout the cell has to be looked up: that is either the layout of the current instance or // the library selected @@ -1853,8 +1853,8 @@ InstService::switch_cell_or_pcell (bool switch_parameters) } - db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name); const lay::CellView &cv = view ()->cellview (m_cv_index); + db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, cv->tech_name ()); // find the layout the cell has to be looked up: that is either the layout of the current instance or // the library selected diff --git a/src/lay/lay/layLibraryController.cc b/src/lay/lay/layLibraryController.cc index c76f13667..8b4dff669 100644 --- a/src/lay/lay/layLibraryController.cc +++ b/src/lay/lay/layLibraryController.cc @@ -122,7 +122,7 @@ LibraryController::sync_files () m_file_watcher->enable (false); } - std::map > new_lib_files; + std::map new_lib_files; // build a list of paths vs. technology std::vector > paths; @@ -174,11 +174,11 @@ LibraryController::sync_files () QFileInfo fi (tl::to_qstring (lib_path)); bool needs_load = false; - std::map >::iterator ll = m_lib_files.find (lib_path); + std::map::iterator ll = m_lib_files.find (lib_path); if (ll == m_lib_files.end ()) { needs_load = true; } else { - if (fi.lastModified () > ll->second.second) { + if (fi.lastModified () > ll->second.time) { needs_load = true; } else { new_lib_files.insert (*ll); @@ -189,7 +189,9 @@ LibraryController::sync_files () std::auto_ptr lib (new db::Library ()); lib->set_description (filename); - lib->set_technology (p->second); + if (! p->second.empty ()) { + lib->set_technology (p->second); + } lib->set_name (tl::to_string (QFileInfo (*im).baseName ())); tl::log << "Reading library '" << lib_path << "'"; @@ -205,8 +207,19 @@ LibraryController::sync_files () } } - tl::log << "Registering as '" << lib->get_name () << "' for tech '" << p->second << "'"; - new_lib_files.insert (std::make_pair (lib_path, std::make_pair (lib->get_name (), fi.lastModified ()))); + if (! p->second.empty ()) { + tl::log << "Registering as '" << lib->get_name () << "' for tech '" << p->second << "'"; + } else { + tl::log << "Registering as '" << lib->get_name () << "'"; + } + + LibInfo li; + li.name = lib->get_name (); + li.time = fi.lastModified (); + if (! p->second.empty ()) { + li.tech.insert (p->second); + } + new_lib_files.insert (std::make_pair (lib_path, li)); db::LibraryManager::instance ().register_lib (lib.release ()); @@ -230,14 +243,14 @@ LibraryController::sync_files () std::set new_names; - for (std::map >::const_iterator lf = new_lib_files.begin (); lf != new_lib_files.end (); ++lf) { - new_names.insert (lf->second.first); + for (std::map::const_iterator lf = new_lib_files.begin (); lf != new_lib_files.end (); ++lf) { + new_names.insert (lf->second.name); } - for (std::map >::const_iterator lf = m_lib_files.begin (); lf != m_lib_files.end (); ++lf) { - if (new_names.find (lf->second.first) == new_names.end ()) { + for (std::map::const_iterator lf = m_lib_files.begin (); lf != m_lib_files.end (); ++lf) { + if (new_names.find (lf->second.name) == new_names.end ()) { try { - std::pair li = db::LibraryManager::instance ().lib_by_name (lf->second.first); + std::pair li = db::LibraryManager::instance ().lib_by_name (lf->second.name, lf->second.tech); if (li.first) { db::LibraryManager::instance ().delete_lib (db::LibraryManager::instance ().lib (li.second)); } diff --git a/src/lay/lay/layLibraryController.h b/src/lay/lay/layLibraryController.h index 86c0bfdcd..e07f50ade 100644 --- a/src/lay/lay/layLibraryController.h +++ b/src/lay/lay/layLibraryController.h @@ -119,9 +119,17 @@ private slots: void sync_with_external_sources (); private: + struct LibInfo + { + LibInfo () : name (), time (), tech () { } + std::string name; + QDateTime time; + std::set tech; + }; + tl::FileSystemWatcher *m_file_watcher; tl::DeferredMethod dm_sync_files; - std::map > m_lib_files; + std::map m_lib_files; void sync_files (); }; diff --git a/src/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc index 425f8485f..c0770ab1b 100644 --- a/src/lay/lay/layMainWindow.cc +++ b/src/lay/lay/layMainWindow.cc @@ -2506,7 +2506,7 @@ void MainWindow::cm_new_layout () { std::string technology = m_initial_technology; - static std::string s_new_cell_cell_name; + static std::string s_new_cell_cell_name ("TOP"); static double s_new_cell_window_size = 2.0; double dbu = 0.0; diff --git a/src/laybasic/laybasic/layCellView.cc b/src/laybasic/laybasic/layCellView.cc index 0b28e12d0..e42317c43 100644 --- a/src/laybasic/laybasic/layCellView.cc +++ b/src/laybasic/laybasic/layCellView.cc @@ -206,13 +206,20 @@ LayoutHandle::remove_ref () } } +const std::string & +LayoutHandle::tech_name () const +{ + static std::string s_empty; + return mp_layout ? mp_layout->technology_name () : s_empty; +} + const db::Technology * LayoutHandle::technology () const { - return db::Technologies::instance ()->technology_by_name (m_tech_name); + return mp_layout ? mp_layout->technology () : 0; } -void +void LayoutHandle::apply_technology (const std::string &tn) { set_tech_name (tn); @@ -223,15 +230,8 @@ LayoutHandle::apply_technology (const std::string &tn) void LayoutHandle::set_tech_name (const std::string &tn) { - if (tn != m_tech_name) { - if (db::Technologies::instance ()->has_technology (tn)) { - m_tech_name = tn; - } else { - m_tech_name = std::string (); - } - if (mp_layout) { - mp_layout->add_meta_info (db::MetaInfo ("technology", tl::to_string (tr ("Technology name")), tn)); - } + if (mp_layout && tn != tech_name ()) { + mp_layout->set_technology_name (tn); technology_changed_event (); } } @@ -347,7 +347,7 @@ LayoutHandle::load (const db::LoadLayoutOptions &options, const std::string &tec // If there is no technology given and the reader reports one, use this one if (technology.empty ()) { - std::string tech_from_reader = layout ().meta_info_value ("technology"); + std::string tech_from_reader = layout ().technology_name (); if (! tech_from_reader.empty ()) { set_tech_name (tech_from_reader); } @@ -373,7 +373,7 @@ LayoutHandle::load () db::LayerMap new_lmap = reader.read (layout (), m_load_options); // Attach the technology from the reader if it reports one - std::string tech_from_reader = layout ().meta_info_value ("technology"); + std::string tech_from_reader = layout ().technology_name (); if (! tech_from_reader.empty ()) { set_tech_name (tech_from_reader); } diff --git a/src/laybasic/laybasic/layCellView.h b/src/laybasic/laybasic/layCellView.h index a1040dc6c..5f036b728 100644 --- a/src/laybasic/laybasic/layCellView.h +++ b/src/laybasic/laybasic/layCellView.h @@ -115,10 +115,7 @@ public: * * An empty name indicates the default technology should be used. */ - const std::string &tech_name () const - { - return m_tech_name; - } + const std::string &tech_name () const; /** * @brief Applies the given technology @@ -300,7 +297,6 @@ private: int m_ref_count; std::string m_name; std::string m_filename; - std::string m_tech_name; bool m_dirty; db::SaveLayoutOptions m_save_options; bool m_save_options_valid; diff --git a/src/laybasic/laybasic/layEditorOptionsPage.cc b/src/laybasic/laybasic/layEditorOptionsPage.cc index cc4a92d91..1d90960c6 100644 --- a/src/laybasic/laybasic/layEditorOptionsPage.cc +++ b/src/laybasic/laybasic/layEditorOptionsPage.cc @@ -24,6 +24,7 @@ #include "tlInternational.h" #include "layEditorOptionsPage.h" #include "layEditorOptionsPages.h" +#include "layLayoutView.h" namespace lay { @@ -31,10 +32,10 @@ namespace lay // ------------------------------------------------------------------ // EditorOptionsPage implementation -EditorOptionsPage::EditorOptionsPage (lay::Dispatcher *dispatcher) - : QWidget (0), mp_owner (0), m_active (true), mp_plugin_declaration (0), mp_dispatcher (dispatcher) +EditorOptionsPage::EditorOptionsPage (lay::LayoutView *view, lay::Dispatcher *dispatcher) + : QWidget (0), mp_owner (0), m_active (true), mp_plugin_declaration (0), mp_dispatcher (dispatcher), mp_view (view) { - // nothing yet .. + attach_events (); } EditorOptionsPage::~EditorOptionsPage () @@ -42,6 +43,30 @@ EditorOptionsPage::~EditorOptionsPage () set_owner (0); } +void +EditorOptionsPage::attach_events () +{ + detach_from_all_events (); + view ()->active_cellview_changed_event.add (this, &EditorOptionsPage::on_active_cellview_changed); + int cv_index = view ()->active_cellview_index (); + if (cv_index >= 0) { + view ()->cellview (cv_index)->technology_changed_event.add (this, &EditorOptionsPage::on_technology_changed); + } +} + +void +EditorOptionsPage::on_active_cellview_changed () +{ + active_cellview_changed (); + attach_events (); +} + +void +EditorOptionsPage::on_technology_changed () +{ + technology_changed (view ()->active_cellview_ref ()->tech_name ()); +} + void EditorOptionsPage::set_owner (EditorOptionsPages *owner) { diff --git a/src/laybasic/laybasic/layEditorOptionsPage.h b/src/laybasic/laybasic/layEditorOptionsPage.h index 3ee70b1a0..d6a6dad84 100644 --- a/src/laybasic/laybasic/layEditorOptionsPage.h +++ b/src/laybasic/laybasic/layEditorOptionsPage.h @@ -25,6 +25,8 @@ #include "laybasicCommon.h" +#include "tlObject.h" + #include namespace lay @@ -32,19 +34,21 @@ namespace lay class PluginDeclaration; class Dispatcher; +class LayoutView; class Plugin; +class CellView; class EditorOptionsPages; /** * @brief The base class for a object properties page */ class LAYBASIC_PUBLIC EditorOptionsPage - : public QWidget + : public QWidget, public tl::Object { Q_OBJECT public: - EditorOptionsPage (lay::Dispatcher *dispatcher); + EditorOptionsPage (lay::LayoutView *view, lay::Dispatcher *dispatcher); virtual ~EditorOptionsPage (); virtual std::string title () const = 0; @@ -72,11 +76,24 @@ protected: return mp_dispatcher; } + lay::LayoutView *view () const + { + return mp_view; + } + + virtual void active_cellview_changed () { } + virtual void technology_changed (const std::string & /*tech*/) { } + private: EditorOptionsPages *mp_owner; bool m_active; const lay::PluginDeclaration *mp_plugin_declaration; lay::Dispatcher *mp_dispatcher; + lay::LayoutView *mp_view; + + void on_active_cellview_changed (); + void on_technology_changed (); + void attach_events (); }; } diff --git a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc index c4628b38c..f8780418a 100644 --- a/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc +++ b/src/plugins/streamers/lefdef/db_plugin/dbLEFDEFImporter.cc @@ -43,11 +43,7 @@ std::string correct_path (const std::string &fn, const db::Layout &layout, const // if a technology is given and the file can be found in the technology's base path, take it // from there. - std::string tn = layout.meta_info_value ("technology"); - const db::Technology *tech = 0; - if (! tn.empty ()) { - tech = db::Technologies::instance ()->technology_by_name (tn); - } + const db::Technology *tech = layout.technology (); if (tech && ! tech->base_path ().empty ()) { std::string new_fn = tl::combine_path (tech->base_path (), fn); diff --git a/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc b/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc index f60be213e..fe7af4cb7 100644 --- a/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc +++ b/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc @@ -74,11 +74,7 @@ MAGReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) { prepare_layers (); - mp_klayout_tech = 0; - std::string klayout_tech_name = layout.meta_info_value ("technology"); - if (! klayout_tech_name.empty () && db::Technologies::instance ()->has_technology (klayout_tech_name)) { - mp_klayout_tech = db::Technologies::instance ()->technology_by_name (klayout_tech_name); - } + mp_klayout_tech = layout.technology (); const db::MAGReaderOptions &specific_options = options.get_options (); m_lambda = specific_options.lambda; diff --git a/src/plugins/streamers/magic/db_plugin/dbMAGReader.h b/src/plugins/streamers/magic/db_plugin/dbMAGReader.h index 8a5fb31a6..3d9d4ecf2 100644 --- a/src/plugins/streamers/magic/db_plugin/dbMAGReader.h +++ b/src/plugins/streamers/magic/db_plugin/dbMAGReader.h @@ -145,7 +145,7 @@ private: std::map m_use_lib_paths; db::VCplxTrans m_dbu_trans_inv; std::string m_tech; - db::Technology *mp_klayout_tech; + const db::Technology *mp_klayout_tech; void do_read (db::Layout &layout, db::cell_index_type to_cell, tl::TextInputStream &stream); void do_read_part (db::Layout &layout, db::cell_index_type cell_index, tl::TextInputStream &stream); diff --git a/src/plugins/streamers/magic/db_plugin/dbMAGWriter.cc b/src/plugins/streamers/magic/db_plugin/dbMAGWriter.cc index 8c54b9f01..eb4b6a743 100644 --- a/src/plugins/streamers/magic/db_plugin/dbMAGWriter.cc +++ b/src/plugins/streamers/magic/db_plugin/dbMAGWriter.cc @@ -122,7 +122,7 @@ MAGWriter::write_dummmy_top (const std::set &cell_set, cons std::string tech = m_options.tech; if (tech.empty ()) { - tech = layout.meta_info_value ("technology"); + tech = layout.technology_name (); } if (! tech.empty ()) { os << "tech " << make_string (tl::to_lower_case (tech)) << "\n"; @@ -177,7 +177,7 @@ MAGWriter::do_write_cell (db::cell_index_type ci, const std::vector Date: Sun, 13 Dec 2020 14:13:59 +0100 Subject: [PATCH 2/8] WIP: bugfixing. --- src/db/db/dbLayout.cc | 5 +++-- src/db/db/dbLibraryManager.cc | 17 ++++++++++---- src/db/unit_tests/dbLibrariesTests.cc | 24 +++++++++++++++++--- src/edt/edt/edtEditorOptionsPages.cc | 27 ++++++++++------------- src/edt/edt/edtRecentConfigurationPage.cc | 6 ++++- src/edt/edt/edtServiceImpl.cc | 7 +++++- src/laybasic/laybasic/layWidgets.cc | 17 +++++++++++--- src/laybasic/laybasic/layWidgets.h | 5 ++++- 8 files changed, 78 insertions(+), 30 deletions(-) diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index e73be99d4..4aa45d4b4 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -481,7 +481,7 @@ Layout::set_technology_name (const std::string &tech) } - if (mapping.empty ()) { + if (! mapping.empty ()) { bool needs_cleanup = false; @@ -495,7 +495,8 @@ Layout::set_technology_name (const std::string &tech) db::LibraryProxy *lib_proxy = dynamic_cast (&*c); if (lib_proxy && (m = mapping.find (lib_proxy->lib_id ())) != mapping.end ()) { - db::Cell *lib_cell = &cell (lib_proxy->library_cell_index ()); + db::Library *lib = db::LibraryManager::instance ().lib (lib_proxy->lib_id ()); + db::Cell *lib_cell = &lib->layout ().cell (lib_proxy->library_cell_index ()); db::PCellVariant *lib_pcell = dynamic_cast (lib_cell); if (lib_pcell) { pcells_to_map.push_back (std::make_pair (lib_proxy, lib_pcell)); diff --git a/src/db/db/dbLibraryManager.cc b/src/db/db/dbLibraryManager.cc index 8a8a0ff9e..2e5e7df86 100644 --- a/src/db/db/dbLibraryManager.cc +++ b/src/db/db/dbLibraryManager.cc @@ -70,11 +70,11 @@ LibraryManager::lib_by_name (const std::string &name, const std::setfirst == name) { - bool found = true; - for (std::set::const_iterator t = for_technologies.begin (); t != for_technologies.end (); ++t) { - if (! lib (l->second)->is_for_technology (*t)) { + const db::Library *lptr = lib (l->second); + bool found = lptr->for_technologies (); + for (std::set::const_iterator t = for_technologies.begin (); t != for_technologies.end () && found; ++t) { + if (! lptr->is_for_technology (*t)) { found = false; - break; } } if (found) { @@ -83,6 +83,15 @@ LibraryManager::lib_by_name (const std::string &name, const std::setfirst == name) { + if (! lib (l->second)->for_technologies ()) { + return std::make_pair (true, l->second); + } + ++l; + } + return std::make_pair (false, lib_id_type (0)); } diff --git a/src/db/unit_tests/dbLibrariesTests.cc b/src/db/unit_tests/dbLibrariesTests.cc index 5e81a819c..971f0df6f 100644 --- a/src/db/unit_tests/dbLibrariesTests.cc +++ b/src/db/unit_tests/dbLibrariesTests.cc @@ -626,7 +626,8 @@ TEST(4) EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a1->get_id ()); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a1->get_id ()); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a1->get_id ()); @@ -637,7 +638,8 @@ TEST(4) EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a2->get_id ()); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a2->get_id ()); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a1->get_id ()); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true); @@ -650,7 +652,23 @@ TEST(4) EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a3->get_id ()); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, false); - EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, false); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a3->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a3->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").second, lib_a2->get_id ()); + + + LIBT_A *lib_a4 = new LIBT_A (); + db::LibraryManager::instance ().register_lib (lib_a4); + + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A").second, lib_a3->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Z").second, lib_a4->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "").second, lib_a3->get_id ()); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").first, true); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "X").second, lib_a3->get_id ()); EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("A", "Y").first, true); diff --git a/src/edt/edt/edtEditorOptionsPages.cc b/src/edt/edt/edtEditorOptionsPages.cc index b8c944587..779398f97 100644 --- a/src/edt/edt/edtEditorOptionsPages.cc +++ b/src/edt/edt/edtEditorOptionsPages.cc @@ -440,14 +440,13 @@ EditorOptionsInst::update_cell_edits () } db::Layout *layout = 0; - lay::LayoutView *view = lay::LayoutView::current (); // find the layout the cell has to be looked up: that is either the layout of the current instance or // the library selected if (mp_ui->lib_cbx->current_library ()) { layout = &mp_ui->lib_cbx->current_library ()->layout (); - } else if (view && view->cellview (m_cv_index).is_valid ()) { - layout = &view->cellview (m_cv_index)->layout (); + } else if (view ()->cellview (m_cv_index).is_valid ()) { + layout = &view ()->cellview (m_cv_index)->layout (); } if (! layout) { @@ -485,7 +484,7 @@ EditorOptionsInst::browse_cell () { BEGIN_PROTECTED - if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) { + if (m_cv_index >= 0 && view ()->cellview (m_cv_index).is_valid ()) { // find the layout the cell has to be looked up: that is either the layout of the current instance or // the library selected @@ -495,7 +494,7 @@ BEGIN_PROTECTED lib = mp_ui->lib_cbx->current_library (); layout = &lib->layout (); } else { - layout = &lay::LayoutView::current ()->cellview (m_cv_index)->layout (); + layout = &view ()->cellview (m_cv_index)->layout (); } bool all_cells = (mp_ui->lib_cbx->current_library () != 0 ? false : true); @@ -605,12 +604,10 @@ EditorOptionsInst::setup (lay::Dispatcher *root) std::string techname; mp_ui->lib_cbx->update_list (); - if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) { - techname = lay::LayoutView::current ()->cellview (m_cv_index)->tech_name (); - mp_ui->lib_cbx->set_technology_filter (techname, true); - } else { - mp_ui->lib_cbx->set_technology_filter (std::string (), false); + if (m_cv_index >= 0 && view ()->cellview (m_cv_index).is_valid ()) { + techname = view ()->cellview (m_cv_index)->tech_name (); } + mp_ui->lib_cbx->set_technology_filter (techname, ! techname.empty ()); // cell name std::string s; @@ -707,11 +704,11 @@ EditorOptionsInstPCellParam::apply (lay::Dispatcher *root) std::string param; db::Layout *layout = 0; - db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, view ()->active_cellview_ref ()->tech_name ()); + db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, view ()->active_cellview ().is_valid () ? view ()->active_cellview ()->tech_name () : std::string ()); if (lib) { layout = &lib->layout (); - } else if (m_cv_index >= 0 && lay::LayoutView::current () && lay::LayoutView::current ()->cellview (m_cv_index).is_valid ()) { - layout = &lay::LayoutView::current ()->cellview (m_cv_index)->layout (); + } else if (m_cv_index >= 0 && view ()->cellview (m_cv_index).is_valid ()) { + layout = &view ()->cellview (m_cv_index)->layout (); } bool ok = true; @@ -760,7 +757,7 @@ EditorOptionsInstPCellParam::setup (lay::Dispatcher *root) needs_update = true; } - db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, view ()->active_cellview_ref ()->tech_name ()); + db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, view ()->active_cellview ().is_valid () ? view ()->active_cellview ()->tech_name () : std::string ()); // pcell parameters std::string param; @@ -840,7 +837,7 @@ EditorOptionsInstPCellParam::update_pcell_parameters (const std::vector active_cellview_ref ()->tech_name ()); + db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, view ()->active_cellview ().is_valid () ? view ()->active_cellview ()->tech_name () : std::string ()); if (lib) { layout = &lib->layout (); } else { diff --git a/src/edt/edt/edtRecentConfigurationPage.cc b/src/edt/edt/edtRecentConfigurationPage.cc index 4c5726b8f..41d7728d2 100644 --- a/src/edt/edt/edtRecentConfigurationPage.cc +++ b/src/edt/edt/edtRecentConfigurationPage.cc @@ -219,7 +219,11 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std const db::Library *lib = 0; for (std::list::const_iterator c = m_cfg.begin (); c != m_cfg.end (); ++c, ++libname_column) { if (c->rendering == RecentConfigurationPage::CellLibraryName) { - lib = db::LibraryManager::instance ().lib_ptr_by_name (values [libname_column], view ()->active_cellview_ref ()->tech_name ()); + if (view ()->active_cellview ().is_valid ()) { + lib = db::LibraryManager::instance ().lib_ptr_by_name (values [libname_column], view ()->active_cellview ()->tech_name ()); + } else { + lib = db::LibraryManager::instance ().lib_ptr_by_name (values [libname_column]); + } break; } } diff --git a/src/edt/edt/edtServiceImpl.cc b/src/edt/edt/edtServiceImpl.cc index 8f9e048be..f2a627842 100644 --- a/src/edt/edt/edtServiceImpl.cc +++ b/src/edt/edt/edtServiceImpl.cc @@ -1854,7 +1854,12 @@ InstService::switch_cell_or_pcell (bool switch_parameters) } const lay::CellView &cv = view ()->cellview (m_cv_index); - db::Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, cv->tech_name ()); + db::Library *lib = 0; + if (cv.is_valid ()) { + lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name, cv->tech_name ()); + } else { + lib = db::LibraryManager::instance ().lib_ptr_by_name (m_lib_name); + } // find the layout the cell has to be looked up: that is either the layout of the current instance or // the library selected diff --git a/src/laybasic/laybasic/layWidgets.cc b/src/laybasic/laybasic/layWidgets.cc index 6ea947b02..a84b96601 100644 --- a/src/laybasic/laybasic/layWidgets.cc +++ b/src/laybasic/laybasic/layWidgets.cc @@ -298,6 +298,7 @@ struct LayerSelectionComboBoxPrivateData const db::Layout *layout; lay::LayoutView *view; int cv_index; + db::LayerProperties last_props; }; LayerSelectionComboBox::LayerSelectionComboBox (QWidget *parent) @@ -424,6 +425,14 @@ LayerSelectionComboBox::set_view (lay::LayoutView *view, int cv_index, bool all_ mp_private->cv_index = cv_index; mp_private->all_layers = all_layers; + view->layer_list_changed_event.add (this, &LayerSelectionComboBox::on_layer_list_changed); + + update_layer_list (); +} + +void +LayerSelectionComboBox::on_layer_list_changed (int) +{ update_layer_list (); } @@ -442,7 +451,7 @@ void LayerSelectionComboBox::update_layer_list () { int i = currentIndex (); - db::LayerProperties props; + db::LayerProperties props = mp_private->last_props; if (i >= 0 && i < int (mp_private->layers.size ())) { props = mp_private->layers [i].first; } @@ -522,6 +531,8 @@ LayerSelectionComboBox::update_layer_list () void LayerSelectionComboBox::set_current_layer (const db::LayerProperties &props) { + mp_private->last_props = props; + for (std::vector >::iterator ll = mp_private->layers.begin (); ll != mp_private->layers.end (); ++ll) { if (ll->first.log_equal (props)) { setCurrentIndex (std::distance (mp_private->layers.begin (), ll)); @@ -562,7 +573,7 @@ LayerSelectionComboBox::current_layer_props () const { int i = currentIndex (); if (i < 0 || i > int (mp_private->layers.size ())) { - return db::LayerProperties (); + return mp_private->last_props; } else { return mp_private->layers [i].first; } @@ -600,7 +611,7 @@ LibrarySelectionComboBox::update_list () for (db::LibraryManager::iterator l = db::LibraryManager::instance ().begin (); l != db::LibraryManager::instance ().end (); ++l) { db::Library *lib = db::LibraryManager::instance ().lib (l->second); - if (! m_tech_set || !lib->for_technologies ()|| lib->is_for_technology (m_tech)) { + if (! m_tech_set || !lib->for_technologies () || lib->is_for_technology (m_tech)) { std::string item_text = lib->get_name (); if (! lib->get_description ().empty ()) { diff --git a/src/laybasic/laybasic/layWidgets.h b/src/laybasic/laybasic/layWidgets.h index 7de0fa33d..3f2002fb5 100644 --- a/src/laybasic/laybasic/layWidgets.h +++ b/src/laybasic/laybasic/layWidgets.h @@ -26,6 +26,8 @@ #include "laybasicCommon.h" +#include "tlObject.h" + #include #include #include @@ -170,7 +172,7 @@ private: * This combo box allows selecting a (physical) layer from a layout */ class LAYBASIC_PUBLIC LayerSelectionComboBox - : public QComboBox + : public QComboBox, public tl::Object { Q_OBJECT @@ -249,6 +251,7 @@ protected slots: private: LayerSelectionComboBoxPrivateData *mp_private; + void on_layer_list_changed (int); void update_layer_list (); }; From ab36a660fb1291cd9a2878be62de44c5756c4fab Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 13 Dec 2020 19:11:12 +0100 Subject: [PATCH 3/8] WIP: cold references - keep reference information while libraries are not there or cells are missing. --- src/db/db/db.pro | 2 + src/db/db/dbColdProxy.cc | 128 +++++++ src/db/db/dbColdProxy.h | 111 ++++++ src/db/db/dbLayout.cc | 340 ++++++++++++------ src/db/db/dbLayout.h | 69 +++- src/db/db/dbLibrary.cc | 30 +- src/db/db/dbLibraryManager.cc | 16 + src/db/db/dbLibraryProxy.cc | 2 - .../gds2/db_plugin/dbGDS2ReaderBase.cc | 10 +- 9 files changed, 578 insertions(+), 130 deletions(-) create mode 100644 src/db/db/dbColdProxy.cc create mode 100644 src/db/db/dbColdProxy.h diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 94c5d291b..82c60a7bb 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -19,6 +19,7 @@ SOURCES = \ dbClipboard.cc \ dbClipboardData.cc \ dbClip.cc \ + dbColdProxy.cc \ dbCommonReader.cc \ dbEdge.cc \ dbEdgePair.cc \ @@ -214,6 +215,7 @@ HEADERS = \ dbClipboardData.h \ dbClipboard.h \ dbClip.h \ + dbColdProxy.h \ dbCommonReader.h \ dbEdge.h \ dbEdgePair.h \ diff --git a/src/db/db/dbColdProxy.cc b/src/db/db/dbColdProxy.cc new file mode 100644 index 000000000..a387f2838 --- /dev/null +++ b/src/db/db/dbColdProxy.cc @@ -0,0 +1,128 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "dbColdProxy.h" +#include "dbLibraryManager.h" +#include "dbLibrary.h" +#include "dbLayout.h" +#include "dbLayoutUtils.h" + +#include "tlThreads.h" + +namespace db +{ + +static tl::Mutex s_map_mutex; +static std::map > s_proxies_per_library_name; + +const tl::weak_collection & +ColdProxy::cold_proxies_per_lib_name (const std::string &libname) +{ + tl::MutexLocker locker (&s_map_mutex); + + std::map >::const_iterator i = s_proxies_per_library_name.find (libname); + if (i != s_proxies_per_library_name.end ()) { + return i->second; + } else { + static tl::weak_collection s_empty; + return s_empty; + } +} + +ColdProxy::ColdProxy (db::cell_index_type ci, db::Layout &layout, const ProxyContextInfo &info) + : Cell (ci, layout), mp_context_info (new ProxyContextInfo (info)) +{ + if (! info.lib_name.empty ()) { + tl::MutexLocker locker (&s_map_mutex); + s_proxies_per_library_name [info.lib_name].push_back (this); + } +} + +ColdProxy::~ColdProxy () +{ + delete mp_context_info; + mp_context_info = 0; +} + +Cell * +ColdProxy::clone (Layout &layout) const +{ + Cell *cell = new ColdProxy (db::Cell::cell_index (), layout, *mp_context_info); + // copy the cell content + *cell = *this; + return cell; +} + +std::string +ColdProxy::get_basic_name () const +{ + if (! mp_context_info->pcell_name.empty ()) { + return "" + mp_context_info->pcell_name; + } else if (! mp_context_info->cell_name.empty ()) { + return "" + mp_context_info->cell_name; + } else { + return Cell::get_basic_name (); + } +} + +std::string +ColdProxy::get_display_name () const +{ + if (! mp_context_info->lib_name.empty ()) { + std::string stem = "" + mp_context_info->lib_name + "."; + if (! mp_context_info->pcell_name.empty ()) { + return stem + mp_context_info->pcell_name; + } else if (! mp_context_info->cell_name.empty ()) { + return stem + mp_context_info->cell_name; + } else { + return stem + ""; + } + } else { + return Cell::get_display_name (); + } +} + +std::string +ColdProxy::get_qualified_name () const +{ + if (! mp_context_info->lib_name.empty ()) { + std::string stem = "" + mp_context_info->lib_name + "."; + if (! mp_context_info->pcell_name.empty ()) { + if (mp_context_info->pcell_parameters.empty ()) { + return stem + mp_context_info->pcell_name; + } else { + // TODO: list parameters? Might be long. + return stem + mp_context_info->pcell_name + "(...)"; + } + } else if (! mp_context_info->cell_name.empty ()) { + return stem + mp_context_info->cell_name; + } else { + return stem + ""; + } + } else { + return Cell::get_qualified_name (); + } +} + +} + diff --git a/src/db/db/dbColdProxy.h b/src/db/db/dbColdProxy.h new file mode 100644 index 000000000..13a586c1c --- /dev/null +++ b/src/db/db/dbColdProxy.h @@ -0,0 +1,111 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#ifndef HDR_dbColdProxy +#define HDR_dbColdProxy + +#include "dbCommon.h" + +#include "dbTypes.h" +#include "dbCell.h" + +#include "tlObject.h" + +namespace db +{ + +struct ProxyContextInfo; + +/** + * @brief A cell specialization: a cold proxy representing a library or PCell which has gone out of scope + * + * If a PCell or library cell gets disconnected - for example, because the technology has changed or during + * development of PCell code - this proxy replaces the original one. It stores the connection information, so + * it can be regenerated when it becomes valid again. + */ +class DB_PUBLIC ColdProxy + : public Cell, public tl::Object +{ +public: + /** + * @brief The constructor + * + * Creates a cold proxy represented by the ProxyContextInfo data. + */ + ColdProxy (db::cell_index_type ci, db::Layout &layout, const ProxyContextInfo &info); + + /** + * @brief The destructor + */ + ~ColdProxy (); + + /** + * @brief Cloning + */ + virtual Cell *clone (Layout &layout) const; + + /** + * @brief Get the library id + */ + const ProxyContextInfo &context_info () const + { + return *mp_context_info; + } + + /** + * @brief Indicates that this cell is a proxy cell + */ + virtual bool is_proxy () const + { + return true; + } + + /** + * @brief Gets a list of cold proxies for a given library name + */ + static const tl::weak_collection &cold_proxies_per_lib_name (const std::string &libname); + + /** + * @brief Gets the basic name + */ + virtual std::string get_basic_name () const; + + /** + * @brief Gets the display name + */ + virtual std::string get_display_name () const; + + /** + * @brief Gets the qualified name + */ + virtual std::string get_qualified_name () const; + +private: + ProxyContextInfo *mp_context_info; +}; + +} + +#endif + + diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index 4aa45d4b4..a9c94c2ad 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -30,6 +30,7 @@ #include "dbPCellVariant.h" #include "dbPCellDeclaration.h" #include "dbLibraryProxy.h" +#include "dbColdProxy.h" #include "dbLibraryManager.h" #include "dbLibrary.h" #include "dbRegion.h" @@ -260,6 +261,65 @@ LayerIterator::operator*() const return std::pair (m_layer_index, &m_layout.get_properties (m_layer_index)); } +// ----------------------------------------------------------------- +// Implementation of the ProxyContextInfo class + +ProxyContextInfo +ProxyContextInfo::deserialize (std::vector::const_iterator from, std::vector::const_iterator to) +{ + ProxyContextInfo info; + + for (std::vector::const_iterator i = from; i != to; ++i) { + + tl::Extractor ex (i->c_str ()); + + if (ex.test ("LIB=")) { + + info.lib_name = ex.skip (); + + } else if (ex.test ("P(")) { + + std::pair vv; + + ex.read_word_or_quoted (vv.first); + ex.test (")"); + ex.test ("="); + ex.read (vv.second); + + info.pcell_parameters.insert (vv); + + } else if (ex.test ("PCELL=")) { + + info.pcell_name = ex.skip (); + + } else if (ex.test ("CELL=")) { + + info.cell_name = ex.skip (); + + } + + } + + return info; +} + +void +ProxyContextInfo::serialize (std::vector &strings) +{ + if (! lib_name.empty ()) { + strings.push_back ("LIB=" + lib_name); + } + for (std::map ::const_iterator p = pcell_parameters.begin (); p != pcell_parameters.end (); ++p) { + strings.push_back ("P(" + tl::to_word_or_quoted_string (p->first) + ")=" + p->second.to_parsable_string ()); + } + if (! pcell_name.empty ()) { + strings.push_back ("PCELL=" + pcell_name); + } + if (! cell_name.empty ()) { + strings.push_back ("CELL=" + cell_name); + } +} + // ----------------------------------------------------------------- // Implementation of the Layout class @@ -522,12 +582,10 @@ Layout::set_technology_name (const std::string &tech) if (! pn.first) { - // substitute by static layout cell - // @@@ TODO: keep reference so we don't loose the connection immediately. - std::string name = cell_name (ci); - db::Cell *old_cell = take_cell (ci); - insert_cell (ci, name, new db::Cell (*old_cell)); - delete old_cell; + // substitute by a cold proxy + db::ProxyContextInfo info; + get_context_info (ci, info); + create_cold_proxy_as (info, ci); } else { @@ -537,12 +595,10 @@ Layout::set_technology_name (const std::string &tech) const db::PCellDeclaration *new_pcell_decl = new_lib->layout ().pcell_declaration (pn.second); if (! old_pcell_decl || ! new_pcell_decl) { - // substitute by static layout cell - // @@@ TODO: keep reference so we don't loose the connection immediately. - std::string name = cell_name (ci); - db::Cell *old_cell = take_cell (ci); - insert_cell (ci, name, new db::Cell (*old_cell)); - delete old_cell; + // substitute by a cold proxy + db::ProxyContextInfo info; + get_context_info (ci, info); + create_cold_proxy_as (info, ci); } else { @@ -566,12 +622,10 @@ Layout::set_technology_name (const std::string &tech) if (! cn.first) { - // unlink this proxy: substitute by static layout cell - // @@@ TODO: keep reference so we don't loose the connection immediately. - std::string name = cell_name (ci); - db::Cell *old_cell = take_cell (ci); - insert_cell (ci, name, new db::Cell (*old_cell)); - delete old_cell; + // unlink this proxy: substitute by a cold proxy + db::ProxyContextInfo info; + get_context_info (ci, info); + create_cold_proxy_as (info, ci); } else { @@ -588,6 +642,9 @@ Layout::set_technology_name (const std::string &tech) } m_tech_name = tech; + + // we may have re-established a connection for pending ("cold") proxies so we can try to restore them + restore_proxies (); } void @@ -1948,8 +2005,26 @@ static const std::vector &gauge_parameters (const std::vectorunregister (); + if (retain_layout) { + new_cell->Cell::operator= (*old_cell); + } + } + + m_cells.erase (iterator (old_cell)); + m_cells.push_back_ptr (new_cell); + m_cell_ptrs [target_cell_index] = new_cell; +} + void -Layout::get_pcell_variant_as (pcell_id_type pcell_id, const std::vector &p, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping) +Layout::get_pcell_variant_as (pcell_id_type pcell_id, const std::vector &p, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping, bool retain_layout) { pcell_header_type *header = pcell_header (pcell_id); tl_assert (header != 0); @@ -1963,16 +2038,13 @@ Layout::get_pcell_variant_as (pcell_id_type pcell_id, const std::vectortransacting ())); tl_assert (m_cell_ptrs [target_cell_index] != 0); - invalidate_hier (); - - m_cells.erase (iterator (m_cell_ptrs [target_cell_index])); - pcell_variant_type *variant = new pcell_variant_type (target_cell_index, *this, pcell_id, parameters); - m_cells.push_back_ptr (variant); - m_cell_ptrs [target_cell_index] = variant; + replace_cell (target_cell_index, variant, retain_layout); - // produce the layout - variant->update (layer_mapping); + if (! retain_layout) { + // produce the layout unless we retained it + variant->update (layer_mapping); + } } cell_index_type @@ -2316,8 +2388,20 @@ Layout::get_pcell_variant_cell (cell_index_type cell_index, const std::vector &context_info) const +bool +Layout::get_context_info (cell_index_type cell_index, std::vector &strings) const +{ + ProxyContextInfo info; + if (! get_context_info (cell_index, info)) { + return false; + } else { + info.serialize (strings); + return true; + } +} + +bool +Layout::get_context_info (cell_index_type cell_index, ProxyContextInfo &info) const { const db::Cell *cptr = &cell (cell_index); const db::Layout *ly = this; @@ -2333,7 +2417,7 @@ Layout::get_context_info (cell_index_type cell_index, std::vector // one level of library indirection ly = &lib->layout (); cptr = &ly->cell (lib_proxy->library_cell_index ()); - context_info.push_back ("LIB=" + lib->get_name ()); + info.lib_name = lib->get_name (); } @@ -2347,19 +2431,36 @@ Layout::get_context_info (cell_index_type cell_index, std::vector const std::vector &pcp = pcell_decl->parameter_declarations (); std::vector::const_iterator pd = pcp.begin (); for (std::vector::const_iterator p = pcell_variant->parameters ().begin (); p != pcell_variant->parameters ().end () && pd != pcp.end (); ++p, ++pd) { - context_info.push_back ("P(" + tl::to_word_or_quoted_string (pd->get_name ()) + ")=" + p->to_parsable_string ()); + info.pcell_parameters.insert (std::make_pair (pd->get_name (), *p)); } const db::PCellHeader *header = ly->pcell_header (pcell_variant->pcell_id ()); - context_info.push_back ("PCELL=" + header->get_name ()); + info.pcell_name = header->get_name (); } else { - context_info.push_back ("CELL=" + std::string (ly->cell_name (cptr->cell_index ()))); + info.cell_name = ly->cell_name (cptr->cell_index ()); } return true; } +void +Layout::restore_proxies (ImportLayerMapping *layer_mapping) +{ + std::vector cold_proxies; + + for (iterator c = begin (); c != end (); ++c) { + db::ColdProxy *proxy = dynamic_cast (c.operator-> ()); + if (proxy) { + cold_proxies.push_back (proxy); + } + } + + for (std::vector::const_iterator p = cold_proxies.begin (); p != cold_proxies.end (); ++p) { + recover_proxy_as ((*p)->cell_index (), (*p)->context_info (), layer_mapping); + } +} + bool Layout::recover_proxy_as (cell_index_type cell_index, std::vector ::const_iterator from, std::vector ::const_iterator to, ImportLayerMapping *layer_mapping) { @@ -2367,17 +2468,21 @@ Layout::recover_proxy_as (cell_index_type cell_index, std::vector : return false; } - tl::Extractor ex (from->c_str ()); + return recover_proxy_as (cell_index, ProxyContextInfo::deserialize (from, to), layer_mapping); +} - if (ex.test ("LIB=")) { +bool +Layout::recover_proxy_as (cell_index_type cell_index, const ProxyContextInfo &info, ImportLayerMapping *layer_mapping) +{ + if (! info.lib_name.empty ()) { - std::string lib_name = ex.skip (); - Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (lib_name, m_tech_name); - if (! lib) { - return false; + db::Cell *lib_cell = 0; + + Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (info.lib_name, m_tech_name); + if (lib) { + lib_cell = lib->layout ().recover_proxy_no_lib (info); } - db::Cell *lib_cell = lib->layout ().recover_proxy (from + 1, to); if (lib_cell) { get_lib_proxy_as (lib, lib_cell->cell_index (), cell_index, layer_mapping); return true; @@ -2385,38 +2490,28 @@ Layout::recover_proxy_as (cell_index_type cell_index, std::vector : } else { - std::map parameters; + if (! info.pcell_name.empty ()) { - while (from != to && (ex = tl::Extractor (from->c_str ())).test ("P(")) { - - std::string name; - ex.read_word_or_quoted (name); - ex.test (")"); - ex.test ("="); - - ex.read (parameters.insert (std::make_pair (name, tl::Variant ())).first->second); - - ++from; - - } - - if (ex.test ("PCELL=")) { - - std::pair pc = pcell_by_name (ex.skip ()); + std::pair pc = pcell_by_name (info.pcell_name.c_str ()); if (pc.first) { - get_pcell_variant_as (pc.second, pcell_declaration (pc.second)->map_parameters (parameters), cell_index, layer_mapping); + get_pcell_variant_as (pc.second, pcell_declaration (pc.second)->map_parameters (info.pcell_parameters), cell_index, layer_mapping); return true; } - } else if (ex.test ("CELL=")) { + } else if (! info.cell_name.empty ()) { - // This should not happen. A cell (given by the cell index) cannot be proxy to another cell in the same layout. + // This should not happen. A cell (given by the cell name) cannot be proxy to another cell in the same layout. tl_assert (false); } } + if (! dynamic_cast (m_cell_ptrs [cell_index])) { + // create a cold proxy representing the context information so we can restore it + create_cold_proxy_as (info, cell_index); + } + return false; } @@ -2427,55 +2522,54 @@ Layout::recover_proxy (std::vector ::const_iterator from, std::vect return 0; } - tl::Extractor ex (from->c_str ()); + return recover_proxy (ProxyContextInfo::deserialize (from, to)); +} - if (ex.test ("LIB=")) { +db::Cell * +Layout::recover_proxy (const ProxyContextInfo &info) +{ + if (! info.lib_name.empty ()) { - std::string lib_name = ex.skip (); - Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (lib_name, m_tech_name); - if (! lib) { - return 0; + Library *lib = db::LibraryManager::instance ().lib_ptr_by_name (info.lib_name, m_tech_name); + + db::Cell *lib_cell = 0; + if (lib) { + lib_cell = lib->layout ().recover_proxy_no_lib (info); } - db::Cell *lib_cell = lib->layout ().recover_proxy (from + 1, to); if (lib_cell) { - cell_index_type cell_index = get_lib_proxy (lib, lib_cell->cell_index ()); - return &cell (cell_index); + return m_cell_ptrs [get_lib_proxy (lib, lib_cell->cell_index ())]; } } else { - std::map parameters; - - while (from != to && (ex = tl::Extractor (from->c_str ())).test ("P(")) { - - std::string name; - ex.read_word_or_quoted (name); - ex.test (")"); - ex.test ("="); - - ex.read (parameters.insert (std::make_pair (name, tl::Variant ())).first->second); - - ++from; - + db::Cell *proxy = recover_proxy_no_lib (info); + if (proxy) { + return proxy; } - if (ex.test ("PCELL=")) { + } - std::pair pc = pcell_by_name (ex.skip ()); - if (pc.first) { - cell_index_type cell_index = get_pcell_variant (pc.second, pcell_declaration (pc.second)->map_parameters (parameters)); - return &cell (cell_index); - } + return m_cell_ptrs [create_cold_proxy (info)]; +} - } else if (ex.test ("CELL=")) { +db::Cell * +Layout::recover_proxy_no_lib (const ProxyContextInfo &info) +{ + if (! info.pcell_name.empty ()) { - std::pair cc = cell_by_name (ex.skip ()); - if (cc.first) { - return &cell (cc.second); - } + std::pair pc = pcell_by_name (info.pcell_name.c_str ()); + if (pc.first) { + cell_index_type cell_index = get_pcell_variant (pc.second, pcell_declaration (pc.second)->map_parameters (info.pcell_parameters)); + return m_cell_ptrs [cell_index]; + } - } + } else if (! info.cell_name.empty ()) { + + std::pair cc = cell_by_name (info.cell_name.c_str ()); + if (cc.first) { + return m_cell_ptrs [cc.second]; + } } @@ -2507,21 +2601,18 @@ Layout::unregister_lib_proxy (db::LibraryProxy *lib_proxy) } void -Layout::get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping) +Layout::get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping, bool retain_layout) { tl_assert (! (manager () && manager ()->transacting ())); tl_assert (m_cell_ptrs [target_cell_index] != 0); - invalidate_hier (); - - m_cells.erase (iterator (m_cell_ptrs [target_cell_index])); - LibraryProxy *proxy = new LibraryProxy (target_cell_index, *this, lib->get_id (), cell_index); - m_cells.push_back_ptr (proxy); - m_cell_ptrs [target_cell_index] = proxy; + replace_cell (target_cell_index, proxy, retain_layout); - // produce the layout - proxy->update (layer_mapping); + if (! retain_layout) { + // produce the layout unless we retained it + proxy->update (layer_mapping); + } } cell_index_type @@ -2552,7 +2643,7 @@ Layout::get_lib_proxy (Library *lib, cell_index_type cell_index) manager ()->queue (this, new NewRemoveCellOp (new_index, m_cell_names [new_index], false /*new*/, 0)); } - // produce the layout + // produce the layout proxy->update (); return new_index; @@ -2560,6 +2651,47 @@ Layout::get_lib_proxy (Library *lib, cell_index_type cell_index) } } +cell_index_type +Layout::create_cold_proxy (const db::ProxyContextInfo &info) +{ + // create a new unique name + std::string b; + if (! info.cell_name.empty ()) { + b = info.cell_name; + } else if (! info.pcell_name.empty ()) { + b = info.pcell_name; + } + if (m_cell_map.find (b.c_str ()) != m_cell_map.end ()) { + b = uniquify_cell_name (b.c_str ()); + } + + // create a new cell (a LibraryProxy) + cell_index_type new_index = allocate_new_cell (); + + ColdProxy *proxy = new ColdProxy (new_index, *this, info); + m_cells.push_back_ptr (proxy); + m_cell_ptrs [new_index] = proxy; + + // enter it's index and cell_name + register_cell_name (b.c_str (), new_index); + + if (manager () && manager ()->transacting ()) { + manager ()->queue (this, new NewRemoveCellOp (new_index, m_cell_names [new_index], false /*new*/, 0)); + } + + return new_index; +} + +void +Layout::create_cold_proxy_as (const db::ProxyContextInfo &info, cell_index_type target_cell_index) +{ + tl_assert (! (manager () && manager ()->transacting ())); + tl_assert (m_cell_ptrs [target_cell_index] != 0); + + ColdProxy *proxy = new ColdProxy (target_cell_index, *this, info); + replace_cell (target_cell_index, proxy, true); +} + void Layout::redo (db::Op *op) { diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index c79629567..779a1ee2f 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -457,6 +457,20 @@ public: virtual std::pair map_layer (const LayerProperties &lprops) = 0; }; +/** + * @brief A binary object representing context information for regenerating library proxies and PCells + */ +struct DB_PUBLIC ProxyContextInfo +{ + std::string lib_name; + std::string cell_name; + std::string pcell_name; + std::map pcell_parameters; + + static ProxyContextInfo deserialize (std::vector::const_iterator from, std::vector::const_iterator to); + void serialize (std::vector &strings); +}; + /** * @brief The layout object * @@ -863,8 +877,9 @@ public: * @param parameters The PCell parameters * @param cell_index The cell index which is to be replaced by the PCell variant proxy * @param layer_mapping The optional layer mapping object that maps the PCell layers to the layout's layers + * @param retain_layout Set to true for not using update() on the PCell but to retain existing layout (conservative approach) */ - void get_pcell_variant_as (pcell_id_type pcell_id, const std::vector ¶meters, cell_index_type cell_index, ImportLayerMapping *layer_mapping = 0); + void get_pcell_variant_as (pcell_id_type pcell_id, const std::vector ¶meters, cell_index_type cell_index, ImportLayerMapping *layer_mapping = 0, bool retain_layout = false); /** * @brief Get the PCell variant cell of a existing cell with new parameters @@ -1010,9 +1025,21 @@ public: /** * @brief Get the proxy cell (index) for a given library an cell index (inside that library) * - * This method replaces the cell with the given target cell index by a library. + * @param retain_layout Set to true for not using update() on the PCell but to retain existing layout (conservative approach) + * + * This method replaces the cell with the given target cell index by a library. */ - void get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping = 0); + void get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping = 0, bool retain_layout = false); + + /** + * @brief Creates a cold proxy representing the given context information + */ + cell_index_type create_cold_proxy (const db::ProxyContextInfo &info); + + /** + * @brief Subsitutes the given cell by a cold proxy representing the given context information + */ + void create_cold_proxy_as (const db::ProxyContextInfo &info, cell_index_type cell_index); /** * @brief Get the context information for a given cell (for writing into a file) @@ -1024,6 +1051,11 @@ public: */ bool get_context_info (cell_index_type cell_index, std::vector &context_info) const; + /** + * @brief Gets the context information as a binary object + */ + bool get_context_info (cell_index_type cell_index, ProxyContextInfo &context_info) const; + /** * @brief Recover a proxy cell from the given context info. * @@ -1035,6 +1067,11 @@ public: */ db::Cell *recover_proxy (std::vector ::const_iterator from, std::vector ::const_iterator to); + /** + * @brief Recover a proxy cell from the given binary context info object. + */ + db::Cell *recover_proxy (const ProxyContextInfo &context_info); + /** * @brief Recover a proxy cell from the given context info. * @@ -1050,6 +1087,27 @@ public: */ bool recover_proxy_as (cell_index_type cell_index, std::vector ::const_iterator from, std::vector ::const_iterator to, ImportLayerMapping *layer_mapping = 0); + /** + * @brief Recover a proxy cell from the given binary context info object + * + * See the string-based version of "recover_proxy_as" for details. + */ + bool recover_proxy_as (cell_index_type cell_index, const ProxyContextInfo &context_info, ImportLayerMapping *layer_mapping = 0); + + /** + * @brief Restores proxies as far as possible + * + * This feature can be used after a library update to make sure that proxies are updated. + * Library updates may enabled lost connections which are help in cold proxies. This method will recover + * these connections. + */ + void restore_proxies(ImportLayerMapping *layer_mapping = 0); + + /** + * @brief Replaces the given cell index with the new cell + */ + void replace_cell (cell_index_type target_cell_index, db::Cell *new_cell, bool retain_layout); + /** * @brief Delete a cell plus the subcells not used otherwise * @@ -1853,6 +1911,11 @@ private: * @brief Implementation of prune_cells and some prune_subcells variants */ void do_prune_cells_or_subcells (const std::set &ids, int levels, bool subcells); + + /** + * @brief Recovers a proxy without considering the library from context_info + */ + db::Cell *recover_proxy_no_lib (const ProxyContextInfo &context_info); }; /** diff --git a/src/db/db/dbLibrary.cc b/src/db/db/dbLibrary.cc index 3103f0c56..c22dff473 100644 --- a/src/db/db/dbLibrary.cc +++ b/src/db/db/dbLibrary.cc @@ -191,12 +191,10 @@ Library::remap_to (db::Library *other) if (! pn.first) { - // substitute by static layout cell - // @@@ TODO: keep reference so we don't loose the connection immediately. - std::string name = r->first->cell_name (ci); - db::Cell *old_cell = r->first->take_cell (ci); - r->first->insert_cell (ci, name, new db::Cell (*old_cell)); - delete old_cell; + // substitute by a cold proxy + db::ProxyContextInfo info; + r->first->get_context_info (ci, info); + r->first->create_cold_proxy_as (info, ci); } else { @@ -204,12 +202,10 @@ Library::remap_to (db::Library *other) const db::PCellDeclaration *new_pcell_decl = other->layout ().pcell_declaration (pn.second); if (! old_pcell_decl || ! new_pcell_decl) { - // substitute by static layout cell - // @@@ TODO: keep reference so we don't loose the connection immediately. - std::string name = r->first->cell_name (ci); - db::Cell *old_cell = r->first->take_cell (ci); - r->first->insert_cell (ci, name, new db::Cell (*old_cell)); - delete old_cell; + // substitute by a cold proxy + db::ProxyContextInfo info; + r->first->get_context_info (ci, info); + r->first->create_cold_proxy_as (info, ci); } else { @@ -234,12 +230,10 @@ Library::remap_to (db::Library *other) if (! cn.first) { - // unlink this proxy: substitute by static layout cell - // @@@ TODO: keep reference so we don't loose the connection immediately. - std::string name = r->first->cell_name (ci); - db::Cell *old_cell = r->first->take_cell (ci); - r->first->insert_cell (ci, name, new db::Cell (*old_cell)); - delete old_cell; + // substitute by a cold proxy + db::ProxyContextInfo info; + r->first->get_context_info (ci, info); + r->first->create_cold_proxy_as (info, ci); } else { diff --git a/src/db/db/dbLibraryManager.cc b/src/db/db/dbLibraryManager.cc index 2e5e7df86..88e526c7c 100644 --- a/src/db/db/dbLibraryManager.cc +++ b/src/db/db/dbLibraryManager.cc @@ -24,6 +24,7 @@ #include "dbLibraryManager.h" #include "dbLibrary.h" #include "dbCommon.h" +#include "dbColdProxy.h" #include "tlAssert.h" #include "tlStaticObjects.h" @@ -158,6 +159,21 @@ LibraryManager::register_lib (Library *library) l = m_lib_by_name.find (library->get_name ()); m_lib_by_name.insert (l, std::make_pair (library->get_name (), id)); + // take care of cold referrers - these may not get valid + // NOTE: this will try to substitute the cold proxies we may have generated during "remap_to" above, but + // "restore_proxies" takes care not to re-substitute cold proxies. + + const tl::weak_collection &cold_proxies = db::ColdProxy::cold_proxies_per_lib_name (library->get_name ()); + std::set to_refresh; + for (tl::weak_collection::const_iterator p = cold_proxies.begin (); p != cold_proxies.end (); ++p) { + to_refresh.insert (const_cast (p->layout ())); + } + + for (std::set::const_iterator l = to_refresh.begin (); l != to_refresh.end (); ++l) { + (*l)->restore_proxies (0); + } + + // issue the change notification changed_event (); return id; diff --git a/src/db/db/dbLibraryProxy.cc b/src/db/db/dbLibraryProxy.cc index 195c82b99..241df85ad 100644 --- a/src/db/db/dbLibraryProxy.cc +++ b/src/db/db/dbLibraryProxy.cc @@ -99,8 +99,6 @@ LibraryProxy::remap (lib_id_type lib_id, cell_index_type lib_cell_index) m_lib_id = lib_id; m_library_cell_index = lib_cell_index; - // It's important to register at the new library, but the old library is about to the deleted, so we don't unregister. - // That does not disturb the old library iterating over the layouts. db::Library *lib = db::LibraryManager::instance ().lib (m_lib_id); if (lib) { lib->register_proxy (this, layout ()); diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc index d79793638..71b6561fc 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc @@ -358,17 +358,21 @@ GDS2ReaderBase::do_read (db::Layout &layout) db::cell_index_type cell_index = make_cell (layout, m_cellname); - db::Cell *cell = &layout.cell (cell_index); - + bool ignore_cell = false; std::map >::const_iterator ctx = m_context_info.find (m_cellname); if (ctx != m_context_info.end ()) { GDS2ReaderLayerMapping layer_mapping (this, &layout, m_create_layers); if (layout.recover_proxy_as (cell_index, ctx->second.begin (), ctx->second.end (), &layer_mapping)) { // ignore everything in that cell since it is created by the import: - cell = 0; + ignore_cell = true; } } + db::Cell *cell = 0; + if (! ignore_cell) { + cell = &layout.cell (cell_index); + } + long attr = 0; db::PropertiesRepository::properties_set cell_properties; From 0fc4caace0373927b872373d7eaac23647b5dece Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 13 Dec 2020 19:39:45 +0100 Subject: [PATCH 4/8] WIP: Libraries View follows technology now. --- src/laybasic/laybasic/layLibrariesView.cc | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/laybasic/laybasic/layLibrariesView.cc b/src/laybasic/laybasic/layLibrariesView.cc index 5209b6f68..ec18a07c5 100644 --- a/src/laybasic/laybasic/layLibrariesView.cc +++ b/src/laybasic/laybasic/layLibrariesView.cc @@ -530,16 +530,28 @@ LibrariesView::do_update_content (int lib_index) size_t imin = (lib_index < 0 ? 0 : (size_t) lib_index); size_t imax = (lib_index < 0 ? std::numeric_limits ::max () : (size_t) lib_index); + std::string tech_name; // rebuild all events detach_from_all_events (); + + mp_view->active_cellview_changed_event.add (this, &LibrariesView::update_required); + lay::CellViewRef cv = mp_view->active_cellview_ref (); + if (cv.is_valid ()) { + cv->technology_changed_event.add (this, &LibrariesView::update_required); + tech_name = cv->tech_name (); + } + db::LibraryManager::instance ().changed_event.add (this, &LibrariesView::update_required); std::vector libraries; for (db::LibraryManager::iterator lib = db::LibraryManager::instance ().begin (); lib != db::LibraryManager::instance ().end (); ++lib) { - libraries.push_back (db::LibraryManager::instance ().lib (lib->second)); - libraries.back ()->layout ().hier_changed_event.add (this, &LibrariesView::update_required); - libraries.back ()->retired_state_changed_event.add (this, &LibrariesView::update_required); + db::Library *lib_ptr = db::LibraryManager::instance ().lib (lib->second); + if (! lib_ptr->for_technologies () || lib_ptr->is_for_technology (tech_name)) { + libraries.push_back (lib_ptr); + libraries.back ()->layout ().hier_changed_event.add (this, &LibrariesView::update_required); + libraries.back ()->retired_state_changed_event.add (this, &LibrariesView::update_required); + } } for (size_t i = imin; i < libraries.size () && i <= imax; ++i) { From 740f5509647f33deaa43cdd1b780e898fe5035e4 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 13 Dec 2020 19:54:23 +0100 Subject: [PATCH 5/8] WIP: handling the case of entirely lost libraries. --- src/db/db/dbLayout.cc | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index a9c94c2ad..d627ac812 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -519,6 +519,7 @@ Layout::set_technology_name (const std::string &tech) // determine which library to map to what std::map mapping; std::set seen; + std::set lost; for (db::Layout::iterator c = begin (); c != end (); ++c) { @@ -535,25 +536,32 @@ Layout::set_technology_name (const std::string &tech) if (new_id.first && new_id.second != l->get_id ()) { mapping.insert (std::make_pair (l->get_id (), new_id.second)); + } else if (! new_id.first) { + lost.insert (lib_proxy->lib_id ()); } } } - if (! mapping.empty ()) { + if (! mapping.empty () || ! lost.empty ()) { bool needs_cleanup = false; std::vector > pcells_to_map; std::vector lib_cells_to_map; + std::vector lib_cells_lost; for (db::Layout::iterator c = begin (); c != end (); ++c) { std::map::const_iterator m; db::LibraryProxy *lib_proxy = dynamic_cast (&*c); - if (lib_proxy && (m = mapping.find (lib_proxy->lib_id ())) != mapping.end ()) { + if (! lib_proxy) { + continue; + } + + if ((m = mapping.find (lib_proxy->lib_id ())) != mapping.end ()) { db::Library *lib = db::LibraryManager::instance ().lib (lib_proxy->lib_id ()); db::Cell *lib_cell = &lib->layout ().cell (lib_proxy->library_cell_index ()); @@ -566,6 +574,12 @@ Layout::set_technology_name (const std::string &tech) needs_cleanup = true; + } else if (lost.find (lib_proxy->lib_id ()) != lost.end ()) { + + lib_cells_lost.push_back (lib_proxy); + + needs_cleanup = true; + } } @@ -635,6 +649,17 @@ Layout::set_technology_name (const std::string &tech) } + for (std::vector::const_iterator lp = lib_cells_lost.begin (); lp != lib_cells_lost.end (); ++lp) { + + db::cell_index_type ci = (*lp)->Cell::cell_index (); + + // substitute by a cold proxy + db::ProxyContextInfo info; + get_context_info (ci, info); + create_cold_proxy_as (info, ci); + + } + if (needs_cleanup) { cleanup (); } From 86e7fa56f02f9001d58b2ef4d2f361c3685c4cfa Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 13 Dec 2020 22:02:19 +0100 Subject: [PATCH 6/8] WIP: undo/redo for applying a technology. --- src/db/db/dbColdProxy.cc | 4 +- src/db/db/dbLayout.cc | 51 +++++++- src/db/db/dbLayout.h | 12 ++ src/db/db/dbLibraryManager.cc | 28 ++-- src/db/unit_tests/dbLayoutTests.cc | 174 ++++++++++++++++++++++++- src/lay/lay/layTechnologyController.cc | 24 +++- src/laybasic/laybasic/layCellView.cc | 9 +- src/laybasic/laybasic/layCellView.h | 2 + 8 files changed, 280 insertions(+), 24 deletions(-) diff --git a/src/db/db/dbColdProxy.cc b/src/db/db/dbColdProxy.cc index a387f2838..33346ef91 100644 --- a/src/db/db/dbColdProxy.cc +++ b/src/db/db/dbColdProxy.cc @@ -77,9 +77,9 @@ std::string ColdProxy::get_basic_name () const { if (! mp_context_info->pcell_name.empty ()) { - return "" + mp_context_info->pcell_name; + return "" + mp_context_info->pcell_name; } else if (! mp_context_info->cell_name.empty ()) { - return "" + mp_context_info->cell_name; + return "" + mp_context_info->cell_name; } else { return Cell::get_basic_name (); } diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index d627ac812..6ff5baecf 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -86,6 +86,27 @@ private: db::properties_id_type m_from, m_to; }; +struct SetLayoutTechName + : public LayoutOp +{ + SetLayoutTechName (const std::string &from, const std::string &to) + : m_from (from), m_to (to) + { } + + virtual void redo (db::Layout *layout) const + { + layout->set_technology_name_without_update (m_to); + } + + virtual void undo (db::Layout *layout) const + { + layout->set_technology_name_without_update (m_from); + } + +private: + std::string m_from, m_to; +}; + struct SetLayoutDBU : public LayoutOp { @@ -509,6 +530,18 @@ Layout::technology () const return db::Technologies::instance ()->technology_by_name (m_tech_name); } +void +Layout::set_technology_name_without_update (const std::string &tech) +{ + if (tech != m_tech_name) { + if (manager () && manager ()->transacting ()) { + manager ()->queue (this, new SetLayoutTechName (m_tech_name, tech)); + } + m_tech_name = tech; + technology_changed_event (); + } +} + void Layout::set_technology_name (const std::string &tech) { @@ -666,7 +699,7 @@ Layout::set_technology_name (const std::string &tech) } - m_tech_name = tech; + set_technology_name_without_update (tech); // we may have re-established a connection for pending ("cold") proxies so we can try to restore them restore_proxies (); @@ -2043,9 +2076,20 @@ Layout::replace_cell (cell_index_type target_cell_index, db::Cell *new_cell, boo } } - m_cells.erase (iterator (old_cell)); + if (manager () && manager ()->transacting ()) { + // note the "take" method - this takes out the cell but does not delete it (we need it inside undo) + m_cells.take (iterator (old_cell)); + manager ()->queue (this, new NewRemoveCellOp (target_cell_index, cell_name (target_cell_index), true /*remove*/, old_cell)); + } else { + m_cells.erase (iterator (old_cell)); + } + m_cells.push_back_ptr (new_cell); m_cell_ptrs [target_cell_index] = new_cell; + + if (manager () && manager ()->transacting ()) { + manager ()->queue (this, new NewRemoveCellOp (target_cell_index, m_cell_names [target_cell_index], false /*new*/, 0)); + } } void @@ -2060,7 +2104,6 @@ Layout::get_pcell_variant_as (pcell_id_type pcell_id, const std::vectorget_variant (*this, parameters) == 0); - tl_assert (! (manager () && manager ()->transacting ())); tl_assert (m_cell_ptrs [target_cell_index] != 0); pcell_variant_type *variant = new pcell_variant_type (target_cell_index, *this, pcell_id, parameters); @@ -2628,7 +2671,6 @@ Layout::unregister_lib_proxy (db::LibraryProxy *lib_proxy) void Layout::get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping, bool retain_layout) { - tl_assert (! (manager () && manager ()->transacting ())); tl_assert (m_cell_ptrs [target_cell_index] != 0); LibraryProxy *proxy = new LibraryProxy (target_cell_index, *this, lib->get_id (), cell_index); @@ -2710,7 +2752,6 @@ Layout::create_cold_proxy (const db::ProxyContextInfo &info) void Layout::create_cold_proxy_as (const db::ProxyContextInfo &info, cell_index_type target_cell_index) { - tl_assert (! (manager () && manager ()->transacting ())); tl_assert (m_cell_ptrs [target_cell_index] != 0); ColdProxy *proxy = new ColdProxy (target_cell_index, *this, info); diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index 779a1ee2f..d9c78019e 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -593,6 +593,13 @@ public: */ void set_technology_name (const std::string &tech); + /** + * @brief Changes the technology name + * This method will only change the technology name, but does not re-assess the library links. + * It's provided mainly to support undo/redo and testing. + */ + void set_technology_name_without_update (const std::string &tech); + /** * @brief Accessor to the array repository */ @@ -1816,6 +1823,11 @@ public: */ const std::string &meta_info_value (const std::string &name) const; + /** + * @brief This event is triggered when the technology changes + */ + tl::Event technology_changed_event; + protected: /** * @brief Establish the graph's internals according to the dirty flags diff --git a/src/db/db/dbLibraryManager.cc b/src/db/db/dbLibraryManager.cc index 88e526c7c..2404f1217 100644 --- a/src/db/db/dbLibraryManager.cc +++ b/src/db/db/dbLibraryManager.cc @@ -69,19 +69,25 @@ LibraryManager::~LibraryManager () std::pair LibraryManager::lib_by_name (const std::string &name, const std::set &for_technologies) const { - iterator l = m_lib_by_name.find (name); - while (l != m_lib_by_name.end () && l->first == name) { - const db::Library *lptr = lib (l->second); - bool found = lptr->for_technologies (); - for (std::set::const_iterator t = for_technologies.begin (); t != for_technologies.end () && found; ++t) { - if (! lptr->is_for_technology (*t)) { - found = false; + iterator l; + + if (! for_technologies.empty ()) { + + l = m_lib_by_name.find (name); + while (l != m_lib_by_name.end () && l->first == name) { + const db::Library *lptr = lib (l->second); + bool found = lptr->for_technologies (); + for (std::set::const_iterator t = for_technologies.begin (); t != for_technologies.end () && found; ++t) { + if (! lptr->is_for_technology (*t)) { + found = false; + } } + if (found) { + return std::make_pair (true, l->second); + } + ++l; } - if (found) { - return std::make_pair (true, l->second); - } - ++l; + } // fallback: technology-unspecific libs diff --git a/src/db/unit_tests/dbLayoutTests.cc b/src/db/unit_tests/dbLayoutTests.cc index addce4eff..49a44f837 100644 --- a/src/db/unit_tests/dbLayoutTests.cc +++ b/src/db/unit_tests/dbLayoutTests.cc @@ -20,9 +20,12 @@ */ - - #include "dbLayout.h" +#include "dbLibraryManager.h" +#include "dbLibrary.h" +#include "dbColdProxy.h" +#include "dbLibraryProxy.h" +#include "dbTextWriter.h" #include "tlString.h" #include "tlUnitTest.h" @@ -464,3 +467,170 @@ TEST(4) prop_id = g.properties_repository ().properties_id (ps); EXPECT_EQ (el.property_ids_dirty, true); } + +static std::string l2s (const db::Layout &layout) +{ + tl::OutputStringStream os; + tl::OutputStream ostream (os); + db::TextWriter writer (ostream); + writer.write (layout); + return os.string (); +} + +TEST(5) +{ + // Technology management and library substitution + + db::cell_index_type ci; + unsigned int li; + db::Cell *cell; + + db::Library *lib_a = new db::Library (); + lib_a->set_name ("LIB"); + ci = lib_a->layout ().add_cell ("LIBCELL"); + li = lib_a->layout ().insert_layer (db::LayerProperties (1, 0)); + lib_a->layout ().cell (ci).shapes (li).insert (db::Box (0, 0, 100, 200)); + lib_a->add_technology ("A"); + db::LibraryManager::instance ().register_lib (lib_a); + + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "A").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "A").second, lib_a->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_ptr_by_name ("LIB", "A") == lib_a, true); + + db::Library *lib_b = new db::Library (); + lib_b->set_name ("LIB"); + ci = lib_b->layout ().add_cell ("LIBCELL"); + li = lib_b->layout ().insert_layer (db::LayerProperties (2, 0)); + lib_b->layout ().cell (ci).shapes (li).insert (db::Box (0, 0, 200, 100)); + lib_b->add_technology ("B"); + db::LibraryManager::instance ().register_lib (lib_b); + + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "B").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "B").second, lib_b->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_ptr_by_name ("LIB", "B") == lib_b, true); + + db::Library *lib_c = new db::Library (); + lib_c->set_name ("LIB"); + ci = lib_c->layout ().add_cell ("LIBCELL2"); + li = lib_c->layout ().insert_layer (db::LayerProperties (2, 0)); + lib_c->layout ().cell (ci).shapes (li).insert (db::Box (0, 0, 200, 100)); + lib_c->add_technology ("C"); + db::LibraryManager::instance ().register_lib (lib_c); + + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "C").first, true); + EXPECT_EQ (db::LibraryManager::instance ().lib_by_name ("LIB", "C").second, lib_c->get_id ()); + EXPECT_EQ (db::LibraryManager::instance ().lib_ptr_by_name ("LIB", "C") == lib_c, true); + + db::Manager m; + db::Layout l (&m); + EXPECT_EQ (l.technology_name (), ""); + + db::ProxyContextInfo info; + info.lib_name = "LIB"; + info.cell_name = "LIBCELL"; + + cell = l.recover_proxy (info); + EXPECT_EQ (dynamic_cast (cell) != 0, true); + EXPECT_EQ (cell->get_qualified_name (), "LIB.LIBCELL"); + EXPECT_EQ (cell->get_basic_name (), "LIBCELL"); + EXPECT_EQ (cell->get_display_name (), "LIB.LIBCELL"); + + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nend_cell\nend_lib\n"); + + // now restore the proxies + l.set_technology_name ("A"); + EXPECT_EQ (l.technology_name (), "A"); + + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 1 0 {0 0} {100 200}\nend_cell\nend_lib\n"); + + // now switch to cold proxies again as the technology does not have "LIBCELL" (but rather LIBCELL2) + l.set_technology_name ("C"); + EXPECT_EQ (l.technology_name (), "C"); + + cell = &l.cell (l.cell_by_name ("LIBCELL").second); + EXPECT_EQ (dynamic_cast (cell) != 0, true); + EXPECT_EQ (cell->get_qualified_name (), "LIB.LIBCELL"); + EXPECT_EQ (cell->get_basic_name (), "LIBCELL"); + EXPECT_EQ (cell->get_display_name (), "LIB.LIBCELL"); + + // NOTE: the box on 1/0 retained + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 1 0 {0 0} {100 200}\nend_cell\nend_lib\n"); + + // switch to another LIBCELL, this time using layer 2/0 + m.transaction ("switch_to_b"); + l.set_technology_name ("B"); + m.commit (); + + EXPECT_EQ (l.technology_name (), "B"); + cell = &l.cell (l.cell_by_name ("LIBCELL").second); + EXPECT_EQ (dynamic_cast (cell) != 0, true); + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 2 0 {0 0} {200 100}\nend_cell\nend_lib\n"); + + m.undo (); + EXPECT_EQ (l.technology_name (), "C"); + + cell = &l.cell (l.cell_by_name ("LIBCELL").second); + EXPECT_EQ (dynamic_cast (cell) != 0, true); + EXPECT_EQ (cell->get_qualified_name (), "LIB.LIBCELL"); + EXPECT_EQ (cell->get_basic_name (), "LIBCELL"); + EXPECT_EQ (cell->get_display_name (), "LIB.LIBCELL"); + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 1 0 {0 0} {100 200}\nend_cell\nend_lib\n"); + + m.redo (); + + EXPECT_EQ (l.technology_name (), "B"); + cell = &l.cell (l.cell_by_name ("LIBCELL").second); + EXPECT_EQ (dynamic_cast (cell) != 0, true); + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {LIBCELL}\nbox 2 0 {0 0} {200 100}\nend_cell\nend_lib\n"); + + db::LibraryManager::instance ().delete_lib (lib_a); + db::LibraryManager::instance ().delete_lib (lib_b); + db::LibraryManager::instance ().delete_lib (lib_c); +} + +TEST(6) +{ + // Cold proxies and context serialization + db::Cell *cell; + + db::Manager m; + db::Layout l (&m); + + EXPECT_EQ (l.technology_name (), ""); + + db::ProxyContextInfo info; + info.lib_name = "Basic"; + info.pcell_name = "CIRCLE"; + info.pcell_parameters ["actual_radius"] = tl::Variant (10.0); + info.pcell_parameters ["npoints"] = tl::Variant (8); + info.pcell_parameters ["layer"] = tl::Variant (db::LayerProperties (1, 0)); + + m.transaction ("import"); + cell = l.recover_proxy (info); + m.commit (); + EXPECT_EQ (cell->get_qualified_name (), "Basic.CIRCLE"); + EXPECT_EQ (cell->get_basic_name (), "CIRCLE"); + EXPECT_EQ (cell->get_display_name (), "Basic.CIRCLE(l=1/0,r=10,n=8)"); + + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-4142 -10000} {-10000 -4142} {-10000 4142} {-4142 10000} {4142 10000} {10000 4142} {10000 -4142} {4142 -10000} {-4142 -10000}\nend_cell\nend_lib\n"); + + db::ProxyContextInfo info2; + l.get_context_info (cell->cell_index (), info2); + info2.pcell_parameters ["actual_radius"] = tl::Variant (5.0); + + m.transaction ("modify"); + db::cell_index_type ci = cell->cell_index (); + l.recover_proxy_as (ci, info2); + m.commit (); + cell = &l.cell (ci); + EXPECT_EQ (cell->get_qualified_name (), "Basic.CIRCLE"); + EXPECT_EQ (cell->get_basic_name (), "CIRCLE"); + EXPECT_EQ (cell->get_display_name (), "Basic.CIRCLE(l=1/0,r=5,n=8)"); + + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-2071 -5000} {-5000 -2071} {-5000 2071} {-2071 5000} {2071 5000} {5000 2071} {5000 -2071} {2071 -5000} {-2071 -5000}\nend_cell\nend_lib\n"); + + m.undo (); + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-4142 -10000} {-10000 -4142} {-10000 4142} {-4142 10000} {4142 10000} {10000 4142} {10000 -4142} {4142 -10000} {-4142 -10000}\nend_cell\nend_lib\n"); + m.redo (); + EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-2071 -5000} {-5000 -2071} {-5000 2071} {-2071 5000} {2071 5000} {5000 2071} {5000 -2071} {2071 -5000} {-2071 -5000}\nend_cell\nend_lib\n"); +} diff --git a/src/lay/lay/layTechnologyController.cc b/src/lay/lay/layTechnologyController.cc index d84876401..53f85f05a 100644 --- a/src/lay/lay/layTechnologyController.cc +++ b/src/lay/lay/layTechnologyController.cc @@ -285,15 +285,33 @@ bool TechnologyController::menu_activated (const std::string &symbol) const { if (symbol == "technology_selector:apply_technology") { + if (lay::LayoutView::current () && lay::LayoutView::current ()->active_cellview ().is_valid ()) { - // Cancels the current modes - changing the technology may make libraries unavailable - // for example. + if (mp_mw) { + + // Cancels the current modes - changing the technology may make libraries unavailable + // for example. mp_mw->cancel (); + + // apply technology with undo + mp_mw->manager ().transaction (tl::sprintf (tl::to_string (tr ("Apply technology '%s'")), m_current_technology)); + try { + lay::LayoutView::current ()->active_cellview ()->apply_technology (m_current_technology); + mp_mw->manager ().commit (); + } catch (...) { + mp_mw->manager ().cancel (); + throw; + } + + } else { + lay::LayoutView::current ()->active_cellview ()->apply_technology (m_current_technology); } - lay::LayoutView::current ()->active_cellview ()->apply_technology (m_current_technology); + } + return true; + } else { return lay::PluginDeclaration::menu_activated (symbol); } diff --git a/src/laybasic/laybasic/layCellView.cc b/src/laybasic/laybasic/layCellView.cc index e42317c43..1aacc1c67 100644 --- a/src/laybasic/laybasic/layCellView.cc +++ b/src/laybasic/laybasic/layCellView.cc @@ -59,6 +59,8 @@ LayoutHandle::LayoutHandle (db::Layout *layout, const std::string &filename) m_dirty (false), m_save_options_valid (false) { + layout->technology_changed_event.add (this, &LayoutHandle::on_technology_changed); + // layouts in the managed layouts space participate in spare proxy cleanup layout->do_cleanup (true); @@ -108,6 +110,12 @@ LayoutHandle::~LayoutHandle () file_watcher ().remove_file (filename ()); } +void +LayoutHandle::on_technology_changed () +{ + technology_changed_event (); +} + void LayoutHandle::layout_changed () { @@ -232,7 +240,6 @@ LayoutHandle::set_tech_name (const std::string &tn) { if (mp_layout && tn != tech_name ()) { mp_layout->set_technology_name (tn); - technology_changed_event (); } } diff --git a/src/laybasic/laybasic/layCellView.h b/src/laybasic/laybasic/layCellView.h index 5f036b728..7d2ac54e4 100644 --- a/src/laybasic/laybasic/layCellView.h +++ b/src/laybasic/laybasic/layCellView.h @@ -302,6 +302,8 @@ private: bool m_save_options_valid; db::LoadLayoutOptions m_load_options; + void on_technology_changed (); + static std::map ms_dict; static tl::FileSystemWatcher *mp_file_watcher; }; From 92d81c58443e7c7a1b025229227f752747015a41 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 13 Dec 2020 22:09:21 +0100 Subject: [PATCH 7/8] WIP: cold proxies are written to GDS2 and OASIS too. This means we keep the library references even if we load and save with the wrong libraries or technology. --- src/db/db/dbLayout.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index 6ff5baecf..ad60aad38 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -2472,6 +2472,13 @@ bool Layout::get_context_info (cell_index_type cell_index, ProxyContextInfo &info) const { const db::Cell *cptr = &cell (cell_index); + + const db::ColdProxy *cold_proxy = dynamic_cast (cptr); + if (cold_proxy) { + info = cold_proxy->context_info (); + return true; + } + const db::Layout *ly = this; const db::LibraryProxy *lib_proxy; From ee47a1e08749accd4f2c8c65bc46bc3a2d9de601 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 13 Dec 2020 22:13:51 +0100 Subject: [PATCH 8/8] Fixed the manager's 'cancel' implementation: with this, redo of a cancelled operation isn't possible any more --- src/db/db/dbManager.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/db/db/dbManager.cc b/src/db/db/dbManager.cc index 5e53b1a83..0a9e24016 100644 --- a/src/db/db/dbManager.cc +++ b/src/db/db/dbManager.cc @@ -156,16 +156,14 @@ Manager::cancel () m_opened = false; if (m_current->first.begin () != m_current->first.end ()) { - ++m_current; undo (); - - } else { - // empty transactions .. just delete - erase_transactions (m_current, m_transactions.end ()); - m_current = m_transactions.end (); } + // wipe following history as we don't want the cancelled operation to be redoable + erase_transactions (m_current, m_transactions.end ()); + m_current = m_transactions.end (); + } }