From 8051bef9acd0f8bb21921a4665675d30441ff41e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 15 Jan 2021 00:31:26 +0100 Subject: [PATCH] Doc update, fixed DRC's 'switch' function --- scripts/extract_doc.rb | 2 +- .../drc/built-in-macros/_drc_complex_ops.rb | 105 ++++--- .../built-in-macros/_drc_cop_integration.rb | 188 +++++++----- src/drc/drc/built-in-macros/_drc_layer.rb | 2 +- src/lay/lay/doc/about/drc_ref_drc.xml | 131 ++++++--- src/lay/lay/doc/about/drc_ref_global.xml | 52 ++-- src/lay/lay/doc/about/drc_ref_layer.xml | 277 +++++++++++++----- src/lay/lay/doc/about/drc_ref_netter.xml | 24 +- src/lay/lay/doc/about/lvs_ref_netter.xml | 2 +- 9 files changed, 499 insertions(+), 284 deletions(-) diff --git a/scripts/extract_doc.rb b/scripts/extract_doc.rb index aaf279ee8..d3eee7e7c 100755 --- a/scripts/extract_doc.rb +++ b/scripts/extract_doc.rb @@ -47,8 +47,8 @@ def escape(mod, s) s.gsub("&", "&"). gsub("<", "<"). gsub(">", ">"). - gsub(/\\([\w:#]+)/) { create_ref(mod, $1) }. gsub(/\\\\([\w:#]+)/) { create_link(mod, $1) }. + gsub(/\\([\w:#]+)/) { create_ref(mod, $1) }. gsub(/RBA::([\w#]+)/) { create_class_doc_ref($1) } end 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 131c8ff06..34aa89352 100644 --- a/src/drc/drc/built-in-macros/_drc_complex_ops.rb +++ b/src/drc/drc/built-in-macros/_drc_complex_ops.rb @@ -27,51 +27,51 @@ module DRC # The following global functions are relevant for the DRC expressions: # # @ul -# @li \\global#angle @/li -# @li \\global#area @/li -# @li \\global#area_ratio @/li -# @li \\global#bbox_area_ratio @/li -# @li \\global#bbox_height @/li -# @li \\global#bbox_max @/li -# @li \\global#bbox_min @/li -# @li \\global#bbox_width @/li -# @li \\global#case @/li -# @li \\global#corners @/li -# @li \\global#covering @/li -# @li \\global#enc @/li -# @li \\global#enclosing @/li -# @li \\global#extent_refs @/li -# @li \\global#extents @/li -# @li \\global#foreign @/li -# @li \\global#holes @/li -# @li \\global#hulls @/li -# @li \\global#if_all @/li -# @li \\global#if_any @/li -# @li \\global#if_none @/li -# @li \\global#inside @/li -# @li \\global#interacting @/li -# @li \\global#iso @/li -# @li \\global#length @/li -# @li \\global#middle @/li -# @li \\global#notch @/li -# @li \\global#odd_polygons @/li -# @li \\global#outside @/li -# @li \\global#overlap @/li -# @li \\global#overlapping @/li -# @li \\global#perimeter @/li -# @li \\global#primary @/li -# @li \\global#rectangles @/li -# @li \\global#rectilinear @/li -# @li \\global#relative_height @/li -# @li \\global#rounded_corners @/li -# @li \\global#secondary @/li -# @li \\global#separation @/li -# @li \\global#sep @/li -# @li \\global#sized @/li -# @li \\global#smoothed @/li -# @li \\global#space @/li -# @li \\global#squares @/li -# @li \\global#width @/li +# @li \global#angle @/li +# @li \global#area @/li +# @li \global#area_ratio @/li +# @li \global#bbox_area_ratio @/li +# @li \global#bbox_height @/li +# @li \global#bbox_max @/li +# @li \global#bbox_min @/li +# @li \global#bbox_width @/li +# @li \global#case @/li +# @li \global#corners @/li +# @li \global#covering @/li +# @li \global#enc @/li +# @li \global#enclosing @/li +# @li \global#extent_refs @/li +# @li \global#extents @/li +# @li \global#foreign @/li +# @li \global#holes @/li +# @li \global#hulls @/li +# @li \global#if_all @/li +# @li \global#if_any @/li +# @li \global#if_none @/li +# @li \global#inside @/li +# @li \global#interacting @/li +# @li \global#iso @/li +# @li \global#length @/li +# @li \global#middle @/li +# @li \global#notch @/li +# @li \global#odd_polygons @/li +# @li \global#outside @/li +# @li \global#overlap @/li +# @li \global#overlapping @/li +# @li \global#perimeter @/li +# @li \global#primary @/li +# @li \global#rectangles @/li +# @li \global#rectilinear @/li +# @li \global#relative_height @/li +# @li \global#rounded_corners @/li +# @li \global#secondary @/li +# @li \global#separation @/li +# @li \global#sep @/li +# @li \global#sized @/li +# @li \global#smoothed @/li +# @li \global#space @/li +# @li \global#squares @/li +# @li \global#width @/li # @/ul # # The following documentation will list the methods available for DRC expression objects. @@ -1428,7 +1428,20 @@ class DRCOpNodeCase < DRCOpNode end def do_create_node(cache) - RBA::CompoundRegionOperationNode::new_case(self.children.collect { |c| c.create_node(cache) }) + + nodes = self.children.collect { |c| c.create_node(cache) } + types = [] + nodes.each_with_index do |a,index| + if index % 2 == 1 + types << a.result_type + end + end + if types.sort.uniq.size > 1 + raise("All result arguments need to have the same type (we got '" + types.collect(:to_s).join(",") + "')") + end + + RBA::CompoundRegionOperationNode::new_case(nodes) + end end diff --git a/src/drc/drc/built-in-macros/_drc_cop_integration.rb b/src/drc/drc/built-in-macros/_drc_cop_integration.rb index 9c7d95395..86f3532fb 100644 --- a/src/drc/drc/built-in-macros/_drc_cop_integration.rb +++ b/src/drc/drc/built-in-macros/_drc_cop_integration.rb @@ -18,35 +18,37 @@ module DRC # # The key concept for this method are DRC expressions. DRC expressions # are formed by using predefined keywords like "width", operators like "&" - # and method to build an abstract definition of the operations to perform + # and methods to build an abstract definition of the operations to perform # within the DRC. # # When the DRC function is executed, it will basically visit all shapes - # from the input layer (the one, the "drc" method is called on), collect - # the neighbor shapes from all involved other inputs and run the requested - # operations on each cluster. Currently, "drc" is only available for polygon - # layers. + # from the input layer. This is the layer, the "drc" method is called on. + # While it does, it collects the neighbor shapes from all involved other inputs + # and runs the requested operations on each cluster. + # Currently, "drc" is only available for polygon layers. # - # The nature of the "drc" operation is that of the loop over all (merged) input + # This way, the nature of the "drc" operation is that of the loop over all (merged) input # polygons. Within the operation executed on each shape, it's possible to make # decisions such as "if the shape has an area larger than something, apply this - # operation" etc. This can be achieved with conventional DRC functions too, + # operation" or similar. This often can be achieved with conventional DRC functions too, # but involves potentially complex and heavy operations such as booleans, interact - # etc. For this reason, the "drc" function may provide a performance benefit. + # etc. For this reason, the "drc" function may provide a better performance. # - # In addition, within the loop, a single shape from the input layer is presented to + # In addition, within the loop a single shape from the input layer is presented to # execution engine which runs the operations. # This allows using operations such as "size" without having to consider # neigbor polygons growing into the area of the initial shape. In this sense, - # the "drc" function allows seeing the layer as individual polygons rather than + # the "drc" function sees the layer as individual polygons rather than # a global "sea of polygons". This enables new applications which are otherwise # difficult to implement. # - # An important concept in the context of "drc" expressions is the "primary". - # This expression represents a single primary shape. "Secondaries" are shapes - # from other inputs. Primary shapes guide the operation - secondaries without + # @h3 Primaries and secondaries @/h3 + # + # An important concept in "drc" expressions is the "primary". + # The primary represents a single shape from the input layer. "Secondaries" are shapes + # from other inputs. Primaries guide the operation - secondaries without # primaries are not seen. The "drc" operation will look for secondaries within - # a certain distance which is determined from the operations within the + # a certain distance which is determined from the operations from the # expression to execute. The secondaries collected in this step will not be # merged, so the secondary polygons may be partial. This is important when # using measurement operations like "area" on secondary polygons. @@ -70,8 +72,8 @@ module DRC # out = in.drc(0.2.um < width < 0.5.um) # @/code # - # To specify the second input for a two-layer check, specify the second input - # with the check function. Here a two-layer separation check is used (\global#separation): + # To specify the second input for a two-layer check, specify it in brackets in + # the check function. This example shows how to use a two-layer separation check (\global#separation): # # @code # l1 = input(1, 0) @@ -81,10 +83,11 @@ module DRC # # The second input of this check function can be a computed expression. In this # case the local loop will first evaluate the expression for the second input and - # then use it inside the check. + # then use the result for second input in the check. Note that this computation is + # performed locally and separately for each primary and its context. # # Options for the checks are also specified inside the brackets. For example, - # to specify a projection metrics for width use: + # to specify projection metrics ("projection") for width use: # # @code # out = in.drc(width(projection) < 0.5.um) @@ -99,26 +102,31 @@ module DRC # in the DRC expressions, methods are available to filter, process and convert # these types. # - # For example, the check produces edge pairs which can be converted into polygons + # For example, all checks produce edge pairs which can be converted into polygons # using the "polygons" method: # # @code # out = in.drc((width(projection) < 0.5.um).polygons) # @/code # - # Note the subtle difference: when putting the "polygons" method inside the "drc" - # brackets, it is executed locally on every checked primary polygon. The result - # may be identical to the global conversion: + # Note a subtle detail: when putting the "polygons" method inside the "drc" + # brackets, it is executed locally on every visited primary polygon. The result + # in this case is identical to the global conversion: # # @code # # same, but with "global" conversion: # out = in.drc(width(projection) < 0.5.um).polygons # @/code # - # but having the check polygons inside the loop opens new opportunities and - # is more efficient in general. + # But having the check polygons inside the loop opens new opportunities and + # is more efficient in general. In the previous example, the local conversion + # will keep a few edge pairs after having converted them to polygons. In + # the global case, all edge pairs are collected first and then converted. + # If there are many edge pairs, this requires more memory and a larger computing + # overhead for managing the bigger number of shapes. # - # Conversion methods are: + # For the conversion of edges, edge pairs and polygons into other types, these + # methods are provided: # # @ul # @li \DRC#polygons: converts edge pairs to polygons @/li @@ -128,7 +136,7 @@ module DRC # @li \DRC#corners: can extract corners from polygons @/li # @/ul # - # This example decomposes the primary polygons into edges: + # The following example decomposes the primary polygons into edges: # # @code # out = in.drc(primary.edges) @@ -137,19 +145,25 @@ module DRC # (for backward compatibility you cannot abbreviate "primary.edges" simply as "edges" like # other functions). # - # The previous isn't quite exciting as it is equivalent to + # The previous example isn't quite exciting as it is equivalent to # # @code # # Same as above # out = in.edges # @/code # - # But it gets more interesting as within the loop, "edges" delivers the edge set for - # each individual polygon. So this will give you the edges of polygons with more than four corners: + # But it gets more interesting, as within the loop, "edges" delivers the edge set for + # each individual polygon. It's possible to work with this distinct set, so for example + # this will give you the edges of polygons with more than four corners: # # @code # out = in.drc(primary.edges.count > 4) # @/code + # + # Explanation: "count" is a "quantifier" which takes any kind of set (edges, edge pairs, polygons) + # and returns the set if the number of inhabitants meets the given condition. Otherwise the set + # is skipped. So it will look at the edges and if there are more than four (per primary shape), + # it will forward this set. # # The same result can be achieved with classic DRC with "interact" and a figure count, but # at a much higher computation cost. @@ -166,11 +180,14 @@ module DRC # # @h3 Filters @/h3 # - # Filter operators select input polygons or edges based on their properties. These filters are: + # Filter operators select input polygons or edges based on their properties. These filters are provided: # # @ul # @li "\DRC#area": selects polygons based on their area @/li # @li "\DRC#perimeter": selects polygons based on their perimeter @/li + # @li "\DRC#area_ratio": selects polygons based on their bounding box to polygon area ratio @/li + # @li "\DRC#bbox_aspect_ratio": selects polygons based on their bounding box aspect ratio @/li + # @li "\DRC#relative_height": selects polygons based on their relative height @/li # @li "\DRC#bbox_min", "\global#bbox_max", "\global#bbox_width", "\global#bbox_height": selects polygons based on their bounding box properties @/li # @li "\DRC#length": selects edges based on their length @/li # @li "\DRC#angle": selects edges based on their orientation @/li @@ -196,19 +213,20 @@ module DRC # "bbox_min" etc. will evaluate a particular dimensions of the polygon's bounding box and # use the respective dimension for filtering the polygon. # - # Note that it's basically possible to use the polygon filters on any kind of input. + # Note that it's basically possible to use the polygon filters on any input - computed and secondaries. # In fact, plain "area" for example is a shortcut for "\global#primary.area" indicating that # the area of primary shapes are supposed to be computed. # However, any input other than the primary is not necessarily complete or it may # consist of multiple polygons. Hence the computed values may be too big or too small. # It's recommended therefore to use the measurement functions on primary polygons - # only. + # unless you know what you're doing. # # @h3 Filter predicates @/h3 # # The "drc" feature also supports some predicates. "predicates" are boolean values # indicating a certain condition. A predicate filter works in a way that it only - # passes the polygons + # passes the polygons if the condition is met. + # # The predicates available currently are: # # @ul @@ -219,7 +237,7 @@ module DRC # # For the same reason as explained above, it's recommended to use these predicates # standalone, so they act on primary shapes. It's possible to use the predicates - # on computed shapes or secondary input, but that may not render the desired results. + # on computed shapes or secondaries, but that may not render the desired results. # # @h3 Logical NOT operator @/h3 # @@ -234,37 +252,54 @@ module DRC # # @h3 Logical combination operators @/h3 # - # The logical "if_any" or "if_all" statements allow connecting multiple + # The logical "if_any" or "if_all" functions allow connecting multiple # conditions and evaluate to "true" (means: a non-empty shape set) if either - # on input is a non-empty shape set ("if_any") or if all inputs are non-empty - # ("if_all"). For example, this will select all polygons which are rectangles + # one input is a non-empty shape set ("if_any") or if all inputs are non-empty + # ("if_all"). + # + # For example, this will select all polygons which are rectangles # and whose area is larger than 20 quare micrometers: # # @code # out = in.drc(if_all(rectangles, area > 20.0)) # @/code # - # In fact, "if_all" renders the result of the last expression, provided all - # previous ones are non-empty. So this operation will render rectangles - # sized by 100 nm and skip all other types of polygons: + # "if_all" delivers the primary shape if all of the input expressions + # render a non-empty result. + # + # In contrast to this, the "if_any" operation will deliver the primary shape + # if one of the input expressions renders a non-empty result. + # + # The "\global#switch" function allows selecting one input based on the results of an + # expression. In the two-input form it's equivalent to "if". The first expression + # is the condition. If it evaluates to a non-empty shape set, the result of the + # second expression is taken. Otherwise, the result is empty. + # + # Hence the following code delivers all rectangles sized by 100 nm. All + # other shapes are skipped: # # @code - # out = in.drc(if_all(rectangles, sized(100.nm))) + # out = in.drc(switch(rectangles, primary.sized(100.nm))) # @/code # - # Contrary to this, the "if_any" operation will render the first non-empty - # expression result and skip the following ones. So this example will - # size all rectangles by 100 nm and leave all other types of polygons - # untouched: + # A third expression will be considered the "else" branch: the result of + # this expression will be taken if the first one is not taken. So this + # example will size all rectangles and leave other shapes untouched: # # @code - # out = in.drc(if_any(rectangles.sized(100.nm), primary)) + # out = in.drc(switch(rectangles, primary.sized(100.nm), primary)) # @/code # + # If more expressions are given, they are considered as a sequence of condition/result + # chain (c1, e1, c2, e2, ...) in the sense of "if(c1) return(e1) else if(c2) return(e2) ...". + # So the e1 is taken if c1 is met, e2 is taken when c1 is not met, but c2 is and so forth. + # If there is an odd number of expressions, the last one will be the default expression + # which is taken if none of the conditions is met. + # # @h3 Polygon manipulations @/h3 # # The "drc" operations feature polygon manipulations where the input is - # either the primary polygon or derived shapes. + # either the primary, secondaries or derived shapes. # Manipulations include sizing ("\global#sized"), corner rounding ("\global#rounded_corners"), smoothing ("\global#smoothed") # and boolean operations. # @@ -289,7 +324,7 @@ module DRC # out = l1.drc((primary & secondary(l2)).area > 1.0) # @/code # - # The "\global#secondar" operator indicates that "l2" is to be used as secondary input to the "drc" function. Only + # The "\global#secondary" operator indicates that "l2" is to be used as secondary input to the "drc" function. Only # in this form, the operators of the boolean AND can be reversed: # # @code @@ -298,25 +333,26 @@ module DRC # # @h3 Quantifiers @/h3 # - # Some filters operate on properties of the full, local shape set. + # Some filters operate on properties of the full, local, per-primary shape set. # While the loop is executed, the DRC expressions will collect shapes, either - # from the primary, it's neighborhood (secondary) or by deriving shape sets. + # from the primary, it's neighborhood (secondaries) or from deriving shape sets. # # Obviously the primary is a simple one: it consists of a single shape, because # this is how the loop operates. Derived shape sets however can be more complex. - # "Quantifiers" allow to assess properties of the complete, per-primary shape - # set. A simple one is "count" which checks if the number of shapes within + # "Quantifiers" allow assessing properties of the complete, per-primary shape + # set. A simple one is "\DRC#count" which checks if the number of shapes within # a shape set is within a given range. # - # Obviously, "primary.count == 1" is always true. The following condition will - # select all primary shapes which have more than 13 corners: + # Obviously, "primary.count == 1" is always true. So using "count" primaries isn't + # much fun. So it's better to use it on derived sets. + # The following condition will select all primary shapes which have more than 13 corners: # # @code # out = in.drc(if_any(primary.corners.count > 13)) # @/code # - # Note an important detail here: the "if_any" function will render primary - # @b polygons @/b, if the expression inside gives a non-empty result. Without + # Note an important detail here: the "if_any" function will make this statement render primary + # polygons, if the expression inside gives a non-empty result. Without # "if_any", the result would be the output of "count" which is the set of all # corners where the corner count is larger than 13. # @@ -339,12 +375,15 @@ module DRC # @/code # # Note that the first line prepares the operation, but does not execute the area computation - # or the boolean operation. But when the "drc" function executes the operation it will - # only compute the area once as it is represented by the same Ruby object. + # or the boolean operation. But when the "drc" function executes the loop over the primaries it will + # only compute the area once per primary as it is represented by the same Ruby object. # - # @h3 Summary @/h3 + # @h3 Outlook @/h3 + # + # DRC expressions are quite rich and powerful. They provide a more intuitive way of + # writing DRC expressions, are more efficient and open new opportunities. DRC + # development is likely to focus on this scheme in the future. # - # The bottom line is: DRC expressions are quite rich and there is a lot more to be said and written. # More formal details about the bits and pieces can be found in the \DRC# class documentation. def drc(op) @@ -375,20 +414,20 @@ module DRC class DRCEngine # %DRC% - # @name case + # @name switch # @brief A conditional selector for the "drc" universal DRC function - # @synopsis case(...) + # @synopsis switch(...) # # This function provides a conditional selector for the "drc" function. # It is used this way: # # @code - # out = in.drc(case(c1, r1, c2, r2, ..., cn, rn) - # out = in.drc(case(c1, r1, c2, r2, ..., cn, rn, rdef) + # out = in.drc(switch(c1, r1, c2, r2, ..., cn, rn) + # out = in.drc(switch(c1, r1, c2, r2, ..., cn, rn, rdef) # @/code # # This function will evaluate c1 which is a universal DRC expression (see \Layer#drc). - # If the result is not empty, "case" will evaluate and return r1. Otherwise it + # If the result is not empty, "switch" will evaluate and return r1. Otherwise it # will continue with c2 and the result of this expression is not empty it will # return r2. Otherwise it will continue with c3/r3 etc. # @@ -398,27 +437,16 @@ module DRC # As a requirement, the result types of all r1..rn expressions and the rdef # needs to be the same - i.e. all need to render polygons or edges or edge pairs. - def case(*args) + def switch(*args) - self._context("case") do - - anum = 1 + self._context("switch") do args = args.collect { |a| self._make_node(a) } - types = [] - args.each do |a| + args.each_with_index do |a,index| if !a.is_a?(DRCOpNode) - raise("All inputs need to be valid compound operation expressions (argument ##{anum} isn't)") + raise("All inputs need to be valid compound operation expressions (argument ##{index + 1} isn't)") end - if a % 2 == 0 - types << a.result_type - end - anum += 1 - end - - if types.sort.uniq.size > 1 - raise("All result arguments need to have the same type (we got '" + types.collect(:to_s).join(",") + "')") end DRCOpNodeCase::new(self, args) diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb index 0732e316e..fb83a5830 100644 --- a/src/drc/drc/built-in-macros/_drc_layer.rb +++ b/src/drc/drc/built-in-macros/_drc_layer.rb @@ -3001,7 +3001,7 @@ CODE # @li @b projecting (in condition) @/b: This specification is equivalent to "projection_limits" # but is more intuitive, as "projecting" is written with a condition, like # "projecting < 2.um". Available operators are: "==", "<", "<=", ">" and ">=". - # Double-bounded ranges are also available, like: "0.5 <= projecting < 2.0". + # 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 # @/ul diff --git a/src/lay/lay/doc/about/drc_ref_drc.xml b/src/lay/lay/doc/about/drc_ref_drc.xml index 446c3f7ec..dee616582 100644 --- a/src/lay/lay/doc/about/drc_ref_drc.xml +++ b/src/lay/lay/doc/about/drc_ref_drc.xml @@ -28,51 +28,51 @@ out = in.drc((width < 2.0).polygons) The following global functions are relevant for the DRC expressions:

The following documentation will list the methods available for DRC expression objects. @@ -237,6 +237,20 @@ out = in.drc(primary.area_ratio > 3) # equivalent The "area_ratio" method is available as a plain function or as a method on DRC# expressions. The plain function is equivalent to "primary.area_ratio".

+

"area_sum" - Selects the input polygons if the sum of all areas meets the condition

+ +

Usage:

+
    +
  • expression.area_sum (in condition)
  • +
+

+Returns the input polygons if the sum of their areas meets the specified +condition. This condition is evaluated on the total of all shapes generated in one step of the +"drc" loop. As there is a single primary in each loop iteration, "primary.area_sum" is +equivalent to "primary.area". +

+See Layer#drc for more details about comparison specs. +

"bbox_aspect_ratio" - Selects the input polygon according to the aspect ratio of the bounding box

Usage:

@@ -569,6 +583,19 @@ out = in.drc(primary.length >= 1.um) # equivalent The "length" method is available as a plain function or as a method on
DRC expressions. The plain function is equivalent to "primary.length".

+

"length_sum" - Selects the input edges if the sum of their lengths meets the condition

+ +

Usage:

+
    +
  • expression.length_sum (in condition)
  • +
+

+Returns the input edges if the sum of their lengths meets the specified +condition. This condition is evaluated on the total of all edges generated in one step of the +"drc" loop. +

