Skip to content

Commit

Permalink
Merge pull request #1694 from KLayout/waive-concept
Browse files Browse the repository at this point in the history
Waive concept
  • Loading branch information
klayoutmatthias authored Apr 30, 2024
2 parents d5a6708 + 14f9d57 commit d14f8b0
Show file tree
Hide file tree
Showing 36 changed files with 4,002 additions and 221 deletions.
20 changes: 14 additions & 6 deletions src/db/db/dbCellVariants.cc
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ VariantsCollectorBase::separate_variants (std::map<db::cell_index_type, std::map
if (! var_table) {
var_table = &var_table_intern;
}
tl_assert (var_table->empty ());

for (db::Layout::bottom_up_const_iterator c = mp_layout->begin_bottom_up (); c != mp_layout->end_bottom_up (); ++c) {

Expand All @@ -311,6 +312,9 @@ VariantsCollectorBase::separate_variants (std::map<db::cell_index_type, std::map

cell.clear_insts ();

bool original_cell_is_variant = false;
db::ICplxTrans original_cell_variant;

int index = 0;
for (auto v = vc->second.begin (); v != vc->second.end (); ++v, ++index) {

Expand All @@ -333,6 +337,8 @@ VariantsCollectorBase::separate_variants (std::map<db::cell_index_type, std::map

} else {
ci_var = *c;
original_cell_is_variant = true;
original_cell_variant = *v;
}

vt.insert (std::make_pair (*v, ci_var));
Expand All @@ -341,12 +347,14 @@ VariantsCollectorBase::separate_variants (std::map<db::cell_index_type, std::map
}

// correct the first (remaining) entry
if (! vt.begin ()->first.is_unity ()) {
std::set<db::ICplxTrans> &tv = m_variants [*c];
tv.clear ();
tv.insert (vt.begin ()->first);
} else {
m_variants.erase (*c);
if (original_cell_is_variant) {
if (! original_cell_variant.is_unity ()) {
std::set<db::ICplxTrans> &tv = m_variants [*c];
tv.clear ();
tv.insert (original_cell_variant);
} else {
m_variants.erase (*c);
}
}

} else {
Expand Down
35 changes: 32 additions & 3 deletions src/db/db/dbDeepShapeStore.cc
Original file line number Diff line number Diff line change
Expand Up @@ -298,28 +298,57 @@ struct DeepShapeStore::LayoutHolder
{
public:
VariantsCreatedListener (DeepShapeStore::LayoutHolder *lh, db::Layout *ly)
: mp_lh (lh)
: mp_lh (lh), m_dbu (ly->dbu ())
{
ly->variants_created_event.add (this, &VariantsCreatedListener::variants_created);
}

private:
std::string var_desc (const db::ICplxTrans &t)
{
std::string s;
if (t.is_mirror ()) {
s += "m";
s += tl::to_string (t.angle () * 0.5);
} else {
s += "r";
s += tl::to_string (t.angle ());
}
if (t.is_mag ()) {
s += tl::sprintf ("*%.9g", t.mag ());
}
if (t.disp () != db::Vector ()) {
s += tl::sprintf ("(%.12g,%.12g)", t.disp ().x () * m_dbu, t.disp ().y () * m_dbu);
}
return s;
}

void variants_created (const std::map<db::cell_index_type, std::map<db::ICplxTrans, db::cell_index_type> > *var_map)
{
for (std::map<db::cell_index_type, std::map<db::ICplxTrans, db::cell_index_type> >::const_iterator i = var_map->begin (); i != var_map->end (); ++i) {
for (std::map<db::ICplxTrans, db::cell_index_type>::const_iterator j = i->second.begin (); j != i->second.end (); ++j) {
mp_lh->builder.register_variant (i->first, j->second);
if (i->first != j->second) {
mp_lh->builder.register_variant (i->first, j->second, var_desc (j->first));
}
}
// NOTE: variant conversion events are registered after variant formation events, so we can
// base the formed variants (first pass) on the originals.
for (std::map<db::ICplxTrans, db::cell_index_type>::const_iterator j = i->second.begin (); j != i->second.end (); ++j) {
if (i->first == j->second) {
mp_lh->builder.register_variant (i->first, j->second, var_desc (j->first));
}
}
}
}

DeepShapeStore::LayoutHolder *mp_lh;
double m_dbu;
};

LayoutHolder (const db::ICplxTrans &trans)
: refs (0), layout (false), builder (&layout, trans), variants_created (this, &layout)
{
// .. nothing yet ..
layout.set_hierarchy_builder (&builder);
}

void add_layer_ref (unsigned int layer)
Expand Down
42 changes: 41 additions & 1 deletion src/db/db/dbHierarchyBuilder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -182,14 +182,24 @@ HierarchyBuilder::reset ()

m_cells_to_be_filled.clear ();
m_cell_map.clear ();
m_variants_of_sources_map.clear ();
m_cells_seen.clear ();
m_cell_stack.clear ();
m_cm_entry = null_iterator;
m_cm_new_entry = false;
}

const std::pair<db::cell_index_type, std::string> &
HierarchyBuilder::variant_of_source (db::cell_index_type target) const
{
static std::pair<db::cell_index_type, std::string> def (std::numeric_limits<db::cell_index_type>::max (), std::string ());

auto vs = m_variants_of_sources_map.find (target);
return vs != m_variants_of_sources_map.end () ? vs->second : def;
}

void
HierarchyBuilder::register_variant (db::cell_index_type non_var, db::cell_index_type var)
HierarchyBuilder::register_variant (db::cell_index_type non_var, db::cell_index_type var, const std::string &description)
{
// non_var (despite its name) may be a variant created previously.
variant_to_original_target_map_type::const_iterator v = m_variants_to_original_target_map.find (non_var);
Expand All @@ -199,11 +209,23 @@ HierarchyBuilder::register_variant (db::cell_index_type non_var, db::cell_index_

m_original_targets_to_variants_map [non_var].push_back (var);
m_variants_to_original_target_map.insert (std::make_pair (var, non_var));

auto vs = m_variants_of_sources_map.find (non_var);
if (vs != m_variants_of_sources_map.end ()) {
std::string new_description = vs->second.second;
if (! new_description.empty ()) {
new_description += ";";
}
new_description += description;
m_variants_of_sources_map [var] = std::make_pair (vs->second.first, new_description);
}
}

void
HierarchyBuilder::unregister_variant (db::cell_index_type var)
{
m_variants_of_sources_map.erase (var);

variant_to_original_target_map_type::iterator v = m_variants_to_original_target_map.find (var);
if (v == m_variants_to_original_target_map.end ()) {
return;
Expand Down Expand Up @@ -257,6 +279,7 @@ HierarchyBuilder::begin (const RecursiveShapeIterator *iter)
if (m_cm_entry == m_cell_map.end ()) {
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;
m_variants_of_sources_map.insert (std::make_pair (new_top_index, std::make_pair (key.original_cell, std::string ())));
}

db::Cell &new_top = mp_target->cell (m_cm_entry->second);
Expand Down Expand Up @@ -324,17 +347,34 @@ HierarchyBuilder::make_cell_variant (const HierarchyBuilder::CellMapKey &key, co
if (m_cm_entry == m_cell_map.end ()) {

std::string cn = cell_name;
std::string description;
if (! key.clip_region.empty ()) {
cn += "$CLIP_VAR";
description += "CLIP";

}
if (key.inactive) {
cn += "$DIS";
if (! description.empty ()) {
description += "/";
}
description += "DISABLED";
}

new_cell = mp_target->add_cell (cn.c_str ());

std::string new_name = mp_target->cell_name (new_cell);
if (new_name.size () > cn.size ()) {
// use cell name extension to uniquify the description
description += new_name.c_str () + cn.size ();
}

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

m_variants_of_sources_map.insert (std::make_pair (new_cell, std::make_pair (key.original_cell, description)));

} else {
new_cell = m_cm_entry->second;
}
Expand Down
18 changes: 17 additions & 1 deletion src/db/db/dbHierarchyBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ class DB_PUBLIC HierarchyBuilder
* The first cell is either the original, non-variant target cell or itself a variant.
* The second cell will be registered as a variant of the first one.
*/
void register_variant (db::cell_index_type non_var, db::cell_index_type var);
void register_variant (db::cell_index_type non_var, db::cell_index_type var, const std::string &description);

/**
* @brief Unregisters a cell as a variant
Expand All @@ -404,8 +404,23 @@ class DB_PUBLIC HierarchyBuilder
return m_variants_to_original_target_map.find (ci) != m_variants_to_original_target_map.end ();
}

/**
* @brief Gets the information about the target/source + variant relationship
*
* For a target cell, returns a pointer to a pair with the cell index of the source cell and
* a string describing the variant this cell forms of the source cell.
*
* The description string is empty if the cell is not a variant.
*/
const std::pair<db::cell_index_type, std::string> &variant_of_source (db::cell_index_type target) const;

/**
* @brief Gets the original target for a variant cell
*
* The original cell is the first-generation target-space cell that variants have been created for.
* This still can mean that the original cell is a clip variant of a source cell.
*
* Target-to-source variants can be derived with "variant_of_source".
*/
db::cell_index_type original_target_for_variant (db::cell_index_type ci) const;

Expand All @@ -419,6 +434,7 @@ class DB_PUBLIC HierarchyBuilder
cell_map_type m_cell_map;
original_target_to_variants_map_type m_original_targets_to_variants_map;
variant_to_original_target_map_type m_variants_to_original_target_map;
std::map<db::cell_index_type, std::pair<db::cell_index_type, std::string> > m_variants_of_sources_map;

std::set<cell_map_type::key_type> m_cells_seen;
std::set<db::cell_index_type> m_cells_to_be_filled;
Expand Down
3 changes: 3 additions & 0 deletions src/db/db/dbLayout.cc
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ LayoutOrCellContextInfo::has_meta_info () const
Layout::Layout (db::Manager *manager)
: db::Object (manager),
mp_library (0),
mp_builder (0),
m_cells_size (0),
m_invalid (0),
m_top_cells (0),
Expand All @@ -454,6 +455,7 @@ Layout::Layout (db::Manager *manager)
Layout::Layout (bool editable, db::Manager *manager)
: db::Object (manager),
mp_library (0),
mp_builder (0),
m_cells_size (0),
m_invalid (0),
m_top_cells (0),
Expand All @@ -473,6 +475,7 @@ Layout::Layout (const db::Layout &layout)
tl::Object (),
tl::UniqueId (),
mp_library (0),
mp_builder (0),
m_cells_size (0),
m_invalid (0),
m_top_cells (0),
Expand Down
20 changes: 20 additions & 0 deletions src/db/db/dbLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class Technology;
class CellMapping;
class LayerMapping;
class VariantsCollectorBase;
class HierarchyBuilder;

template <class Coord> class generic_repository;
typedef generic_repository<db::Coord> GenericRepository;
Expand Down Expand Up @@ -2113,6 +2114,24 @@ class DB_PUBLIC Layout
*/
const MetaInfo &meta_info (db::cell_index_type ci, meta_info_name_id_type name_id) const;

/**
* @brief Sets the hierarchy builder reference
* Used internally
*/
void set_hierarchy_builder (db::HierarchyBuilder *builder)
{
mp_builder = builder;
}

/**
* @brief Gets the hierarchy builder
* Used internally
*/
db::HierarchyBuilder *builder () const
{
return mp_builder;
}

/**
* @brief This event is triggered when the technology changes
*/
Expand All @@ -2138,6 +2157,7 @@ class DB_PUBLIC Layout

private:
db::Library *mp_library;
db::HierarchyBuilder *mp_builder;
cell_list m_cells;
size_t m_cells_size;
cell_ptr_vector m_cell_ptrs;
Expand Down
43 changes: 43 additions & 0 deletions src/doc/doc/manual/drc_basic.xml
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,49 @@ gate.width(min_width).output("gate_width", "Gate width violations")</pre>
Hence such files can only be run from the macro IDE.
</p>

<h2>DRC waiving flow</h2>

<p>
DRC waiving is a process of signing off DRC violations that cannot be avoided.
Usually DRC waiving is not encouraged, as manufacturability of the device cannot
be guaranteed if DRC violations are present. Even worse, giving a non-clean layout
into manufacturing may create a contamination risk that manufacturers will try
to avoid. Hence, non-DRC-clean layouts are usually rejected.
</p>

<p>
Still there are some legit reasons for DRC waiving. Sometimes DRC rules do not apply
because a specific technology option is not used by the device and corresponding
DRC rules do not apply. Or, a certain DRC rule may be a recommended rule, and violating
it is not forbidden. In that case, a DRC violation can be waived at your own risk.
Waiving is not a formal process. Usually, the manufacturer will ask for a confirmation
if DRC violations are present. KLayout can help documenting violations and copying
the waivers from one DRC run to the next.
</p>

<p>
The DRC waiving flow of KLayout is the following:
</p>

<ul>
<li>In the initial step, a RDB database is created by the DRC run, using the "report" command with a destination file.</li>
<li>This report is inspected in the marker browser. You can add comments, set flags and add screenshots. This is
also the time to waive DRC violations that you deem necessary to be waived. The marker browser has a "waive"
button which sets or resets the waived flag of the selected markers.</li>
<li>When finished, save the edited database to a 'waiver DB' using the marker browser's 'Save As Waiver DB' feature from
the File menu. Technically, this will write the report database to a second file. This second file is named
like the original one, with a ".w" added to the file name.</li>
<li>When you run the DRC again, KLayout will find this waiver DB file and apply attributes from the waiver DB
to the current report database. These attributes include the flags, images and comments.
This will - among the other annotations - apply the waived flag to the report database items.</li>
</ul>

<p>
In the waiving step, KLayout will apply attributes to items with the same value (i.e. shape), category and cell.
This specifically means, that when you rename a cell, waivers will no longer be applied, or - in the worst case -
be applied to the wrong cell. Hence, waiving should be done late in the process, when cell names are unlikely to change.
</p>

<h2>Using KLayout as a standalone DRC engine</h2>

<p>
Expand Down
Loading

0 comments on commit d14f8b0

Please sign in to comment.