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 ();