From 78da3effa2258352162e53383ff937c2f8d79fe9 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 18 Apr 2023 21:24:26 +0200 Subject: [PATCH] Next steps - persistency of meta info --- src/db/db/dbColdProxy.cc | 4 +- src/db/db/dbColdProxy.h | 8 +- src/db/db/dbLayout.cc | 173 ++++++++++++++++-- src/db/db/dbLayout.h | 65 +++++-- src/db/db/dbLibrary.cc | 6 +- src/db/unit_tests/dbLayoutTests.cc | 6 +- .../gds2/db_plugin/dbGDS2ReaderBase.cc | 41 ++++- .../gds2/db_plugin/dbGDS2WriterBase.cc | 171 ++++++++++------- .../gds2/db_plugin/dbGDS2WriterBase.h | 1 + 9 files changed, 368 insertions(+), 107 deletions(-) diff --git a/src/db/db/dbColdProxy.cc b/src/db/db/dbColdProxy.cc index 738d9dea9..8cc57aacd 100644 --- a/src/db/db/dbColdProxy.cc +++ b/src/db/db/dbColdProxy.cc @@ -49,8 +49,8 @@ ColdProxy::cold_proxies_per_lib_name (const std::string &libname) } } -ColdProxy::ColdProxy (db::cell_index_type ci, db::Layout &layout, const ProxyContextInfo &info) - : Cell (ci, layout), mp_context_info (new ProxyContextInfo (info)) +ColdProxy::ColdProxy (db::cell_index_type ci, db::Layout &layout, const LayoutOrCellContextInfo &info) + : Cell (ci, layout), mp_context_info (new LayoutOrCellContextInfo (info)) { if (! info.lib_name.empty ()) { tl::MutexLocker locker (&s_map_mutex); diff --git a/src/db/db/dbColdProxy.h b/src/db/db/dbColdProxy.h index 4c2681e29..5c642a9a1 100644 --- a/src/db/db/dbColdProxy.h +++ b/src/db/db/dbColdProxy.h @@ -35,7 +35,7 @@ namespace db { -struct ProxyContextInfo; +struct LayoutOrCellContextInfo; /** * @brief A cell specialization: a cold proxy representing a library or PCell which has gone out of scope @@ -53,7 +53,7 @@ public: * * Creates a cold proxy represented by the ProxyContextInfo data. */ - ColdProxy (db::cell_index_type ci, db::Layout &layout, const ProxyContextInfo &info); + ColdProxy (db::cell_index_type ci, db::Layout &layout, const LayoutOrCellContextInfo &info); /** * @brief The destructor @@ -68,7 +68,7 @@ public: /** * @brief Get the library id */ - const ProxyContextInfo &context_info () const + const LayoutOrCellContextInfo &context_info () const { return *mp_context_info; } @@ -102,7 +102,7 @@ public: virtual std::string get_qualified_name () const; private: - ProxyContextInfo *mp_context_info; + LayoutOrCellContextInfo *mp_context_info; ColdProxy (const ColdProxy &d); ColdProxy &operator= (const ColdProxy &d); diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index f92b19a47..247fb5c58 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -258,12 +258,12 @@ private: // ----------------------------------------------------------------- // Implementation of the ProxyContextInfo class -ProxyContextInfo -ProxyContextInfo::deserialize (std::vector::const_iterator from, std::vector::const_iterator to) +LayoutOrCellContextInfo +LayoutOrCellContextInfo::deserialize (std::vector::const_iterator from, std::vector::const_iterator to) { - ProxyContextInfo info; + LayoutOrCellContextInfo info; - for (std::vector::const_iterator i = from; i != to; ++i) { + for (auto i = from; i != to; ++i) { tl::Extractor ex (i->c_str ()); @@ -290,6 +290,20 @@ ProxyContextInfo::deserialize (std::vector::const_iterator from, st info.cell_name = ex.skip (); + } else if (ex.test ("META(")) { + + std::pair > vv; + + ex.read_word_or_quoted (vv.first); + if (ex.test (",")) { + ex.read_word_or_quoted (vv.second.second); + } + ex.test (")"); + ex.test ("="); + ex.read (vv.second.first); + + info.meta_info.insert(vv); + } } @@ -298,12 +312,12 @@ ProxyContextInfo::deserialize (std::vector::const_iterator from, st } void -ProxyContextInfo::serialize (std::vector &strings) +LayoutOrCellContextInfo::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) { + for (auto 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 ()) { @@ -312,6 +326,20 @@ ProxyContextInfo::serialize (std::vector &strings) if (! cell_name.empty ()) { strings.push_back ("CELL=" + cell_name); } + + std::string mv; + for (auto m = meta_info.begin (); m != meta_info.end (); ++m) { + mv.clear (); + mv += "META("; + mv += tl::to_word_or_quoted_string (m->first); + if (! m->second.second.empty ()) { + mv += ","; + mv += tl::to_word_or_quoted_string (m->second.second); + } + mv += ")="; + mv += m->second.first.to_parsable_string (); + strings.push_back (mv); + } } // ----------------------------------------------------------------- @@ -593,7 +621,7 @@ Layout::set_technology_name (const std::string &tech) if (! pn.first) { // substitute by a cold proxy - db::ProxyContextInfo info; + db::LayoutOrCellContextInfo info; get_context_info (ci, info); create_cold_proxy_as (info, ci); @@ -606,7 +634,7 @@ Layout::set_technology_name (const std::string &tech) if (! old_pcell_decl || ! new_pcell_decl) { // substitute by a cold proxy - db::ProxyContextInfo info; + db::LayoutOrCellContextInfo info; get_context_info (ci, info); create_cold_proxy_as (info, ci); @@ -633,7 +661,7 @@ Layout::set_technology_name (const std::string &tech) if (! cn.first) { // unlink this proxy: substitute by a cold proxy - db::ProxyContextInfo info; + db::LayoutOrCellContextInfo info; get_context_info (ci, info); create_cold_proxy_as (info, ci); @@ -650,7 +678,7 @@ Layout::set_technology_name (const std::string &tech) db::cell_index_type ci = (*lp)->Cell::cell_index (); // substitute by a cold proxy - db::ProxyContextInfo info; + db::LayoutOrCellContextInfo info; get_context_info (ci, info); create_cold_proxy_as (info, ci); @@ -2446,10 +2474,85 @@ Layout::get_pcell_variant_cell (cell_index_type cell_index, const std::vectorsecond.persisted) { + return true; + } + } + + return false; +} + +bool +Layout::has_context_info (cell_index_type cell_index) const +{ + auto c = m_meta_info_by_cell.find (cell_index); + if (c != m_meta_info_by_cell.end ()) { + for (auto i = c->second.begin (); i != c->second.end (); ++i) { + if (i->second.persisted) { + return true; + } + } + } + + const db::Cell &cref = cell (cell_index); + if (cref.is_proxy () && ! cref.is_top ()) { + return true; + } else { + return false; + } +} + +bool +Layout::get_context_info (std::vector &strings) const +{ + LayoutOrCellContextInfo info; + if (! get_context_info (info)) { + return false; + } else { + info.serialize (strings); + return true; + } +} + +bool +Layout::get_context_info (LayoutOrCellContextInfo &info) const +{ + for (auto i = m_meta_info.begin (); i != m_meta_info.end (); ++i) { + if (i->second.persisted) { + std::pair &mi = info.meta_info [m_meta_info_names [i->first] ]; + mi.first = i->second.value; + mi.second = i->second.description; + } + } + + return true; +} + +void +Layout::fill_meta_info_from_context (std::vector ::const_iterator from, std::vector ::const_iterator to) +{ + fill_meta_info_from_context (LayoutOrCellContextInfo::deserialize (from, to)); +} + +void +Layout::fill_meta_info_from_context (const LayoutOrCellContextInfo &context_info) +{ + if (! context_info.meta_info.empty ()) { + for (auto i = context_info.meta_info.begin (); i != context_info.meta_info.end (); ++i) { + meta_info_name_id_type name_id = meta_info_name_id (i->first); + m_meta_info [name_id] = MetaInfo (i->second.second, i->second.first, true); + } + } +} + bool Layout::get_context_info (cell_index_type cell_index, std::vector &strings) const { - ProxyContextInfo info; + LayoutOrCellContextInfo info; if (! get_context_info (cell_index, info)) { return false; } else { @@ -2459,8 +2562,19 @@ Layout::get_context_info (cell_index_type cell_index, std::vector } bool -Layout::get_context_info (cell_index_type cell_index, ProxyContextInfo &info) const +Layout::get_context_info (cell_index_type cell_index, LayoutOrCellContextInfo &info) const { + auto cmi = m_meta_info_by_cell.find (cell_index); + if (cmi != m_meta_info_by_cell.end ()) { + for (auto i = cmi->second.begin (); i != cmi->second.end (); ++i) { + if (i->second.persisted) { + std::pair &mi = info.meta_info [m_meta_info_names [i->first] ]; + mi.first = i->second.value; + mi.second = i->second.description; + } + } + } + const db::Cell *cptr = &cell (cell_index); const db::ColdProxy *cold_proxy = dynamic_cast (cptr); @@ -2509,6 +2623,27 @@ Layout::get_context_info (cell_index_type cell_index, ProxyContextInfo &info) co return true; } +void +Layout::fill_meta_info_from_context (cell_index_type cell_index, std::vector ::const_iterator from, std::vector ::const_iterator to) +{ + fill_meta_info_from_context (cell_index, LayoutOrCellContextInfo::deserialize (from, to)); +} + +void +Layout::fill_meta_info_from_context (cell_index_type cell_index, const LayoutOrCellContextInfo &context_info) +{ + if (! context_info.meta_info.empty ()) { + + meta_info_map &mi = m_meta_info_by_cell [cell_index]; + + for (auto i = context_info.meta_info.begin (); i != context_info.meta_info.end (); ++i) { + meta_info_name_id_type name_id = meta_info_name_id (i->first); + mi [name_id] = MetaInfo (i->second.second, i->second.first, true); + } + + } +} + void Layout::restore_proxies (ImportLayerMapping *layer_mapping) { @@ -2540,11 +2675,11 @@ Layout::recover_proxy_as (cell_index_type cell_index, std::vector : return false; } - return recover_proxy_as (cell_index, ProxyContextInfo::deserialize (from, to), layer_mapping); + return recover_proxy_as (cell_index, LayoutOrCellContextInfo::deserialize (from, to), layer_mapping); } bool -Layout::recover_proxy_as (cell_index_type cell_index, const ProxyContextInfo &info, ImportLayerMapping *layer_mapping) +Layout::recover_proxy_as (cell_index_type cell_index, const LayoutOrCellContextInfo &info, ImportLayerMapping *layer_mapping) { if (! info.lib_name.empty ()) { @@ -2594,11 +2729,11 @@ Layout::recover_proxy (std::vector ::const_iterator from, std::vect return 0; } - return recover_proxy (ProxyContextInfo::deserialize (from, to)); + return recover_proxy (LayoutOrCellContextInfo::deserialize (from, to)); } db::Cell * -Layout::recover_proxy (const ProxyContextInfo &info) +Layout::recover_proxy (const LayoutOrCellContextInfo &info) { if (! info.lib_name.empty ()) { @@ -2626,7 +2761,7 @@ Layout::recover_proxy (const ProxyContextInfo &info) } db::Cell * -Layout::recover_proxy_no_lib (const ProxyContextInfo &info) +Layout::recover_proxy_no_lib (const LayoutOrCellContextInfo &info) { if (! info.pcell_name.empty ()) { @@ -2723,7 +2858,7 @@ Layout::get_lib_proxy (Library *lib, cell_index_type cell_index) } cell_index_type -Layout::create_cold_proxy (const db::ProxyContextInfo &info) +Layout::create_cold_proxy (const db::LayoutOrCellContextInfo &info) { // create a new unique name std::string b; @@ -2754,7 +2889,7 @@ Layout::create_cold_proxy (const db::ProxyContextInfo &info) } void -Layout::create_cold_proxy_as (const db::ProxyContextInfo &info, cell_index_type target_cell_index) +Layout::create_cold_proxy_as (const db::LayoutOrCellContextInfo &info, cell_index_type target_cell_index) { tl_assert (m_cell_ptrs [target_cell_index] != 0); diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index 2038ae52b..36730efa1 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -417,14 +417,15 @@ public: /** * @brief A binary object representing context information for regenerating library proxies and PCells */ -struct DB_PUBLIC ProxyContextInfo +struct DB_PUBLIC LayoutOrCellContextInfo { std::string lib_name; std::string cell_name; std::string pcell_name; std::map pcell_parameters; + std::map > meta_info; - static ProxyContextInfo deserialize (std::vector::const_iterator from, std::vector::const_iterator to); + static LayoutOrCellContextInfo deserialize (std::vector::const_iterator from, std::vector::const_iterator to); void serialize (std::vector &strings); }; @@ -1015,27 +1016,69 @@ public: /** * @brief Creates a cold proxy representing the given context information */ - cell_index_type create_cold_proxy (const db::ProxyContextInfo &info); + cell_index_type create_cold_proxy (const db::LayoutOrCellContextInfo &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); + void create_cold_proxy_as (const db::LayoutOrCellContextInfo &info, cell_index_type cell_index); + + /** + * @brief Gets a value indicating whether layout context info is provided / needed + */ + bool has_context_info() const; + + /** + * @brief Gets a value indicating whether layout context info is provided / needed + */ + bool has_context_info(cell_index_type cell_index) const; + + /** + * @brief Get the context information for the layout (for writing into a file) + * + * The context information is a sequence of strings which is pushed onto the given + * vector. It can be used to fill meta information with fill_meta_info_from_context. + */ + bool get_context_info (std::vector &strings) const; + + /** + * @brief Gets the context information as a binary object + */ + bool get_context_info (LayoutOrCellContextInfo &context_info) const; + + /** + * @brief Fills the layout's meta information from the context + */ + void fill_meta_info_from_context (std::vector ::const_iterator from, std::vector ::const_iterator to); + + /** + * @brief Fills the layout's meta information from the binary context + */ + void fill_meta_info_from_context (const LayoutOrCellContextInfo &context_info); /** * @brief Get the context information for a given cell (for writing into a file) * * The context information is a sequence of strings which is pushed onto the given - * vector. It can be used to recover a respective proxy cell with the recover_proxy method. - * If the given cell is not a valid proxy or library references are missing, the method - * will return false. + * vector. It can be used to recover a respective proxy cell with the recover_proxy method + * or to fill meta information using fill_meta_info_from_context. */ 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; + bool get_context_info (cell_index_type cell_index, LayoutOrCellContextInfo &context_info) const; + + /** + * @brief Fills the layout's meta information from the context + */ + void fill_meta_info_from_context (cell_index_type cell_index, std::vector ::const_iterator from, std::vector ::const_iterator to); + + /** + * @brief Fills the layout's meta information from the binary context + */ + void fill_meta_info_from_context (cell_index_type cell_index, const LayoutOrCellContextInfo &context_info); /** * @brief Recover a proxy cell from the given context info. @@ -1051,7 +1094,7 @@ public: /** * @brief Recover a proxy cell from the given binary context info object. */ - db::Cell *recover_proxy (const ProxyContextInfo &context_info); + db::Cell *recover_proxy (const LayoutOrCellContextInfo &context_info); /** * @brief Recover a proxy cell from the given context info. @@ -1073,7 +1116,7 @@ public: * * 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); + bool recover_proxy_as (cell_index_type cell_index, const LayoutOrCellContextInfo &context_info, ImportLayerMapping *layer_mapping = 0); /** * @brief Restores proxies as far as possible @@ -2026,7 +2069,7 @@ private: /** * @brief Recovers a proxy without considering the library from context_info */ - db::Cell *recover_proxy_no_lib (const ProxyContextInfo &context_info); + db::Cell *recover_proxy_no_lib (const LayoutOrCellContextInfo &context_info); }; /** diff --git a/src/db/db/dbLibrary.cc b/src/db/db/dbLibrary.cc index a6075f5d6..59acfa95f 100644 --- a/src/db/db/dbLibrary.cc +++ b/src/db/db/dbLibrary.cc @@ -205,7 +205,7 @@ Library::remap_to (db::Library *other) if (! pn.first) { // substitute by a cold proxy - db::ProxyContextInfo info; + db::LayoutOrCellContextInfo info; r->first->get_context_info (ci, info); r->first->create_cold_proxy_as (info, ci); @@ -216,7 +216,7 @@ Library::remap_to (db::Library *other) if (! old_pcell_decl || ! new_pcell_decl) { // substitute by a cold proxy - db::ProxyContextInfo info; + db::LayoutOrCellContextInfo info; r->first->get_context_info (ci, info); r->first->create_cold_proxy_as (info, ci); @@ -254,7 +254,7 @@ Library::remap_to (db::Library *other) if (! cn.first) { // substitute by a cold proxy - db::ProxyContextInfo info; + db::LayoutOrCellContextInfo info; r->first->get_context_info (ci, info); r->first->create_cold_proxy_as (info, ci); diff --git a/src/db/unit_tests/dbLayoutTests.cc b/src/db/unit_tests/dbLayoutTests.cc index e159ec41c..372a495b3 100644 --- a/src/db/unit_tests/dbLayoutTests.cc +++ b/src/db/unit_tests/dbLayoutTests.cc @@ -543,7 +543,7 @@ TEST(5) db::Layout l (&m); EXPECT_EQ (l.technology_name (), ""); - db::ProxyContextInfo info; + db::LayoutOrCellContextInfo info; info.lib_name = "LIB"; info.cell_name = "LIBCELL"; @@ -624,7 +624,7 @@ TEST(6) EXPECT_EQ (l.technology_name (), ""); - db::ProxyContextInfo info; + db::LayoutOrCellContextInfo info; info.lib_name = "Basic"; info.pcell_name = "CIRCLE"; info.pcell_parameters ["actual_radius"] = tl::Variant (10.0); @@ -644,7 +644,7 @@ TEST(6) 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; + db::LayoutOrCellContextInfo info2; l.get_context_info (cell->cell_index (), info2); info2.pcell_parameters ["actual_radius"] = tl::Variant (5.0); diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc index 91c940d1c..1ae260b5c 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc @@ -289,13 +289,19 @@ GDS2ReaderBase::do_read (db::Layout &layout) db::cell_index_type cell_index = make_cell (layout, m_cellname); bool ignore_cell = false; - std::map >::const_iterator ctx = m_context_info.find (m_cellname); + auto ctx = m_context_info.find (m_cellname); if (ctx != m_context_info.end ()) { + CommonReaderLayerMapping layer_mapping (this, &layout); - if (layout.recover_proxy_as (cell_index, ctx->second.begin (), ctx->second.end (), &layer_mapping)) { + LayoutOrCellContextInfo ci = LayoutOrCellContextInfo::deserialize (ctx->second.begin (), ctx->second.end ()); + + if (layout.recover_proxy_as (cell_index, ci, &layer_mapping)) { // ignore everything in that cell since it is created by the import: ignore_cell = true; } + + layout.fill_meta_info_from_context (cell_index, ci); + } db::Cell *cell = 0; @@ -386,6 +392,13 @@ GDS2ReaderBase::do_read (db::Layout &layout) } + // deserialize global context information + auto ctx = m_context_info.find (std::string ()); + if (ctx != m_context_info.end ()) { + LayoutOrCellContextInfo ci = LayoutOrCellContextInfo::deserialize (ctx->second.begin (), ctx->second.end ()); + layout.fill_meta_info_from_context (ci); + } + // check, if the last record is a ENDLIB if (rec_id != sENDLIB) { error (tl::to_string (tr ("ENDLIB record expected"))); @@ -396,12 +409,16 @@ void GDS2ReaderBase::read_context_info_cell () { short rec_id = 0; + std::string cn; // read cell content while ((rec_id = get_record ()) != sENDSTR) { progress_checkpoint (); + bool valid_hook = false; + cn.clear (); + if (rec_id == sSREF) { do { @@ -411,7 +428,7 @@ GDS2ReaderBase::read_context_info_cell () error (tl::to_string (tr ("SNAME record expected"))); } - std::string cn = get_string (); + cn = get_string (); rec_id = get_record (); while (rec_id == sSTRANS || rec_id == sANGLE || rec_id == sMAG) { @@ -421,6 +438,24 @@ GDS2ReaderBase::read_context_info_cell () error (tl::to_string (tr ("XY record expected"))); } + valid_hook = true; + + } else if (rec_id == sBOUNDARY) { + + rec_id = get_record (); + while (rec_id == sLAYER || rec_id == sDATATYPE) { + rec_id = get_record (); + } + if (rec_id != sXY) { + error (tl::to_string (tr ("XY record expected"))); + } + + valid_hook = true; + + } + + if (valid_hook) { + std::vector &strings = m_context_info.insert (std::make_pair (cn, std::vector ())).first->second; size_t attr = 0; diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.cc b/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.cc index f6bb95413..048ded3d6 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.cc +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.cc @@ -72,6 +72,109 @@ inline int scale (double sf, int value) } } +void +GDS2WriterBase::write_context_cell (db::Layout &layout, const short *time_data, const std::vector &cells) +{ + write_record_size (4 + 12 * 2); + write_record (sBGNSTR); + write_time (time_data); + write_time (time_data); + + write_string_record (sSTRNAME, "$$$CONTEXT_INFO$$$"); + + std::vector context_prop_strings; + + if (layout.has_context_info ()) { + + // Use a dummy BOUNDARY element to attach the global context + + write_record_size (4); + write_record (sBOUNDARY); + + write_record_size (6); + write_record (sLAYER); + write_short (0); + + write_record_size (6); + write_record (sDATATYPE); + write_short (0); + + write_record_size (4 + 5 * 2 * 4); + write_record (sXY); + for (unsigned int i = 0; i < 10; ++i) { + write_int (0); + } + + context_prop_strings.clear (); + + if (layout.get_context_info (context_prop_strings)) { + + // Hint: write in the reverse order since this way, the reader is more efficient (it knows how many strings + // will arrive) + for (std::vector ::const_iterator s = context_prop_strings.end (); s != context_prop_strings.begin (); ) { + + --s; + + write_record_size (6); + write_record (sPROPATTR); + write_short (short (std::distance (std::vector ::const_iterator (context_prop_strings.begin ()), s))); // = user string + + write_string_record (sPROPVALUE, *s); + + } + + } + + write_record_size (4); + write_record (sENDEL); + + } + + for (std::vector::const_iterator cell = cells.begin (); cell != cells.end (); ++cell) { + + if (layout.has_context_info (*cell)) { + + write_record_size (4); + write_record (sSREF); + + write_string_record (sSNAME, m_cell_name_map.cell_name (*cell)); + + write_record_size (12); + write_record (sXY); + write_int (0); + write_int (0); + + context_prop_strings.clear (); + + if (layout.get_context_info (*cell, context_prop_strings)) { + + // Hint: write in the reverse order since this way, the reader is more efficient (it knows how many strings + // will arrive) + for (std::vector ::const_iterator s = context_prop_strings.end (); s != context_prop_strings.begin (); ) { + + --s; + + write_record_size (6); + write_record (sPROPATTR); + write_short (short (std::distance (std::vector ::const_iterator (context_prop_strings.begin ()), s))); // = user string + + write_string_record (sPROPVALUE, *s); + + } + + } + + write_record_size (4); + write_record (sENDEL); + + } + + } + + write_record_size (4); + write_record (sENDSTR); +} + void GDS2WriterBase::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLayoutOptions &options) { @@ -178,73 +281,17 @@ GDS2WriterBase::write (db::Layout &layout, tl::OutputStream &stream, const db::S // write context info - bool any_proxy = false; + bool has_context = false; if (options.write_context_info ()) { - for (std::vector::const_iterator cell = cells.begin (); cell != cells.end () && !any_proxy; ++cell) { - const db::Cell &cref = layout.cell (*cell); - if (cref.is_proxy () && ! cref.is_top ()) { - any_proxy = true; - } + has_context = layout.has_context_info (); + for (std::vector::const_iterator cell = cells.begin (); cell != cells.end () && !has_context; ++cell) { + has_context = layout.has_context_info (*cell); } } - if (any_proxy) { - - write_record_size (4 + 12 * 2); - write_record (sBGNSTR); - write_time (time_data); - write_time (time_data); - - write_string_record (sSTRNAME, "$$$CONTEXT_INFO$$$"); - - std::vector context_prop_strings; - - for (std::vector::const_iterator cell = cells.begin (); cell != cells.end (); ++cell) { - - const db::Cell &cref = layout.cell (*cell); - if (cref.is_proxy () && ! cref.is_top ()) { - - write_record_size (4); - write_record (sSREF); - - write_string_record (sSNAME, m_cell_name_map.cell_name (*cell)); - - write_record_size (12); - write_record (sXY); - write_int (0); - write_int (0); - - context_prop_strings.clear (); - - if (layout.get_context_info (*cell, context_prop_strings)) { - - // Hint: write in the reverse order since this way, the reader is more efficient (it knows how many strings - // will arrive) - for (std::vector ::const_iterator s = context_prop_strings.end (); s != context_prop_strings.begin (); ) { - - --s; - - write_record_size (6); - write_record (sPROPATTR); - write_short (short (std::distance (std::vector ::const_iterator (context_prop_strings.begin ()), s))); // = user string - - write_string_record (sPROPVALUE, *s); - - } - - } - - write_record_size (4); - write_record (sENDEL); - - } - - } - - write_record_size (4); - write_record (sENDSTR); - + if (has_context) { + write_context_cell (layout, time_data, cells); } // body diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.h b/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.h index 52ef2b7ee..94a4a81d5 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.h +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.h @@ -168,6 +168,7 @@ private: db::WriterCellNameMap m_cell_name_map; void write_properties (const db::Layout &layout, db::properties_id_type prop_id); + void write_context_cell (db::Layout &layout, const short *time_data, const std::vector &cells); }; } // namespace db