From a92ebd0e17909af5f862250b63b79bf7c66cd151 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 3 Nov 2020 00:13:55 +0100 Subject: [PATCH] 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 ())); }