From eb3600d6200c59bed6db5c39d777a9f45c4ef964 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 2 Nov 2020 01:23:27 +0100 Subject: [PATCH 01/11] WIP: First implementation. Needs testing. --- src/db/db/dbCommonReader.cc | 273 ++++++++++++++++++ src/db/db/dbCommonReader.h | 130 ++++++++- src/db/db/dbLayout.h | 6 +- src/db/db/gsiDeclDbCommonStreamOptions.cc | 31 ++ .../db_plugin/contrib/dbGDS2TextReader.cc | 4 +- .../gds2/db_plugin/contrib/dbGDS2TextReader.h | 2 +- .../streamers/gds2/db_plugin/dbGDS2Reader.cc | 4 +- .../streamers/gds2/db_plugin/dbGDS2Reader.h | 2 +- .../gds2/db_plugin/dbGDS2ReaderBase.cc | 69 +---- .../gds2/db_plugin/dbGDS2ReaderBase.h | 17 +- .../oasis/db_plugin/dbOASISReader.cc | 203 +------------ .../streamers/oasis/db_plugin/dbOASISReader.h | 16 +- 12 files changed, 483 insertions(+), 274 deletions(-) diff --git a/src/db/db/dbCommonReader.cc b/src/db/db/dbCommonReader.cc index 9802aedb9..da13a0b6f 100644 --- a/src/db/db/dbCommonReader.cc +++ b/src/db/db/dbCommonReader.cc @@ -29,6 +29,279 @@ namespace db { +// --------------------------------------------------------------- +// Common reader implementation + +static const size_t null_id = std::numeric_limits::max (); + +CommonReader::CommonReader () + : m_cc_resolution (AddToCell) +{ + // .. nothing yet .. +} + +db::cell_index_type +CommonReader::make_cell (db::Layout &layout, const std::string &cn) +{ + tl_assert (! cn.empty ()); + + std::map >::iterator iname = m_name_map.find (cn); + if (iname != m_name_map.end ()) { + + db::Cell &cell = layout.cell (iname->second.second); + + if (! cell.is_ghost_cell ()) { + common_reader_error (tl::sprintf (tl::to_string (tr ("A cell with name %s already exists")), cn)); + } + + cell.set_ghost_cell (false); + return cell.cell_index (); + + } else { + + db::cell_index_type ci = layout.add_cell (); + + m_name_map [cn] = std::make_pair (null_id, ci); + return ci; + + } +} + +bool +CommonReader::has_cell (const std::string &cn) const +{ + return m_name_map.find (cn) != m_name_map.end (); +} + +std::pair +CommonReader::cell_by_name (const std::string &cn) const +{ + std::map >::const_iterator iname = m_name_map.find (cn); + if (iname != m_name_map.end ()) { + return std::make_pair (true, iname->second.second); + } else { + return std::make_pair (false, size_t (0)); + } +} + +db::cell_index_type +CommonReader::make_cell (db::Layout &layout, size_t id) +{ + tl_assert (id != null_id); + + std::map >::iterator iid = m_id_map.find (id); + if (iid != m_id_map.end ()) { + + db::Cell &cell = layout.cell (iid->second.second); + + if (! cell.is_ghost_cell ()) { + common_reader_error (tl::sprintf (tl::to_string (tr ("A cell with ID %ld already exists")), id)); + } + + cell.set_ghost_cell (false); + return cell.cell_index (); + + } else { + + db::cell_index_type ci = layout.add_cell (); + + m_id_map [id] = std::make_pair (std::string (), ci); + return ci; + + } +} + +bool +CommonReader::has_cell (size_t id) const +{ + return m_id_map.find (id) != m_id_map.end (); +} + +std::pair +CommonReader::cell_by_id (size_t id) const +{ + std::map >::const_iterator iid = m_id_map.find (id); + if (iid != m_id_map.end ()) { + return std::make_pair (true, iid->second.second); + } else { + return std::make_pair (false, size_t (0)); + } +} + +void +CommonReader::rename_cell (db::Layout &layout, size_t id, const std::string &cn) +{ + std::map >::iterator iid = m_id_map.find (id); + std::map >::iterator iname = m_name_map.find (cn); + + if (iid != m_id_map.end () && iname != m_name_map.end ()) { + + if (iid->second.first != cn) { + common_reader_error (tl::sprintf (tl::to_string (tr ("Cell named %s with ID %ld was already given name %s")), cn, id, iid->second.first)); + } + + if (iname->second.second != iid->second.second) { + + // Both cells already exist and are not identical: merge ID-declared cell into the name-declared one + layout.force_update (); + merge_cell (layout, iname->second.second, iid->second.second); + iid->second.second = iname->second.second; + + } + + } else if (iid != m_id_map.end ()) { + + m_name_map [cn] = std::make_pair (id, iid->second.second); + + } else if (iname != m_name_map.end ()) { + + m_id_map [id] = std::make_pair (cn, iname->second.second); + + } else { + + db::cell_index_type ci = layout.add_cell (); + + m_id_map [id] = std::make_pair (std::string (), ci); + m_name_map [cn] = std::make_pair (null_id, ci); + + } +} + +db::cell_index_type +CommonReader::cell_for_instance (db::Layout &layout, size_t id) +{ + tl_assert (id != null_id); + + std::map >::iterator iid = m_id_map.find (id); + if (iid != m_id_map.end ()) { + + return iid->second.second; + + } else { + + db::cell_index_type ci = layout.add_cell (); + layout.cell (ci).set_ghost_cell (true); + + m_id_map [id] = std::make_pair (std::string (), ci); + return ci; + + } +} + +db::cell_index_type +CommonReader::cell_for_instance (db::Layout &layout, const std::string &cn) +{ + tl_assert (! cn.empty ()); + + std::map >::iterator iname = m_name_map.find (cn); + if (iname != m_name_map.end ()) { + + return iname->second.second; + + } else { + + db::cell_index_type ci = layout.add_cell (); + layout.cell (ci).set_ghost_cell (true); + + m_name_map [cn] = std::make_pair (null_id, ci); + return ci; + + } +} + +void +CommonReader::merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const +{ + const db::Cell &src_cell = layout.cell (src_cell_index); + db::Cell &target_cell = layout.cell (target_cell_index); + + // copy over the instances + for (db::Cell::const_iterator i = src_cell.begin (); ! i.at_end (); ++i) { + target_cell.insert (*i); + } + + // copy over the shapes + for (unsigned int l = 0; l < layout.layers (); ++l) { + if (layout.is_valid_layer (l) && ! src_cell.shapes (l).empty ()) { + target_cell.shapes (l).insert (src_cell.shapes (l)); + } + } + + // replace all instances of the new cell with the original one + std::vector > parents; + for (db::Cell::parent_inst_iterator pi = src_cell.begin_parent_insts (); ! pi.at_end (); ++pi) { + parents.push_back (std::make_pair (pi->parent_cell_index (), pi->child_inst ())); + } + + for (std::vector >::const_iterator p = parents.begin (); p != parents.end (); ++p) { + db::CellInstArray ia = p->second.cell_inst (); + ia.object ().cell_index (target_cell.cell_index ()); + layout.cell (p->first).replace (p->second, ia); + } + + // finally delete the new cell + layout.delete_cell (src_cell.cell_index ()); +} + +void +CommonReader::finish (db::Layout &layout) +{ + bool any_missing = false; + + for (std::map >::const_iterator i = m_id_map.begin (); i != m_id_map.end (); ++i) { + if (i->second.first.empty ()) { + common_reader_warn (tl::sprintf (tl::to_string (tr ("Cell name missing for ID %ld")), i->first)); + any_missing = true; + } + } + + if (any_missing) { + common_reader_error (tl::to_string (tr ("Some cell IDs don't have a name (see previous warnings)"))); + } + + for (std::map >::const_iterator i = m_name_map.begin (); i != m_name_map.end (); ++i) { + + if (layout.has_cell (i->first.c_str ())) { + + db::cell_index_type ci_org = layout.cell_by_name (i->first.c_str ()).second; + db::cell_index_type ci_new = i->second.second; + + if (m_cc_resolution == RenameCell || layout.cell (ci_org).is_proxy ()) { + + // NOTE: we never reopen proxies (they are always local to their layout). Instead we + // always rename for proxies + layout.rename_cell (i->second.second, i->first.c_str ()); + + } else { + + // we have a cell conflict + layout.force_update (); + + if (m_cc_resolution == OverwriteCell && ! layout.cell (ci_new).is_ghost_cell ()) { + + layout.prune_subcells (ci_org); + layout.cell (ci_org).clear_shapes (); + + } else if (m_cc_resolution == SkipNewCell && ! layout.cell (ci_org).is_ghost_cell ()) { + + layout.prune_subcells (ci_new); + layout.cell (ci_new).clear_shapes (); + + } + + merge_cell (layout, ci_org, ci_new); + + } + + } else { + + layout.rename_cell (i->second.second, i->first.c_str ()); + + } + + } +} + // --------------------------------------------------------------- // Common format declaration diff --git a/src/db/db/dbCommonReader.h b/src/db/db/dbCommonReader.h index 45c09861d..8bdf8ffb6 100644 --- a/src/db/db/dbCommonReader.h +++ b/src/db/db/dbCommonReader.h @@ -31,6 +31,117 @@ namespace db { +/** + * @brief A common reader base for GDS2 and OASIS providing common services for both readers + */ +class DB_PUBLIC CommonReader + : public ReaderBase +{ +public: + /** + * @brief The CellConflictResolution enum + */ + enum CellConflictResolution + { + AddToCell = 0, + OverwriteCell = 1, + SkipNewCell = 2, + RenameCell = 3 + }; + + /** + * @brief Constructor + */ + CommonReader (); + + /** + * @brief Sets the cell name conflict resolution mode + */ + void set_cell_conflict_resolution (CellConflictResolution cc_resolution) + { + m_cc_resolution = cc_resolution; + } + + /** + * @brief Sets the cell name conflict resolution mode + */ + CellConflictResolution cell_conflict_resolution () const + { + return m_cc_resolution; + } + + /** + * @brief Make a cell from a name + */ + db::cell_index_type make_cell (db::Layout &layout, const std::string &cn); + + /** + * @brief Returns true, if there is a cell with the given name already + */ + bool has_cell (const std::string &cn) const; + + /** + * @brief Returns a pair with a bool (indicating whether the cell name is known) and the cell index for this name + */ + std::pair cell_by_name (const std::string &name) const; + + /** + * @brief Make a cell from an ID (OASIS) + */ + db::cell_index_type make_cell (db::Layout &layout, size_t id); + + /** + * @brief Returns true, if there is a cell with the given ID alreay + */ + bool has_cell (size_t id) const; + + /** + * @brief Returns a pair with a bool (indicating whether the cell ID is known) and the cell index for this ID + */ + std::pair cell_by_id (size_t id) const; + + /** + * @brief Registers a cell name for an ID + */ + void rename_cell (db::Layout &layout, size_t id, const std::string &cn); + + /** + * @brief Returns a cell reference by ID + * If the cell does not exist, it's created. It is marked as ghost cell until + * "make_cell" is called. + */ + db::cell_index_type cell_for_instance (db::Layout &layout, size_t id); + + /** + * @brief Returns a cell reference by name + * Same as the previous method, but acting on cell names. + */ + db::cell_index_type cell_for_instance (db::Layout &layout, const std::string &cn); + + /** + * @brief Finishes the reading process + * + * This method will first check if all cells IDs got a name. + * After this, the cells are renamed and cell conflict resolution will happen in the + * specified way (cell_conflict_resolution attribute). + */ + void finish (db::Layout &layout); + +protected: + virtual void common_reader_error (const std::string &msg) = 0; + virtual void common_reader_warn (const std::string &msg) = 0; + + /** + * @brief Merge (and delete) the src_cell into target_cell + */ + void merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const; + +private: + std::map > m_id_map; + std::map > m_name_map; + CellConflictResolution m_cc_resolution; +}; + /** * @brief Structure that holds the GDS2 and OASIS specific options for the reader */ @@ -44,7 +155,8 @@ public: CommonReaderOptions () : create_other_layers (true), enable_text_objects (true), - enable_properties (true) + enable_properties (true), + cell_conflict_resolution (CommonReader::AddToCell) { // .. nothing yet .. } @@ -83,6 +195,22 @@ public: */ bool enable_properties; + /** + * @brief Specifies the cell merge behavior + * + * This enum controls how cells are read if a cell with the requested name already + * exists. + * + * AddToCell In this mode, instances or shapes are added to any existing cell + * OverwriteCell Overwrite existing cell. If the existing cell has children, those are removed unless used otherwise + * SkipNewCell Ignore the new cell and it's children + * RenameCell Rename the new cell + * + * If the existing opr the new cell is a ghost cell, AddToCell is applied always. In other words, + * ghost cells are always merged. + */ + CommonReader::CellConflictResolution cell_conflict_resolution; + /** * @brief Implementation of FormatSpecificReaderOptions */ diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index 827dee2b3..b1184fa26 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -1065,8 +1065,7 @@ public: * @brief Delete the subcells of the given cells which are not used otherwise * * All subcells referenced directy or indirectly but not used otherwise - * are deleted as well. This basically prunes the cell tree by this cell. - * All instances of this cell are deleted as well. + * are deleted as well. * This method is more efficent than calling prune_subcells for single cells multiple times. * * @param from A begin iterator delivering the cell id's to delete @@ -1085,8 +1084,7 @@ public: * @brief Delete the subcells of the given cells which are not used otherwise * * All subcells referenced directy or indirectly but not used otherwise - * are deleted as well. This basically prunes the cell tree by this cell. - * All instances of this cell are deleted as well. + * are deleted as well. * This method is more efficent than calling prune_subcells for single cells multiple times. * * @param cells A set of cell id's to prune diff --git a/src/db/db/gsiDeclDbCommonStreamOptions.cc b/src/db/db/gsiDeclDbCommonStreamOptions.cc index ac2fb3223..a208b8962 100644 --- a/src/db/db/gsiDeclDbCommonStreamOptions.cc +++ b/src/db/db/gsiDeclDbCommonStreamOptions.cc @@ -25,6 +25,7 @@ #include "dbCommonReader.h" #include "dbLoadLayoutOptions.h" #include "gsiDecl.h" +#include "gsiEnums.h" namespace dn { @@ -160,6 +161,36 @@ gsi::ClassExt common_reader_options ( "" ); + +gsi::EnumIn decl_dbCommonReader_CellConflictResolution ("db", "CellConflictResolution", + gsi::enum_const ("AddToCell", db::CommonReader::AddToCell, + "@brief Add content to existing cell\n" + "This is the mode use in before version 0.27. Content of new cells is simply added to existing cells with the same name." + ) + + gsi::enum_const ("OverwriteCell", db::CommonReader::OverwriteCell, + "@brief The old cell is overwritten entirely (including child cells which are not used otherwise)\n" + ) + + gsi::enum_const ("SkipNewCell", db::CommonReader::SkipNewCell, + "@brief The new cell is skipped entirely (including child cells which are not used otherwise)\n" + ) + + gsi::enum_const ("RenameCell", db::CommonReader::RenameCell, + "@brief The new cell will be renamed to become unique\n" + ), + "@brief This enum specifies how cell conflicts are handled if a layout read into another layout and a cell name conflict arises. " + "Until version 0.26.8 and before, the mode was always 'AddToCell'. On reading, a cell was 'reopened' when encountering a cell name " + "which already existed. This mode is still the default. The other modes are made available to support other ways of merging layouts.\n" + "\n" + "Proxy cells are never modified in the existing layout. Proxy cells are always local to their layout file. So if the existing cell is " + "a proxy cell, the new cell will be renamed.\n" + "\n" + "If the new or existing cell is a ghost cell, both cells are merged always.\n" + "\n" + "This enum was introduced in version 0.27.\n" +); + +// Inject the NetlistCrossReference::Status declarations into NetlistCrossReference: +gsi::ClassExt inject_CellConflictResolution_in_parent (decl_dbCommonReader_CellConflictResolution.defs ()); + } diff --git a/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.cc b/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.cc index 028d801a9..ee363ed67 100644 --- a/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.cc +++ b/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.cc @@ -61,7 +61,7 @@ GDS2ReaderText::read (db::Layout &layout, const db::LoadLayoutOptions &options) db::GDS2ReaderOptions gds2_options = options.get_options (); db::CommonReaderOptions common_options = options.get_options (); - return basic_read (layout, common_options.layer_map, common_options.create_other_layers, common_options.enable_text_objects, common_options.enable_properties, false, gds2_options.box_mode); + return basic_read (layout, common_options.layer_map, common_options.create_other_layers, common_options.enable_text_objects, common_options.enable_properties, false, gds2_options.box_mode, common_options.cell_conflict_resolution); } const LayerMap & @@ -259,7 +259,7 @@ GDS2ReaderText::get_double () } void -GDS2ReaderText::get_string (tl::string &s) const +GDS2ReaderText::get_string (std::string &s) const { // TODO: get rid of this const_cast hack s = (const_cast (this))->reader.skip (); diff --git a/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.h b/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.h index 4b394d13b..56de72863 100644 --- a/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.h +++ b/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.h @@ -112,7 +112,7 @@ private: virtual std::string path () const; const char *get_string (); - void get_string (tl::string &s) const; + void get_string (std::string &s) const; int get_int (); short get_short (); unsigned short get_ushort (); diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.cc b/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.cc index f0fc9ac22..772da9429 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.cc +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.cc @@ -64,7 +64,7 @@ GDS2Reader::read (db::Layout &layout, const db::LoadLayoutOptions &options) --m_recnum; m_reclen = 0; - return basic_read (layout, m_common_options.layer_map, m_common_options.create_other_layers, m_common_options.enable_text_objects, m_common_options.enable_properties, m_options.allow_multi_xy_records, m_options.box_mode); + return basic_read (layout, m_common_options.layer_map, m_common_options.create_other_layers, m_common_options.enable_text_objects, m_common_options.enable_properties, m_options.allow_multi_xy_records, m_options.box_mode, m_common_options.cell_conflict_resolution); } const LayerMap & @@ -210,7 +210,7 @@ GDS2Reader::get_string () } void -GDS2Reader::get_string (tl::string &s) const +GDS2Reader::get_string (std::string &s) const { s.assign ((const char *) mp_rec_buf, 0, m_reclen); } diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.h b/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.h index e5bbb4aa3..2b51144dd 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.h +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.h @@ -126,7 +126,7 @@ private: virtual std::string path () const; virtual const char *get_string (); - virtual void get_string (tl::string &s) const; + virtual void get_string (std::string &s) const; virtual int get_int (); virtual short get_short (); virtual unsigned short get_ushort (); diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc index 1541960e0..d79793638 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc @@ -84,7 +84,7 @@ GDS2ReaderBase::~GDS2ReaderBase () } const LayerMap & -GDS2ReaderBase::basic_read (db::Layout &layout, const LayerMap &layer_map, bool create_other_layers, bool enable_text_objects, bool enable_properties, bool allow_multi_xy_records, unsigned int box_mode) +GDS2ReaderBase::basic_read (db::Layout &layout, const LayerMap &layer_map, bool create_other_layers, bool enable_text_objects, bool enable_properties, bool allow_multi_xy_records, unsigned int box_mode, db::CommonReader::CellConflictResolution cc_resolution) { m_layer_map = layer_map; m_layer_map.prepare (layout); @@ -95,9 +95,17 @@ GDS2ReaderBase::basic_read (db::Layout &layout, const LayerMap &layer_map, bool m_box_mode = box_mode; m_create_layers = create_other_layers; + set_cell_conflict_resolution (cc_resolution); + layout.start_changes (); - do_read (layout); - layout.end_changes (); + try { + do_read (layout); + finish (layout); + layout.end_changes (); + } catch (...) { + layout.end_changes (); + throw; + } return m_layer_map; } @@ -235,7 +243,6 @@ GDS2ReaderBase::do_read (db::Layout &layout) { m_cellname = ""; m_libname = ""; - m_mapped_cellnames.clear (); // read header if (get_record () != sHEADER) { @@ -349,7 +356,7 @@ GDS2ReaderBase::do_read (db::Layout &layout) } else { - db::cell_index_type cell_index = make_cell (layout, m_cellname.c_str (), false); + db::cell_index_type cell_index = make_cell (layout, m_cellname); db::Cell *cell = &layout.cell (cell_index); @@ -359,8 +366,6 @@ GDS2ReaderBase::do_read (db::Layout &layout) 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; - // marks the cell for begin addressed by REF's despite being a proxy: - m_mapped_cellnames.insert (std::make_pair (m_cellname, m_cellname)); } } @@ -973,54 +978,6 @@ GDS2ReaderBase::read_box (db::Layout &layout, db::Cell &cell) } } -db::cell_index_type -GDS2ReaderBase::make_cell (db::Layout &layout, const char *cn, bool for_instance) -{ - db::cell_index_type ci = 0; - - // map to the real name which maybe a different one due to localization - // of proxy cells (they are not to be reopened) - bool is_mapped = false; - if (! m_mapped_cellnames.empty ()) { - std::map::const_iterator n = m_mapped_cellnames.find (cn); - if (n != m_mapped_cellnames.end ()) { - cn = n->second.c_str (); - is_mapped = true; - } - } - - std::pair c = layout.cell_by_name (cn); - if (c.first && (is_mapped || ! layout.cell (c.second).is_proxy ())) { - - // cell already there: just add instance (cell might have been created through forward reference) - // NOTE: we don't address "reopened" proxies as proxies are always local to a layout - - ci = c.second; - - // mark the cell as read - if (! for_instance) { - layout.cell (ci).set_ghost_cell (false); - } - - } else { - - ci = layout.add_cell (cn); - - if (for_instance) { - // mark this cell a "ghost cell" until it's actually read - layout.cell (ci).set_ghost_cell (true); - } - - if (c.first) { - // this cell has been given a new name: remember this name for localization - m_mapped_cellnames.insert (std::make_pair (cn, layout.cell_name (ci))); - } - - } - - return ci; -} - void GDS2ReaderBase::read_ref (db::Layout &layout, db::Cell & /*cell*/, bool array, tl::vector &instances, tl::vector &instances_with_props) { @@ -1033,7 +990,7 @@ GDS2ReaderBase::read_ref (db::Layout &layout, db::Cell & /*cell*/, bool array, t error (tl::to_string (tr ("SNAME record expected"))); } - db::cell_index_type ci = make_cell (layout, get_string (), true); + db::cell_index_type ci = cell_for_instance (layout, get_string ()); bool mirror = false; int angle = 0; diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.h b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.h index 829ccea71..a094da9fb 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.h +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.h @@ -29,6 +29,7 @@ #include "dbLayout.h" #include "dbReader.h" #include "dbStreamLayers.h" +#include "dbCommonReader.h" #include "tlException.h" #include "tlInternational.h" @@ -49,7 +50,7 @@ struct GDS2XY * @brief The GDS2 format basic stream reader */ class DB_PLUGIN_PUBLIC GDS2ReaderBase - : public ReaderBase + : public CommonReader { public: /** @@ -86,20 +87,21 @@ protected: * @param enable_properties A flag indicating whether to read user properties * @param allow_multi_xy_records If true, tries to check for multiple XY records for BOUNDARY elements * @param box_mode How to treat BOX records (0: ignore, 1: as rectangles, 2: as boundaries, 3: error) + * @param cc_resolution The cell name conflict resolution mode * @return The LayerMap object that tells where which layer was loaded */ - const LayerMap &basic_read (db::Layout &layout, const LayerMap &layer_map, bool create_other_layers, bool enable_text_objects, bool enable_properties, bool allow_multi_xy_records, unsigned int box_mode); + const LayerMap &basic_read (db::Layout &layout, const LayerMap &layer_map, bool create_other_layers, bool enable_text_objects, bool enable_properties, bool allow_multi_xy_records, unsigned int box_mode, db::CommonReader::CellConflictResolution cc_resolution); /** * @brief Accessor method to the current cellname */ - const tl::string &cellname () const { return m_cellname; } + const std::string &cellname () const { return m_cellname; } private: friend class GDS2ReaderLayerMapping; LayerMap m_layer_map; - tl::string m_cellname; + std::string m_cellname; std::string m_libname; double m_dbu, m_dbuu; bool m_create_layers; @@ -109,7 +111,6 @@ private: unsigned int m_box_mode; std::map > m_context_info; std::vector m_all_points; - std::map m_mapped_cellnames; void read_context_info_cell (); void read_boundary (db::Layout &layout, db::Cell &cell, bool from_box_record); @@ -117,7 +118,6 @@ private: void read_text (db::Layout &layout, db::Cell &cell); void read_box (db::Layout &layout, db::Cell &cell); void read_ref (db::Layout &layout, db::Cell &cell, bool array, tl::vector &instances, tl::vector &insts_wp); - db::cell_index_type make_cell (db::Layout &layout, const char *cn, bool for_instance); void do_read (db::Layout &layout); @@ -125,12 +125,15 @@ private: std::pair finish_element (db::PropertiesRepository &rep); void finish_element (); + virtual void common_reader_error (const std::string &msg) { error (msg); } + virtual void common_reader_warn (const std::string &msg) { warn (msg); } + virtual void error (const std::string &txt) = 0; virtual void warn (const std::string &txt) = 0; virtual std::string path () const = 0; virtual const char *get_string () = 0; - virtual void get_string (tl::string &s) const = 0; + virtual void get_string (std::string &s) const = 0; virtual int get_int () = 0; virtual short get_short () = 0; virtual unsigned short get_ushort () = 0; diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc index d7b4fd67d..c6d229870 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc @@ -144,9 +144,12 @@ OASISReader::read (db::Layout &layout, const db::LoadLayoutOptions &options) m_read_all_properties = oasis_options.read_all_properties; m_expect_strict_mode = oasis_options.expect_strict_mode; + set_cell_conflict_resolution (common_options.cell_conflict_resolution); + layout.start_changes (); try { do_read (layout); + finish (layout); layout.end_changes (); } catch (...) { layout.end_changes (); @@ -758,17 +761,11 @@ OASISReader::do_read (db::Layout &layout) id_mode propstring_id_mode = any; id_mode propname_id_mode = any; - m_cellnames.clear (); m_cellname_properties.clear (); m_textstrings.clear (); m_propstrings.clear (); m_propnames.clear (); m_layernames.clear (); - m_cells_by_id.clear (); - m_cells_by_name.clear (); - m_defined_cells_by_id.clear (); - m_defined_cells_by_name.clear (); - m_mapped_cellnames.clear (); m_instances.clear (); m_instances_with_props.clear (); @@ -826,9 +823,7 @@ OASISReader::do_read (db::Layout &layout) get (id); } - if (! m_cellnames.insert (std::make_pair (id, name)).second) { - error (tl::sprintf (tl::to_string (tr ("A CELLNAME with id %ld is present already")), id)); - } + rename_cell (layout, id, name); reset_modal_variables (); @@ -1150,37 +1145,11 @@ OASISReader::do_read (db::Layout &layout) unsigned long id = 0; get (id); - if (! m_defined_cells_by_id.insert (id).second) { + if (has_cell (id)) { error (tl::sprintf (tl::to_string (tr ("A cell with id %ld is defined already")), id)); } - std::map ::const_iterator c = m_cells_by_id.find (id); - if (c != m_cells_by_id.end ()) { - - cell_index = c->second; - layout.cell (cell_index).set_ghost_cell (false); - - } else { - - std::map ::const_iterator name = m_cellnames.find (id); - if (name == m_cellnames.end ()) { - - cell_index = layout.add_cell (); - // force a cell rename to empty to avoid name clashes of the generated - // $x names with the same inside the OASIS file. - layout.rename_cell (cell_index, ""); - m_forward_references.insert (std::make_pair (id, cell_index)); - - } else { - - cell_index = make_cell (layout, name->second.c_str (), false); - m_cells_by_name.insert (std::make_pair (name->second, cell_index)); - - } - - m_cells_by_id.insert (std::make_pair (id, cell_index)); - - } + cell_index = make_cell (layout, id); } else { @@ -1189,22 +1158,11 @@ OASISReader::do_read (db::Layout &layout) } std::string name = get_str (); - if (! m_defined_cells_by_name.insert (name).second) { + if (has_cell (name)) { error (tl::sprintf (tl::to_string (tr ("A cell with name %s is defined already")), name.c_str ())); } - std::map ::const_iterator c = m_cells_by_name.find (name); - if (c != m_cells_by_name.end ()) { - - cell_index = c->second; - layout.cell (cell_index).set_ghost_cell (false); - - } else { - - cell_index = make_cell (layout, name.c_str (), false); - m_cells_by_name.insert (std::make_pair (name, cell_index)); - - } + cell_index = make_cell (layout, name); } @@ -1326,72 +1284,16 @@ OASISReader::do_read (db::Layout &layout) } - for (std::map ::const_iterator fw = m_forward_references.begin (); fw != m_forward_references.end (); ++fw) { - - std::map ::const_iterator cn = m_cellnames.find (fw->first); - if (cn == m_cellnames.end ()) { - - error (tl::sprintf (tl::to_string (tr ("No cellname defined for cell name id %ld")), fw->first)); - - } else { - - std::pair c = layout.cell_by_name (cn->second.c_str ()); - if (c.first) { - - // needed, since we have disabled updates - layout.force_update (); - - // add-on reading of forward-referenced cell: need to copy the new cell to the original one plus - // change instances of the new cell and delete the new cell then. - - const db::Cell &new_cell = layout.cell (fw->second); - db::Cell &org_cell = layout.cell (c.second); - - // copy over the instances - for (db::Cell::const_iterator i = new_cell.begin (); ! i.at_end (); ++i) { - org_cell.insert (*i); - } - - // copy over the shapes - for (unsigned int l = 0; l < layout.layers (); ++l) { - if (layout.is_valid_layer (l) && ! new_cell.shapes (l).empty ()) { - org_cell.shapes (l).insert (new_cell.shapes (l)); - } - } - - // replace all instances of the new cell with the original one - std::vector > parents; - for (db::Cell::parent_inst_iterator pi = new_cell.begin_parent_insts (); ! pi.at_end (); ++pi) { - parents.push_back (std::make_pair (pi->parent_cell_index (), pi->child_inst ())); - } - - for (std::vector >::const_iterator p = parents.begin (); p != parents.end (); ++p) { - db::CellInstArray ia = p->second.cell_inst (); - ia.object ().cell_index (org_cell.cell_index ()); - layout.cell (p->first).replace (p->second, ia); - } - - // finally delete the new cell - layout.delete_cell (new_cell.cell_index ()); - - } else { - layout.rename_cell (fw->second, cn->second.c_str ()); - } - - } - - } - // attach the properties found in CELLNAME to the cells (which may have other properties) for (std::map::const_iterator p = m_cellname_properties.begin (); p != m_cellname_properties.end (); ++p) { - std::map ::const_iterator c = m_cells_by_id.find (p->first); - if (c != m_cells_by_id.end ()) { + std::pair c = cell_by_id (p->first); + if (c.first) { db::PropertiesRepository::properties_set cnp = layout.properties_repository ().properties (p->second); // Merge existing properties with the ones from CELLNAME - db::Cell &cell = layout.cell (c->second); + db::Cell &cell = layout.cell (c.second); if (cell.prop_id () != 0) { db::PropertiesRepository::properties_set cp = layout.properties_repository ().properties (cell.prop_id ()); cnp.insert (cp.begin (), cp.end ()); @@ -1844,54 +1746,6 @@ OASISReader::read_repetition () return mm_repetition.get ().size () > 1; } -db::cell_index_type -OASISReader::make_cell (db::Layout &layout, const char *cn, bool for_instance) -{ - db::cell_index_type ci = 0; - - // map to the real name which maybe a different one due to localization - // of proxy cells (they are not to be reopened) - bool is_mapped = false; - if (! m_mapped_cellnames.empty ()) { - std::map::const_iterator n = m_mapped_cellnames.find (cn); - if (n != m_mapped_cellnames.end ()) { - cn = n->second.c_str (); - is_mapped = true; - } - } - - std::pair c = layout.cell_by_name (cn); - if (c.first && (is_mapped || ! layout.cell (c.second).is_proxy ())) { - - // cell already there: just add instance (cell might have been created through forward reference) - // NOTE: we don't address "reopened" proxies as proxies are always local to a layout - - ci = c.second; - - // mark the cell as read - if (! for_instance) { - layout.cell (ci).set_ghost_cell (false); - } - - } else { - - ci = layout.add_cell (cn); - - if (for_instance) { - // mark this cell a "ghost cell" until it's actually read - layout.cell (ci).set_ghost_cell (true); - } - - if (c.first) { - // this cell has been given a new name: remember this name for localization - m_mapped_cellnames.insert (std::make_pair (cn, layout.cell_name (ci))); - } - - } - - return ci; -} - void OASISReader::do_read_placement (unsigned char r, bool xy_absolute, @@ -1909,31 +1763,8 @@ OASISReader::do_read_placement (unsigned char r, // cell by id unsigned long id; get (id); - std::map ::const_iterator cid = m_cells_by_id.find (id); - if (cid == m_cells_by_id.end ()) { - // create the cell - std::map ::const_iterator name = m_cellnames.find (id); - if (name == m_cellnames.end ()) { - - mm_placement_cell = layout.add_cell (); - m_forward_references.insert (std::make_pair (id, mm_placement_cell.get ())); - - // temporarily mark as "ghost cell" - layout.cell (mm_placement_cell.get ()).set_ghost_cell (true); - - } else { - - mm_placement_cell = make_cell (layout, name->second.c_str (), true); - m_cells_by_name.insert (std::make_pair (name->second, mm_placement_cell.get ())); - - } - - m_cells_by_id.insert (std::make_pair (id, mm_placement_cell.get ())); - - } else { - mm_placement_cell = cid->second; - } + mm_placement_cell = cell_for_instance (layout, id); } else { @@ -1941,15 +1772,7 @@ OASISReader::do_read_placement (unsigned char r, std::string name; get_str (name); - std::map ::const_iterator cid = m_cells_by_name.find (name); - if (cid == m_cells_by_name.end ()) { - - mm_placement_cell = make_cell (layout, name.c_str (), true); - m_cells_by_name.insert (std::make_pair (name, mm_placement_cell.get ())); - - } else { - mm_placement_cell = cid->second; - } + mm_placement_cell = cell_for_instance (layout, name); } diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.h b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.h index 63315e78a..a8a56e173 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.h +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.h @@ -33,6 +33,7 @@ #include "dbOASISFormat.h" #include "dbStreamLayers.h" #include "dbPropertiesRepository.h" +#include "dbCommonReader.h" #include "tlException.h" #include "tlInternational.h" @@ -62,7 +63,7 @@ public: * @brief The OASIS format stream reader */ class DB_PLUGIN_PUBLIC OASISReader - : public ReaderBase, + : public CommonReader, public OASISDiagnostics { public: @@ -118,6 +119,7 @@ public: */ virtual const char *format () const { return "OASIS"; } +protected: /** * @brief Issue an error with positional information * @@ -132,6 +134,9 @@ public: */ virtual void warn (const std::string &txt); + virtual void common_reader_error (const std::string &msg) { error (msg); } + virtual void common_reader_warn (const std::string &msg) { warn (msg); } + private: friend class OASISReaderLayerMapping; @@ -194,7 +199,6 @@ private: modal_variable mm_last_property_is_sprop; modal_variable mm_last_value_list; - std::map m_cellnames; std::map m_cellname_properties; std::map m_textstrings; std::map m_text_forward_references; @@ -205,18 +209,11 @@ private: tl::vector m_instances; tl::vector m_instances_with_props; - std::map m_cells_by_id; - std::map m_forward_references; - std::map m_cells_by_name; bool m_create_layers; bool m_read_texts; bool m_read_properties; bool m_read_all_properties; - std::set m_defined_cells_by_id; - std::set m_defined_cells_by_name; - std::map m_mapped_cellnames; - std::map m_propname_forward_references; std::map m_propvalue_forward_references; db::property_names_id_type m_s_gds_property_name_id; @@ -238,7 +235,6 @@ private: void do_read_trapezoid (unsigned char r, bool xy_absolute,db::cell_index_type cell_index, db::Layout &layout); void do_read_ctrapezoid (bool xy_absolute,db::cell_index_type cell_index, db::Layout &layout); void do_read_circle (bool xy_absolute,db::cell_index_type cell_index, db::Layout &layout); - db::cell_index_type make_cell (db::Layout &layout, const char *cn, bool for_instance); void reset_modal_variables (); From 85869c329d0b4abf2f744df3bf3f583aa3e7bc8e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 3 Nov 2020 00:13:28 +0100 Subject: [PATCH 02/11] BUGFIX: db::Shapes::insert(db::Shapes) wasn't working correctly! --- src/db/db/dbShapes.cc | 12 +++++++++--- src/db/db/dbShapes.h | 1 + src/db/db/dbShapes2.cc | 8 ++++++++ src/db/db/dbShapes2.h | 1 + 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/db/db/dbShapes.cc b/src/db/db/dbShapes.cc index aef79fa21..dedd81cb2 100644 --- a/src/db/db/dbShapes.cc +++ b/src/db/db/dbShapes.cc @@ -174,9 +174,15 @@ Shapes::do_insert (const Shapes &d) if (layout () == d.layout ()) { // both shape containers reside in the same repository space - simply copy - m_layers.reserve (d.m_layers.size ()); - for (tl::vector::const_iterator l = d.m_layers.begin (); l != d.m_layers.end (); ++l) { - m_layers.push_back ((*l)->clone (this, manager ())); + if (m_layers.empty ()) { + m_layers.reserve (d.m_layers.size ()); + for (tl::vector::const_iterator l = d.m_layers.begin (); l != d.m_layers.end (); ++l) { + m_layers.push_back ((*l)->clone (this, manager ())); + } + } else { + for (tl::vector::const_iterator l = d.m_layers.begin (); l != d.m_layers.end (); ++l) { + (*l)->insert_into (this); + } } } else if (layout () == 0) { diff --git a/src/db/db/dbShapes.h b/src/db/db/dbShapes.h index 1942906a0..6f7dcbb20 100644 --- a/src/db/db/dbShapes.h +++ b/src/db/db/dbShapes.h @@ -493,6 +493,7 @@ public: virtual void transform_into (Shapes *target, const Trans &trans, GenericRepository &rep, ArrayRepository &array_rep, pm_delegate_type &pm) const = 0; virtual void transform_into (Shapes *target, const ICplxTrans &trans, GenericRepository &rep, ArrayRepository &array_rep) const = 0; virtual void transform_into (Shapes *target, const ICplxTrans &trans, GenericRepository &rep, ArrayRepository &array_rep, pm_delegate_type &pm) const = 0; + virtual void insert_into (Shapes *target) = 0; virtual void deref_into (Shapes *target) = 0; virtual void deref_into (Shapes *target, pm_delegate_type &pm) = 0; virtual void deref_and_transform_into (Shapes *target, const Trans &trans) = 0; diff --git a/src/db/db/dbShapes2.cc b/src/db/db/dbShapes2.cc index 73fd33aad..19396588e 100644 --- a/src/db/db/dbShapes2.cc +++ b/src/db/db/dbShapes2.cc @@ -834,6 +834,13 @@ layer_class::transform_into (Shapes *target, const ICplxTrans &tr } } +template +void +layer_class::insert_into (Shapes *target) +{ + target->insert (m_layer.begin (), m_layer.end ()); +} + template void layer_class::deref_into (Shapes *target) @@ -870,6 +877,7 @@ layer_class::deref_and_transform_into (Shapes *target, const Tran { deref_and_transform_into_shapes deref_op (target); for (typename layer_type::iterator s = m_layer.begin (); s != m_layer.end (); ++s) { + deref_op (*s, trans, pm); } } diff --git a/src/db/db/dbShapes2.h b/src/db/db/dbShapes2.h index d60678e28..7c7d3ba60 100644 --- a/src/db/db/dbShapes2.h +++ b/src/db/db/dbShapes2.h @@ -149,6 +149,7 @@ public: virtual void transform_into (Shapes *target, const Trans &trans, GenericRepository &rep, ArrayRepository &array_rep, pm_delegate_type &pm) const; virtual void transform_into (Shapes *target, const ICplxTrans &trans, GenericRepository &rep, ArrayRepository &array_rep) const; virtual void transform_into (Shapes *target, const ICplxTrans &trans, GenericRepository &rep, ArrayRepository &array_rep, pm_delegate_type &pm) const; + virtual void insert_into (Shapes *target); virtual void deref_into (Shapes *target); virtual void deref_into (Shapes *target, pm_delegate_type &pm); virtual void deref_and_transform_into (Shapes *target, const Trans &trans); From a92ebd0e17909af5f862250b63b79bf7c66cd151 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 3 Nov 2020 00:13:55 +0100 Subject: [PATCH 03/11] WIP: cell name conflict resolution modes, bugfixed first implementation --- src/db/db/dbCommonReader.cc | 106 +++++++++++++----- src/db/db/dbLayout.cc | 35 +++++- src/db/db/dbLayout.h | 12 +- src/db/db/gsiDeclDbCommonStreamOptions.cc | 26 +++++ .../streamers/gds2/unit_tests/dbGDS2Reader.cc | 2 + .../oasis/db_plugin/dbOASISReader.cc | 8 +- 6 files changed, 153 insertions(+), 36 deletions(-) diff --git a/src/db/db/dbCommonReader.cc b/src/db/db/dbCommonReader.cc index da13a0b6f..8028653eb 100644 --- a/src/db/db/dbCommonReader.cc +++ b/src/db/db/dbCommonReader.cc @@ -59,7 +59,7 @@ CommonReader::make_cell (db::Layout &layout, const std::string &cn) } else { - db::cell_index_type ci = layout.add_cell (); + db::cell_index_type ci = layout.add_anonymous_cell (); m_name_map [cn] = std::make_pair (null_id, ci); return ci; @@ -103,7 +103,7 @@ CommonReader::make_cell (db::Layout &layout, size_t id) } else { - db::cell_index_type ci = layout.add_cell (); + db::cell_index_type ci = layout.add_anonymous_cell (); m_id_map [id] = std::make_pair (std::string (), ci); return ci; @@ -136,7 +136,7 @@ CommonReader::rename_cell (db::Layout &layout, size_t id, const std::string &cn) if (iid != m_id_map.end () && iname != m_name_map.end ()) { - if (iid->second.first != cn) { + if (! iid->second.first.empty () && iid->second.first != cn) { common_reader_error (tl::sprintf (tl::to_string (tr ("Cell named %s with ID %ld was already given name %s")), cn, id, iid->second.first)); } @@ -149,20 +149,26 @@ CommonReader::rename_cell (db::Layout &layout, size_t id, const std::string &cn) } + iid->second.first = cn; + iname->second.first = id; + } else if (iid != m_id_map.end ()) { m_name_map [cn] = std::make_pair (id, iid->second.second); + iid->second.first = cn; } else if (iname != m_name_map.end ()) { m_id_map [id] = std::make_pair (cn, iname->second.second); + iname->second.first = id; } else { - db::cell_index_type ci = layout.add_cell (); + db::cell_index_type ci = layout.add_anonymous_cell (); + layout.cell (ci).set_ghost_cell (true); - m_id_map [id] = std::make_pair (std::string (), ci); - m_name_map [cn] = std::make_pair (null_id, ci); + m_id_map [id] = std::make_pair (cn, ci); + m_name_map [cn] = std::make_pair (id, ci); } } @@ -179,7 +185,7 @@ CommonReader::cell_for_instance (db::Layout &layout, size_t id) } else { - db::cell_index_type ci = layout.add_cell (); + db::cell_index_type ci = layout.add_anonymous_cell (); layout.cell (ci).set_ghost_cell (true); m_id_map [id] = std::make_pair (std::string (), ci); @@ -200,7 +206,7 @@ CommonReader::cell_for_instance (db::Layout &layout, const std::string &cn) } else { - db::cell_index_type ci = layout.add_cell (); + db::cell_index_type ci = layout.add_anonymous_cell (); layout.cell (ci).set_ghost_cell (true); m_name_map [cn] = std::make_pair (null_id, ci); @@ -259,44 +265,84 @@ CommonReader::finish (db::Layout &layout) common_reader_error (tl::to_string (tr ("Some cell IDs don't have a name (see previous warnings)"))); } - for (std::map >::const_iterator i = m_name_map.begin (); i != m_name_map.end (); ++i) { + // check if we need to resolve conflicts - if (layout.has_cell (i->first.c_str ())) { + bool has_conflict = false; + for (std::map >::const_iterator i = m_name_map.begin (); i != m_name_map.end () && ! has_conflict; ++i) { + has_conflict = layout.cell_by_name (i->first.c_str ()).first; + } - db::cell_index_type ci_org = layout.cell_by_name (i->first.c_str ()).second; - db::cell_index_type ci_new = i->second.second; + if (! has_conflict) { - if (m_cc_resolution == RenameCell || layout.cell (ci_org).is_proxy ()) { + // no conflict - plain rename - // NOTE: we never reopen proxies (they are always local to their layout). Instead we - // always rename for proxies - layout.rename_cell (i->second.second, i->first.c_str ()); + for (std::map >::const_iterator i = m_name_map.begin (); i != m_name_map.end () && ! has_conflict; ++i) { + layout.rename_cell (i->second.second, i->first.c_str ()); + } - } else { + } else { - // we have a cell conflict - layout.force_update (); + // elaborate conflict resolution - if (m_cc_resolution == OverwriteCell && ! layout.cell (ci_new).is_ghost_cell ()) { + layout.force_update (); - layout.prune_subcells (ci_org); - layout.cell (ci_org).clear_shapes (); + std::map new_cells; + for (std::map >::const_iterator i = m_name_map.begin (); i != m_name_map.end (); ++i) { + new_cells.insert (std::make_pair (i->second.second, i->first)); + } - } else if (m_cc_resolution == SkipNewCell && ! layout.cell (ci_org).is_ghost_cell ()) { + // NOTE: by iterating bottom up we don't need to update the layout (we need the parents for merge_cell) + for (db::Layout::bottom_up_iterator bu = layout.begin_bottom_up (); bu != layout.end_bottom_up (); ++bu) { - layout.prune_subcells (ci_new); - layout.cell (ci_new).clear_shapes (); + db::cell_index_type ci_new = *bu; + + if (new_cells.find (ci_new) == new_cells.end ()) { + // not a new cell + continue; + } else if (! layout.is_valid_cell_index (ci_new)) { + // this can happen if the new cell has been deleted by "prune_subcells" + continue; + } + + std::map::const_iterator i = new_cells.find (ci_new); + + std::pair c2n = layout.cell_by_name (i->second.c_str ()); + db::cell_index_type ci_org = c2n.second; + + if (c2n.first) { + + if (m_cc_resolution == RenameCell || layout.cell (ci_org).is_proxy ()) { + + // NOTE: we never reopen proxies (they are always local to their layout). Instead we + // always rename for proxies + layout.rename_cell (ci_new, layout.uniquify_cell_name (i->second.c_str ()).c_str ()); + + } else { + + // we have a cell conflict + + if (m_cc_resolution == OverwriteCell && ! layout.cell (ci_new).is_ghost_cell ()) { + + layout.prune_subcells (ci_org); + layout.cell (ci_org).clear_shapes (); + + } else if (m_cc_resolution == SkipNewCell && ! layout.cell (ci_org).is_ghost_cell ()) { + + layout.prune_subcells (ci_new); + layout.cell (ci_new).clear_shapes (); + + } + + merge_cell (layout, ci_org, ci_new); } - merge_cell (layout, ci_org, ci_new); + } else { + + layout.rename_cell (ci_new, layout.uniquify_cell_name (i->second.c_str ()).c_str ()); } - } else { - - layout.rename_cell (i->second.second, i->first.c_str ()); - } } diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index 55c19ef78..199441231 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -1068,14 +1068,41 @@ Layout::add_cell (const char *name) return new_index; } +cell_index_type +Layout::add_anonymous_cell () +{ + std::string b; + + // create a new cell + cell_index_type new_index = allocate_new_cell (); + + cell_type *new_cell = new cell_type (new_index, *this); + m_cells.push_back_ptr (new_cell); + m_cell_ptrs [new_index] = new_cell; + + // enter it's index and cell_name + register_cell_name (0, 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::register_cell_name (const char *name, cell_index_type ci) { // enter it's index and cell_name char *cp; - cp = new char [strlen (name) + 1]; - strcpy (cp, name); + if (name == 0) { + cp = new char [1]; + *cp = 0; + } else { + cp = new char [strlen (name) + 1]; + strcpy (cp, name); + } while (m_cell_names.size () < ci) { char *e = new char [1]; @@ -1090,7 +1117,9 @@ Layout::register_cell_name (const char *name, cell_index_type ci) m_cell_names.push_back (cp); } - m_cell_map.insert (std::make_pair (cp, ci)); + if (name) { + m_cell_map.insert (std::make_pair (cp, ci)); + } } void diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index b1184fa26..fd6d897aa 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -727,7 +727,17 @@ public: */ cell_index_type add_cell (const char *name = 0); - /** + /** + * @brief Add a cell without a name + * + * The cell is created, but cannot be found by name. The name returned is an empty string. + * The cell is created with the purpose of being renamed later. + * + * @return The index of the new cell + */ + cell_index_type add_anonymous_cell (); + + /** * @brief Rename a cell * * Rename the cell with the given id. diff --git a/src/db/db/gsiDeclDbCommonStreamOptions.cc b/src/db/db/gsiDeclDbCommonStreamOptions.cc index a208b8962..669dbd7e0 100644 --- a/src/db/db/gsiDeclDbCommonStreamOptions.cc +++ b/src/db/db/gsiDeclDbCommonStreamOptions.cc @@ -85,6 +85,16 @@ static void set_properties_enabled (db::LoadLayoutOptions *options, bool l) options->get_options ().enable_properties = l; } +static db::CommonReader::CellConflictResolution get_cell_conflict_resolution (const db::LoadLayoutOptions *options) +{ + return options->get_options ().cell_conflict_resolution; +} + +static void set_cell_conflict_resolution (db::LoadLayoutOptions *options, db::CommonReader::CellConflictResolution cc) +{ + options->get_options ().cell_conflict_resolution = cc; +} + // extend lay::LoadLayoutOptions with the Common options static gsi::ClassExt common_reader_options ( @@ -157,6 +167,22 @@ gsi::ClassExt common_reader_options ( "@param enabled True, if properties should be read." "\n" "Starting with version 0.25 this option only applies to GDS2 and OASIS format. Other formats provide their own configuration." + ) + + gsi::method_ext ("cell_conflict_resolution", &get_cell_conflict_resolution, + "@brief Gets the cell conflict resolution mode\n" + "\n" + "Multiple layout files can be collected into a single Layout object by reading file after file into the Layout object. " + "Cells with same names are considered a conflict. This mode indicates how such conflicts are resolved. See \\CellConflictResolution " + "for the values allowed. The default mode is \\CellConflictResolution#AddToCell.\n" + "\n" + "This option has been introduced in version 0.27." + ) + + gsi::method_ext ("cell_conflict_resolution=", &set_cell_conflict_resolution, gsi::arg ("mode"), + "@brief Sets the cell conflict resolution mode\n" + "\n" + "See \\cell_conflict_resolution for details about this option.\n" + "\n" + "This option has been introduced in version 0.27." ), "" ); diff --git a/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc b/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc index b1971b0e4..58b4cb80f 100644 --- a/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc +++ b/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc @@ -366,6 +366,8 @@ TEST(Bug_121_1) reader.read (layout); } + fflush(stdout); + std::string fn_au (tl::testsrc () + "/testdata/gds/bug_121_au1.gds"); db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1); } diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc index c6d229870..0dbe5e759 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc @@ -1145,7 +1145,9 @@ OASISReader::do_read (db::Layout &layout) unsigned long id = 0; get (id); - if (has_cell (id)) { + + std::pair cc = cell_by_id (id); + if (cc.first && ! layout.cell (cc.second).is_ghost_cell ()) { error (tl::sprintf (tl::to_string (tr ("A cell with id %ld is defined already")), id)); } @@ -1158,7 +1160,9 @@ OASISReader::do_read (db::Layout &layout) } std::string name = get_str (); - if (has_cell (name)) { + + std::pair cc = cell_by_name (name); + if (cc.first && ! layout.cell (cc.second).is_ghost_cell ()) { error (tl::sprintf (tl::to_string (tr ("A cell with name %s is defined already")), name.c_str ())); } From 2ef3290f65f98d3340ce06137bea2515d6e23a34 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 3 Nov 2020 21:18:47 +0100 Subject: [PATCH 04/11] WIP: updated some golden data (only sequence of cells), restored old error messages, proper reporting of cell names in OASIS error messages --- src/db/db/dbCommonReader.cc | 16 +++++++++++++- src/db/db/dbCommonReader.h | 6 +++++ .../oasis/db_plugin/dbOASISReader.cc | 8 ++++++- .../oasis/unit_tests/dbOASISWriter.cc | 22 +++++++++---------- testdata/oasis/t2.4.ot | 4 ++-- testdata/oasis/t2.4_au.txt | 4 ++-- testdata/oasis/t2.6_au.txt | 4 ++-- 7 files changed, 45 insertions(+), 19 deletions(-) diff --git a/src/db/db/dbCommonReader.cc b/src/db/db/dbCommonReader.cc index 8028653eb..8728f986d 100644 --- a/src/db/db/dbCommonReader.cc +++ b/src/db/db/dbCommonReader.cc @@ -128,9 +128,23 @@ CommonReader::cell_by_id (size_t id) const } } +const std::string & +CommonReader::name_for_id (size_t id) const +{ + std::map::const_iterator n = m_name_for_id.find (id); + if (n != m_name_for_id.end ()) { + return n->second; + } else { + static std::string empty; + return empty; + } +} + void CommonReader::rename_cell (db::Layout &layout, size_t id, const std::string &cn) { + m_name_for_id.insert (std::make_pair (id, cn)); + std::map >::iterator iid = m_id_map.find (id); std::map >::iterator iname = m_name_map.find (cn); @@ -256,7 +270,7 @@ CommonReader::finish (db::Layout &layout) for (std::map >::const_iterator i = m_id_map.begin (); i != m_id_map.end (); ++i) { if (i->second.first.empty ()) { - common_reader_warn (tl::sprintf (tl::to_string (tr ("Cell name missing for ID %ld")), i->first)); + common_reader_warn (tl::sprintf (tl::to_string (tr ("No cellname defined for cell name id %ld")), i->first)); any_missing = true; } } diff --git a/src/db/db/dbCommonReader.h b/src/db/db/dbCommonReader.h index 8bdf8ffb6..2bcecfaa7 100644 --- a/src/db/db/dbCommonReader.h +++ b/src/db/db/dbCommonReader.h @@ -105,6 +105,11 @@ public: */ void rename_cell (db::Layout &layout, size_t id, const std::string &cn); + /** + * @brief Gets the name for a given cell ID if known, otherwise returns an empty string + */ + const std::string &name_for_id (size_t id) const; + /** * @brief Returns a cell reference by ID * If the cell does not exist, it's created. It is marked as ghost cell until @@ -139,6 +144,7 @@ protected: private: std::map > m_id_map; std::map > m_name_map; + std::map m_name_for_id; CellConflictResolution m_cc_resolution; }; diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc index 0dbe5e759..3bf5485a5 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc @@ -1153,6 +1153,11 @@ OASISReader::do_read (db::Layout &layout) cell_index = make_cell (layout, id); + m_cellname = name_for_id (id); + if (m_cellname.empty ()) { + m_cellname = std::string ("#") + tl::to_string (id); + } + } else { if (m_expect_strict_mode == 1) { @@ -1168,6 +1173,8 @@ OASISReader::do_read (db::Layout &layout) cell_index = make_cell (layout, name); + m_cellname = name; + } reset_modal_variables (); @@ -3260,7 +3267,6 @@ OASISReader::do_read_cell (db::cell_index_type cell_index, db::Layout &layout) m_instances_with_props.clear (); m_progress.set (m_stream.pos ()); - m_cellname = layout.cell_name (cell_index); bool xy_absolute = true; diff --git a/src/plugins/streamers/oasis/unit_tests/dbOASISWriter.cc b/src/plugins/streamers/oasis/unit_tests/dbOASISWriter.cc index ce4f6c479..9e7e48aef 100644 --- a/src/plugins/streamers/oasis/unit_tests/dbOASISWriter.cc +++ b/src/plugins/streamers/oasis/unit_tests/dbOASISWriter.cc @@ -570,11 +570,11 @@ TEST(100) const char *expected = "begin_lib 0.001\n" + "begin_cell {$4}\n" + "end_cell\n" "begin_cell {$1}\n" "box 1 0 {0 100} {1000 1200}\n" "end_cell\n" - "begin_cell {$4}\n" - "end_cell\n" "begin_cell {$3}\n" "sref {$1} 90 1 1 {-10 20}\n" "sref {$4} 90 1 1 {-10 20}\n" @@ -1327,14 +1327,14 @@ TEST(116) " {{name} {117}}\n" "}\n" "begin_libp $props 0.001\n" + "begin_cell {$2}\n" + "end_cell\n" "set props {\n" " {42 {42}}\n" "}\n" "begin_cellp $props {$1}\n" "path 1 0 0 0 0 {0 100} {1000 1200}\n" "end_cell\n" - "begin_cell {$2}\n" - "end_cell\n" "end_lib\n" ; @@ -1376,14 +1376,14 @@ TEST(116) " {{name} {117}}\n" "}\n" "begin_libp $props 0.001\n" + "begin_cell {$2}\n" + "end_cell\n" "set props {\n" " {42 {42}}\n" "}\n" "begin_cellp $props {$1}\n" "path 1 0 0 0 0 {0 100} {1000 1200}\n" "end_cell\n" - "begin_cell {$2}\n" - "end_cell\n" "end_lib\n" ; @@ -1431,17 +1431,17 @@ TEST(116) "}\n" "begin_libp $props 0.001\n" "set props {\n" + " {{S_BOUNDING_BOX} {2,0,0,0,0}}\n" + "}\n" + "begin_cellp $props {$2}\n" + "end_cell\n" + "set props {\n" " {{S_BOUNDING_BOX} {0,0,100,1000,1100}}\n" " {42 {42}}\n" "}\n" "begin_cellp $props {$1}\n" "path 1 0 0 0 0 {0 100} {1000 1200}\n" "end_cell\n" - "set props {\n" - " {{S_BOUNDING_BOX} {2,0,0,0,0}}\n" - "}\n" - "begin_cellp $props {$2}\n" - "end_cell\n" "end_lib\n" ; diff --git a/testdata/oasis/t2.4.ot b/testdata/oasis/t2.4.ot index 8a625c7cf..d1def8758 100644 --- a/testdata/oasis/t2.4.ot +++ b/testdata/oasis/t2.4.ot @@ -7,10 +7,10 @@ # Explicit assignment of ID's # # begin_lib 0.001 -# begin_cell {ABC} -# end_cell # begin_cell {XYZ} # end_cell +# begin_cell {ABC} +# end_cell # end_lib # # diff --git a/testdata/oasis/t2.4_au.txt b/testdata/oasis/t2.4_au.txt index ede7f7760..aee39fbb5 100644 --- a/testdata/oasis/t2.4_au.txt +++ b/testdata/oasis/t2.4_au.txt @@ -1,6 +1,6 @@ begin_lib 0.001 -begin_cell {ABC} -end_cell begin_cell {XYZ} end_cell +begin_cell {ABC} +end_cell end_lib diff --git a/testdata/oasis/t2.6_au.txt b/testdata/oasis/t2.6_au.txt index 3c0ebf770..ec8221a98 100644 --- a/testdata/oasis/t2.6_au.txt +++ b/testdata/oasis/t2.6_au.txt @@ -1,6 +1,6 @@ begin_lib 0.001 -begin_cell {ABC} -end_cell begin_cell { XYZ} end_cell +begin_cell {ABC} +end_cell end_lib From 61696f1ae75e04ff4ca34186f0d717832067084e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 3 Nov 2020 23:10:50 +0100 Subject: [PATCH 05/11] Don't emit CELLNAME records for cells which are not written. This was confusing the new implementation of the OASIS reader. --- .../oasis/db_plugin/dbOASISWriter.cc | 120 +++++++++--------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc b/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc index a3e5b8c21..358018f4e 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc @@ -1150,6 +1150,12 @@ OASISWriter::reset_modal_variables () mm_last_value_list.reset (); } +static bool must_write_cell (const db::Cell &cref) +{ + // don't write ghost cells if not empty and don't write proxy cells which are not employed + return (! cref.is_ghost_cell () || ! cref.empty ()) && (! cref.is_proxy () || ! cref.is_top ()); +} + void OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLayoutOptions &options) { @@ -1184,13 +1190,13 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save cells_by_index.reserve (cell_set.size ()); for (db::Layout::bottom_up_const_iterator cell = layout.begin_bottom_up (); cell != layout.end_bottom_up (); ++cell) { - if (cell_set.find (*cell) != cell_set.end ()) { + if (cell_set.find (*cell) != cell_set.end () && must_write_cell (layout.cell (*cell))) { cells.push_back (*cell); } } for (db::Layout::const_iterator cell = layout.begin (); cell != layout.end (); ++cell) { - if (cell_set.find (cell->cell_index ()) != cell_set.end ()) { + if (cell_set.find (cell->cell_index ()) != cell_set.end () && must_write_cell (layout.cell (cell->cell_index ()))) { cells_by_index.push_back (cell->cell_index ()); } } @@ -1594,80 +1600,74 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save const db::Cell &cref (layout.cell (*cell)); mp_cell = &cref; - // don't write ghost cells unless they are not empty (any more) - // also don't write proxy cells which are not employed - if ((! cref.is_ghost_cell () || ! cref.empty ()) && (! cref.is_proxy () || ! cref.is_top ())) { + // cell header - // cell header + cell_positions.insert (std::make_pair (*cell, mp_stream->pos ())); - cell_positions.insert (std::make_pair (*cell, mp_stream->pos ())); + write_record_id (13); // CELL + write ((unsigned long) *cell); - write_record_id (13); // CELL - write ((unsigned long) *cell); + reset_modal_variables (); - reset_modal_variables (); + if (m_options.write_cblocks) { + begin_cblock (); + } - if (m_options.write_cblocks) { - begin_cblock (); - } + // context information as property named KLAYOUT_CONTEXT + if (cref.is_proxy () && options.write_context_info ()) { - // context information as property named KLAYOUT_CONTEXT - if (cref.is_proxy () && options.write_context_info ()) { + context_prop_strings.clear (); - context_prop_strings.clear (); + if (layout.get_context_info (*cell, context_prop_strings)) { - if (layout.get_context_info (*cell, context_prop_strings)) { + write_record_id (28); + write_byte (char (0xf6)); + std::map ::const_iterator pni = m_propnames.find (klayout_context_name); + tl_assert (pni != m_propnames.end ()); + write (pni->second); - write_record_id (28); - write_byte (char (0xf6)); - std::map ::const_iterator pni = m_propnames.find (klayout_context_name); - tl_assert (pni != m_propnames.end ()); - write (pni->second); - - write ((unsigned long) context_prop_strings.size ()); - - for (std::vector ::const_iterator c = context_prop_strings.begin (); c != context_prop_strings.end (); ++c) { - write_byte (14); // b-string by reference number - std::map ::const_iterator psi = m_propstrings.find (*c); - tl_assert (psi != m_propstrings.end ()); - write (psi->second); - } - - mm_last_property_name = klayout_context_name; - mm_last_property_is_sprop = false; - mm_last_value_list.reset (); + write ((unsigned long) context_prop_strings.size ()); + for (std::vector ::const_iterator c = context_prop_strings.begin (); c != context_prop_strings.end (); ++c) { + write_byte (14); // b-string by reference number + std::map ::const_iterator psi = m_propstrings.find (*c); + tl_assert (psi != m_propstrings.end ()); + write (psi->second); } + mm_last_property_name = klayout_context_name; + mm_last_property_is_sprop = false; + mm_last_value_list.reset (); + } - if (cref.prop_id () != 0) { - write_props (cref.prop_id ()); - } - - // instances - if (cref.cell_instances () > 0) { - write_insts (cell_set); - } - - // shapes - for (std::vector >::const_iterator l = layers.begin (); l != layers.end (); ++l) { - const db::Shapes &shapes = cref.shapes (l->first); - if (! shapes.empty ()) { - write_shapes (l->second, shapes); - m_progress.set (mp_stream->pos ()); - } - } - - // end CBLOCK if required - if (m_options.write_cblocks) { - end_cblock (); - } - - // end of cell - } + if (cref.prop_id () != 0) { + write_props (cref.prop_id ()); + } + + // instances + if (cref.cell_instances () > 0) { + write_insts (cell_set); + } + + // shapes + for (std::vector >::const_iterator l = layers.begin (); l != layers.end (); ++l) { + const db::Shapes &shapes = cref.shapes (l->first); + if (! shapes.empty ()) { + write_shapes (l->second, shapes); + m_progress.set (mp_stream->pos ()); + } + } + + // end CBLOCK if required + if (m_options.write_cblocks) { + end_cblock (); + } + + // end of cell + } // write cell table at the end in strict mode (in that mode we need the cell positions From 888b0936f768c4ee4c36f64e4239a0d115d74148 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 3 Nov 2020 23:11:07 +0100 Subject: [PATCH 06/11] Updated test golden data (order of cells only) --- src/db/unit_tests/dbHierProcessorTests.cc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/db/unit_tests/dbHierProcessorTests.cc b/src/db/unit_tests/dbHierProcessorTests.cc index de0508386..32a6b40b6 100644 --- a/src/db/unit_tests/dbHierProcessorTests.cc +++ b/src/db/unit_tests/dbHierProcessorTests.cc @@ -460,8 +460,8 @@ TEST(BasicAnd9) // from atop the CHILD cell don't interact with shapes inside CHILD, so there are 4 shapes rather than // 6. And the shapes from top inside the ring are not seen by the RING's subject shapes. "TOP[1] 0 insts, 0 shapes (1 times)\n" - "RING[1] 0 insts, 0 shapes (1 times)\n" "CHILD1[1] 0 insts, 4 shapes (2 times)\n" + "RING[1] 0 insts, 0 shapes (1 times)\n" ); } @@ -476,8 +476,8 @@ TEST(BasicNot9) // from atop the CHILD cell don't interact with shapes inside CHILD, so there are 4 shapes rather than // 6. And the shapes from top inside the ring are not seen by the RING's subject shapes. "TOP[1] 0 insts, 0 shapes (1 times)\n" - "RING[1] 0 insts, 0 shapes (1 times)\n" "CHILD1[1] 0 insts, 4 shapes (2 times)\n" + "RING[1] 0 insts, 0 shapes (1 times)\n" ); } @@ -600,8 +600,8 @@ TEST(BasicAndWithSize9) // from atop the CHILD cell don't interact with shapes inside CHILD, so there are 4 shapes rather than // 6. And the shapes from top inside the ring are not seen by the RING's subject shapes. "TOP[1] 0 insts, 0 shapes (1 times)\n" - "RING[1] 0 insts, 0 shapes (1 times)\n" "CHILD1[1] 0 insts, 6 shapes (2 times)\n" + "RING[1] 0 insts, 0 shapes (1 times)\n" ); } @@ -616,8 +616,8 @@ TEST(BasicNotWithSize9) // from atop the CHILD cell don't interact with shapes inside CHILD, so there are 4 shapes rather than // 6. And the shapes from top inside the ring are not seen by the RING's subject shapes. "TOP[1] 0 insts, 0 shapes (1 times)\n" - "RING[1] 0 insts, 0 shapes (1 times)\n" "CHILD1[1] 0 insts, 6 shapes (2 times)\n" + "RING[1] 0 insts, 0 shapes (1 times)\n" ); } @@ -752,8 +752,8 @@ TEST(TwoInputsAnd9) // from atop the CHILD cell don't interact with shapes inside CHILD, so there are 4 shapes rather than // 6. And the shapes from top inside the ring are not seen by the RING's subject shapes. "TOP[1] 0 insts, 0 shapes (1 times)\n" - "RING[1] 1 insts, 0 shapes (1 times)\n" "CHILD1[1] 0 insts, 4 shapes (2 times)\n" + "RING[1] 1 insts, 0 shapes (1 times)\n" ); } @@ -768,8 +768,8 @@ TEST(TwoInputsNot9) // from atop the CHILD cell don't interact with shapes inside CHILD, so there are 4 shapes rather than // 6. And the shapes from top inside the ring are not seen by the RING's subject shapes. "TOP[1] 0 insts, 0 shapes (1 times)\n" - "RING[1] 1 insts, 0 shapes (1 times)\n" "CHILD1[1] 0 insts, 4 shapes (2 times)\n" + "RING[1] 1 insts, 0 shapes (1 times)\n" ); } @@ -892,8 +892,8 @@ TEST(TwoInputsAndWithSize9) // from atop the CHILD cell don't interact with shapes inside CHILD, so there are 4 shapes rather than // 6. And the shapes from top inside the ring are not seen by the RING's subject shapes. "TOP[1] 0 insts, 0 shapes (1 times)\n" - "RING[1] 1 insts, 0 shapes (1 times)\n" "CHILD1[1] 0 insts, 6 shapes (2 times)\n" + "RING[1] 1 insts, 0 shapes (1 times)\n" ); } @@ -908,8 +908,8 @@ TEST(TwoInputsNotWithSize9) // from atop the CHILD cell don't interact with shapes inside CHILD, so there are 4 shapes rather than // 6. And the shapes from top inside the ring are not seen by the RING's subject shapes. "TOP[1] 0 insts, 0 shapes (1 times)\n" - "RING[1] 1 insts, 0 shapes (1 times)\n" "CHILD1[1] 0 insts, 6 shapes (2 times)\n" + "RING[1] 1 insts, 0 shapes (1 times)\n" ); } @@ -984,8 +984,8 @@ TEST(BasicSelfOverlap9) // from atop the CHILD cell don't interact with shapes inside CHILD, so there are 4 shapes rather than // 6. And the shapes from top inside the ring are not seen by the RING's subject shapes. "TOP[1] 0 insts, 0 shapes (1 times)\n" - "RING[1] 0 insts, 1 shapes (1 times)\n" "CHILD1[1] 0 insts, 4 shapes (2 times)\n" + "RING[1] 0 insts, 1 shapes (1 times)\n" ); } @@ -1054,8 +1054,8 @@ TEST(BasicSelfOverlapWithSize9) // from atop the CHILD cell don't interact with shapes inside CHILD, so there are 4 shapes rather than // 6. And the shapes from top inside the ring are not seen by the RING's subject shapes. "TOP[1] 0 insts, 0 shapes (1 times)\n" - "RING[1] 0 insts, 1 shapes (1 times)\n" "CHILD1[1] 0 insts, 6 shapes (2 times)\n" + "RING[1] 0 insts, 1 shapes (1 times)\n" ); } From 6c8f8024440fc801a48f27fd7bff020bb40aaf94 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 12 Nov 2020 00:27:49 +0100 Subject: [PATCH 07/11] Correct production of ghost cells for OASIS --- .../streamers/oasis/db_plugin/dbOASISWriter.cc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc b/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc index 358018f4e..667c80b80 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISWriter.cc @@ -1152,8 +1152,14 @@ OASISWriter::reset_modal_variables () static bool must_write_cell (const db::Cell &cref) { - // don't write ghost cells if not empty and don't write proxy cells which are not employed - return (! cref.is_ghost_cell () || ! cref.empty ()) && (! cref.is_proxy () || ! cref.is_top ()); + // Don't write proxy cells which are not employed + return ! cref.is_proxy () || ! cref.is_top (); +} + +static bool skip_cell_body (const db::Cell &cref) +{ + // Skip cell bodies for ghost cells unless empty (they are not longer ghost cells in this case) + return cref.is_ghost_cell () && cref.empty (); } void @@ -1600,6 +1606,11 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save const db::Cell &cref (layout.cell (*cell)); mp_cell = &cref; + // skip cell body if the cell is not to be written + if (skip_cell_body (cref)) { + continue; + } + // cell header cell_positions.insert (std::make_pair (*cell, mp_stream->pos ())); From f61aac6b1bd7f9e8c349baaa06351c0fc630fc51 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 12 Nov 2020 10:22:22 +0100 Subject: [PATCH 08/11] Doc: resolve references to child classes too. --- src/db/db/gsiDeclDbCommonStreamOptions.cc | 4 +- src/lay/lay/layGSIHelpProvider.cc | 58 +++++++++++++++++++++-- testdata/ruby/dbReaders.rb | 8 ++++ 3 files changed, 65 insertions(+), 5 deletions(-) diff --git a/src/db/db/gsiDeclDbCommonStreamOptions.cc b/src/db/db/gsiDeclDbCommonStreamOptions.cc index 669dbd7e0..32b8ede8c 100644 --- a/src/db/db/gsiDeclDbCommonStreamOptions.cc +++ b/src/db/db/gsiDeclDbCommonStreamOptions.cc @@ -172,8 +172,8 @@ gsi::ClassExt common_reader_options ( "@brief Gets the cell conflict resolution mode\n" "\n" "Multiple layout files can be collected into a single Layout object by reading file after file into the Layout object. " - "Cells with same names are considered a conflict. This mode indicates how such conflicts are resolved. See \\CellConflictResolution " - "for the values allowed. The default mode is \\CellConflictResolution#AddToCell.\n" + "Cells with same names are considered a conflict. This mode indicates how such conflicts are resolved. See \\LoadLayoutOptions::CellConflictResolution " + "for the values allowed. The default mode is \\LoadLayoutOptions::CellConflictResolution#AddToCell.\n" "\n" "This option has been introduced in version 0.27." ) + diff --git a/src/lay/lay/layGSIHelpProvider.cc b/src/lay/lay/layGSIHelpProvider.cc index 171b3fc6a..01c678f12 100644 --- a/src/lay/lay/layGSIHelpProvider.cc +++ b/src/lay/lay/layGSIHelpProvider.cc @@ -318,6 +318,55 @@ real_class (const gsi::ClassBase *cls) return cls->declaration () ? cls->declaration () : cls; } +namespace { + +class RecursiveClassIterator +{ +public: + typedef const gsi::ClassBase &reference; + typedef const gsi::ClassBase *pointer; + + RecursiveClassIterator () + { + if (gsi::ClassBase::begin_classes () != gsi::ClassBase::end_classes ()) { + m_cls_iter_stack.push_back (std::make_pair (gsi::ClassBase::begin_classes (), gsi::ClassBase::end_classes ())); + } + } + + bool at_end () const + { + return m_cls_iter_stack.empty (); + } + + RecursiveClassIterator &operator++ () + { + if (operator* ().begin_child_classes () != operator* ().end_child_classes ()) { + m_cls_iter_stack.push_back (std::make_pair (operator* ().begin_child_classes (), operator* ().end_child_classes ())); + } else { + while (! m_cls_iter_stack.empty () && ++m_cls_iter_stack.back ().first == m_cls_iter_stack.back ().second) { + m_cls_iter_stack.pop_back (); + } + } + + return *this; + } + + const gsi::ClassBase &operator* () const + { + return *m_cls_iter_stack.back ().first; + } + + const gsi::ClassBase *operator-> () const + { + return m_cls_iter_stack.back ().first.operator-> (); + } + +private: + std::list > m_cls_iter_stack; +}; + +} + static std::string replace_references (const std::string &t, const gsi::ClassBase *cls_base) { @@ -341,7 +390,7 @@ replace_references (const std::string &t, const gsi::ClassBase *cls_base) r += std::string (t, q, p - q); size_t pp = ++p; - while (p < t.size () && (t[p] == '_' || isalnum (t [p]))) { + while (p < t.size () && (t[p] == '_' || t[p] == ':' || isalnum (t [p]))) { ++p; } if (p < t.size () && (t[p] == '?' || t [p] == '=')) { @@ -369,8 +418,11 @@ replace_references (const std::string &t, const gsi::ClassBase *cls_base) found = true; } - for (gsi::ClassBase::class_iterator c = gsi::ClassBase::begin_classes (); c != gsi::ClassBase::end_classes () && !found; ++c) { - if (c->name () == id) { + for (RecursiveClassIterator c; ! c.at_end (); ++c) { +if (id.find ("CellConflict") != std::string::npos) { +printf("@@@ %s <-> %s\n", c->qname().c_str(), id.c_str()); fflush(stdout); +} + if (c->qname () == id) { r += " Date: Thu, 12 Nov 2020 22:22:12 +0100 Subject: [PATCH 09/11] Removed debug output. --- src/lay/lay/layGSIHelpProvider.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/lay/lay/layGSIHelpProvider.cc b/src/lay/lay/layGSIHelpProvider.cc index 01c678f12..b44c91a4a 100644 --- a/src/lay/lay/layGSIHelpProvider.cc +++ b/src/lay/lay/layGSIHelpProvider.cc @@ -419,9 +419,6 @@ replace_references (const std::string &t, const gsi::ClassBase *cls_base) } for (RecursiveClassIterator c; ! c.at_end (); ++c) { -if (id.find ("CellConflict") != std::string::npos) { -printf("@@@ %s <-> %s\n", c->qname().c_str(), id.c_str()); fflush(stdout); -} if (c->qname () == id) { r += " Date: Fri, 13 Nov 2020 00:31:56 +0100 Subject: [PATCH 10/11] Added test for the collect modes, bugfixed the new modes. --- src/db/db/dbCommonReader.cc | 53 +++++----- .../streamers/gds2/unit_tests/dbGDS2Reader.cc | 97 ++++++++++++++++++ testdata/gds/collect_add_au.gds | Bin 0 -> 12990 bytes testdata/gds/collect_added.gds | Bin 0 -> 4990 bytes testdata/gds/collect_basic.gds | Bin 0 -> 9360 bytes testdata/gds/collect_overwrite_au.gds | Bin 0 -> 8008 bytes testdata/gds/collect_rename_au.gds | Bin 0 -> 13248 bytes testdata/gds/collect_skip_au.gds | Bin 0 -> 9598 bytes 8 files changed, 126 insertions(+), 24 deletions(-) create mode 100644 testdata/gds/collect_add_au.gds create mode 100644 testdata/gds/collect_added.gds create mode 100644 testdata/gds/collect_basic.gds create mode 100644 testdata/gds/collect_overwrite_au.gds create mode 100644 testdata/gds/collect_rename_au.gds create mode 100644 testdata/gds/collect_skip_au.gds diff --git a/src/db/db/dbCommonReader.cc b/src/db/db/dbCommonReader.cc index 8728f986d..741cf1f0d 100644 --- a/src/db/db/dbCommonReader.cc +++ b/src/db/db/dbCommonReader.cc @@ -305,55 +305,60 @@ CommonReader::finish (db::Layout &layout) new_cells.insert (std::make_pair (i->second.second, i->first)); } - // NOTE: by iterating bottom up we don't need to update the layout (we need the parents for merge_cell) + std::vector > cells_with_conflict; + + // First treat all the cells without conflict for (db::Layout::bottom_up_iterator bu = layout.begin_bottom_up (); bu != layout.end_bottom_up (); ++bu) { db::cell_index_type ci_new = *bu; + std::map::const_iterator i = new_cells.find (ci_new); - if (new_cells.find (ci_new) == new_cells.end ()) { + if (i == new_cells.end ()) { // not a new cell continue; - } else if (! layout.is_valid_cell_index (ci_new)) { - // this can happen if the new cell has been deleted by "prune_subcells" - continue; } - std::map::const_iterator i = new_cells.find (ci_new); - std::pair c2n = layout.cell_by_name (i->second.c_str ()); db::cell_index_type ci_org = c2n.second; - if (c2n.first) { + // NOTE: proxy cells are never resolved. "RenameCell" is a plain and simple case. + if (c2n.first && m_cc_resolution != RenameCell && ! layout.cell (ci_org).is_proxy ()) { + cells_with_conflict.push_back (std::make_pair (ci_new, ci_org)); + } else { + layout.rename_cell (ci_new, layout.uniquify_cell_name (i->second.c_str ()).c_str ()); + } - if (m_cc_resolution == RenameCell || layout.cell (ci_org).is_proxy ()) { + } - // NOTE: we never reopen proxies (they are always local to their layout). Instead we - // always rename for proxies - layout.rename_cell (ci_new, layout.uniquify_cell_name (i->second.c_str ()).c_str ()); + // Then treat all the cells with conflict + for (std::vector >::const_iterator cc = cells_with_conflict.begin (); cc != cells_with_conflict.end (); ++cc) { - } else { + db::cell_index_type ci_new = cc->first; + db::cell_index_type ci_org = cc->second; - // we have a cell conflict + // we have a cell conflict - if (m_cc_resolution == OverwriteCell && ! layout.cell (ci_new).is_ghost_cell ()) { + layout.force_update (); - layout.prune_subcells (ci_org); - layout.cell (ci_org).clear_shapes (); + if (m_cc_resolution == OverwriteCell && ! layout.cell (ci_new).is_ghost_cell ()) { - } else if (m_cc_resolution == SkipNewCell && ! layout.cell (ci_org).is_ghost_cell ()) { + layout.prune_subcells (ci_org); + layout.cell (ci_org).clear_shapes (); - layout.prune_subcells (ci_new); - layout.cell (ci_new).clear_shapes (); + merge_cell (layout, ci_org, ci_new); - } + } else if (m_cc_resolution == SkipNewCell && ! layout.cell (ci_org).is_ghost_cell ()) { - merge_cell (layout, ci_org, ci_new); + layout.prune_subcells (ci_new); + layout.cell (ci_new).clear_shapes (); - } + // we need the instances of the cell we just cleaned + layout.force_update (); + merge_cell (layout, ci_org, ci_new); } else { - layout.rename_cell (ci_new, layout.uniquify_cell_name (i->second.c_str ()).c_str ()); + merge_cell (layout, ci_org, ci_new); } diff --git a/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc b/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc index 58b4cb80f..838260bf3 100644 --- a/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc +++ b/src/plugins/streamers/gds2/unit_tests/dbGDS2Reader.cc @@ -436,3 +436,100 @@ TEST(3_AdvancedMapping) std::string fn_au (tl::testsrc () + "/testdata/gds/alm_au.gds"); db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1); } + +TEST(4_CollectModeRename) +{ + db::Manager m (false); + db::Layout layout (&m); + + db::LoadLayoutOptions options; + options.get_options ().cell_conflict_resolution = db::CommonReader::RenameCell; + + { + tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_basic.gds"); + db::Reader reader (file); + reader.read (layout, options); + } + + { + tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_added.gds"); + db::Reader reader (file); + reader.read (layout, options); + } + + std::string fn_au (tl::testsrc () + "/testdata/gds/collect_rename_au.gds"); + db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1); +} + +TEST(4_CollectModeOverwrite) +{ + db::Manager m (false); + db::Layout layout (&m); + + db::LoadLayoutOptions options; + options.get_options ().cell_conflict_resolution = db::CommonReader::OverwriteCell; + + { + tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_basic.gds"); + db::Reader reader (file); + reader.read (layout, options); + } + + { + tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_added.gds"); + db::Reader reader (file); + reader.read (layout, options); + } + + std::string fn_au (tl::testsrc () + "/testdata/gds/collect_overwrite_au.gds"); + db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1); +} + +TEST(4_CollectModeSkip) +{ + db::Manager m (false); + db::Layout layout (&m); + + db::LoadLayoutOptions options; + options.get_options ().cell_conflict_resolution = db::CommonReader::SkipNewCell; + + { + tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_basic.gds"); + db::Reader reader (file); + reader.read (layout, options); + } + + { + tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_added.gds"); + db::Reader reader (file); + reader.read (layout, options); + } + + std::string fn_au (tl::testsrc () + "/testdata/gds/collect_skip_au.gds"); + db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1); +} + +TEST(4_CollectModeAdd) +{ + db::Manager m (false); + db::Layout layout (&m); + + db::LoadLayoutOptions options; + options.get_options ().cell_conflict_resolution = db::CommonReader::AddToCell; + + { + tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_basic.gds"); + db::Reader reader (file); + reader.read (layout, options); + } + + { + tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_added.gds"); + db::Reader reader (file); + reader.read (layout, options); + } + + std::string fn_au (tl::testsrc () + "/testdata/gds/collect_add_au.gds"); + db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1); +} + diff --git a/testdata/gds/collect_add_au.gds b/testdata/gds/collect_add_au.gds new file mode 100644 index 0000000000000000000000000000000000000000..ca0206610f735d387d7be8c495ec574f7d97e7bd GIT binary patch literal 12990 zcmeHNJ8xV?6rO$fdgE*?CkhWmE|6l8M2Uzu563|=%KCv6VI?W@aKghZeh^EJL9xX{ zqM)EbqM)LIf&z&qB|<4uA%yr5loV8mf(lXaeP`y}o!Q;HcO1ehL3gC}xqHvtbI&>7 zdCbn(B&J+mGUKK4@ULdCshelae)E)nZEEFY@#3s82P;D_H9tM~%1__^aen^($*;e> zb=8ayWk2_Hl1xlY%w4{8bz$l1^2JLpU&dEc9WkbUAmP1uoHKQkz zD{~8ri!+>KcyFKFJG%bP*3Pk+!;^BaZVqDJ(Y5vU<<+~mdwBAN$+N=Q+vaS(Z#fMk zoRKzX<+kNaTh1PjBxa1dy|vNW_T~@S`5RmB zt=-*TJ2tc4+T30fy{gu}J1r64kb4#LEM;uAK3s!&uL^zf)XB-$g=L$Rqf=6Dx(hhRE=pX~?APYGeQnMYT$d7^K$7~K7+RslFcnk!O zxkx-t7kCT=kNHSE&J=hI1dqJ#G3tJQG$zr|3ru!{$wU7pZ06*MuCbBX)Iz4YJzN{`KusUkymmmv?mZ*nuIX6d^3e9=P&k|D8pOc!_z1dpYh{Lr4> zm@HOVgXtl+Vi76Uy#wkYeY^Uw>3gPCPueF})f!G(_LWW9B%@rjedL{F$%$6^0m!N` zO3fGeuAjefjZf(fd$06)n{s~XPx~Axhs@&zpMy-1!|!&;IZlr5BTo0TMl~-v%{N7J zO4Z@6Rdc1O_TY;~r2RBkKIK}OyU}#2OVd@+^k-EQ)LpBFO2tpkSE3<(4Nb`pe2eEx zC!9PhYd0F6>(cOXj{=Qg?wo5JXaw6h@SNM}Eu0kFh<217rT0=wPZD!S<(d)9doGfl z_!uwOY{aH|YP|l~E7JmWd+CWx6FsT(5B9qJJSgtdE{O_9Wgh478R)I{C>48{xf;IE)U$x%viOYaqh>vT1Ktt0Y`lgFuPNP;Tc+&m+{O$ zu~4aRDWBh+rKh_r?U_%487%}xsm9K7!9?Sbm{2pd821Hh_Z&4B4}j8AscF>Nj@@8% zrc3k3Et`@gxz_KrKgL?fxE{&~PpBhh+z4far>Y{O&wq);ykpe$I=i3PS?9j$svnGY zMn7YU^}vrU#E-^Un#-&Uj47qerhc&n@tn^gRJ*uR%i`Y{>$HY*XYPr!tro7D1Pk#m zj3;G2mVd_w7*xKuw0Z~>yvlQy27L(_RDQEq2n80EPwYH>uDXctkW0$Jc_{@3l*igF z6qin)7%a3#w~^2;^`u7`a(&k3X|JRX02;5-s*7D7$JGbm3JRLKlYz=_brtD&9$ zC-Dg1lJl!WYZdoMwN`0{>_{C(eU$;K{g=7QA^C_^L`vD?k*DeU4c}Q$$(LTP6wk{V zjP)6HS%!U2WVAG!!G9`to`J+l36T!>?L7>TXBkL?lYw;YZ)1jjN&kZn*@i3;DYO=q z(vy$aPdUj2pMzLTIeXqrIoaoNF_vphJpaTXt{P8wY5bsbt)MGni7Tubw68ysnAP=! zi(6T5@Eu&AV(7bsA}{=3xw2a4z4nN~3f1*y7^UIfxfeyv%ve0|8p3EijUL1z=Jtwc z-GA&nG4bEh%!>FPZ)tYFC9)oI2eh*ueb$9FYX<8Q*KVvkp!^VPp{z$3uJd)(A>t-= zh&71MlM*9fs(1;uxThF{!x4j>*47604m)l6AFMv$T>pQQ!!ragVi3QmksrH=qw_Qt zb7BFpf6Kl@zaLpL6KOn=iJJY^u!d5?{)TuE&yJ2kN0%X? zd~%Wtz903?NB6|PjE8qC3>E{X+(CM3-pK)f88CW pCw5t^p2!^W=-BPHr70&v&+aOW97?5x-uF47_y6siVP~~!{sDSI4=4Zt literal 0 HcmV?d00001 diff --git a/testdata/gds/collect_added.gds b/testdata/gds/collect_added.gds new file mode 100644 index 0000000000000000000000000000000000000000..e4882b6d8354f758abd8171d00e5d3c2dcc31d6d GIT binary patch literal 4990 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 literal 0 HcmV?d00001 From 5988c92f052a9aee6dac958f8e5c914f5ecb1ca4 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 13 Nov 2020 01:19:18 +0100 Subject: [PATCH 11/11] Trying to save some (potentially expensive) layout updates on 'overwrite' cell name conflict resolution. --- src/db/db/dbCell.cc | 6 +++--- src/db/db/dbCommonReader.cc | 31 ++++++++++++++++++++++++------- src/db/db/dbCommonReader.h | 5 +++++ 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/db/db/dbCell.cc b/src/db/db/dbCell.cc index 0b1522e82..4a1adf813 100644 --- a/src/db/db/dbCell.cc +++ b/src/db/db/dbCell.cc @@ -506,7 +506,7 @@ Cell::collect_caller_cells (std::set &callers, const std::setis_valid_cell_index (*cc)) { callers.insert (*cc); mp_layout->cell (*cc).collect_caller_cells (callers, levels < 0 ? levels : levels - 1); } @@ -519,7 +519,7 @@ Cell::collect_caller_cells (std::set &callers, int levels) cons { if (levels != 0) { for (parent_cell_iterator cc = begin_parent_cells (); cc != end_parent_cells (); ++cc) { - if (callers.find (*cc) == callers.end ()) { + if (callers.find (*cc) == callers.end () && mp_layout->is_valid_cell_index (*cc)) { callers.insert (*cc); mp_layout->cell (*cc).collect_caller_cells (callers, levels < 0 ? levels : levels - 1); } @@ -538,7 +538,7 @@ Cell::collect_called_cells (std::set &called, int levels) const { if (levels != 0) { for (child_cell_iterator cc = begin_child_cells (); ! cc.at_end (); ++cc) { - if (called.find (*cc) == called.end ()) { + if (called.find (*cc) == called.end () && mp_layout->is_valid_cell_index (*cc)) { called.insert (*cc); mp_layout->cell (*cc).collect_called_cells (called, levels < 0 ? levels : levels - 1); } diff --git a/src/db/db/dbCommonReader.cc b/src/db/db/dbCommonReader.cc index 741cf1f0d..2d4afc86d 100644 --- a/src/db/db/dbCommonReader.cc +++ b/src/db/db/dbCommonReader.cc @@ -237,9 +237,21 @@ CommonReader::merge_cell (db::Layout &layout, db::cell_index_type target_cell_in // copy over the instances for (db::Cell::const_iterator i = src_cell.begin (); ! i.at_end (); ++i) { - target_cell.insert (*i); + // NOTE: cell indexed may be invalid because we delete subcells without update() + if (layout.is_valid_cell_index (i->cell_index ())) { + target_cell.insert (*i); + } } + merge_cell_without_instances (layout, target_cell_index, src_cell_index); +} + +void +CommonReader::merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const +{ + const db::Cell &src_cell = layout.cell (src_cell_index); + db::Cell &target_cell = layout.cell (target_cell_index); + // copy over the shapes for (unsigned int l = 0; l < layout.layers (); ++l) { if (layout.is_valid_layer (l) && ! src_cell.shapes (l).empty ()) { @@ -338,11 +350,17 @@ CommonReader::finish (db::Layout &layout) // we have a cell conflict - layout.force_update (); - if (m_cc_resolution == OverwriteCell && ! layout.cell (ci_new).is_ghost_cell ()) { - layout.prune_subcells (ci_org); + if (! layout.cell (ci_org).begin ().at_end ()) { + + // NOTE: because prune_subcells needs the parents for sub cells and we are going do delete + // the current cell, we cannot save the "update()" just by traversing bottom-up. + layout.force_update (); + layout.prune_subcells (ci_org); + + } + layout.cell (ci_org).clear_shapes (); merge_cell (layout, ci_org, ci_new); @@ -352,9 +370,8 @@ CommonReader::finish (db::Layout &layout) layout.prune_subcells (ci_new); layout.cell (ci_new).clear_shapes (); - // we need the instances of the cell we just cleaned - layout.force_update (); - merge_cell (layout, ci_org, ci_new); + // NOTE: ignore instances -> this saves us a layout update + merge_cell_without_instances (layout, ci_org, ci_new); } else { diff --git a/src/db/db/dbCommonReader.h b/src/db/db/dbCommonReader.h index 2bcecfaa7..f0ed56bcf 100644 --- a/src/db/db/dbCommonReader.h +++ b/src/db/db/dbCommonReader.h @@ -141,6 +141,11 @@ protected: */ void merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const; + /** + * @brief Merge (and delete) the src_cell into target_cell without instances + */ + void merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index) const; + private: std::map > m_id_map; std::map > m_name_map;