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 +
+ 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: +
+ ++ "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. +
+