WIP: cell name conflict resolution modes, bugfixed first implementation

This commit is contained in:
Matthias Koefferlein 2020-11-03 00:13:55 +01:00
parent 85869c329d
commit a92ebd0e17
6 changed files with 153 additions and 36 deletions

View File

@ -59,7 +59,7 @@ CommonReader::make_cell (db::Layout &layout, const std::string &cn)
} else { } 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); m_name_map [cn] = std::make_pair (null_id, ci);
return ci; return ci;
@ -103,7 +103,7 @@ CommonReader::make_cell (db::Layout &layout, size_t id)
} else { } 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); m_id_map [id] = std::make_pair (std::string (), ci);
return 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 != 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)); 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 ()) { } else if (iid != m_id_map.end ()) {
m_name_map [cn] = std::make_pair (id, iid->second.second); m_name_map [cn] = std::make_pair (id, iid->second.second);
iid->second.first = cn;
} else if (iname != m_name_map.end ()) { } else if (iname != m_name_map.end ()) {
m_id_map [id] = std::make_pair (cn, iname->second.second); m_id_map [id] = std::make_pair (cn, iname->second.second);
iname->second.first = id;
} else { } 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_id_map [id] = std::make_pair (cn, ci);
m_name_map [cn] = std::make_pair (null_id, 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 { } 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); layout.cell (ci).set_ghost_cell (true);
m_id_map [id] = std::make_pair (std::string (), ci); 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 { } 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); layout.cell (ci).set_ghost_cell (true);
m_name_map [cn] = std::make_pair (null_id, ci); 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)"))); common_reader_error (tl::to_string (tr ("Some cell IDs don't have a name (see previous warnings)")));
} }
for (std::map<std::string, std::pair<size_t, db::cell_index_type> >::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<std::string, std::pair<size_t, db::cell_index_type> >::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; if (! has_conflict) {
db::cell_index_type ci_new = i->second.second;
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 for (std::map<std::string, std::pair<size_t, db::cell_index_type> >::const_iterator i = m_name_map.begin (); i != m_name_map.end () && ! has_conflict; ++i) {
// always rename for proxies layout.rename_cell (i->second.second, i->first.c_str ());
layout.rename_cell (i->second.second, i->first.c_str ()); }
} else { } else {
// we have a cell conflict // elaborate conflict resolution
layout.force_update ();
if (m_cc_resolution == OverwriteCell && ! layout.cell (ci_new).is_ghost_cell ()) { layout.force_update ();
layout.prune_subcells (ci_org); std::map<db::cell_index_type, std::string> new_cells;
layout.cell (ci_org).clear_shapes (); for (std::map<std::string, std::pair<size_t, db::cell_index_type> >::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); db::cell_index_type ci_new = *bu;
layout.cell (ci_new).clear_shapes ();
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<db::cell_index_type, std::string>::const_iterator i = new_cells.find (ci_new);
std::pair<bool, db::cell_index_type> 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 ());
} }
} }

View File

@ -1068,14 +1068,41 @@ Layout::add_cell (const char *name)
return new_index; 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 void
Layout::register_cell_name (const char *name, cell_index_type ci) Layout::register_cell_name (const char *name, cell_index_type ci)
{ {
// enter it's index and cell_name // enter it's index and cell_name
char *cp; char *cp;
cp = new char [strlen (name) + 1]; if (name == 0) {
strcpy (cp, name); cp = new char [1];
*cp = 0;
} else {
cp = new char [strlen (name) + 1];
strcpy (cp, name);
}
while (m_cell_names.size () < ci) { while (m_cell_names.size () < ci) {
char *e = new char [1]; 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_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 void

View File

@ -727,6 +727,16 @@ public:
*/ */
cell_index_type add_cell (const char *name = 0); 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 * @brief Rename a cell
* *

View File

@ -85,6 +85,16 @@ static void set_properties_enabled (db::LoadLayoutOptions *options, bool l)
options->get_options<db::CommonReaderOptions> ().enable_properties = l; options->get_options<db::CommonReaderOptions> ().enable_properties = l;
} }
static db::CommonReader::CellConflictResolution get_cell_conflict_resolution (const db::LoadLayoutOptions *options)
{
return options->get_options<db::CommonReaderOptions> ().cell_conflict_resolution;
}
static void set_cell_conflict_resolution (db::LoadLayoutOptions *options, db::CommonReader::CellConflictResolution cc)
{
options->get_options<db::CommonReaderOptions> ().cell_conflict_resolution = cc;
}
// extend lay::LoadLayoutOptions with the Common options // extend lay::LoadLayoutOptions with the Common options
static static
gsi::ClassExt<db::LoadLayoutOptions> common_reader_options ( gsi::ClassExt<db::LoadLayoutOptions> common_reader_options (
@ -157,6 +167,22 @@ gsi::ClassExt<db::LoadLayoutOptions> common_reader_options (
"@param enabled True, if properties should be read." "@param enabled True, if properties should be read."
"\n" "\n"
"Starting with version 0.25 this option only applies to GDS2 and OASIS format. Other formats provide their own configuration." "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."
), ),
"" ""
); );

View File

@ -366,6 +366,8 @@ TEST(Bug_121_1)
reader.read (layout); reader.read (layout);
} }
fflush(stdout);
std::string fn_au (tl::testsrc () + "/testdata/gds/bug_121_au1.gds"); std::string fn_au (tl::testsrc () + "/testdata/gds/bug_121_au1.gds");
db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1); db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1);
} }

View File

@ -1145,7 +1145,9 @@ OASISReader::do_read (db::Layout &layout)
unsigned long id = 0; unsigned long id = 0;
get (id); get (id);
if (has_cell (id)) {
std::pair<bool, db::cell_index_type> 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)); 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 (); std::string name = get_str ();
if (has_cell (name)) {
std::pair<bool, db::cell_index_type> 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 ())); error (tl::sprintf (tl::to_string (tr ("A cell with name %s is defined already")), name.c_str ()));
} }