Skip to content

Commit ff7d7f2

Browse files
Merge pull request #2089 from KLayout/bugfix/issue-2087
Bugfix/issue 2087
2 parents 131f36a + 60af530 commit ff7d7f2

19 files changed

+276
-29
lines changed

src/db/db/dbFillTool.cc

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,16 @@ class GenericRasterizer
7777
}
7878

7979
// because the rasterizer can't handle overlapping cells we need to multiply the row and columns steps
80-
// with an integer until the effective rasterizer pitch get big enough.
80+
// with an integer until the effective rasterizer pitch gets big enough.
8181
m_row_steps *= (m_dim.x () - 1) / (m_row_steps * m_row_step.x ()) + 1;
8282
m_column_steps *= (m_dim.y () - 1) / (m_column_steps * m_column_step.y ()) + 1;
8383

8484
db::Box fp_bbox = fp.box ();
8585

8686
// compensate for distortion by sheared kernel
87-
fp_bbox.enlarge (db::Vector (db::coord_traits<db::Coord>::rounded (double (fp_bbox.height ()) * std::abs (m_column_step.x ()) / dy), db::coord_traits<db::Coord>::rounded (double (fp_bbox.width ()) * std::abs (m_row_step.y ()) / dx)));
87+
db::Coord ex = std::max (std::abs (db::Coord (m_column_step.x () * m_column_steps)), std::abs (db::Coord (m_row_step.x () * m_row_steps)));
88+
db::Coord ey = std::max (std::abs (db::Coord (m_column_step.y () * m_column_steps)), std::abs (db::Coord (m_row_step.y () * m_row_steps)));
89+
fp_bbox.enlarge (db::Vector (ex, ey));
8890

8991
int columns_per_rows = (int (m_row_steps) * m_row_step.y ()) / dy;
9092
int rows_per_columns = (int (m_column_steps) * m_column_step.x ()) / dx;
@@ -167,6 +169,11 @@ class GenericRasterizer
167169
return m_area_maps [i];
168170
}
169171

172+
db::AreaMap &area_map (unsigned int i)
173+
{
174+
return m_area_maps [i];
175+
}
176+
170177
private:
171178
std::vector<db::AreaMap> m_area_maps;
172179
db::Vector m_row_step, m_column_step;
@@ -246,7 +253,7 @@ fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type f
246253

247254
for (unsigned int i = 0; i < am.area_maps (); ++i) {
248255

249-
const db::AreaMap &am1 = am.area_map (i);
256+
db::AreaMap &am1 = am.area_map (i);
250257

251258
size_t nx = am1.nx ();
252259
size_t ny = am1.ny ();
@@ -263,31 +270,54 @@ fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type f
263270
++jj;
264271
}
265272

266-
ninsts += (jj - j);
267-
268273
db::Vector p0 = (am1.p0 () - db::Point ()) - kernel_origin;
269274
p0 += db::Vector (i * am1.d ().x (), j * am1.d ().y ());
270275

271276
db::CellInstArray array;
272277

273-
if (jj > j + 1) {
274-
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0), db::Vector (0, am1.d ().y ()), db::Vector (), (unsigned long) (jj - j), 1);
278+
// try to expand the array in x direction
279+
size_t ii = i + 1;
280+
for ( ; ii < nx; ++ii) {
281+
bool all = true;
282+
for (size_t k = j; k < jj && all; ++k) {
283+
all = am1.get (ii, k) == am1.pixel_area ();
284+
}
285+
if (all) {
286+
for (size_t k = j; k < jj; ++k) {
287+
// disable pixel, so we do not see it again in the following columns
288+
am1.get (ii, k) = 0;
289+
}
290+
} else {
291+
break;
292+
}
293+
}
294+
295+
ninsts += (jj - j) * (ii - i);
296+
297+
if (jj > j + 1 || ii > i + 1) {
298+
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0), db::Vector (0, am1.d ().y ()), db::Vector (am1.d ().x (), 0), (unsigned long) (jj - j), (unsigned long) (ii - i));
275299
} else {
276300
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0));
277301
}
278302

