diff --git a/src/drc/drc/built-in-macros/_drc_complex_ops.rb b/src/drc/drc/built-in-macros/_drc_complex_ops.rb index 9296d2a98..1c1f6845d 100644 --- a/src/drc/drc/built-in-macros/_drc_complex_ops.rb +++ b/src/drc/drc/built-in-macros/_drc_complex_ops.rb @@ -1055,12 +1055,16 @@ class DRCOpNodeWithCompare < DRCOpNode attr_accessor :reverse attr_accessor :original attr_accessor :lt, :le, :gt, :ge, :arg + attr_accessor :ne_allowed + attr_accessor :mode_or def initialize(engine, original = nil, reverse = false) super(engine) self.reverse = reverse self.original = original self.description = original ? original.description : "BasicWithCompare" + self.mode_or = false + self.ne_allowed = false end def _description_for_dump @@ -1076,12 +1080,12 @@ class DRCOpNodeWithCompare < DRCOpNode self.le && (cmp << ("<=%.12g" % self.le)) self.gt && (cmp << (">%.12g" % self.gt)) self.ge && (cmp << (">=%.12g" % self.ge)) - return indent + self.description + " " + cmp.join(" ") + return indent + self.description + " " + cmp.join(" ") + (self.mode_or ? " [or]" : "") end end def _check_bounds - if (self.lt || self.le) && (self.gt || self.ge) + if ! self.mode_or && (self.lt || self.le) && (self.gt || self.ge) epsilon = 1e-10 lower = self.ge ? self.ge - epsilon : self.gt + epsilon upper = self.le ? self.le + epsilon : self.lt - epsilon @@ -1123,6 +1127,20 @@ class DRCOpNodeWithCompare < DRCOpNode return (self.original || self).dup end + def !=(other) + if !self.ne_allowed + raise("!= operator is not allowed for '" + self.description + "'") + end + if !(other.is_a?(Float) || other.is_a?(Integer)) + raise("!= operator needs a numerical argument for '" + self.description + "' argument") + end + res = self._self_or_original + res.mode_or = true + res.set_lt(other) + res.set_gt(other) + return res + end + def ==(other) if !(other.is_a?(Float) || other.is_a?(Integer)) raise("== operator needs a numerical argument for '" + self.description + "' argument") @@ -1477,6 +1495,7 @@ class DRCOpNodeCheck < DRCOpNodeWithCompare self.other = other self.args = args self.description = check.to_s + self.ne_allowed = true end def _description_for_dump @@ -1516,12 +1535,16 @@ class DRCOpNodeCheck < DRCOpNodeWithCompare if res if self.check == :width || self.check == :notch # Same polygon check - we need to take both edges of the result - and_with = RBA::CompoundRegionOperationNode::new_edges(res) + other = RBA::CompoundRegionOperationNode::new_edges(res) else - and_with = RBA::CompoundRegionOperationNode::new_edge_pair_to_first_edges(res) + other = RBA::CompoundRegionOperationNode::new_edge_pair_to_first_edges(res) end res_max = RBA::CompoundRegionOperationNode::new_edge_pair_to_first_edges(max_check) - res = RBA::CompoundRegionOperationNode::new_geometrical_boolean(RBA::CompoundRegionOperationNode::GeometricalOp::And, and_with, res_max) + if self.mode_or + res = RBA::CompoundRegionOperationNode::new_join([ other, res_max ]) + else + res = RBA::CompoundRegionOperationNode::new_geometrical_boolean(RBA::CompoundRegionOperationNode::GeometricalOp::And, other, res_max) + end else res = max_check end diff --git a/src/lay/lay/doc/manual/drc_runsets.xml b/src/lay/lay/doc/manual/drc_runsets.xml index 3b2927d78..cfca61a1e 100644 --- a/src/lay/lay/doc/manual/drc_runsets.xml +++ b/src/lay/lay/doc/manual/drc_runsets.xml @@ -399,6 +399,9 @@ output(w, "width violations") enclosure (enc), overlap +
  • Universal DRC (see below):
    + drc +
  • Boolean operations:
    & (and), | (or), @@ -767,6 +770,139 @@ overlaps = layer.size(0.2).raw.merged(2) +

    Universal DRC

    + + + +

    + Starting with version 0.27, the DRC language got a new feature which is "universal DRC". +

    + +

    + On one hand, this is a more convenient way to write DRC checks because it allows + specifications using natural compare operators. For example, the following plain width check +

    + +
    +  ...
    +  drc_w = input(1, 0).width(0.2)
    +  ...
    +  
    + +

    + can be written as: +

    + +
    +  ...
    +  drc_w = input(1, 0).drc(width < 0.2)
    +  ...
    +  
    + +

    + The drc method is the "universal DRC" method. + It takes an operator. In the simple case, this operator is a simple constraint of the + form "measurement < value", but it supports a number of different variants: +

    + +
      +
    • + drc( measurement != value )
    • : + renders markers where the dimension is not matching the value + +
    • + drc( measurement == value )
    • : + renders markers where the dimension is matching the given value + +
    • + drc( measurement less_op value )
    • : + ("less_op" is < or <=) + renders markers where the dimension is less than or less or equal to the given value + +
    • + drc( measurement greater_op value )
    • : + ("greater_op" is > or >=) + renders markers where the dimension is greater than or greater or equal to the given value + +
    • + drc( lower_value less_op measurement greater_op upper_value )
    • : + renders markers where the dimension is between the lower and upper value + +
    + +

    + "measurement" is "width", "notch", "isolated" ("iso"), "separation" ("sep"), "overlap" or "enclosure" ("enc"). They have the + The last three checks are two-layer checks which require a second layer. The + second layer is specified together with the measurement like this: +

    + +
    +  ...
    +  l1 = input(1, 0)
    +  l2 = input(2, 0)
    +  drc_sep = l1.drc(separation(l2) <= 0.5)
    +  ...
    +  
    + +

    + Options are also specified together with the measurement and follow the same notation + as the plain methods. For example to specify "projection" metrics, use: +

    + +
    +  ...
    +  drc_w = input(1, 0).drc(width(projection) < 0.2)
    +  ...
    +  
    + +

    + However, the universal DRC is much more: it offers a number of options to further process + the results. The functionality behind the universal DRC function is basically a kind of + loop over all primary shapes (the ones from the layer the "drc" function is called on). + The operations in the drc function's brackets is executed on each of the primary shapes + where the neighborhood of that single shape is considered. This scheme is more efficient + and enables applications beyond the capabilities of the plain layer methods. +

    + +

    + For example, the boolean "&" operator implements a "local" boolean AND inside this + loop. This allows to efficiently check for both space and width violations: +

    + +
    +  ...
    +  drc_ws = input(1, 0).drc((width < 0.2) & (space < 0.3))
    +  ...
    +  
    + +

    + The boolean AND is computed between the edges on the primary shape and returns these + parts where both space and width violations are flagged. The boolean operation is + more efficient than the plain alternative: +

    + +
    +  ...
    +  drc_ws1 = input(1, 0).width(0.2).edges
    +  drc_ws2 = input(1, 0).space(0.3).edges
    +  drc_ws = drc_ws1 & drc_ws2
    +  ...
    +  
    + +

    + The reson is that performing the boolean computation in the local loop can be + shortcut if one input is empty and it does not need to store a (potentially big) + layer set with edges as produced by the plain-method implementation. Instead it + will work with a temporary and local edge set only and free the memory space as + soon as it moves on to the next primary shape. +

    + +

    + The universal DRC function is a rich feature and offers filters based on + polygons or edge properties, polygon or edge manipulation, conditionals + and a lot more. For more details see the drc function documentation. +

    +

    Logging and verbosity

    diff --git a/testdata/drc/drcGenericTests_1.drc b/testdata/drc/drcGenericTests_1.drc index 3bbb96f4b..51649495a 100644 --- a/testdata/drc/drcGenericTests_1.drc +++ b/testdata/drc/drcGenericTests_1.drc @@ -27,4 +27,6 @@ l1.drc(1.5 <= wcheck).output(107, 0) l1.drc(wcheck == 1.5).output(108, 0) l1.drc(1.0 <= wcheck <= 1.5).output(109, 0) l1.drc(1.0 < wcheck < 2.0).output(110, 0) +l1.drc(wcheck != 1.5).output(111, 0) +l1.drc(wcheck != 1.0).output(112, 0) diff --git a/testdata/drc/drcGenericTests_au1.gds b/testdata/drc/drcGenericTests_au1.gds index 8b1e44020..8ffc55a48 100644 Binary files a/testdata/drc/drcGenericTests_au1.gds and b/testdata/drc/drcGenericTests_au1.gds differ diff --git a/testdata/drc/drcGenericTests_au1d.gds b/testdata/drc/drcGenericTests_au1d.gds index 3e467d9dd..d3eb185b1 100644 Binary files a/testdata/drc/drcGenericTests_au1d.gds and b/testdata/drc/drcGenericTests_au1d.gds differ