Merge pull request #877 from KLayout/drc-extent-of-cells

Implemented extent(cell_filter) for DRC, added Layout#cells with name…
This commit is contained in:
Matthias Köfferlein 2021-07-21 23:37:10 +02:00 committed by GitHub
commit df022316b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 164 additions and 24 deletions

View File

@ -379,6 +379,12 @@ OriginalLayerRegion::init ()
void
OriginalLayerRegion::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const
{
// explicitly update the layout if the source is equal to the target
// (needed because we lock the layout below and no update would happen)
if (layout == m_iter.layout ()) {
layout->update ();
}
db::Shapes &sh = layout->cell (into_cell).shapes (into_layer);
// NOTE: if the source (r) is from the same layout than the shapes live in, we better

View File

@ -41,6 +41,7 @@
#include "dbCellMapping.h"
#include "dbTechnology.h"
#include "tlStream.h"
#include "tlGlobPattern.h"
namespace gsi
{
@ -708,6 +709,22 @@ static db::Cell *cell_from_name (db::Layout *ly, const std::string &name)
}
}
static std::vector<db::Cell *> cells_from_name (db::Layout *layout, const std::string &filter)
{
tl::GlobPattern gp (filter);
std::vector<db::Cell *> result;
db::Layout::top_down_iterator td = layout->begin_top_down ();
while (td != layout->end_top_down ()) {
if (gp.match (layout->cell_name (*td))) {
result.push_back (&layout->cell (*td));
}
++td;
}
return result;
}
static std::vector<db::Cell *> top_cells (db::Layout *layout)
{
std::vector<db::Cell *> tc;
@ -1488,6 +1505,14 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"\n"
"@return The number of cells (the maximum cell index)\n"
) +
gsi::method_ext ("cells", &cells_from_name, gsi::arg ("name_filter"),
"@brief Gets the cell objects for a given name filter\n"
"\n"
"@param name_filter The cell name filter (glob pattern)\n"
"@return A list of \\Cell object of the cells matching the pattern\n"
"\n"
"This method has been introduced in version 0.27.3.\n"
) +
gsi::method_ext ("cell", &cell_from_name, gsi::arg ("name"),
"@brief Gets a cell object from the cell name\n"
"\n"

View File

@ -1484,13 +1484,14 @@ module DRC
# %DRC%
# @name extent
# @brief Creates a new layer with the bounding box of the default source
# @brief Creates a new layer with the bounding box of the default source or cell bounding boxes
# @synopsis extent
# @synopsis extent(cell_filter)
# See \Source#extent for a description of that function.
def extent
def extent(cell_filter = nil)
self._context("extent") do
layout.extent
layout.extent(cell_filter)
end
end
@ -1615,6 +1616,8 @@ CODE
# # shapes now will be taken from the given rectangle and clipped to it
# l1 = input(1, 0)
# @/code
#
# To remove the clip condition, call "clip" without any arguments.
def clip(*args)
self._context("clip") do
@ -2638,16 +2641,6 @@ CODE
end
end
private
def _make_string(v)
if v.class.respond_to?(:from_s)
v.class.to_s + "::from_s(" + v.to_s.inspect + ")"
else
v.inspect
end
end
def _input(layout, cell_index, layers, sel, box, clip, overlapping, shape_flags, global_trans, cls)
if layers.empty? && ! @deep
@ -2714,6 +2707,16 @@ CODE
end
private
def _make_string(v)
if v.class.respond_to?(:from_s)
v.class.to_s + "::from_s(" + v.to_s.inspect + ")"
else
v.inspect
end
end
def _layout(name)
@layout_sources[name].layout
end

View File

@ -101,7 +101,9 @@ module DRC
@engine._context(method) do
box = nil
if args.size == 1
if args.size == 0
# unclip
elsif args.size == 1
box = args[0]
box.is_a?(RBA::DBox) || raise("Method requires a box specification")
elsif args.size == 2
@ -112,7 +114,7 @@ module DRC
else
raise("Invalid number of arguments (1, 2 or 4 expected)")
end
@box = RBA::Box::from_dbox(box * (1.0 / @layout.dbu))
@box = box && RBA::Box::from_dbox(box * (1.0 / @layout.dbu))
self
@ -311,24 +313,55 @@ CODE
# %DRC%
# @name extent
# @brief Returns a layer with the bounding box of the selected layout
# @brief Returns a layer with the bounding box of the selected layout or cells
# @synopsis source.extent
# @synopsis source.extent(cell_filter)
#
# Without an argument, the extent method returns a layer with the bounding box
# of the top cell. With a cell filter argument, the method returns a layer
# with the bounding boxes of the selected cells. The cell filter is a glob
# pattern.
#
# The extent function is useful to invert a layer:
#
# @code
# inverse_1 = extent.sized(100.0) - input(1, 0)
# @/code
#
# The following example returns the bounding boxes of all cells whose
# names start with "A":
#
# @code
# a_cells = extent("A*")
# @/code
def extent
def extent(cell_filter = nil)
@engine._context("extent") do
layer = input
if @box
layer.insert(RBA::DBox::from_ibox(@box) * @layout.dbu)
else
layer.insert((RBA::DBox::from_ibox(@cell.bbox) * @layout.dbu).transformed(@global_trans))
if cell_filter
cell_filter.is_a?(String) || raise("Invalid cell filter argument - must be a string")
end
if cell_filter
tmp = @layout_var.insert_layer(RBA::LayerInfo::new)
@tmp_layers << tmp
@layout_var.cells(cell_filter).each do |cell|
cell.shapes(tmp).insert(cell.bbox)
end
layer = DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, [tmp], @sel, @box, @clip, @overlapping, RBA::Shapes::SAll, @global_trans, RBA::Region))
else
layer = input
layer.insert((RBA::DBox::from_ibox(@cell.bbox) * @layout.dbu).transformed(@global_trans))
if @box
layer.data &= RBA::Region::new(@box)
end
end
layer
end
end
# %DRC%

