mirror of https://github.com/KLayout/klayout.git
WIP: bug fixes, more tests for complex DRC
This commit is contained in:
parent
f993e4c31b
commit
7093dfd0eb
|
|
@ -1553,7 +1553,8 @@ void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,
|
||||||
|
|
||||||
for (std::vector<unsigned int>::const_iterator il = contexts.intruder_layers ().begin (); il != contexts.intruder_layers ().end (); ++il) {
|
for (std::vector<unsigned int>::const_iterator il = contexts.intruder_layers ().begin (); il != contexts.intruder_layers ().end (); ++il) {
|
||||||
|
|
||||||
db::box_convert <db::CellInst, true> inst_bcii (*mp_intruder_layout, contexts.actual_intruder_layer (*il));
|
unsigned int ail = contexts.actual_intruder_layer (*il);
|
||||||
|
db::box_convert <db::CellInst, true> inst_bcii (*mp_intruder_layout, ail);
|
||||||
|
|
||||||
for (std::unordered_set<const db::CellInstArray *>::const_iterator j = i->second.first.begin (); j != i->second.first.end (); ++j) {
|
for (std::unordered_set<const db::CellInstArray *>::const_iterator j = i->second.first.begin (); j != i->second.first.end (); ++j) {
|
||||||
for (db::CellInstArray::iterator k = (*j)->begin_touching (safe_box_enlarged (nbox, -1, -1), inst_bcii); ! k.at_end (); ++k) {
|
for (db::CellInstArray::iterator k = (*j)->begin_touching (safe_box_enlarged (nbox, -1, -1), inst_bcii); ! k.at_end (); ++k) {
|
||||||
|
|
@ -1561,7 +1562,7 @@ void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,
|
||||||
// NOTE: no self-interactions
|
// NOTE: no self-interactions
|
||||||
if (i->first != *j || tn != tk) {
|
if (i->first != *j || tn != tk) {
|
||||||
// optimize the intruder instance so it will be as low as possible
|
// optimize the intruder instance so it will be as low as possible
|
||||||
std::pair<bool, db::CellInstArray> ei = effective_instance (contexts.subject_layer (), i->first->object ().cell_index (), contexts.actual_intruder_layer (*il), (*j)->object ().cell_index (), tni * tk, dist);
|
std::pair<bool, db::CellInstArray> ei = effective_instance (contexts.subject_layer (), i->first->object ().cell_index (), ail, (*j)->object ().cell_index (), tni * tk, dist);
|
||||||
if (ei.first) {
|
if (ei.first) {
|
||||||
intruders_below.first.insert (ei.second);
|
intruders_below.first.insert (ei.second);
|
||||||
}
|
}
|
||||||
|
|
@ -1902,7 +1903,7 @@ local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_conte
|
||||||
|
|
||||||
db::box_convert<db::CellInstArray, true> inst_bci (*mp_intruder_layout, ail);
|
db::box_convert<db::CellInstArray, true> inst_bci (*mp_intruder_layout, ail);
|
||||||
|
|
||||||
typename std::map<unsigned int, std::set<TI> >::const_iterator ipl = intruders.second.find (ail);
|
typename std::map<unsigned int, std::set<TI> >::const_iterator ipl = intruders.second.find (*il);
|
||||||
static std::set<TI> empty_intruders;
|
static std::set<TI> empty_intruders;
|
||||||
|
|
||||||
if (! subject_shapes->empty () && (intruder_shapes || ipl != intruders.second.end ())) {
|
if (! subject_shapes->empty () && (intruder_shapes || ipl != intruders.second.end ())) {
|
||||||
|
|
@ -1932,7 +1933,7 @@ local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_conte
|
||||||
|
|
||||||
unsigned int inst_id = 0;
|
unsigned int inst_id = 0;
|
||||||
|
|
||||||
if (subject_cell == intruder_cell && contexts.subject_layer () == ail) {
|
if (subject_cell == intruder_cell && contexts.subject_layer () == ail && !foreign) {
|
||||||
|
|
||||||
// Same cell, same layer -> no shape to child instance interactions because this will be taken care of
|
// Same cell, same layer -> no shape to child instance interactions because this will be taken care of
|
||||||
// by the instances themselves (and their intruders). This also means, we prefer to deal with
|
// by the instances themselves (and their intruders). This also means, we prefer to deal with
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,56 @@ void insert_into_hash (std::unordered_set<T> &hash, const T &shape)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class TS>
|
||||||
|
static
|
||||||
|
uint32_t compute_error_pattern (const TS &subject, std::unordered_set<db::EdgePair> &result, std::map<db::Edge, uint32_t> &edges_with_errors)
|
||||||
|
{
|
||||||
|
uint32_t p = 1;
|
||||||
|
for (typename TS::polygon_edge_iterator e = subject.begin_edge (); ! e.at_end (); ++e) {
|
||||||
|
edges_with_errors [*e] = p;
|
||||||
|
p <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t error_pattern = 0;
|
||||||
|
for (std::unordered_set<db::EdgePair>::const_iterator ep = result.begin (); ep != result.end (); ++ep) {
|
||||||
|
std::map<db::Edge, unsigned int>::iterator i = edges_with_errors.find (ep->first ());
|
||||||
|
if (i != edges_with_errors.end ()) {
|
||||||
|
if ((error_pattern & i->second) == 0) {
|
||||||
|
error_pattern |= i->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return error_pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool rect_filter_can_be_waived (uint32_t error_pattern, uint32_t rect_filter)
|
||||||
|
{
|
||||||
|
if (! error_pattern) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool can_be_waived = false;
|
||||||
|
|
||||||
|
// decode pattern: consider each group of 4 bits and match them against the error pattern in their four rotation variants
|
||||||
|
uint32_t p32 = (uint32_t) rect_filter;
|
||||||
|
while (p32 != 0 && ! can_be_waived) {
|
||||||
|
|
||||||
|
uint32_t p4 = p32 & 0xf;
|
||||||
|
p32 >>= 4;
|
||||||
|
|
||||||
|
if (p4 > 0) {
|
||||||
|
for (unsigned int r = 0; r < 4 && ! can_be_waived; ++r) {
|
||||||
|
can_be_waived = (error_pattern == p4);
|
||||||
|
p4 = ((p4 << 1) & 0xf) | ((p4 & 0x8) >> 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return can_be_waived;
|
||||||
|
}
|
||||||
|
|
||||||
template <class TS, class TI>
|
template <class TS, class TI>
|
||||||
void
|
void
|
||||||
check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<db::EdgePair> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<db::EdgePair> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||||
|
|
@ -413,52 +463,16 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int p = 1;
|
std::map<db::Edge, uint32_t> edges_with_errors;
|
||||||
std::map<db::Edge, unsigned int> edges_with_errors;
|
unsigned int error_pattern = compute_error_pattern (subject, result, edges_with_errors);
|
||||||
for (typename TS::polygon_edge_iterator e = subject.begin_edge (); ! e.at_end (); ++e) {
|
|
||||||
edges_with_errors [*e] = p;
|
|
||||||
p <<= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int error_pattern = 0;
|
if (rect_filter_can_be_waived (error_pattern, (uint32_t) m_options.rect_filter)) {
|
||||||
for (std::unordered_set<db::EdgePair>::const_iterator ep = result.begin (); ep != result.end (); ++ep) {
|
|
||||||
std::map<db::Edge, unsigned int>::iterator i = edges_with_errors.find (ep->first ());
|
for (std::unordered_set<db::EdgePair>::const_iterator ep = result.begin (); ep != result.end (); ++ep) {
|
||||||
if (i != edges_with_errors.end ()) {
|
if (edges_with_errors.find (ep->first ()) != edges_with_errors.end ()) {
|
||||||
if ((error_pattern & i->second) == 0) {
|
waived.insert (*ep);
|
||||||
error_pattern |= i->second;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (error_pattern != 0) {
|
|
||||||
|
|
||||||
bool can_be_waived = false;
|
|
||||||
|
|
||||||
// decode pattern: consider each group of 4 bits and match them against the error pattern in their four rotation variants
|
|
||||||
uint32_t p32 = (uint32_t) m_options.rect_filter;
|
|
||||||
while (p32 != 0 && ! can_be_waived) {
|
|
||||||
|
|
||||||
uint32_t p4 = p32 & 0xf;
|
|
||||||
p32 >>= 4;
|
|
||||||
|
|
||||||
if (p4 > 0) {
|
|
||||||
for (unsigned int r = 0; r < 4 && ! can_be_waived; ++r) {
|
|
||||||
can_be_waived = (error_pattern == p4);
|
|
||||||
p4 = ((p4 << 1) & 0xf) | ((p4 & 0x8) >> 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (can_be_waived) {
|
|
||||||
|
|
||||||
for (std::unordered_set<db::EdgePair>::const_iterator ep = result.begin (); ep != result.end (); ++ep) {
|
|
||||||
if (edges_with_errors.find (ep->first ()) != edges_with_errors.end ()) {
|
|
||||||
waived.insert (*ep);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -470,9 +484,28 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
if (! m_has_other) {
|
||||||
|
|
||||||
results.front ().insert (result.begin (), result.end ());
|
// this is the case of single-layer interaction. We need to separate the results
|
||||||
|
// from edge pairs into single edges (basically returning the first edge only)
|
||||||
|
// Reasoning: we cannot say what's going to happen on the other side of the
|
||||||
|
// error - it may not be waived and we cannot waive half of an edge pair.
|
||||||
|
|
||||||
|
for (std::unordered_set<db::EdgePair>::const_iterator i = result.begin (); i != result.end (); ++i) {
|
||||||
|
results.front ().insert (db::EdgePair (i->first (), i->first ().swapped_points ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
results.front ().insert (result.begin (), result.end ());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
results.front ().insert (result.begin (), result.end ());
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class TS, class TI>
|
template <class TS, class TI>
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,8 @@ module DRC
|
||||||
@engine._context("drc") do
|
@engine._context("drc") do
|
||||||
requires_region
|
requires_region
|
||||||
op.is_a?(DRCOpNode) || raise("A DRC expression is required for the argument (got #{op.inspect})")
|
op.is_a?(DRCOpNode) || raise("A DRC expression is required for the argument (got #{op.inspect})")
|
||||||
DRCLayer::new(@engine, self.data.complex_op(op.create_node({})))
|
# @@@ proper output type!!!
|
||||||
|
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, RBA::Region, :complex_op, op.create_node({})))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,3 +88,13 @@ TEST(2d)
|
||||||
{
|
{
|
||||||
run_test (_this, "2", true);
|
run_test (_this, "2", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(3)
|
||||||
|
{
|
||||||
|
run_test (_this, "3", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(3d)
|
||||||
|
{
|
||||||
|
run_test (_this, "3", true);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
|
||||||
|
source $drc_test_source
|
||||||
|
target $drc_test_target
|
||||||
|
|
||||||
|
if $drc_test_deep
|
||||||
|
deep
|
||||||
|
threads(0) # easier to debug
|
||||||
|
end
|
||||||
|
|
||||||
|
l1 = input(1, 0)
|
||||||
|
l2 = input(2, 0)
|
||||||
|
l3 = input(3, 0)
|
||||||
|
|
||||||
|
l1.output(1, 0)
|
||||||
|
l2.output(2, 0)
|
||||||
|
l3.output(3, 0)
|
||||||
|
|
||||||
|
# space with rectangle side selection option
|
||||||
|
l1.drc(space(projection) < 1.um).polygons.output(100, 0)
|
||||||
|
l1.drc(space(projection, one_side_allowed) < 1.um).output(101, 0)
|
||||||
|
l1.drc(space(projection, two_sides_allowed) < 1.um).output(102, 0)
|
||||||
|
l1.drc(space(projection, three_sides_allowed) < 1.um).output(103, 0)
|
||||||
|
|
||||||
|
# space with rectangle side selection option
|
||||||
|
l1.drc(iso(projection) < 1.um).polygons.output(110, 0)
|
||||||
|
l1.drc(iso(projection, one_side_allowed) < 1.um).output(111, 0)
|
||||||
|
l1.drc(iso(projection, two_sides_allowed) < 1.um).output(112, 0)
|
||||||
|
l1.drc(iso(projection, three_sides_allowed) < 1.um).output(113, 0)
|
||||||
|
|
||||||
|
# separation with rectangle side selection option
|
||||||
|
l1.drc(sep(l2, projection) < 1.um).polygons.output(120, 0)
|
||||||
|
l1.drc(sep(l2, projection, one_side_allowed) < 1.um).polygons.output(121, 0)
|
||||||
|
l1.drc(sep(l2, projection, two_sides_allowed) < 1.um).polygons.output(122, 0)
|
||||||
|
l1.drc(sep(l2, projection, three_sides_allowed) < 1.um).polygons.output(123, 0)
|
||||||
|
|
||||||
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,30 @@
|
||||||
|
|
||||||
|
source $drc_test_source
|
||||||
|
target $drc_test_target
|
||||||
|
|
||||||
|
if $drc_test_deep
|
||||||
|
deep
|
||||||
|
end
|
||||||
|
|
||||||
|
l1 = input(1, 0)
|
||||||
|
l2 = input(2, 0)
|
||||||
|
l3 = input(3, 0)
|
||||||
|
|
||||||
|
l1.output(1, 0)
|
||||||
|
l2.output(2, 0)
|
||||||
|
l3.output(3, 0)
|
||||||
|
|
||||||
|
l1.space(1.0, projection).polygons.output(100, 0)
|
||||||
|
|
||||||
|
l1.space(1.0, euclidian).polygons.output(110, 0)
|
||||||
|
l1.space(1.0, projection, projection_limits(0..2.0)).polygons.output(111, 0)
|
||||||
|
l1.space(1.0, projection, whole_edges).polygons.output(112, 0)
|
||||||
|
l1.space(1.0, projection, only_opposite).output(113, 0)
|
||||||
|
l1.space(1.0, projection, not_opposite).output(114, 0)
|
||||||
|
|
||||||
|
l1.isolated(1.0, euclidian).polygons.output(120, 0)
|
||||||
|
l1.isolated(1.0, projection, projection_limits(0..2.0)).polygons.output(121, 0)
|
||||||
|
l1.isolated(1.0, projection, whole_edges).polygons.output(122, 0)
|
||||||
|
l1.isolated(1.0, projection, only_opposite).output(123, 0)
|
||||||
|
l1.isolated(1.0, projection, not_opposite).output(124, 0)
|
||||||
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue