From 1a71b018594dc83dcd15c25e2ef6c82f23484df4 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 20 Jan 2023 23:44:51 +0100 Subject: [PATCH] WIP: refactoring, added more properties support, bug fixing, added a test for the new DRC features --- src/db/db/dbAsIfFlatRegion.cc | 17 +++++----- src/db/db/dbDeepRegion.cc | 2 +- src/db/db/dbRegionCheckUtils.h | 37 ++++++++++++++-------- src/db/db/gsiDeclDbRegion.cc | 19 +++++++---- src/drc/drc/built-in-macros/_drc_engine.rb | 4 +++ src/drc/drc/built-in-macros/_drc_layer.rb | 31 +++++++++++------- src/drc/drc/built-in-macros/_drc_tags.rb | 6 ++++ testdata/drc/drcSimpleTests_70.drc | 14 ++++++++ 8 files changed, 88 insertions(+), 42 deletions(-) diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index cf6750783..31780d0eb 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -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 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 edge_check (check, *result, options.negative, false /*=same polygons*/, false /*=same layers*/, options.shielded, true /*symmetric edge pairs*/); - poly2poly_check poly_check (edge_check); + for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { - do { + edge2edge_check_negative_or_positive 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 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 (); } diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 44cb94387..1becfa40e 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -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 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 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 poly_check (edge_check); db::Polygon poly; diff --git a/src/db/db/dbRegionCheckUtils.h b/src/db/db/dbRegionCheckUtils.h index ded2c375f..b2a55fd84 100644 --- a/src/db/db/dbRegionCheckUtils.h +++ b/src/db/db/dbRegionCheckUtils.h @@ -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 { 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 (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 (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::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 (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 (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 { 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 (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 (check, output, different_polygons, requires_different_layers, with_shielding, symmetric, prop_id) { edge2edge_check::set_has_negative_edge_output (negative_output); edge2edge_check::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 (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 (check, output_inter, output_intra, different_polygons, requires_different_layers, with_shielding, symmetric, prop_id) { edge2edge_check::set_has_negative_edge_output (negative_output); edge2edge_check::set_has_edge_pair_output (! negative_output); diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 4952b03f1..04ad9ae04 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -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 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 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 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 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", ¬ch2, 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", ¬ch2, 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 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" diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index 80085335a..7e5ebecbd 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -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 diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb index 372d749bc..70890edcb 100644 --- a/src/drc/drc/built-in-macros/_drc_layer.rb +++ b/src/drc/drc/built-in-macros/_drc_layer.rb @@ -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 diff --git a/src/drc/drc/built-in-macros/_drc_tags.rb b/src/drc/drc/built-in-macros/_drc_tags.rb index a02f20ee4..317f882b4 100644 --- a/src/drc/drc/built-in-macros/_drc_tags.rb +++ b/src/drc/drc/built-in-macros/_drc_tags.rb @@ -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 diff --git a/testdata/drc/drcSimpleTests_70.drc b/testdata/drc/drcSimpleTests_70.drc index d8a471f37..57071a3e3 100644 --- a/testdata/drc/drcSimpleTests_70.drc +++ b/testdata/drc/drcSimpleTests_70.drc @@ -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) +