View File

@ -1303,3 +1303,12 @@ TEST(51_epInternalAngle)
run_test (_this, "51", false);
}
TEST(52_cellWiseExtent)
{
run_test (_this, "52", false);
}
TEST(53_cellWiseExtentWithClip)
{
run_test (_this, "53", false);
}

View File

@ -306,6 +306,8 @@ clip(0.mm, 0.mm, 0.5.mm, 0.6.mm)
# shapes now will be taken from the given rectangle and clipped to it
l1 = input(1, 0)
</pre>
</p><p>
To remove the clip condition, call "clip" without any arguments.
</p>
<a name="connect"/><h2>"connect" - Specifies a connection between two layers</h2>
<keyword name="connect"/>
@ -619,11 +621,12 @@ actual edges from the first input (see <a href="#separation">separation</a> for
<p>
Similar to <a href="#log">log</a>, but the message is printed formatted as an error
</p>
<a name="extent"/><h2>"extent" - Creates a new layer with the bounding box of the default source</h2>
<a name="extent"/><h2>"extent" - Creates a new layer with the bounding box of the default source or cell bounding boxes</h2>
<keyword name="extent"/>
<p>Usage:</p>
<ul>
<li><tt>extent</tt></li>
<li><tt>extent(cell_filter)</tt></li>
</ul>
<p>
See <a href="/about/drc_ref_source.xml#extent">Source#extent</a> for a description of that function.

View File

@ -96,18 +96,31 @@ Use the global version of "edges" without a source object to address the default
</p><p>
This method has been introduced in version 0.27.
</p>
<a name="extent"/><h2>"extent" - Returns a layer with the bounding box of the selected layout</h2>
<a name="extent"/><h2>"extent" - Returns a layer with the bounding box of the selected layout or cells</h2>
<keyword name="extent"/>
<p>Usage:</p>
<ul>
<li><tt>source.extent</tt></li>
<li><tt>source.extent(cell_filter)</tt></li>
</ul>
<p>
Without an argument, the extent method returns a layer with the bounding box
of the top cell. With a cell filter argument, the method returns a layer
with the bounding boxes of the selected cells. The cell filter is a glob
pattern.
</p><p>
The extent function is useful to invert a layer:
</p><p>
<pre>
inverse_1 = extent.sized(100.0) - input(1, 0)
</pre>
</p><p>
The following example returns the bounding boxes of all cells whose
names start with "A":
</p><p>
<pre>
a_cells = extent("A*")
</pre>
</p>
<a name="global_transform"/><h2>"global_transform" - Gets or sets a global transformation</h2>
<keyword name="global_transform"/>

14
testdata/drc/drcSimpleTests_52.drc vendored Normal file
View File

@ -0,0 +1,14 @@
source $drc_test_source
target $drc_test_target
extent.output(2000)
extent("PMOS*").output(2001)
extent("NMOS*").output(2002)
deep
extent.output(2100)
extent("PMOS*").output(2101)
extent("NMOS*").output(2102)

BIN
testdata/drc/drcSimpleTests_52.gds vendored Normal file

Binary file not shown.

16
testdata/drc/drcSimpleTests_53.drc vendored Normal file
View File

@ -0,0 +1,16 @@
source $drc_test_source
target $drc_test_target
clip(7.0, -1.0, 15.0, 10.0)
extent.output(2000)
extent("PMOS*").output(2001)
extent("NMOS*").output(2002)
deep
extent.output(2100)
extent("PMOS*").output(2101)
extent("NMOS*").output(2102)

BIN
testdata/drc/drcSimpleTests_53.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au52.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au53.gds vendored Normal file

Binary file not shown.

View File

@ -79,6 +79,7 @@ class DBLayout_TestClass < TestBase
assert_equal( ly.cell_name(ci), "new_cell" )
assert_equal( ly.cell_by_name("new_cell"), ci )
assert_equal( ly.cells("A*"), [] )
assert_equal( ly.cell("new_cell").name, "new_cell" )
assert_equal( ly.cell("x").inspect, "nil" )
@ -1175,6 +1176,23 @@ class DBLayout_TestClass < TestBase
end
# Layout#cells
def test_15
g = RBA::Layout::new
c1 = g.create_cell("B1")
c2 = g.create_cell("B2")
c0 = g.create_cell("A")
c0.insert(RBA::CellInstArray::new(c1.cell_index, RBA::Trans::new))
c0.insert(RBA::CellInstArray::new(c2.cell_index, RBA::Trans::new))
assert_equal(g.cells("B*").collect(&:name).join(","), "B1,B2")
assert_equal(g.cells("*").collect(&:name).join(","), "A,B1,B2")
assert_equal(g.cells("A").collect(&:name).join(","), "A")
assert_equal(g.cells("X").collect(&:name).join(","), "")
end
end
load("test_epilogue.rb")