Skip to content

Commit

Permalink
Fixed #651 (DRC "select" feature issues) (#654)
Browse files Browse the repository at this point in the history
* WIP: added test case, fixed dup problem and '-' shortcut

* WIP: updated DRC doc and could not resist the temptation to fix 'it's' vs. 'its'

* Deep mode also working with select now. Updated tests.
  • Loading branch information
klayoutmatthias committed Oct 10, 2020
1 parent 4b0e122 commit 9d3d3e8
Show file tree
Hide file tree
Showing 35 changed files with 290 additions and 97 deletions.
16 changes: 9 additions & 7 deletions src/db/db/dbDeepShapeStore.cc
Expand Up @@ -911,7 +911,7 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout
cm = m_delivery_mapping_cache.insert (std::make_pair (key, db::CellMapping ())).first;

// collects the cell mappings we skip because they are variants (variant building or box variants)
std::map<db::cell_index_type, std::pair<db::cell_index_type, std::set<db::Box> > > cm_skipped_variants;
std::map<db::cell_index_type, db::HierarchyBuilder::CellMapKey> cm_skipped_variants;

if (into_layout == original_builder.source ().layout () && &into_layout->cell (into_cell) == original_builder.source ().top_cell ()) {

Expand All @@ -925,14 +925,14 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout
HierarchyBuilder::cell_map_type::const_iterator mm = m;
++mm;
bool skip = original_builder.is_variant (m->second); // skip variant cells
while (mm != original_builder.end_cell_map () && mm->first.first == m->first.first) {
while (mm != original_builder.end_cell_map () && mm->first.original_cell == m->first.original_cell) {
// we have cell (box) variants and cannot simply map
++mm;
skip = true;
}

if (! skip) {
cm->second.map (m->second, m->first.first);
cm->second.map (m->second, m->first.original_cell);
} else {
for (HierarchyBuilder::cell_map_type::const_iterator n = m; n != mm; ++n) {
tl_assert (cm_skipped_variants.find (n->second) == cm_skipped_variants.end ());
Expand Down Expand Up @@ -968,17 +968,19 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout

db::cell_index_type var_org = original_builder.original_target_for_variant (np->first);

std::map<db::cell_index_type, std::pair<db::cell_index_type, std::set<db::Box> > >::const_iterator icm = cm_skipped_variants.find (var_org);
std::map<db::cell_index_type, db::HierarchyBuilder::CellMapKey>::const_iterator icm = cm_skipped_variants.find (var_org);
if (icm != cm_skipped_variants.end ()) {

// create the variant clone in the original layout too and delete this cell
VariantsCollectorBase::copy_shapes (*into_layout, np->second, icm->second.first);
cells_to_delete.insert (icm->second.first);
VariantsCollectorBase::copy_shapes (*into_layout, np->second, icm->second.original_cell);
cells_to_delete.insert (icm->second.original_cell);

// forget the original cell (now separated into variants) and map the variants back into the
// DSS layout
original_builder.unmap (icm->second);
original_builder.map (std::make_pair (np->second, icm->second.second), np->first);
db::HierarchyBuilder::CellMapKey k = icm->second;
k.original_cell = np->second;
original_builder.map (k, np->first);

// forget the variant as now it's a real cell in the source layout
original_builder.unregister_variant (np->first);
Expand Down
74 changes: 45 additions & 29 deletions src/db/db/dbHierarchyBuilder.cc
Expand Up @@ -62,6 +62,14 @@ compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIter
return iter1.max_depth () < iter2.max_depth () ? -1 : 1;
}

// take potential selection of cells into account
if (iter1.disables () != iter2.disables ()) {
return iter1.disables () < iter2.disables () ? -1 : 1;
}
if (iter1.enables () != iter2.enables ()) {
return iter1.enables () < iter2.enables () ? -1 : 1;
}

// if a region is set, the hierarchical appearance is the same only if the layers and
// complex region are identical
if ((iter1.region () == db::Box::world ()) != (iter2.region () == db::Box::world ())) {
Expand Down Expand Up @@ -238,11 +246,11 @@ HierarchyBuilder::begin (const RecursiveShapeIterator *iter)
return;
}

std::pair<db::cell_index_type, std::set<db::Box> > key (iter->top_cell ()->cell_index (), std::set<db::Box> ());
CellMapKey key (iter->top_cell ()->cell_index (), false, std::set<db::Box> ());
m_cm_entry = m_cell_map.find (key);

if (m_cm_entry == m_cell_map.end ()) {
db::cell_index_type new_top_index = mp_target->add_cell (iter->layout ()->cell_name (key.first));
db::cell_index_type new_top_index = mp_target->add_cell (iter->layout ()->cell_name (key.original_cell));
m_cm_entry = m_cell_map.insert (std::make_pair (key, new_top_index)).first;
}

Expand Down Expand Up @@ -300,27 +308,47 @@ HierarchyBuilder::leave_cell (const RecursiveShapeIterator * /*iter*/, const db:
m_cell_stack.pop_back ();
}

HierarchyBuilder::new_inst_mode
HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
db::cell_index_type
HierarchyBuilder::make_cell_variant (const HierarchyBuilder::CellMapKey &key, const std::string &cell_name)
{
if (all) {
m_cm_entry = m_cell_map.find (key);
m_cm_new_entry = false;

std::pair<db::cell_index_type, std::set<db::Box> > key (inst.object ().cell_index (), std::set<db::Box> ());
db::cell_index_type new_cell;

m_cm_entry = m_cell_map.find (key);
m_cm_new_entry = false;
if (m_cm_entry == m_cell_map.end ()) {

if (m_cm_entry == m_cell_map.end ()) {
db::cell_index_type new_cell = mp_target->add_cell (iter->layout ()->cell_name (inst.object ().cell_index ()));
m_cm_entry = m_cell_map.insert (std::make_pair (key, new_cell)).first;
m_cm_new_entry = true;
m_cells_to_be_filled.insert (new_cell);
std::string cn = cell_name;
if (! key.clip_region.empty ()) {
cn += "$CLIP_VAR";
}
if (key.inactive) {
cn += "$DIS";
}
new_cell = mp_target->add_cell (cn.c_str ());
m_cm_entry = m_cell_map.insert (std::make_pair (key, new_cell)).first;
m_cm_new_entry = true;
m_cells_to_be_filled.insert (new_cell);

} else {
new_cell = m_cm_entry->second;
}

return new_cell;
}

HierarchyBuilder::new_inst_mode
HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
{
if (all) {

CellMapKey key (inst.object ().cell_index (), iter->is_child_inactive (inst.object ().cell_index ()), std::set<db::Box> ());
db::cell_index_type new_cell = make_cell_variant (key, iter->layout ()->cell_name (inst.object ().cell_index ()));

// for new cells, create this instance
if (m_cell_stack.back ().first) {
db::CellInstArray new_inst (inst, &mp_target->array_repository ());
new_inst.object () = db::CellInst (m_cm_entry->second);
new_inst.object () = db::CellInst (new_cell);
new_inst.transform_into (m_trans);
for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) {
(*c)->insert (new_inst);
Expand Down Expand Up @@ -353,24 +381,12 @@ HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db:
return false;
}

std::pair<db::cell_index_type, std::set<db::Box> > key (inst.object ().cell_index (), clip_variant.second);
m_cm_entry = m_cell_map.find (key);
m_cm_new_entry = false;

if (m_cm_entry == m_cell_map.end ()) {
std::string suffix;
if (! key.second.empty ()) {
suffix = "$CLIP_VAR";
}
db::cell_index_type new_cell = mp_target->add_cell ((std::string (iter->layout ()->cell_name (inst.object ().cell_index ())) + suffix).c_str ());
m_cm_entry = m_cell_map.insert (std::make_pair (key, new_cell)).first;
m_cm_new_entry = true;
m_cells_to_be_filled.insert (new_cell);
}
CellMapKey key (inst.object ().cell_index (), iter->is_child_inactive (inst.object ().cell_index ()), clip_variant.second);
db::cell_index_type new_cell = make_cell_variant (key, iter->layout ()->cell_name (inst.object ().cell_index ()));

// for a new cell, create this instance
if (m_cell_stack.back ().first) {
db::CellInstArray new_inst (db::CellInst (m_cm_entry->second), trans);
db::CellInstArray new_inst (db::CellInst (new_cell), trans);
new_inst.transform_into (m_trans);
for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) {
(*c)->insert (new_inst);
Expand Down
32 changes: 31 additions & 1 deletion src/db/db/dbHierarchyBuilder.h
Expand Up @@ -208,8 +208,36 @@ class DB_PUBLIC HierarchyBuilder
: public db::RecursiveShapeReceiver
{
public:
struct CellMapKey
{
CellMapKey ()
: original_cell (0), inactive (false)
{ }

CellMapKey (db::cell_index_type _original_cell, bool _inactive, const std::set<db::Box> &_clip_region)
: original_cell (_original_cell), inactive (_inactive), clip_region (_clip_region)
{ }

typedef std::map<std::pair<db::cell_index_type, std::set<db::Box> >, db::cell_index_type> cell_map_type;
bool operator== (const CellMapKey &other) const
{
return original_cell == other.original_cell && inactive == other.inactive && clip_region == other.clip_region;
}

bool operator< (const CellMapKey &other) const
{
if (original_cell != other.original_cell) { return original_cell < other.original_cell; }
if (inactive != other.inactive) { return inactive < other.inactive; }
if (clip_region != other.clip_region) { return clip_region < other.clip_region; }
return false;
}

db::cell_index_type original_cell;
bool inactive;
std::set<db::Box> clip_region;
};


typedef std::map<CellMapKey, db::cell_index_type> cell_map_type;
typedef std::map<db::cell_index_type, std::vector<db::cell_index_type> > original_target_to_variants_map_type;
typedef std::map<db::cell_index_type, db::cell_index_type> variant_to_original_target_map_type;

Expand Down Expand Up @@ -329,6 +357,8 @@ class DB_PUBLIC HierarchyBuilder
db::cell_index_type original_target_for_variant (db::cell_index_type ci) const;

private:
db::cell_index_type make_cell_variant (const HierarchyBuilder::CellMapKey &key, const std::string &cell_name);

tl::weak_ptr<db::Layout> mp_target;
HierarchyBuilderShapeReceiver *mp_pipe;
bool m_initial_pass;
Expand Down
19 changes: 15 additions & 4 deletions src/db/db/dbRecursiveShapeIterator.cc
Expand Up @@ -864,10 +864,9 @@ RecursiveShapeIterator::new_cell (RecursiveShapeReceiver *receiver) const
m_layer = m_layers.front ();
}

if (! m_start.empty () && m_start.find (cell_index ()) != m_start.end ()) {
set_inactive (false);
} else if (! m_stop.empty () && m_stop.find (cell_index ()) != m_stop.end ()) {
set_inactive (true);
bool new_cell_inactive = is_child_inactive (cell_index ());
if (is_inactive () != new_cell_inactive) {
set_inactive (new_cell_inactive);
}

new_layer ();
Expand Down Expand Up @@ -975,6 +974,18 @@ RecursiveShapeIterator::is_outside_complex_region (const db::Box &box) const
}
}

bool
RecursiveShapeIterator::is_child_inactive (db::cell_index_type new_child) const
{
bool inactive = is_inactive ();
if (! m_start.empty () && m_start.find (new_child) != m_start.end ()) {
inactive = false;
} else if (! m_stop.empty () && m_stop.find (new_child) != m_stop.end ()) {
inactive = true;
}
return inactive;
}

void
RecursiveShapeIterator::push (RecursiveShapeReceiver *receiver)
{
Expand Down
18 changes: 13 additions & 5 deletions src/db/db/dbRecursiveShapeIterator.h
Expand Up @@ -704,6 +704,19 @@ class DB_PUBLIC RecursiveShapeIterator
*/
void push (RecursiveShapeReceiver *receiver);

/**
* @brief Returns a value indicating whether the current cell is inactive (disabled)
*/
bool is_inactive () const
{
return (reinterpret_cast<size_t> (mp_cell) & size_t (1)) != 0;
}

/**
* @brief Returns a value indicating whether a new child cell of the current cell will be inactive
*/
bool is_child_inactive (db::cell_index_type new_child) const;

private:
std::vector<unsigned int> m_layers;
bool m_has_layers;
Expand Down Expand Up @@ -760,11 +773,6 @@ class DB_PUBLIC RecursiveShapeIterator

bool is_outside_complex_region (const db::Box &box) const;

bool is_inactive () const
{
return (reinterpret_cast<size_t> (mp_cell) & size_t (1)) != 0;
}

void set_inactive (bool a) const
{
size_t c = reinterpret_cast<size_t> (mp_cell);
Expand Down
4 changes: 2 additions & 2 deletions src/drc/drc/built-in-macros/_drc_engine.rb
Expand Up @@ -1233,7 +1233,7 @@ def clip(*args)
# @/code
#
# (Technically, the cheat code block is a Ruby Proc and cannot create variables
# outside it's scope. Hence the results of this code block have to be passed
# outside its scope. Hence the results of this code block have to be passed
# through the "cheat" method).
#
# To apply cheats for device extraction, use the following scheme:
Expand Down Expand Up @@ -1809,7 +1809,7 @@ def _input(layout, cell_index, layers, sel, box, clip, overlapping, shape_flags)

sel.each do |s|
if s == "-"
iter.unselect_cells(cell.cell_index)
iter.unselect_cells([cell_index])
elsif s == "-*"
iter.unselect_all_cells
elsif s == "+*"
Expand Down
2 changes: 1 addition & 1 deletion src/drc/drc/built-in-macros/_drc_netter.rb
Expand Up @@ -156,7 +156,7 @@ def connect_global(l, name)
# @li \global#capacitor_with_bulk - A capacitor with a separate bulk terminal @/li
# @/ul
#
# Each device class (e.g. n-MOS/p-MOS or high Vt/low Vt) needs it's own instance
# Each device class (e.g. n-MOS/p-MOS or high Vt/low Vt) needs its own instance
# of device extractor. The device extractor beside the algorithm and specific
# extraction settings defines the name of the device to be built.
#
Expand Down
44 changes: 36 additions & 8 deletions src/drc/drc/built-in-macros/_drc_source.rb
Expand Up @@ -22,14 +22,27 @@ def initialize(engine, layout, layout_var, cell, path)
@layout_var = layout_var
@path = path
@cell = cell
@inside = nil
@box = nil
@layers = nil
@sel = []
@clip = false
@overlapping = false
@tmp_layers = []
end

# Conceptual deep copy (not including the temp layers)
def dup
d = DRCSource::new(@engine, @layout, @layout_var, @cell, @path)
d._init_internal(@box ? @box.dup : nil, @sel.dup, @clip, @overlapping)
d
end

# internal copy initialization
def _init_internal(box, sel, clip, overlapping)
@box = box
@sel = sel
@clip = clip
@overlapping = overlapping
end

# %DRC%
# @name layout
Expand Down Expand Up @@ -139,19 +152,34 @@ def inplace_select(*args)
# code:
#
# @code
# layout_with_selection = layout.select("-TOP", "+B")
# l1 = layout_with_selection.input(1, 0)
# layout_with_selection = source.select("-TOP", "+B")
# l1 = source.input(1, 0)
# ...
# @/code
#
# Please note that the sample above will deliver the children of "B" because there is
# nothing said about how to proceed with cells other than "TOP" or "B".
# The following code will just select "B" without it's children, because in the
# nothing said about how to proceed with cells other than "TOP" or "B". Conceptually,
# the instantiation path of a cell will be matched against the different filters in the
# order they are given.
# A matching negative expression will disable the cell, a matching positive expression
# will enable the cell. Hence, every cell that has a "B" in the instantiation path
# is enabled.
#
# The following code will just select "B" without its children, because in the
# first "-*" selection, all cells including the children of "B" are disabled:
#
# @code
# layout_with_selection = layout.select("-*", "+B")
# l1 = layout_with_selection.input(1, 0)
# layout_with_selection = source.select("-*", "+B")
# l1 = source.input(1, 0)
# ...
# @/code
#
# The short form "-" will disable the top cell. This code is identical to the first example
# and will start with a disabled top cell regardless of its name:
#
# @code
# layout_with_selection = source.select("-", "+B")
# l1 = source.input(1, 0)
# ...
# @/code

Expand Down

0 comments on commit 9d3d3e8

Please sign in to comment.