Virtual layers¶
Derived layers, declared in pdk.yml under virtual_layers: and referenced by rules
like any drawn layer. Each is a name and the sentence that makes it:
virtual_layers:
poly_otp: poly2_drawn and otp_mk
opl3a_poly: (tgate or poly_field_otp_all) and otp_mk
sab_otp_lv: (sab and otp_mk) not_interacting v5_xtor
nat4_gate: poly_nat_lv grow 0.5 inside ngate
pl7_nom: (nom_gate edges inside_part comp) with_angle min 25 max 65
mdp3c_edges: mdp3c_ncomp edges centers 99%
vdd_pins: Metal1.pin with_text "VDD*" TEXT
top_metal: metal5
Reading a sentence¶
A sentence is read from left to right: an operand, then operations, each applied to
everything before it. Parentheses group; nothing else does, so there is no table of
precedences. a grow 0.5 inside b grows a and then keeps the grown regions inside
b; a and b or c is the union of c with the intersection of a and b,
and a and (b or c) is the other thing.
An operation is a word, then its values, then — for the operations that take one — a second operand:
Values are a number, a percentage or a quoted string, as the operation wants:
grow 0.5,centers 99%,with_text "VDD*".Bounds are
minandmax, each followed by a number:with_area min 0.1444,with_angle min 25 max 65,interacting min 2 b. A bare number where a bound is expected means exactly:interacting 2 bis exactly two neighbours,with_length 0.5exactly half a micron.The second operand is a name or a parenthesised sentence:
a inside b,a and (b or c).
A name alone is an alias — top_metal: metal5 — and reads like one.
Distances are in µm, areas in µm², angles in degrees. The words are the operation names
below, under their KLayout names, so a foundry deck’s a.and(b).not(c) is written a
and b not c. What a word means follows from what stands left of it: and on two
regions is an area intersection, on two edge layers the collinear overlap; edges
turns a region into its boundary, and from there on the sentence is about edges. A word
applied to the wrong kind of layer, an unknown name, or a missing operand is refused when
the PDK loads, with the column it happened at.
Every operation in a sentence becomes one derived layer of the tiled merge cache, named
after its owner (opl3a_poly#1) where it has no name of its own; a chain of one word
(a and b and c) is the single n-ary operation it reads as. Naming an intermediate
result is therefore only a matter of reading: name it when it is a thing in its own right
or when a second sentence needs it.
Where a layer is built¶
A virtual layer is built per tile in the merge cache, from its sources’ tiles, on
first use. It costs nothing until a rule needs it, and its memory profile is the same
tile+halo bound as a drawn layer — which is what lets a chain over a dense, chip-wide
layer (Activ, the metals) stay bounded on a full chip.
The exceptions are decided by what reads the layer, not declared. A check that reads the
layout rather than the cache — no_ring, ring_covers_boundary, max_vertices,
and forbidden with op: beyond — needs its layers as shapes in the layout, so a virtual layer such a rule names is materialised up front instead
(pdk.rs → compute_virtual_layers), as is one made by inside_ring, which only
exists that way. Only union, intersection, difference, close and
inside_ring over drawn layers can be built like that; a rule that asks for
anything else is refused before the layout is read, naming the rule and the operation.
Booleans¶
or(union)The union of the operands. Duplicate polygons contributed by more than one source (e.g. two layers that happen to carry the same pad shape) are only counted once.
and(intersection)The geometric AND — empty wherever any operand is empty. Used for device-recognition layers:
CuPillarPad: Passiv.pillar and dfpad.not(difference)The first operand minus every other one:
ContNoSealring: Cont not EdgeSeal.
Region selectors¶
These keep or drop whole regions of the left operand according to how they relate to the right one. All resolve region membership by stitching each source’s tile-local pieces into whole connected regions first (see Architecture), so a region is kept or dropped as a unit and never split by a tile boundary. Each has a negated form that keeps exactly the regions the positive form drops.
The names follow KLayout’s, including its distinction between overlapping and interacting — they differ only on zero-area contact, and choosing the wrong one is a silent error, so both exist under the names a rule author reading a foundry deck expects:
Word |
Keeps the regions of the left operand that… |
|---|---|
|
share positive area with the right operand. Also spelled |
|
share area or touch the right operand — a zero-area contact counts. The right operand may also be an edge layer: the regions a boundary segment touches. |
|
lie entirely within the right operand. |
|
contain a whole region of the right operand. |
overlapping, interacting and covering take a neighbour count: metal1
interacting 2 pad keeps the metal touching exactly two pads, interacting min 2 at
least two, interacting min 2 max 4 the span. Without a count, at least one.
An empty right operand matches nothing, so the four positive words yield an empty layer
and the four negated ones pass the left operand through unchanged — inside included,
since nothing is contained in nothing.
Sizing¶
grow rMorphological dilation by
rµm, outward only. Pair withinteracting/not_interactingdownstream when the grown reach is a proximity test.within rgrow rplus one grid step of reach (5 nm). For a selection radius — “everything within r of this” — where a shape at exactlyrmerely touches the grown region, and a whole-region test reads a zero-area touch as no overlap; the hair of extra reach turns that into a hairline overlap and the shape is selected. Wanted nowhere else: a band that decides which of two limits applies, or a region a rule must not reach into, is judged wrong by any slack at all.grow_round r/within_round rgrowandwithinwith round corners (arcs of 0.01π segments): everything withinrof the source in any direction, the reach a Euclidean space rule measures. Anchoring a long-reach space rule on the sparse layer this way — grow the pad opening, then intersect with Activ — avoids giving the dense layer a halo of the full value.shrink rMorphological erosion by
rµm. A region narrower than2 × rdisappears.close rClosing (dilate then erode): regions whose gap is under
2 × rmerge into one. Used for same-net merging (NWell tie regions closer together than the rule distance). A closed pair of regions that stays separate keeps its true outer edges, so a downstreammin_spacestill measures the real gap correctly.open rOpening (erode then dilate): removes every part of a region narrower than
2 × r. A region that vanishes entirely had no spot wider than that anywhere —openfollowed bynot_interactingagainst the opened layer says “minimum width somewhere”.grow_x r/grow_y r/shrink_x r/shrink_y rSizing along one axis, leaving the other exactly as drawn — KLayout’s
sized(r, 0)and kin. Chaining all four is an opening with a box structuring element, the standard wide-metal idiom, keeping only regions at least2 × racross in both axes:WideM1: Metal1 shrink_x 5.0 shrink_y 5.0 grow_x 5.0 grow_y 5.0
Corners stay square, as KLayout’s sized keeps them, so a box’s reach along its
diagonal is √2 × radius.
Shape filters¶
Unary words that keep the regions of a certain shape:
square/not_squareA single (approximately) square region.
rectangle/not_rectangleA filled axis-aligned rectangle; a region with a hole is not filled and so is not one.
squareis the stricter special case.not_circle/not_circle_or_octagonNot an (approximately) regular circle, or neither a circle nor a regular octagon — for flagging disallowed bond-pad shapes.
with_holesRegions containing at least one hole — a ring-shaped NWell encircling an iso-PWell.
holesThe hole area of each region, as filled polygons (KLayout’s
.holes) — the interior of a substrate-tie ring. A hole only materialises in a tile whose bucket assembles the whole ring, so this serves device-scale rings, not a chip-perimeter ring whose “hole” is the entire die.extentsEach region’s bounding box, filled.
with_area min a max bRegions whose area (µm²) is in the half-open range
[min, max); either bound may be omitted, both may not.with_bbox_min min a max b/with_bbox_max min a max bFilters on a region’s bounding box:
with_bbox_mintests the shorter side,with_bbox_maxthe longer one, both in µm and half-open — a side exactly onminis kept, one exactly onmaxis not.NarrowSlots: MetalSlot with_bbox_min max 2.0keeps the slots under 2 µm across.with_text "pattern" TEXTRegions containing a text label on the
TEXTlayer matching the pattern — a trailing*makes it a case-insensitive prefix match, otherwise a case-insensitive exact match. Reads the layout’s label records directly. KLayout’sinteracting_with_text.enclosure_above d/enclosure_below d/separation_below dThe parts of the left operand whose enclosure by (or separation from) the right one is above or below
dµm — a measurement kept as geometry rather than reported, so a rule can ask where it lies.inside_ringThe part of the left operand within the area enclosed by the right one, a ring: the ring’s own holes are filled first (a seal frame becomes “frame + interior”), since there is usually no drawn layer for that interior. Built up front from drawn layers only, as the section above says. Not to be confused with the
insideselector: this one clips and fills, that one keeps or drops whole regions.
Edge layers¶
A region’s atom is a filled area: booleans combine areas, selectors keep or drop whole regions, and the checks measure between facing walls. That leaves a class of rules unsayable, because they are about one piece of a boundary rather than about a region. A transistor’s channel width is the length of the Activ boundary running under the gate; no region has that length, and the source/drain region’s own width is a different quantity.
edges turns a region into its boundary segments, and every word after it in the
sentence is an edge operation. An edge layer takes a synthetic number from the same range
and is referenced by rules exactly like any other layer — a check that accepts one says
so, and rejects a region rather than silently reporting nothing.
channel_edges: SourceDrain edges and (GatPoly edges)
res_mk_off_hres: (res_mk edges not (hres_outline edges)) inside_part poly2_drawn
mdn4a_narrow: ldnmos_body width_below 4.0
The parentheses around GatPoly edges are the left-to-right rule at work: without
them, and GatPoly would try to intersect the edges with a region, and the loader
would say so.
Word |
Right operand |
Result |
|---|---|---|
|
— |
every contour segment of the region, holes included. |
|
— |
the facing walls of the region closer than |
|
edges |
the stretches the two share collinearly. Not an area intersection: two layers that overlap in area but share no wall have no common edge at all, and a partial overlap yields the fragment rather than either whole segment. |
|
edges |
the first with every shared stretch removed, so one segment can become two. |
|
edges |
every segment of both, kept as they are. |
|
region |
the parts lying inside (or outside) the region, cut at its boundary. Every
region selector keeps or drops a region whole; these keep a piece of a segment.
A piece lying on the region’s wall is inside, on every side alike - the reading
of KLayout’s |
|
region |
the segments that touch (or do not touch) the region. |
|
edges |
the segments that touch (or do not touch) a segment of the other layer. |
|
— |
segments whose length (µm) is in the half-open range |
|
— |
segments whose orientation in degrees is in |
|
— |
the middle part of each segment: a percentage of its length, an absolute length in
µm, or both (the longer wins). Two abutting regions share a vertex, so an
|
Checks that take an edge layer: min_edge_length and max_edge_length.
Note
An edge expression upstream is not always an edge problem. poly.edges.and(
gate.edges).width(v) is the gate-length shape — the poly’s own width, measured only
between the walls it shares with the gate outline — which min_gate_length answers
on the region, choosing the walls, and no edge layer at all; walls: unshared picks
the other kind, outside: cuts them to a region’s exterior and angle: bent keeps
the 45° runs, which between them say every channel-length rule in GF180. Reach for an
edge layer when the rule measures a property of the boundary itself: a segment’s
length, or which edge of a shape is the line end.