279303
{
280304
// In case we run this from a tiling processor we need to lock against multithread races
281-
tl::MutexLocker locker (&db::TilingProcessor::output_lock ());
305+
tl_assert (cell->layout () != 0);
306+
tl::MutexLocker locker (&cell->layout ()->lock ());
282307
cell->insert (array);
283308
}
284309

285310
if (remaining_parts) {
286-
if (am1.d ().y () == am1.p ().y ()) {
287-
filled_regions.push_back (db::Polygon (db::Box (db::Point (), db::Point (am1.p ().x (), am1.p ().y () * db::Coord (jj - j))).moved (kernel_origin + p0)));
311+
if (am1.d ().y () == am1.p ().y () && am1.d ().x () == am1.p ().x ()) {
312+
db::Box fill_box (db::Point (), db::Point (am1.p ().x () * db::Coord (ii - i), am1.p ().y () * db::Coord (jj - j)));
313+
filled_regions.push_back (db::Polygon (fill_box.enlarged (fill_margin).moved (kernel_origin + p0)));
288314
} else {
315+
db::Box fill_box (db::Point (), db::Point () + am1.p ());
316+
fill_box.enlarge (fill_margin);
289317
for (size_t k = 0; k < jj - j; ++k) {
290-
filled_regions.push_back (db::Polygon (db::Box (db::Point (), db::Point () + am1.p ()).moved (kernel_origin + p0 + db::Vector (0, am1.d ().y () * db::Coord (k)))));
318+
for (size_t l = 0; l < ii - i; ++l) {
319+
filled_regions.push_back (db::Polygon (fill_box.moved (kernel_origin + p0 + db::Vector (am1.d ().x () * db::Coord (l), am1.d ().y () * db::Coord (k)))));
320+
}
291321
}
292322
}
293323
}
@@ -314,19 +344,9 @@ fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type f
314344
if (any_fill) {
315345

316346
if (remaining_parts) {
317-
318347
std::vector <db::Polygon> fp1;
319-
320-
if (fill_margin != db::Vector ()) {
321-
ep.size (filled_regions, fill_margin.x (), fill_margin.y (), fp1, 3 /*mode*/, false /*=don't resolve holes*/);
322-
filled_regions.swap (fp1);
323-
fp1.clear ();
324-
}
325-
326348
fp1.push_back (fp0);
327349
ep.boolean (fp1, filled_regions, *remaining_parts, db::BooleanOp::ANotB, false /*=don't resolve holes*/);
328-
329-
330350
}
331351

332352
return true;

src/db/db/dbPolygonTools.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1918,7 +1918,7 @@ rasterize_impl (const db::polygon<C> &polygon, db::area_map<C> &am)
19181918

19191919
area_type aa = a;
19201920

1921-
if (dx == py) {
1921+
if (dx == px) {
19221922

19231923
box_type cell (x, y, xx, yy);
19241924

src/db/db/dbRecursiveShapeIterator.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,15 +500,21 @@ RecursiveShapeIterator::validate (RecursiveShapeReceiver *receiver) const
500500
}
501501

502502
if (mp_shapes) {
503+
503504
// Ensures the trees are built properly - this is important in MT contexts (i.e. TilingProcessor)
504505
// TODO: get rid of that const cast
505506
(const_cast <db::Shapes *> (mp_shapes))->update ();
507+
506508
start_shapes ();
509+
507510
} else if (mp_layout && (! m_has_layers || m_current_layer < m_layers.size ())) {
511+
508512
// Ensures the trees are built properly - this is important in MT contexts (i.e. TilingProcessor)
509513
mp_layout->update ();
514+
510515
new_cell (receiver);
511516
next_shape (receiver);
517+
512518
}
513519

514520
if (mp_layout && ! at_end ()) {

src/db/db/dbShapes.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,10 +1127,20 @@ void Shapes::reset_bbox_dirty ()
11271127

11281128
void Shapes::update ()
11291129
{
1130+
std::unique_ptr<tl::MutexLocker> locker;
1131+
1132+
// If not in a layout context, we should lock here against multiple calls from different threads.
1133+
// In a layout context, the Layout object will do that for us.
1134+
if (layout () == 0) {
1135+
static tl::Mutex lock;
1136+
locker.reset (new tl::MutexLocker (&lock));
1137+
}
1138+
11301139
for (tl::vector<LayerBase *>::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) {
11311140
(*l)->sort ();
11321141
(*l)->update_bbox ();
11331142
}
1143+
11341144
set_dirty (false);
11351145
}
11361146

src/db/unit_tests/dbFillToolTests.cc

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,3 +345,35 @@ TEST(5)
345345
CHECKPOINT();
346346
db::compare_layouts (_this, ly, tl::testdata () + "/algo/fill_tool_au5.oas", db::WriteOAS);
347347
}
348+
349+
// issue #2087
350+
TEST(6)
351+
{
352+
db::Layout ly;
353+
{
354+
std::string fn (tl::testdata ());
355+
fn += "/algo/fill_tool6.gds";
356+
tl::InputStream stream (fn);
357+
db::Reader reader (stream);
358+
reader.read (ly);
359+
}
360+
361+
db::cell_index_type fill_cell = ly.cell_by_name ("FILL_CELL").second;
362+
db::cell_index_type top_cell = ly.cell_by_name ("TOP").second;
363+
unsigned int fill_layer = ly.get_layer (db::LayerProperties (1, 0));
364+
365+
db::Region fill_region (db::RecursiveShapeIterator (ly, ly.cell (top_cell), fill_layer));
366+
367+
db::Region remaining_polygons;
368+
369+
db::Vector rs (2500, 0);
370+
db::Vector cs (650, 2500);
371+
db::Box fc_box = ly.cell (fill_cell).bbox ();
372+
db::fill_region (&ly.cell (top_cell), fill_region, fill_cell, fc_box, rs, cs, db::Point (), false, &remaining_polygons);
373+
374+
unsigned int l100 = ly.insert_layer (db::LayerProperties (100, 0));
375+
remaining_polygons.insert_into (&ly, top_cell, l100);
376+
377+
CHECKPOINT();
378+
db::compare_layouts (_this, ly, tl::testdata () + "/algo/fill_tool_au6.oas", db::WriteOAS);
379+
}

src/drc/drc/built-in-macros/_drc_layer.rb

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5460,8 +5460,17 @@ def output(*args)
54605460
# as the reference point. The reference point will also defined the footprint of the fill cell - more precisely
54615461
# the lower left corner. When step vectors are given, the fill cell's footprint is taken to be a rectangle
54625462
# having the horizontal and vertical step pitch for width and height respectively. This way the fill cells
5463-
# will be arrange seamlessly. However, the cell's dimensions can be changed, so that the fill cells
5463+
# will be arrange seamlessly.
5464+
#
5465+
# However, the cell's dimensions can be changed, so that the fill cells
54645466
# can overlap or there is a space between the cells. To change the dimensions use the "dim" method.
5467+
# This example will use a fill cell footprint of 1x1 micrometers, regardless of the step pitch:
5468+
#
5469+
# @code
5470+
# p = fill_pattern("FILL_CELL")
5471+
# p.shape(1, 0, box(0.0, 0.0, 1.0, 1.0))
5472+
# p.dim(1.0, 1.0)
5473+
# @/code
54655474
#
54665475
# The following example specifies a fill cell with an active area of -0.5 .. 1.5 in both directions
54675476
# (2 micron width and height). With these dimensions the fill cell's footprint is independent of the
@@ -5474,6 +5483,18 @@ def output(*args)
54745483
# p.dim(2.0, 2.0)
54755484
# @/code
54765485
#
5486+
# Finally, the fill cell can be given a margin: this is a space around the fill cell which needs
5487+
# to be inside the fill region. Hence, the margin can be used to implement a distance, the fill
5488+
# cells (more precisely: their footprints) will maintain to the outside border of the fill region.
5489+
# The following example implements a margin of 200 nm in horizontal and 250 nm in vertical direction:
5490+
#
5491+
# @code
5492+
# p = fill_pattern("FILL_CELL")
5493+
# p.shape(1, 0, box(0.0, 0.0, 1.0, 1.0))
5494+
# p.dim(1.0, 1.0)
5495+
# p.margin(0.2, 0.25)
5496+
# @/code
5497+
#
54775498
# With these ingredients will can use the fill function. The first example fills the polygons
54785499
# of "to_fill" with an orthogonal pattern of 1x1 micron rectangles with a pitch of 2 microns:
54795500
#
@@ -5574,6 +5595,7 @@ def _fill(with_left, *args)
55745595
fill_cell = pattern.create_cell(@engine._output_layout, @engine)
55755596
top_cell = @engine._output_cell
55765597
fc_box = dbu_trans * pattern.cell_box(row_step.x, column_step.y)
5598+
fill_margin = dbu_trans * pattern.fill_margin
55775599
rs = dbu_trans * row_step
55785600
cs = dbu_trans * column_step
55795601
origin = origin ? dbu_trans * origin : nil
@@ -5604,6 +5626,7 @@ def _fill(with_left, *args)
56045626
tp.var("rs", rs)
56055627
tp.var("cs", cs)
56065628
tp.var("origin", origin)
5629+
tp.var("fill_margin", fill_margin)
56075630
tp.var("fc_index", fc_index)
56085631
tp.var("repeat", repeat)
56095632
tp.var("with_left", with_left)
@@ -5616,8 +5639,8 @@ def _fill(with_left, *args)
56165639
tile_box = tile_box & tc_box;
56175640
var left = with_left ? Region.new : nil;
56185641
repeat ?
5619-
(region & tile_box).fill_multi(top_cell, fc_index, fc_box, rs, cs, Vector.new, left, _tile.bbox) :
5620-
(region & tile_box).fill(top_cell, fc_index, fc_box, rs, cs, origin, left, Vector.new, left, _tile.bbox);
5642+
(region & tile_box).fill_multi(top_cell, fc_index, fc_box, rs, cs, fill_margin, left, _tile.bbox) :
5643+
(region & tile_box).fill(top_cell, fc_index, fc_box, rs, cs, origin, left, fill_margin, left, _tile.bbox);
56215644
with_left && _output(#{result_arg}, left)
56225645
)
56235646
END
@@ -5639,9 +5662,9 @@ def _fill(with_left, *args)
56395662

56405663
@engine.run_timed("\"#{m}\" in: #{@engine.src_line}", self.data) do
56415664
if repeat
5642-
self.data.fill_multi(top_cell, fc_index, fc_box, rs, cs, RBA::Vector::new, result)
5665+
self.data.fill_multi(top_cell, fc_index, fc_box, rs, cs, fill_margin, result)
56435666
else
5644-
self.data.fill(top_cell, fc_index, fc_box, rs, cs, origin, result, RBA::Vector::new, result)
5667+
self.data.fill(top_cell, fc_index, fc_box, rs, cs, origin, result, fill_margin, result)
56455668
end
56465669
end
56475670

src/drc/drc/built-in-macros/_drc_tags.rb

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ def initialize(name)
335335
@shapes = []
336336
@origin = nil
337337
@dim = nil
338+
@margin = RBA::DVector::new
338339
end
339340

340341
def create_cell(layout, engine)
@@ -350,7 +351,11 @@ def create_cell(layout, engine)
350351
def cell_box(def_w, def_h)
351352
o = @origin || self._computed_origin
352353
d = @dim || RBA::DVector::new(def_w, def_h)
353-
RBA::DBox::new(o, o + d)
354+
RBA::DBox::new(o, o + d).enlarged(@margin)
355+
end
356+
357+
def fill_margin
358+
-@margin
354359
end
355360

356361
def default_xpitch
@@ -454,6 +459,20 @@ def dim(w, h)
454459

455460
end
456461

462+
def margin(w, h)
463+
464+
if !w.is_a?(1.class) && !w.is_a?(1.0.class)
465+
raise("w argument not numeric FillCell#dim")
466+
end
467+
if !h.is_a?(1.class) && !h.is_a?(1.0.class)
468+
raise("h argument not numeric FillCell#dim")
469+
end
470+
@margin = RBA::DVector::new(w, h)
471+
472+
self
473+
474+
end
475+
457476
end
458477

459478
# A wrapper for the fill step definition

0 commit comments

Comments
 (0)