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 {
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<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;
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<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) {
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<db::cell_index_type, std::string> new_cells;
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);
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<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;
}
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

View File

@ -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.

View File

@ -85,6 +85,16 @@ static void set_properties_enabled (db::LoadLayoutOptions *options, bool 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
static
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."
"\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."
),
""
);

View File

@ -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);
}

View File

@ -1145,7 +1145,9 @@ OASISReader::do_read (db::Layout &layout)
unsigned long id = 0;
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));
}
@ -1158,7 +1160,9 @@ OASISReader::do_read (db::Layout &layout)
}
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 ()));
}