mirror of https://github.com/KLayout/klayout.git
* 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.
This commit is contained in:
parent
4b0e122a83
commit
9d3d3e8df6
|
|
@ -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 ()) {
|
||||
|
||||
|
|
@ -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 ());
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 ())) {
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -300,27 +308,47 @@ HierarchyBuilder::leave_cell (const RecursiveShapeIterator * /*iter*/, const db:
|
|||
m_cell_stack.pop_back ();
|
||||
}
|
||||
|
||||
db::cell_index_type
|
||||
HierarchyBuilder::make_cell_variant (const HierarchyBuilder::CellMapKey &key, const std::string &cell_name)
|
||||
{
|
||||
m_cm_entry = m_cell_map.find (key);
|
||||
m_cm_new_entry = false;
|
||||
|
||||
db::cell_index_type new_cell;
|
||||
|
||||
if (m_cm_entry == m_cell_map.end ()) {
|
||||
|
||||
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) {
|
||||
|
||||
std::pair<db::cell_index_type, std::set<db::Box> > key (inst.object ().cell_index (), std::set<db::Box> ());
|
||||
|
||||
m_cm_entry = m_cell_map.find (key);
|
||||
m_cm_new_entry = false;
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -208,8 +208,36 @@ class DB_PUBLIC HierarchyBuilder
|
|||
: public db::RecursiveShapeReceiver
|
||||
{
|
||||
public:
|
||||
struct CellMapKey
|
||||
{
|
||||
CellMapKey ()
|
||||
: original_cell (0), inactive (false)
|
||||
{ }
|
||||
|
||||
typedef std::map<std::pair<db::cell_index_type, std::set<db::Box> >, db::cell_index_type> cell_map_type;
|
||||
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)
|
||||
{ }
|
||||
|
||||
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;
|
||||
|
||||
|
|
@ -329,6 +357,8 @@ public:
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -704,6 +704,19 @@ public:
|
|||
*/
|
||||
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;
|
||||
|
|
@ -760,11 +773,6 @@ private:
|
|||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -1233,7 +1233,7 @@ module DRC
|
|||
# @/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:
|
||||
|
|
@ -1809,7 +1809,7 @@ CODE
|
|||
|
||||
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 == "+*"
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ module DRC
|
|||
# @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.
|
||||
#
|
||||
|
|
|
|||
|
|
@ -22,14 +22,27 @@ module DRC
|
|||
@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
|
||||
|
|
@ -139,19 +152,34 @@ module DRC
|
|||
# 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
|
||||
|
||||
|
|
|
|||
|
|
@ -714,3 +714,44 @@ TEST(15_issue548)
|
|||
|
||||
db::compare_layouts (_this, layout, au, db::NoNormalization);
|
||||
}
|
||||
|
||||
// Problems with Source#select
|
||||
TEST(17_issue570)
|
||||
{
|
||||
std::string rs = tl::testsrc ();
|
||||
rs += "/testdata/drc/drcSimpleTests_17.drc";
|
||||
|
||||
std::string input = tl::testsrc ();
|
||||
input += "/testdata/drc/drcSimpleTests_17.gds";
|
||||
|
||||
std::string au = tl::testsrc ();
|
||||
au += "/testdata/drc/drcSimpleTests_au17.gds";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.gds");
|
||||
|
||||
{
|
||||
// Set some variables
|
||||
lym::Macro config;
|
||||
config.set_text (tl::sprintf (
|
||||
"$drc_test_source = '%s'\n"
|
||||
"$drc_test_target = '%s'\n"
|
||||
, input, output)
|
||||
);
|
||||
config.set_interpreter (lym::Macro::Ruby);
|
||||
EXPECT_EQ (config.run (), 0);
|
||||
}
|
||||
|
||||
lym::Macro drc;
|
||||
drc.load_from (rs);
|
||||
EXPECT_EQ (drc.run (), 0);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (_this, layout, au, db::NoNormalization);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ cells T*
|
|||
</pre>
|
||||
|
||||
<p>
|
||||
A cell expression can already be used by it's own. The report of such a query will simply contain the cells
|
||||
A cell expression can already be used by its own. The report of such a query will simply contain the cells
|
||||
selected by that expression. If combined with an action, such expressions already provide useful manipulation
|
||||
functionality.
|
||||
</p>
|
||||
|
|
@ -243,7 +243,7 @@ cells TOP..A
|
|||
is used in (including top cells and all child contexts). Used after a cell, it will return the cell
|
||||
plus all child cells in each possible context. Used before a cell it will deliver all contexts that cell
|
||||
is used in every top cells.
|
||||
The following query will deliver "TOP" plus all it's direct and indirect children:
|
||||
The following query will deliver "TOP" plus all its direct and indirect children:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
|
|
@ -398,7 +398,7 @@ with shapes on layer 6 from instances of TOP.. do initial_cell.shapes(<10/0&g
|
|||
</pre>
|
||||
|
||||
<p>
|
||||
That expression reads all shapes of cell "TOP" and it's children, inserts them into a new layer 10, datatype 0 and
|
||||
That expression reads all shapes of cell "TOP" and its children, inserts them into a new layer 10, datatype 0 and
|
||||
transforms the shape after it has been inserted. This expression makes use of the variables "initial_cell" (a Cell object
|
||||
representing the root cell of the cell query), "shape" (a pointer to the currently selected shape and "path_trans"
|
||||
(a Trans object representing the transformation of the current shape into the root cell of the query).
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ end
|
|||
</pre>
|
||||
</p><p>
|
||||
(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).
|
||||
</p><p>
|
||||
To apply cheats for device extraction, use the following scheme:
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ Predefined device extractors are:
|
|||
<li><a href="/about/drc_ref_global.xml#capacitor_with_bulk">global#capacitor_with_bulk</a> - A capacitor with a separate bulk terminal </li>
|
||||
</ul>
|
||||
</p><p>
|
||||
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.
|
||||
</p><p>
|
||||
|
|
|
|||
|
|
@ -233,19 +233,34 @@ To disable the TOP cell but enabled a hypothetical cell B below the top cell, us
|
|||
code:
|
||||
</p><p>
|
||||
<pre>
|
||||
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)
|
||||
...
|
||||
</pre>
|
||||
</p><p>
|
||||
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.
|
||||
</p><p>
|
||||
The following code will just select "B" without its children, because in the
|
||||
first "-*" selection, all cells including the children of "B" are disabled:
|
||||
</p><p>
|
||||
<pre>
|
||||
layout_with_selection = layout.select("-*", "+B")
|
||||
l1 = layout_with_selection.input(1, 0)
|
||||
layout_with_selection = source.select("-*", "+B")
|
||||
l1 = source.input(1, 0)
|
||||
...
|
||||
</pre>
|
||||
</p><p>
|
||||
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:
|
||||
</p><p>
|
||||
<pre>
|
||||
layout_with_selection = source.select("-", "+B")
|
||||
l1 = source.input(1, 0)
|
||||
...
|
||||
</pre>
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@
|
|||
<p>
|
||||
If the match expression includes a numerical range or wildcards
|
||||
for the layer or datatype number, by default all these layers
|
||||
will be combined into a single one, where it's layer or datatype number is derived
|
||||
will be combined into a single one, where its layer or datatype number is derived
|
||||
from the least permitted number.
|
||||
</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
edited. Instead, a library installed in the system comes with a technology
|
||||
association itself.</li>
|
||||
<li>File format options: technology specific file reader or writer options can be
|
||||
given. When a layout is saved, it will use the writer options from it's technology.
|
||||
given. When a layout is saved, it will use the writer options from its technology.
|
||||
When loading a layout, the reader options from the active technology will be used.</li>
|
||||
</ul>
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
cells with the same name will be used as child cells.
|
||||
</li>
|
||||
<li>
|
||||
<b>Deep copy</b>: In deep copy mode, the cell plus it's child cells are copied. All cells will be carried
|
||||
<b>Deep copy</b>: In deep copy mode, the cell plus its child cells are copied. All cells will be carried
|
||||
along and when pasting the cell, copies of all children will be created as well.
|
||||
</li>
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@
|
|||
<p>
|
||||
KLayout offers a unique feature for the PCell implementation: a PCell can employ "guiding shapes".
|
||||
"Guiding shapes" are shapes that do not appear as layout themselves but are used by the PCell
|
||||
to derive it's geometry from. For example the "rounded path" PCell of the "Basic" library
|
||||
to derive its geometry from. For example the "rounded path" PCell of the "Basic" library
|
||||
uses a path as a guiding shape. This path is manipulated to obtain the final shape.
|
||||
</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@
|
|||
</p>
|
||||
|
||||
<ul>
|
||||
<li><b>Shallow delete:</b> Just the cell (it's shapes and instances) are deleted, not
|
||||
<li><b>Shallow delete:</b> Just the cell (its shapes and instances) are deleted, not
|
||||
any cells referenced by this cell. Since cells might no longer be referenced after
|
||||
that, they may appear as new top cells in the layout.</li>
|
||||
<li><b>Deep delete:</b> The cell and all it's subcells are deleted, unless the subcells are
|
||||
<li><b>Deep delete:</b> The cell and all its subcells are deleted, unless the subcells are
|
||||
referenced otherwise (by cells that are not deleted).
|
||||
In this delete mode a complete hierarchy of cells can be removed without side effects.</li>
|
||||
<li><b>Complete delete:</b> The cell and all it's subcells are deleted, even if other cells
|
||||
<li><b>Complete delete:</b> The cell and all its subcells are deleted, even if other cells
|
||||
would reference these subcells.</li>
|
||||
</ul>
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
<keyword name="Editing"/>
|
||||
|
||||
<p>
|
||||
The "flatten cell" operation flattens a cell into all of it's parents.
|
||||
The "flatten cell" operation flattens a cell into all of its parents.
|
||||
This basically removes a cell by promoting her shapes and instances up in the hierarchy.
|
||||
</p>
|
||||
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
Cell flattening can be applied to single instances or cells as a whole.
|
||||
When applied to an instance, the individual instance is resolved into shapes. The
|
||||
instantiated cell will still exist afterwards. When applied to a cell, the cell
|
||||
will disappear and replaced by it's contents in all places it is used.
|
||||
will disappear and replaced by its contents in all places it is used.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
are brought up to the current cell's level and removed from the original cell.<br/>
|
||||
A non-destructive way of moving a shape up in the hierarchy is to copy and paste the shape. This does an
|
||||
explicit flattening of the shapes selected when inserting them.<br/>
|
||||
<b>Hint:</b> the current implementation removes the selected object from it's original cell. Since it only creates
|
||||
<b>Hint:</b> the current implementation removes the selected object from its original cell. Since it only creates
|
||||
new copies for the selected instances, the object ist lost for all other instances of the cell. This may create undesired
|
||||
side effects and it is likely that this behaviour will change in future implementations.
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@
|
|||
act as a wrapper to something else. In layouts, devices are often implemented as PCells and
|
||||
appear as specific cells for no other reason than being implemented in a subcell. The same
|
||||
might happen for schematic subcircuits which wrap a device. "Flattening" means that a circuit
|
||||
is removed and it's contents are integrated into the calling circuits.
|
||||
is removed and its contents are integrated into the calling circuits.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
The main window is divided into three parts: the left area is the hierarchy browser and navigator, the
|
||||
center part of the canvas and the right part is the layer list with the layer toolbox.
|
||||
The individual components can be rearranged, so the arrangement described is just the default
|
||||
arrangement. You can move a component to a new place by dragging it with it's title bar to
|
||||
arrangement. You can move a component to a new place by dragging it with its title bar to
|
||||
some other place or detach it from the main window to form a floating separate window.
|
||||
</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
In the same way, "Move To" allows one to reposition the selection to a certain point. The point which
|
||||
is positioned can be chosen relative to the bounding box of the selection. If first example,
|
||||
the lower-left corner of the selection is picked as the reference point and a certain position
|
||||
is given in the dialog, the selection is moved such that the lower left position of it's
|
||||
is given in the dialog, the selection is moved such that the lower left position of its
|
||||
bounding box will match the given coordinate.
|
||||
</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
<p>
|
||||
Choose "Pull In Other Layout" to combine other layouts already loaded into the
|
||||
current panel. Basically, KLayout allows viewsing a layout in multiple panels, either
|
||||
on it's own in different configurations or together with other layouts. "Pull In Other Layout"
|
||||
on its own in different configurations or together with other layouts. "Pull In Other Layout"
|
||||
allows configuration of a panel to show another layout which has been loaded into another panel.
|
||||
In that sense it's the reverse of closing one layout from a panel showing multiple layouts.
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
The Alignment of the labels can be specified too: whether the appear left or right-aligned
|
||||
or centered.
|
||||
</li>
|
||||
<li><b>Style:</b> the style determines how the ruler or it's components are drawn. This can be
|
||||
<li><b>Style:</b> the style determines how the ruler or its components are drawn. This can be
|
||||
"ruler-like" (with ticks), arrow style, a plain line or with cross markers at the end.
|
||||
</li>
|
||||
<li><b>Outline:</b> the outline determines how the two points forming the ruler are connected
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
</li>
|
||||
<li><b>Angle constraint:</b> the orientation of the ruler can be restricted in several ways, i.e.
|
||||
just being horizontal. By default, the ruler uses the global setting. It can however be configured
|
||||
to provide it's own constraint.
|
||||
to provide its own constraint.
|
||||
</li>
|
||||
<li><b>Object snapping:</b> each ruler can be configure to snap to the closest object edge or vertex.
|
||||
By default, the rulers use the global setting. It may be disabled however for each ruler.
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ Application::instance.main_window.views</pre>
|
|||
to a large degree, so different colors can be used for example. Markers are objects of class
|
||||
Marker (<class_doc href="Marker"/>).
|
||||
</li>
|
||||
<li><b>Local configuration</b>: be default, the layout view pulls it's configuration from the global
|
||||
<li><b>Local configuration</b>: be default, the layout view pulls its configuration from the global
|
||||
configuration database. It is possible however to override certain configuration parameters for a
|
||||
particular view. This allows for example to set the background color for a particular view without
|
||||
affecting the other views.
|
||||
|
|
@ -703,7 +703,7 @@ layout_view.insert_layer(lp, props)
|
|||
Width is a "weak" property. That means that for computing the effective width, child nodes
|
||||
can override the settings inherited from the parent nodes. A width of 0 is considered "not set" and does not
|
||||
override parent defined widths. Other properties like visibility are "strong", i.e.
|
||||
the parent can override the properties set for it's children. Another form of combination is "additive" where
|
||||
the parent can override the properties set for its children. Another form of combination is "additive" where
|
||||
the effective property value is the "sum" (or in general combination) of all local properties from parent
|
||||
to child.
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ layout.write("my_layout.gds")</pre>
|
|||
</p>
|
||||
|
||||
<p>
|
||||
A layout can provide and import PCells. PCells are cells that provide it's geometry through program code
|
||||
A layout can provide and import PCells. PCells are cells that provide its geometry through program code
|
||||
(for example written in Ruby) and provide parameters which can be adjusted to change the appearance of the
|
||||
cell. For each PCell a "declaration" must be provided which basically contains the code for the
|
||||
PCell and some information about the parameters provided by the PCell. PCells are stored in the layout
|
||||
|
|
@ -813,7 +813,7 @@ end</pre>
|
|||
|
||||
<keyword name="CellInstArray"/>
|
||||
<p>
|
||||
Despite it's name, a <class_doc href="CellInstArray"/> object holds a cell reference which is
|
||||
Despite its name, a <class_doc href="CellInstArray"/> object holds a cell reference which is
|
||||
not only an array, but also a single instances. The object represents a raw instance, in contrast to the
|
||||
Instance object which is basically a pointer to an instance inside the database. CellInstArray objects as raw instances can be created,
|
||||
copied, modified and stored in the usual containers, but once they are stored inside the Cell object, they can
|
||||
|
|
@ -1060,7 +1060,7 @@ end</pre>
|
|||
The <class_doc href="Shape"/> object provides a unified view to a geometrical primitive inside
|
||||
a Shapes container. It also plays an important role for addressing geometrical primitives
|
||||
inside a Shapes container. A Shape object has general methods and specific methods that apply
|
||||
depending on it's identity.
|
||||
depending on its identity.
|
||||
</p>
|
||||
|
||||
<h3>General methods</h3>
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ end</pre>
|
|||
<p>
|
||||
Events are the callback variant which is the easiest one to use. Using an event it is possible
|
||||
to directly attach a block of code to a callback. An event has a specific signature, i.e.
|
||||
the parameters it provides. The block can obtain this parameters by listing them in it's argument list.
|
||||
the parameters it provides. The block can obtain this parameters by listing them in its argument list.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
The <class_doc href="Point"/> object represents an integer coordinate in the 2-dimensional layout space,
|
||||
expressed in database units.
|
||||
That object provides the x and y coordinates through the <class_doc href="Point#x"/> and <class_doc href="Point#y"/> attributes. Points can be added,
|
||||
subtracted, the euclidian distance and it's square can be computed using the <class_doc href="Point#distance"/> and <class_doc href="Point#sq_distance"/>
|
||||
subtracted, the euclidian distance and its square can be computed using the <class_doc href="Point#distance"/> and <class_doc href="Point#sq_distance"/>
|
||||
methods. The <b>*</b> operator used with a factor as the second operand will scale both the x and y coordinates.
|
||||
</p>
|
||||
|
||||
|
|
@ -113,7 +113,7 @@
|
|||
<li><b>Box + Point</b>: computes the box that encloses the box and the point given
|
||||
as the second operand. It basically enlarges the first box so it includes the second point as well.
|
||||
</li>
|
||||
<li><b>contains?(Point)</b>: returns true, if the point is inside the box or on it's edges.
|
||||
<li><b>contains?(Point)</b>: returns true, if the point is inside the box or on its edges.
|
||||
</li>
|
||||
<li><b>enlarge(Point)</b>: will enlarge the box by the x and y coordinates of the Point. Basically the x value
|
||||
of the point is subtracted from the left side and added to the right. The same way, the y coordinate is added
|
||||
|
|
@ -272,7 +272,7 @@ box = RBA::Box::new(dbox)
|
|||
|
||||
<p>
|
||||
A <class_doc href="Path"/> object represents a line with a certain width. The figure above depicts the basic properties
|
||||
of a path. The basic geometry of a path is defined by it's spine - a sequence of points that the path follows.
|
||||
of a path. The basic geometry of a path is defined by its spine - a sequence of points that the path follows.
|
||||
By default, a path has rectangular end caps with variable length. The end caps can be round, in which case the extension
|
||||
should be half the path width to avoid paths which are not compatible with the GDS2 format. Round-ended paths return
|
||||
true on <class_doc href="Path#is_round?"/>. An example for such a path is depicted in the following figure:
|
||||
|
|
@ -641,7 +641,7 @@ ly.top_cell.shapes(ly.layer(100, 0)).insert(r11 & r21)
|
|||
<class_doc href="EdgePairs"/> edge pair collections, not regions. Each edge pair marks a
|
||||
violation of the given check.
|
||||
</p>
|
||||
<p><class_doc href="Region#extents"/> replaces each polygon with it's bounding box.</p>
|
||||
<p><class_doc href="Region#extents"/> replaces each polygon with its bounding box.</p>
|
||||
<p><class_doc href="Region#grid_check"/> performs an on-grid check returning edge pairs for off-grid markers.</p>
|
||||
<p><class_doc href="Region#holes"/> identifies holes and delivers a new region with the holes as filled polygons.</p>
|
||||
<p><class_doc href="Region#hulls"/> identifies holes and delivers a new region without the holes.</p>
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ end</pre>
|
|||
</p>
|
||||
|
||||
<p>
|
||||
When a Qt object is created in Ruby space with a parent, it's
|
||||
When a Qt object is created in Ruby space with a parent, its
|
||||
ownership is passed to the parent. It is safe however to keep a reference to that object, because
|
||||
KLayout's Ruby binding employs a special Ruby class internally (a proxy) which keeps track of the lifetime
|
||||
of the Qt object. If the parent is destroyed, the Qt object is destroyed as well. The internal Qt object will
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ cell.shapes(layer).insert(box)</pre>
|
|||
An exception to the lifetime control rule given above are Qt objects: a common pattern is to create Qt objects
|
||||
and add them to a container (i.e. widgets to a dialog). This implies a lifetime control transfer from
|
||||
Ruby to C++. RBA handles that case by explicitly transferring control when a QObject or one of the
|
||||
derived objects is created with a parent reference in Ruby code. Qt implements it's own mechanism of controlling
|
||||
derived objects is created with a parent reference in Ruby code. Qt implements its own mechanism of controlling
|
||||
the lifetime which includes monitoring of the lifetime of child objects. This feature makes transferring the
|
||||
control feasible for these kind of objects. For some Qt methods which are know to transfer the ownership
|
||||
of an object, the ownership is transferred explicitly.
|
||||
|
|
|
|||
|
|
@ -310,7 +310,7 @@ end</pre>
|
|||
is used for the cell tree and cell box labels. To avoid confusion, it should start with the name of the
|
||||
PCell. The bracket notation is not mandatory, but it's always a good idea to follow some common style.
|
||||
The information delivered by this method should be short but contain enough information so that a
|
||||
PCell variant can be distinguished from it's sibling.
|
||||
PCell variant can be distinguished from its sibling.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
source($drc_test_source)
|
||||
in_cell = source.select("-", "+S*")
|
||||
not_in_cell = source.select("-SPECIAL")
|
||||
in_cell_local = source.select("-*", "+SPECIAL")
|
||||
not_in_cell_local = source.select("+*", "-SPECIAL")
|
||||
|
||||
target($drc_test_target)
|
||||
|
||||
deep
|
||||
|
||||
input(2,0).output(2, 0)
|
||||
input(3,0).output(3, 0)
|
||||
|
||||
flat
|
||||
|
||||
in_cell.input(2, 0).output(102, 0)
|
||||
in_cell.input(3, 0).output(103, 0)
|
||||
|
||||
not_in_cell.input(2, 0).output(202, 0)
|
||||
not_in_cell.input(3, 0).output(203, 0)
|
||||
|
||||
in_cell_local.input(2, 0).output(302, 0)
|
||||
in_cell_local.input(3, 0).output(303, 0)
|
||||
|
||||
not_in_cell_local.input(2, 0).output(402, 0)
|
||||
not_in_cell_local.input(3, 0).output(403, 0)
|
||||
|
||||
deep
|
||||
|
||||
in_cell.input(2, 0).output(502, 0)
|
||||
in_cell.input(3, 0).output(503, 0)
|
||||
|
||||
not_in_cell.input(2, 0).output(602, 0)
|
||||
not_in_cell.input(3, 0).output(603, 0)
|
||||
|
||||
in_cell_local.input(2, 0).output(702, 0)
|
||||
in_cell_local.input(3, 0).output(703, 0)
|
||||
|
||||
not_in_cell_local.input(2, 0).output(802, 0)
|
||||
not_in_cell_local.input(3, 0).output(803, 0)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue