.ledrc is the LayoutEditor rule-file language. The Rule File DRC button and Execute on a .ledrc tab in the Text Editor both run this language.
The engine is beta and ships from LayoutEditor 20260823. The operators in the chapters below run. There is no remaining Partial item in this reference.
This page is the language overview. Each operator — with a figure — is listed in the chapters below.
Each operator page shows input on the left and result on the right.
Coordinates in the sketches are schematic, not to scale. Y points up, as in the layout.
A check is an expression. width(m1) < 0.14 um already produces markers. check "id" "text" : only attaches a name and a report line.
A filter keeps shapes; it does not create markers. The complement is a - with_*(a, …) (or without_* where that short form exists).
| Type | What it is | Typical origin |
|---|---|---|
| polygons | Closed rings, optionally with holes | input, boolean, sized, selection, filters |
| edges | Open contour segments | edges(a), inside_part, with_length |
| edge_pairs | Two edges plus a measured distance | Spacing checks, ongrid as a layer, with_angle on polygons |
| texts | Anchor + string | texts |
Nets are polygons that carry an identity after connect. They are not a fifth type.
units 1e-6
grid 0.005 um
mode flat
source TOP
layer m1 = input(68, 20)
layer via = input(70, 20)
layer gate = input(66, 20)
connect m1, via
connect gate, via
check "M1.W" "min width" : width(m1) < 0.14 um
check "M1.S" "min space" : space(m1) < 0.14 um
check "VIA.E" "enclosure" : enc(m1, via) < 0.05 um
check "M1.A" "min area" : area(m1) < 0.09 um2
check "M1.G" "off grid" : ongrid(m1) != 0.005 um
check "ANT.1" "antenna" : antenna(gate, m1) > 200
check "DEN.1" "density" : density(m1, window=50 um, step=25 um) < 0.20
layer dummy = fill(bounds(), exclude=m1 | via, shape=rect(0.5 um, 0.5 um), step=1.0 um)
output dummy 99, 0
inside(a, b) and a.inside(b) are the same.
UTF-8, one statement per line. # starts a comment outside "…".
units 1e-6
grid 0.005 um
mode flat
source TOP
include "common.ledrc"
| Statement | Meaning |
|---|---|
units |
Metres per user unit (default 1e-6) |
grid |
Manufacturing grid; default for ongrid(layer) without a number |
mode flat |
Flatten into the source cell (default) |
mode deep |
Hierarchical: intra-cell, then a flatten pass for neighbourhood |
mode tiles … |
Tiles; border and threads belong on this line |
threads N |
Workers for the flat scheduler (1 = serial; 0 / omitted = idealThreadCount) |
source |
Start cell |
include |
Insert another .ledrc file |
cells |
Keep shapes from matching cell names |
clip |
Clip window (AND with the rectangle) |
gds name = "file" |
Bind a second layout; input(…, from=name) |
select_checks / unselect_checks |
Which check IDs run |
max_results |
Marker cap, or all |
chip yes |
Antenna / rules on the chip top cell only |
The GDS database unit comes from the layout, not from the deck.
mode deep and mode tiles exclude each other. If border is omitted for tiles, the engine uses the largest check limit in the file. mode tiles … threads N parallelises the statement DAG inside each tile (tiles themselves stay sequential). The setup line threads N drives the flat pass; mode deep stays serial.
0.18
0.18 um
180 nm
180 dbu
0.2 um + 1 dbu
inf
Bare numbers are user units. Area uses um2. Comparisons: < <= > >= == !=.
layer name = expr
input(n) / input(n, d) read GDS layer/datatype. Unmerged: input(n, d).raw. A second layout: gds other = "file.gds" then input(n, d, from=other).
Boolean operators, weak to strong: | (OR), ^ (XOR), & (AND), - (difference). + is the same as |. a & b connected / not_connected keeps only result pieces whose A- and B-shapes sit on the same (connected) or a different (not_connected) geometric net of a|b.
sized(a, d) grows or shrinks. merged(a) unions overlapping shapes; merged(a, n) keeps n-fold overlap. extents(a) is the bbox of each shape; bounds() / bounds(a) is one bbox for the cell or the union of a. hulls / holes split outer contour and holes. snap(a, g) snaps to a grid. flatten(a) copies the layer as polygons. moved / rotated / scaled transform. rounded_corners and smoothed change vertices.
edges(a) is the contour. first_edges / second_edges take the sides of an edge pair. extended turns an edge into a band. start_segments / end_segments / centers cut a piece of length d. corners / bbox_center / intersections yield small boxes. with_edge(a, b) keeps A-shapes that share a collinear edge piece with B. polygons(x) turns pairs back into area.
Keep whole shapes of A when the relation holds to at least one shape of B: inside, outside, not_inside, interacting, overlapping, covering, touching, cutting, abutting, and the not_* forms.
Clipping (cut edges, do not keep whole polygons): inside_part / outside_part. edges(a) & b is inside_part.
One number = exact value (tolerance 0.5 dbu² for area). Two numbers = [min, max]. inf is an open end.
with_area, with_perimeter, with_holes, with_angle, with_length, with_width, rectangles, squares, rectilinear, with_bbox, with_area_ratio, with_vertex_count, path_length, with_distance.
without_* is a - with_*(a, …) except the existing short form without_length.
ongrid(a) as a layer yields off-grid vertices as degenerate edge pairs, not the whole polygons. The check ongrid(a) != g marks the same vertices.
inside(a, b) keeps A when all vertices of A lie in some polygon of B — not a full edge-inside test on concave B.
check "M1.S.1" "min space" : space(m1) < 0.18 um
check "M1.S.1" "min space" severity warn : space(m1) < 0.18 um -> 200, 0
layer nar = width(m1) < 0.14 um
severity is error (default), warn or info. The level is stored on every violation, appears as a column in .drc.rpt, and is counted as warnings / infos. The error count and exit code stay the total number of markers.
| Check | Meaning |
|---|---|
width(a) |
Inside |
space(a) |
Outside, all pairs |
notch(a) |
Outside, same shape |
isolated(a) |
Outside, different shapes |
sep(a, b) |
Outside, two layers |
enc(a, b) |
a encloses b |
enclosed(a, b) |
The reverse |
overlap(a, b) |
Overlap width |
width(a, b) |
Inside width of the overlap (AND, then RelWidth) |
Maximum width: width(m1) > 20 um. Hole area: area(holes(m1)) < 0.2 um2.
Width table: layer wide = polygons(width(m1) >= 0.5 um) then space(wide).
area, ongrid, angle, length, count / empty / not_empty, density, self_intersecting, zero_width, spikes.
Bare words after the limit (already available):
check "S.1" : space(m1) < 0.18 um projection whole_edges angle_limit(90)
euclidean (default), projection, square, manhattan, shielded (default), unshielded, without_touching_corners, without_touching_edges, whole_edges, angle_limit(α) (default 90).
New options use name=value: nets=same / nets=different, projecting=min .. max, relation=parallel|acute|perpendicular|obtuse, opposite=only|waive, rect_sides=…, eol=yes, coincident=yes.
Example: enc(m1, via) < 0.05 um eol=yes.
connect m1, via
connect gate, via
label m1, txt
check "S.U" : space(m1) < 0.18 um nets=different
check "ANT.M1" : antenna(gate, m1) > 200
connect is transitive. connect reset starts a new block. soft_connect counts for connected() / floating(), but is not conducting for nets= / antenna. Without connect, nets= on a spacing check uses geometric components of a|b; connected() / floating() / antenna have no graph.
layer dummy = fill(bounds(), exclude=m1 | via, shape=rect(0.5 um, 0.5 um), step=1.0 um)
check "D.1" : density(m1, window=50 um, step=25 um) < 0.20
The first argument of fill is always the fill region, not the keep-out. exclude= is the keep-out.
texts(n, d) reads text anchors; expand_text(t, d) makes a mini-box around each anchor. label m1, txt copies a text string onto the net.
| Path | Form |
|---|---|
| Violation list / markers | Dock button, or JSON from the Text Editor |
| Extra layer into the result | output name gds, dt |
| Check onto a GDS layer | check … -> gds, dt |
| Report / result file | report "file.rdb" / target "out.gds" — .rdb writes KLayout RDB XML, any other extension writes marker GDS |
Fill and DFM layers are geometry, not violations, unless a check runs on them.
The file may use these; new decks should write the canonical name.
| Canonical | Alias |
|---|---|
isolated |
iso |
sep |
separation |
enc |
enclosing |
euclidean |
euclidian |
\| |
+ |
unshielded |
transparent |
nets=same / nets=different |
connected / not_connected |
extended(e, out=d, in=0) |
extended_out(e, d) |
empty(a) |
count(a) == 0 |
self_intersecting |
odd_polygons |
On each operator page: