WIP: refactoring, added more properties support, bug fixing, added a test for the new DRC features

This commit is contained in:
Matthias Koefferlein 2023-01-20 23:44:51 +01:00
parent 9130492881
commit 1a71b01859
8 changed files with 88 additions and 42 deletions

View File

@ -1198,6 +1198,7 @@ EdgePairsDelegate *
AsIfFlatRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord d, const RegionCheckOptions &options) const
{
std::unique_ptr<FlatEdgePairs> result (new FlatEdgePairs ());
db::PropertyMapper pm (result->properties_repository (), properties_repository ());
EdgeRelationFilter check (rel, d, options.metrics);
check.set_include_zero (false);
@ -1206,18 +1207,16 @@ AsIfFlatRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord
check.set_min_projection (options.min_projection);
check.set_max_projection (options.max_projection);
edge2edge_check_negative_or_positive<db::FlatEdgePairs> edge_check (check, *result, options.negative, false /*=same polygons*/, false /*=same layers*/, options.shielded, true /*symmetric edge pairs*/);
poly2poly_check<db::Polygon> poly_check (edge_check);
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) {
do {
edge2edge_check_negative_or_positive<db::Shapes> edge_check (check, result->raw_edge_pairs (), options.negative, false /*=same polygons*/, false /*=same layers*/, options.shielded, true /*symmetric edge pairs*/, options.prop_constraint == db::IgnoreProperties ? 0 : pm (p.prop_id ()));
poly2poly_check<db::Polygon> poly_check (edge_check);
size_t n = 0;
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) {
poly_check.single (*p, n);
n += 2;
}
do {
poly_check.single (*p, 0);
} while (edge_check.prepare_next_pass ());
} while (edge_check.prepare_next_pass ());
}
return result.release ();
}

View File

@ -2004,7 +2004,7 @@ DeepRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord d, c
for (db::Shapes::shape_iterator s = shapes.begin (db::ShapeIterator::Polygons); ! s.at_end (); ++s) {
edge2edge_check_negative_or_positive<db::Shapes> edge_check (check, result, options.negative, false /*does not require different polygons*/, false /*does not require different layers*/, options.shielded, true /*symmetric edge pairs*/);
edge2edge_check_negative_or_positive<db::Shapes> edge_check (check, result, options.negative, false /*does not require different polygons*/, false /*does not require different layers*/, options.shielded, true /*symmetric edge pairs*/, options.prop_constraint == db::IgnoreProperties ? 0 : s->prop_id ());
poly2poly_check<db::Polygon> poly_check (edge_check);
db::Polygon poly;

View File

@ -156,14 +156,14 @@ class DB_PUBLIC_TEMPLATE edge2edge_check
: public Edge2EdgeCheckBase
{
public:
edge2edge_check (const EdgeRelationFilter &check, Output &output, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric_edges)
: Edge2EdgeCheckBase (check, different_polygons, requires_different_layers, with_shielding, symmetric_edges), mp_output_inter (&output), mp_output_intra (0)
edge2edge_check (const EdgeRelationFilter &check, Output &output, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric_edges, db::properties_id_type prop_id = 0)
: Edge2EdgeCheckBase (check, different_polygons, requires_different_layers, with_shielding, symmetric_edges), mp_output_inter (&output), mp_output_intra (0), m_prop_id (prop_id)
{
// .. nothing yet ..
}
edge2edge_check (const EdgeRelationFilter &check, Output &output_inter, Output &output_intra, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric_edges)
: Edge2EdgeCheckBase (check, different_polygons, requires_different_layers, with_shielding, symmetric_edges), mp_output_inter (&output_inter), mp_output_intra (&output_intra)
edge2edge_check (const EdgeRelationFilter &check, Output &output_inter, Output &output_intra, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric_edges, db::properties_id_type prop_id = 0)
: Edge2EdgeCheckBase (check, different_polygons, requires_different_layers, with_shielding, symmetric_edges), mp_output_inter (&output_inter), mp_output_intra (&output_intra), m_prop_id (prop_id)
{
// .. nothing yet ..
}
@ -172,15 +172,24 @@ protected:
void put (const db::EdgePair &edge, bool inter_polygon) const
{
if (! inter_polygon || ! mp_output_intra) {
mp_output_inter->insert (edge);
if (m_prop_id != 0) {
mp_output_inter->insert (db::EdgePairWithProperties(edge, m_prop_id));
} else {
mp_output_inter->insert (edge);
}
} else {
mp_output_intra->insert (edge);
if (m_prop_id != 0) {
mp_output_intra->insert (db::EdgePairWithProperties(edge, m_prop_id));
} else {
mp_output_intra->insert (edge);
}
}
}
private:
Output *mp_output_inter;
Output *mp_output_intra;
db::properties_id_type m_prop_id;
};
/**
@ -194,16 +203,16 @@ class DB_PUBLIC_TEMPLATE edge2edge_check_with_negative_output
: public edge2edge_check<Output>
{
public:
edge2edge_check_with_negative_output (const EdgeRelationFilter &check, Output &output, NegativeEdgeOutput &l1_negative_output, NegativeEdgeOutput &l2_negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric_edges)
: edge2edge_check<Output> (check, output, different_polygons, requires_different_layers, with_shielding, symmetric_edges),
edge2edge_check_with_negative_output (const EdgeRelationFilter &check, Output &output, NegativeEdgeOutput &l1_negative_output, NegativeEdgeOutput &l2_negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric_edges, db::properties_id_type prop_id = 0)
: edge2edge_check<Output> (check, output, different_polygons, requires_different_layers, with_shielding, symmetric_edges, prop_id),
mp_l1_negative_output (&l1_negative_output),
mp_l2_negative_output (&l2_negative_output)
{
edge2edge_check<Output>::set_has_negative_edge_output (true);
}
edge2edge_check_with_negative_output (const EdgeRelationFilter &check, Output &output_inter, Output &output_intra, NegativeEdgeOutput &l1_negative_output, NegativeEdgeOutput &l2_negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric_edges)
: edge2edge_check<Output> (check, output_inter, output_intra, different_polygons, requires_different_layers, with_shielding, symmetric_edges),
edge2edge_check_with_negative_output (const EdgeRelationFilter &check, Output &output_inter, Output &output_intra, NegativeEdgeOutput &l1_negative_output, NegativeEdgeOutput &l2_negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric_edges, db::properties_id_type prop_id = 0)
: edge2edge_check<Output> (check, output_inter, output_intra, different_polygons, requires_different_layers, with_shielding, symmetric_edges, prop_id),
mp_l1_negative_output (&l1_negative_output),
mp_l2_negative_output (&l2_negative_output)
{
@ -272,15 +281,15 @@ class DB_PUBLIC_TEMPLATE edge2edge_check_negative_or_positive
: public edge2edge_check<Output>
{
public:
edge2edge_check_negative_or_positive (const EdgeRelationFilter &check, Output &output, bool negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric)
: edge2edge_check<Output> (check, output, different_polygons, requires_different_layers, with_shielding, symmetric)
edge2edge_check_negative_or_positive (const EdgeRelationFilter &check, Output &output, bool negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric, db::properties_id_type prop_id = 0)
: edge2edge_check<Output> (check, output, different_polygons, requires_different_layers, with_shielding, symmetric, prop_id)
{
edge2edge_check<Output>::set_has_negative_edge_output (negative_output);
edge2edge_check<Output>::set_has_edge_pair_output (! negative_output);
}
edge2edge_check_negative_or_positive (const EdgeRelationFilter &check, Output &output_inter, Output &output_intra, bool negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric)
: edge2edge_check<Output> (check, output_inter, output_intra, different_polygons, requires_different_layers, with_shielding, symmetric)
edge2edge_check_negative_or_positive (const EdgeRelationFilter &check, Output &output_inter, Output &output_intra, bool negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric, db::properties_id_type prop_id = 0)
: edge2edge_check<Output> (check, output_inter, output_intra, different_polygons, requires_different_layers, with_shielding, symmetric, prop_id)
{
edge2edge_check<Output>::set_has_negative_edge_output (negative_output);
edge2edge_check<Output>::set_has_edge_pair_output (! negative_output);

View File

@ -510,7 +510,7 @@ static db::Region merged_ext2 (db::Region *r, bool min_coherence, int min_wc)
return r->merged (min_coherence, std::max (0, min_wc - 1));
}
static db::EdgePairs width2 (const db::Region *r, db::Region::distance_type d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, bool negative)
static db::EdgePairs width2 (const db::Region *r, db::Region::distance_type d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, bool negative, db::PropertyConstraint prop_constraint)
{
return r->width_check (d, db::RegionCheckOptions (whole_edges,
metrics,
@ -520,11 +520,12 @@ static db::EdgePairs width2 (const db::Region *r, db::Region::distance_type d, b
shielded,
db::NoOppositeFilter,
db::NoRectFilter,
negative)
negative,
prop_constraint)
);
}
static db::EdgePairs notch2 (const db::Region *r, db::Region::distance_type d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, bool negative)
static db::EdgePairs notch2 (const db::Region *r, db::Region::distance_type d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, bool negative, db::PropertyConstraint prop_constraint)
{
return r->notch_check (d, db::RegionCheckOptions (whole_edges,
metrics,
@ -534,7 +535,8 @@ static db::EdgePairs notch2 (const db::Region *r, db::Region::distance_type d, b
shielded,
db::NoOppositeFilter,
db::NoRectFilter,
negative)
negative,
prop_constraint)
);
}
@ -2513,7 +2515,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"This variant was introduced in version 0.27.\n"
) +
method_ext ("width_check", &width2, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max"), gsi::arg ("shielded", true), gsi::arg ("negative", false),
method_ext ("width_check", &width2, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max"), gsi::arg ("shielded", true), gsi::arg ("negative", false), gsi::arg ("property_constraint", db::IgnoreProperties),
"@brief Performs a width check with options\n"
"@param d The minimum width for which the polygons are checked\n"
"@param whole_edges If true, deliver the whole edges\n"
@ -2523,6 +2525,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"@param max_projection The upper limit of the projected length of one edge onto another\n"
"@param shielded Enables shielding\n"
"@param negative If true, edges not violation the condition will be output as pseudo-edge pairs\n"
"@param property_constraint Only \\IgnoreProperties and \\NoPropertyConstraint are allowed - in the last case, properties are copied from the original shapes to the output"
"\n"
"This version is similar to the simple version with one parameter. In addition, it allows "
"to specify many more options.\n"
@ -2551,7 +2554,8 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The 'shielded' and 'negative' options have been introduced in version 0.27."
"The 'shielded' and 'negative' options have been introduced in version 0.27. "
"'property_constraint' has been added in version 0.28.4."
) +
method_ext ("space_check", &space2, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max"), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter, "NoOppositeFilter"), gsi::arg ("rect_filter", db::NoRectFilter, "NoRectFilter"), gsi::arg ("negative", false), gsi::arg ("property_constraint", db::IgnoreProperties),
"@brief Performs a space check with options\n"
@ -2596,7 +2600,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27.\n"
"'property_constraint' has been added in version 0.28.4."
) +
method_ext ("notch_check", &notch2, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max"), gsi::arg ("shielded", true), gsi::arg ("negative", false),
method_ext ("notch_check", &notch2, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max"), gsi::arg ("shielded", true), gsi::arg ("negative", false), gsi::arg ("property_constraint", db::IgnoreProperties),
"@brief Performs a space check between edges of the same polygon with options\n"
"@param d The minimum space for which the polygons are checked\n"
"@param whole_edges If true, deliver the whole edges\n"
@ -2607,6 +2611,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"@param shielded Enables shielding\n"
"@param negative If true, edges not violation the condition will be output as pseudo-edge pairs\n"
"@param property_constraint Specifies whether to consider only shapes with a certain property relation\n"
"@param property_constraint Only \\IgnoreProperties and \\NoPropertyConstraint are allowed - in the last case, properties are copied from the original shapes to the output"
"\n"
"This version is similar to the simple version with one parameter. In addition, it allows "
"to specify many more options.\n"

View File

@ -319,6 +319,10 @@ module DRC
DRCPropertiesConstraint::new(RBA::Region::NoPropertyConstraint)
end
end
def negative
DRCNegative::new
end
def pattern(p)
self._context("pattern") do

View File

@ -3689,7 +3689,7 @@ CODE
# Double-bounded ranges are also available, like: "0.5 <= projecting < 2.0". @/li
# @li @b transparent @/b: performs the check without shielding (polygon layers only) @/li
# @li @b shielded @/b: performs the check with shielding (polygon layers only) @/li
# @li @b props_eq @/b, @b props_ne @/b, @b props_copy @/b: (does not apply to width check) -
# @li @b props_eq @/b, @b props_ne @/b, @b props_copy @/b: (only props_copy applies to width check) -
# see "Properties constraints" below.
# @/ul
#
@ -3757,8 +3757,8 @@ CODE
# @h3 Properties constraints (available on intra-polygon checks such as \space, \sep etc.) @/h3
#
# This feature is listed here, because this documentation is generic and used for other checks
# as well. It is not available on 'width' as it applies to intra-polygon checks - when
# pairs of different polygons are involved - something that width does not apply to.
# as well. \props_eq and \props_ne are not available on 'width' or 'notch' as these apply to intra-polygon checks - when
# pairs of different polygons are involved - something that 'width' or 'notch' does need.
#
# With properties constraints, the check is performed between shapes with the same
# or different properties. "properties" refers to the full set of key/value pairs
@ -3783,6 +3783,8 @@ CODE
# \props_copy is a special properties constraint that does not alter the behaviour of
# the checks, but copies the primary shape's properties to the output markers
# (a behaviour that is implied by \props_eq and \props_ne, but not there by default).
# This constraint is applicable to \width and \notch checks too. The effect is that
# the original polygon's properties are copied to the error markers.
# %DRC%
# @name space
@ -4108,6 +4110,7 @@ CODE
whole_edges = false
other = nil
shielded = nil
negative = false
opposite_filter = RBA::Region::NoOppositeFilter
rect_filter = RBA::Region::NoRectFilter
prop_constraint = RBA::Region::IgnoreProperties
@ -4118,6 +4121,8 @@ CODE
metrics = a.value
elsif a.is_a?(DRCWholeEdges)
whole_edges = a.value
elsif a.is_a?(DRCNegative)
negative = true
elsif a.is_a?(DRCPropertiesConstraint)
prop_constraint = a.value
elsif a.is_a?(DRCOppositeErrorFilter)
@ -4152,15 +4157,19 @@ CODE
if :#{f} != :width && :#{f} != :notch
args << opposite_filter
args << rect_filter
args << false # negative
args << prop_constraint
elsif opposite_filter != RBA::Region::NoOppositeFilter
raise("An opposite error filter cannot be used with this check")
elsif rect_filter != RBA::Region::NoRectFilter
raise("A rectangle error filter cannot be used with this check")
elsif prop_constraint != RBA::Region::IgnoreProperties
raise("A properties constraint cannot be used with this check")
else
if opposite_filter != RBA::Region::NoOppositeFilter
raise("An opposite error filter cannot be used with this check")
elsif rect_filter != RBA::Region::NoRectFilter
raise("A rectangle error filter cannot be used with this check")
elsif prop_constraint != RBA::Region::IgnoreProperties && prop_constraint != RBA::Region::NoPropertyConstraint
raise("A specific properties constraint cannot be used with this check (only 'props_copy' can be used)")
end
end
args << negative
args << prop_constraint
elsif negative
raise("Negative output can only be used for polygon layers")
elsif shielded != nil
raise("Shielding can only be used for polygon layers")
elsif opposite_filter != RBA::Region::NoOppositeFilter

View File

@ -153,6 +153,12 @@ module DRC
end
end
# Negative output on checks
class DRCNegative
def initialize
end
end
# A wrapper for a pair of limit values
# This class is used to identify projection limits for DRC
# functions

View File

@ -73,11 +73,15 @@ l1_nets.space(1.0.um, projection).polygons.output(200, 0)
l1_nets.space(1.0.um, projection, props_eq).polygons.output(201, 0)
l1_nets.space(1.0.um, projection, props_ne).polygons.output(202, 0)
l1_nets.space(1.0.um, projection, props_copy).polygons.output(203, 0)
l1_nets.width(1.0.um, projection).polygons.output(204, 0)
l1_nets.width(1.0.um, projection, props_copy).polygons.output(205, 0)
l1_nets.drc(space(projection) < 1.0.um).polygons.output(210, 0)
l1_nets.drc(space(projection) < 1.0.um, props_eq).polygons.output(211, 0)
l1_nets.drc(space(projection) < 1.0.um, props_ne).polygons.output(212, 0)
l1_nets.drc(space(projection) < 1.0.um, props_copy).polygons.output(213, 0)
l1_nets.drc(width(projection) < 1.0.um).polygons.output(214, 0)
l1_nets.drc(width(projection) < 1.0.um, props_copy).polygons.output(215, 0)
# edge pair to edge/polygon conversion with properties
@ -87,3 +91,13 @@ l1_nets.space(1.0.um, projection, props_copy).second_edges.output(222, 0)
l1_nets.space(1.0.um, projection, props_copy).edges.output(223, 0)
l1_nets.space(1.0.um, projection, props_copy).edges.extended_in(10.nm).output(224, 0)
# sizing with properties
l1_nets_sized = l1_nets.sized(0.2.um)
l1_nets_sized.and(l1_nets_sized, props_ne).output(300, 0) # overlap of different nets, same layer
l1_nets.drc(primary.sized(0.2.um) & foreign.sized(0.2.um)).output(310, 0)
l1_nets.drc(primary.sized(0.2.um) & foreign.sized(0.2.um), props_ne).output(311, 0)
l1_nets.drc(primary.sized(0.2.um) & foreign.sized(0.2.um), props_eq).output(312, 0)
l1_nets.drc(primary.sized(0.2.um) & foreign.sized(0.2.um), props_copy).output(313, 0)