+See Layer#drc for more details about comparison specs. +

"merged" - Returns the merged input polygons, optionally selecting multi-overlap

Usage:

@@ -635,6 +662,20 @@ out = in.drc(primary.perimeter < 10.0) # equivalent The perimeter method is available as a plain function or as a method on
DRC expressions. The plain function is equivalent to "primary.perimeter".

+

"perimeter_sum" - Selects the input polygons if the sum of all perimeters meets the condition

+ +

Usage:

+
    +
  • expression.perimeter_sum (in condition)
  • +
+

+Returns the input polygons if the sum of their perimeters meets the specified +condition. This condition is evaluated on the total of all shapes generated in one step of the +"drc" loop. As there is a single primary in each loop iteration, "primary.perimeter_sum" is +equivalent to "primary.perimeter". +

+See Layer#drc for more details about comparison specs. +

"polygons" - Converts the input shapes into polygons

Usage:

diff --git a/src/lay/lay/doc/about/drc_ref_global.xml b/src/lay/lay/doc/about/drc_ref_global.xml index 08a667dc8..bb620d7d4 100644 --- a/src/lay/lay/doc/about/drc_ref_global.xml +++ b/src/lay/lay/doc/about/drc_ref_global.xml @@ -165,32 +165,6 @@ The area_cap argument is the capacitance in Farad per square micrometer. See DeviceExtractorCapacitorWithBulk for more details about this extractor.

-

"case" - A conditional selector for the "drc" universal DRC function

- -

Usage:

-
    -
  • case(...)
  • -
-

-This function provides a conditional selector for the "drc" function. -It is used this way: -

-

-out = in.drc(case(c1, r1, c2, r2, ..., cn, rn)
-out = in.drc(case(c1, r1, c2, r2, ..., cn, rn, rdef)
-
-

-This function will evaluate c1 which is a universal DRC expression (see Layer#drc). -If the result is not empty, "case" will evaluate and return r1. Otherwise it -will continue with c2 and the result of this expression is not empty it will -return r2. Otherwise it will continue with c3/r3 etc. -

-If an odd number of arguments is given, the last expression is evaluated if -none of the conditions c1..cn gives a non-empty result. -

-As a requirement, the result types of all r1..rn expressions and the rdef -needs to be the same - i.e. all need to render polygons or edges or edge pairs. -

"cell" - Selects a cell for input on the default source

Usage:

@@ -1460,6 +1434,32 @@ is equivalent to "layer.squares" (see
DRC expressions (see Layer#drc and DRC#squares for more details).

+

"switch" - A conditional selector for the "drc" universal DRC function

+ +

Usage:

+
    +
  • switch(...)
  • +
+

+This function provides a conditional selector for the "drc" function. +It is used this way: +

+

+out = in.drc(switch(c1, r1, c2, r2, ..., cn, rn)
+out = in.drc(switch(c1, r1, c2, r2, ..., cn, rn, rdef)
+
+

+This function will evaluate c1 which is a universal DRC expression (see Layer#drc). +If the result is not empty, "switch" will evaluate and return r1. Otherwise it +will continue with c2 and the result of this expression is not empty it will +return r2. Otherwise it will continue with c3/r3 etc. +

+If an odd number of arguments is given, the last expression is evaluated if +none of the conditions c1..cn gives a non-empty result. +

+As a requirement, the result types of all r1..rn expressions and the rdef +needs to be the same - i.e. all need to render polygons or edges or edge pairs. +

"target" - Specify the target layout

Usage:

diff --git a/src/lay/lay/doc/about/drc_ref_layer.xml b/src/lay/lay/doc/about/drc_ref_layer.xml index e8e1f2ce9..e571e9476 100644 --- a/src/lay/lay/doc/about/drc_ref_layer.xml +++ b/src/lay/lay/doc/about/drc_ref_layer.xml @@ -332,41 +332,45 @@ improved performance in some applications and better readability.

The key concept for this method are DRC expressions. DRC expressions are formed by using predefined keywords like "width", operators like "&" -and method to build an abstract definition of the operations to perform +and methods to build an abstract definition of the operations to perform within the DRC.

When the DRC function is executed, it will basically visit all shapes -from the input layer (the one, the "drc" method is called on), collect -the neighbor shapes from all involved other inputs and run the requested -operations on each cluster. Currently, "drc" is only available for polygon -layers. +from the input layer. This is the layer, the "drc" method is called on. +While it does, it collects the neighbor shapes from all involved other inputs +and runs the requested operations on each cluster. +Currently, "drc" is only available for polygon layers.

-The nature of the "drc" operation is that of the loop over all (merged) input +This way, the nature of the "drc" operation is that of the loop over all (merged) input polygons. Within the operation executed on each shape, it's possible to make decisions such as "if the shape has an area larger than something, apply this -operation" etc. This can be achieved with conventional DRC functions too, +operation" or similar. This often can be achieved with conventional DRC functions too, but involves potentially complex and heavy operations such as booleans, interact -etc. For this reason, the "drc" function may provide a performance benefit. +etc. For this reason, the "drc" function may provide a better performance.

-In addition, within the loop, a single shape from the input layer is presented to +In addition, within the loop a single shape from the input layer is presented to execution engine which runs the operations. This allows using operations such as "size" without having to consider neigbor polygons growing into the area of the initial shape. In this sense, -the "drc" function allows seeing the layer as individual polygons rather than +the "drc" function sees the layer as individual polygons rather than a global "sea of polygons". This enables new applications which are otherwise difficult to implement.

-An important concept in the context of "drc" expressions is the "primary". -This expression represents a single primary shape. "Secondaries" are shapes -from other inputs. Primary shapes guide the operation - secondaries without +

Primaries and secondaries

+

+An important concept in "drc" expressions is the "primary". +The primary represents a single shape from the input layer. "Secondaries" are shapes +from other inputs. Primaries guide the operation - secondaries without primaries are not seen. The "drc" operation will look for secondaries within -a certain distance which is determined from the operations within the +a certain distance which is determined from the operations from the expression to execute. The secondaries collected in this step will not be merged, so the secondary polygons may be partial. This is important when using measurement operations like "area" on secondary polygons.

+

Checks

+

Here is an example for a generic DRC operation which performs a width -check for less than 0.5.um on the primary shapes. It uses the global#width operator: +check for less than 0.5.um on the primary shapes. It uses the width operator:

 out = in.drc(width < 0.5.um)
@@ -382,8 +386,8 @@ out = in.drc(width != 0.5.um)
 out = in.drc(0.2.um < width < 0.5.um)
 

-To specify the second input for a two-layer check, specify the second input -with the check function. Here a two-layer separation check is used (global#separation): +To specify the second input for a two-layer check, specify it in brackets in +the check function. This example shows how to use a two-layer separation check (separation):

 l1 = input(1, 0)
@@ -393,22 +397,113 @@ out = l1.drc(separation(l2) < 0.5.um)
 

The second input of this check function can be a computed expression. In this case the local loop will first evaluate the expression for the second input and -then use it inside the check. +then use the result for second input in the check. Note that this computation is +performed locally and separately for each primary and its context.

Options for the checks are also specified inside the brackets. For example, -to specify a projection metrics for width use: +to specify projection metrics ("projection") for width use:

 out = in.drc(width(projection) < 0.5.um)
 

-The "drc" function supports filter operators. These select input or derived polygons -based on their properties. These filters are: +

Edges and edge pairs

+

+Although the "drc" function operates on polygon layers, internally it is +able to handle edge and edge pair types too. Some operations generate edge pairs, +some other generate edges. As results from one operation can be processed further +in the DRC expressions, methods are available to filter, process and convert +these types. +

+For example, all checks produce edge pairs which can be converted into polygons +using the "polygons" method: +

+

+out = in.drc((width(projection) < 0.5.um).polygons)
+
+

+Note a subtle detail: when putting the "polygons" method inside the "drc" +brackets, it is executed locally on every visited primary polygon. The result +in this case is identical to the global conversion: +

+

+# same, but with "global" conversion:
+out = in.drc(width(projection) < 0.5.um).polygons
+
+

+But having the check polygons inside the loop opens new opportunities and +is more efficient in general. In the previous example, the local conversion +will keep a few edge pairs after having converted them to polygons. In +the global case, all edge pairs are collected first and then converted. +If there are many edge pairs, this requires more memory and a larger computing +overhead for managing the bigger number of shapes. +

+For the conversion of edges, edge pairs and polygons into other types, these +methods are provided:

+

+The following example decomposes the primary polygons into edges: +

+

+out = in.drc(primary.edges)
+
+

+(for backward compatibility you cannot abbreviate "primary.edges" simply as "edges" like +other functions). +

+The previous example isn't quite exciting as it is equivalent to +

+

+# Same as above
+out = in.edges
+
+

+But it gets more interesting, as within the loop, "edges" delivers the edge set for +each individual polygon. It's possible to work with this distinct set, so for example +this will give you the edges of polygons with more than four corners: +

+

+out = in.drc(primary.edges.count > 4)
+
+

+Explanation: "count" is a "quantifier" which takes any kind of set (edges, edge pairs, polygons) +and returns the set if the number of inhabitants meets the given condition. Otherwise the set +is skipped. So it will look at the edges and if there are more than four (per primary shape), +it will forward this set. +

+The same result can be achieved with classic DRC with "interact" and a figure count, but +at a much higher computation cost. +

+

Edge and edge/polygon operations

+

+The "drc" framework supports the following edge and edge/polygon operations: +

+

+

+

Filters

+

+Filter operators select input polygons or edges based on their properties. These filters are provided: +

+

For example, to select polygons with an area larger than one square micrometer, use: @@ -431,27 +526,33 @@ In the same fashion, "perimeter" applies to the perimeter of the polygon. "bbox_min" etc. will evaluate a particular dimensions of the polygon's bounding box and use the respective dimension for filtering the polygon.

-Note that it's basically possible to use the polygon filters on any kind of input. -In fact, plain "area" for example is a shortcut for "global#primary.area" indicating that +Note that it's basically possible to use the polygon filters on any input - computed and secondaries. +In fact, plain "area" for example is a shortcut for "primary.area" indicating that the area of primary shapes are supposed to be computed. However, any input other than the primary is not necessarily complete or it may consist of multiple polygons. Hence the computed values may be too big or too small. It's recommended therefore to use the measurement functions on primary polygons -only. +unless you know what you're doing. +

+

Filter predicates

The "drc" feature also supports some predicates. "predicates" are boolean values indicating a certain condition. A predicate filter works in a way that it only -passes the polygons +passes the polygons if the condition is met. +

The predicates available currently are:

For the same reason as explained above, it's recommended to use these predicates standalone, so they act on primary shapes. It's possible to use the predicates -on computed shapes or secondary input, but that may not render the desired results. +on computed shapes or secondaries, but that may not render the desired results. +

+

Logical NOT operator

The "!" operator will evaluate the expression behind it and return the current primary shape if the input is empty and return an empty polygon set @@ -462,36 +563,57 @@ not rectangles: out = in.drc(! rectangles)

-The logical "if_any" or "if_all" statements allow connecting multiple +

Logical combination operators

+

+The logical "if_any" or "if_all" functions allow connecting multiple conditions and evaluate to "true" (means: a non-empty shape set) if either -on input is a non-empty shape set ("if_any") or if all inputs are non-empty -("if_all"). For example, this will select all polygons which are rectangles +one input is a non-empty shape set ("if_any") or if all inputs are non-empty +("if_all"). +

+For example, this will select all polygons which are rectangles and whose area is larger than 20 quare micrometers:

 out = in.drc(if_all(rectangles, area > 20.0))
 

-In fact, "if_all" renders the result of the last expression, provided all -previous ones are non-empty. So this operation will render rectangles -sized by 100 nm and skip all other types of polygons: +"if_all" delivers the primary shape if all of the input expressions +render a non-empty result. +

+In contrast to this, the "if_any" operation will deliver the primary shape +if one of the input expressions renders a non-empty result. +

+The "switch" function allows selecting one input based on the results of an +expression. In the two-input form it's equivalent to "if". The first expression +is the condition. If it evaluates to a non-empty shape set, the result of the +second expression is taken. Otherwise, the result is empty. +

+Hence the following code delivers all rectangles sized by 100 nm. All +other shapes are skipped:

-out = in.drc(if_all(rectangles, sized(100.nm)))
+out = in.drc(switch(rectangles, primary.sized(100.nm)))
 

-Contrary to this, the "if_any" operation will render the first non-empty -expression result and skip the following ones. So this example will -size all rectangles by 100 nm and leave all other types of polygons -untouched: +A third expression will be considered the "else" branch: the result of +this expression will be taken if the first one is not taken. So this +example will size all rectangles and leave other shapes untouched:

-out = in.drc(if_any(rectangles.sized(100.nm), primary))
+out = in.drc(switch(rectangles, primary.sized(100.nm), primary))
 

+If more expressions are given, they are considered as a sequence of condition/result +chain (c1, e1, c2, e2, ...) in the sense of "if(c1) return(e1) else if(c2) return(e2) ...". +So the e1 is taken if c1 is met, e2 is taken when c1 is not met, but c2 is and so forth. +If there is an odd number of expressions, the last one will be the default expression +which is taken if none of the conditions is met. +

+

Polygon manipulations

+

The "drc" operations feature polygon manipulations where the input is -either the primary polygon or derived shapes. -Manipulations include sizing ("global#sized"), corner rounding ("global#rounded_corners"), smoothing ("global#smoothed") +either the primary, secondaries or derived shapes. +Manipulations include sizing ("sized"), corner rounding ("rounded_corners"), smoothing ("smoothed") and boolean operations.

This example computes a boolean AND between two layers before selecting @@ -515,13 +637,40 @@ Note that the precise form of the example above is out = l1.drc((primary & secondary(l2)).area > 1.0)

-The "global#secondar" operator indicates that "l2" is to be used as secondary input to the "drc" function. Only +The "secondary" operator indicates that "l2" is to be used as secondary input to the "drc" function. Only in this form, the operators of the boolean AND can be reversed:

 out = l1.drc((secondary(l2) & primary).area > 1.0)
 

+

Quantifiers

+

+Some filters operate on properties of the full, local, per-primary shape set. +While the loop is executed, the DRC expressions will collect shapes, either +from the primary, it's neighborhood (secondaries) or from deriving shape sets. +

+Obviously the primary is a simple one: it consists of a single shape, because +this is how the loop operates. Derived shape sets however can be more complex. +"Quantifiers" allow assessing properties of the complete, per-primary shape +set. A simple one is "DRC#count" which checks if the number of shapes within +a shape set is within a given range. +

+Obviously, "primary.count == 1" is always true. So using "count" primaries isn't +much fun. So it's better to use it on derived sets. +The following condition will select all primary shapes which have more than 13 corners: +

+

+out = in.drc(if_any(primary.corners.count > 13))
+
+

+Note an important detail here: the "if_any" function will make this statement render primary +polygons, if the expression inside gives a non-empty result. Without +"if_any", the result would be the output of "count" which is the set of all +corners where the corner count is larger than 13. +

+

Expressions as objects

+

The expression inside the "drc" function is a Ruby object and can be stored in variables. If you need the same expression multiple times, it can be more efficient to use the same Ruby object. In this example, the same expression @@ -539,31 +688,15 @@ out = l1.drc((overlap_area == 1.0) + (overlap_area == 2.0))

Note that the first line prepares the operation, but does not execute the area computation -or the boolean operation. But when the "drc" function executes the operation it will -only compute the area once as it is represented by the same Ruby object. +or the boolean operation. But when the "drc" function executes the loop over the primaries it will +only compute the area once per primary as it is represented by the same Ruby object.

-The "drc" functionality also offers support for edge pairs and edges. Edge pairs -are the results of check operations and can be turned into polygons using the -"polygons" method: +

Outlook

-

-drc = in.drc((width < 0.5.um).polygons)
-
+DRC expressions are quite rich and powerful. They provide a more intuitive way of +writing DRC expressions, are more efficient and open new opportunities. DRC +development is likely to focus on this scheme in the future.

-Similarly, polygons can be converted into edges: -

-

-drc = in.drc(primary.edges)
-
-

-The "drc" framework supports edge vs. edge and edge vs. polygon booleans, edge -filters (global#length, global#angle), edge vs. polygon interactions (global#interacting, global#overlapping), -edge sampling (global#start_segments, global#centers, global#end_segments) and edge to polygon -conversions (global#extended, global#extended_in, global#extended_out). Edge pairs -can be converted into polygons and edges and separated into first and second edges (global#first_edges, -global#second_edges). -

-The bottom line is: DRC expressions are quite rich and there is a lot more to be said and written. More formal details about the bits and pieces can be found in the DRC class documentation.

"dup" - Duplicates a layer

@@ -1014,10 +1147,10 @@ The following image shows the effect of the "in" method (input1: red, input2: bl

Objects that can be inserted are Edge objects (into edge layers) or DPolygon, DSimplePolygon, Path, DBox (into polygon layers). -Convenience methods exist to create such objects (global#edge, global#polygon, global#box and #global#path). +Convenience methods exist to create such objects (edge, polygon, box and #global#path). However, RBA constructors can used as well.

-The insert method is useful in combination with the global#polygon_layer or global#edge_layer functions: +The insert method is useful in combination with the polygon_layer or edge_layer functions:

 el = edge_layer
@@ -1683,7 +1816,7 @@ one to three parameters: a layer number, a data type (optional, default is 0)
 and a layer name (optional). Alternatively, the output can be specified by 
 a single LayerInfo object.
 

-See global#report and global#target on how to configure output to a target layout +See report and target on how to configure output to a target layout or report database.

"outside" - Selects shapes or regions of self which are outside the other region

@@ -2689,7 +2822,7 @@ each other is more or equal than min and less than max
  • projecting (in condition) : This specification is equivalent to "projection_limits" but is more intuitive, as "projecting" is written with a condition, like "projecting < 2.um". Available operators are: "==", "<", "<=", ">" and ">=". -Double-bounded ranges are also available, like: "0.5 <= projecting < 2.0". +Double-bounded ranges are also available, like: "0.5 <= projecting < 2.0".
  • transparent : performs the check without shielding (polygon layers only)
  • shielded : performs the check with shielding (polygon layers only)
  • diff --git a/src/lay/lay/doc/about/drc_ref_netter.xml b/src/lay/lay/doc/about/drc_ref_netter.xml index a0b2b14b3..f57ed7a06 100644 --- a/src/lay/lay/doc/about/drc_ref_netter.xml +++ b/src/lay/lay/doc/about/drc_ref_netter.xml @@ -281,7 +281,7 @@ form, the extractor object is given. In the second form, the extractor's class object and the new extractor's name is given.

    The device extractor is either an instance of one of the predefined extractor -classes (e.g. obtained from the utility methods such as global#mos4) or a custom class. +classes (e.g. obtained from the utility methods such as mos4) or a custom class. It provides the algorithms for deriving the device parameters from the device geometry. It needs several device recognition layers which are passed in the layer hash. @@ -289,17 +289,17 @@ several device recognition layers which are passed in the layer hash. Predefined device extractors are:

    Each device class (e.g. n-MOS/p-MOS or high Vt/low Vt) needs its own instance diff --git a/src/lay/lay/doc/about/lvs_ref_netter.xml b/src/lay/lay/doc/about/lvs_ref_netter.xml index e73991d46..91e11b964 100644 --- a/src/lay/lay/doc/about/lvs_ref_netter.xml +++ b/src/lay/lay/doc/about/lvs_ref_netter.xml @@ -19,7 +19,7 @@ The LVS Netter object inherits all methods of the global#netter function: +a Netter object, use the global netter function:

     # create a new Netter object: