Layout Knowledge Base

Rules · Tools

What a DRC rule deck is

A DRC rule deck is the file that turns a rule manual into layer definitions, derived layers, checks, and named report categories that a design-rule-check tool runs on a layout.

Last edited: October 22, 2026

LayoutEditor window after a DRC run on SKY130 metal 1: a wide amber strap that the deck classified as huge metal, thin blue wires, and two red markers

A DRC rule deck, also called a runset or a DRC script, is a file in the language of one design rule check (DRC) tool. It reads the shapes of a layout by GDS layer and datatype, builds derived layers from them, measures widths, spacings, enclosures, and areas, and writes every violation as a marker under a named category. The foundry's rule manual states the same rules for people, as tables of rule IDs, descriptions, flags, and values. A DRC run executes the deck, not the manual. This page describes what a deck file contains, how its categories relate to the rows of a manual, and which settings in the deck decide what a clean result covers.

The picture at the top is a LayoutEditor window after a deck has run on a patch of SKY130 metal 1 drawn for this article. Blue are 26 signal wires 0.140 µm wide and a 0.5 µm bus on the right. The amber block on the left is a 5 µm supply strap, also drawn on metal 1. Its amber color is a derived layer that the deck computed and wrote out: metal 1 that the deck classifies as huge metal. Red marks the two violations. The long red band fills a 0.120 µm gap between two wires, below the 0.140 µm minimum of rule m1.2. The small red wedge on the strap edge marks a wire that ends 0.200 µm from the strap, below the 0.280 µm that applies next to huge metal. The wire ends at the bus on the right have the same gap and no marker, because the bus is not huge metal. Which shapes count as huge is decided by one line of the deck, and the manual does not contain that line.

The rule manual and the rule deck

The SkyWater SKY130 periphery rules page is a set of tables. Each row has a rule ID in parentheses, a description, flags, a value, and a unit. Parsed on October 22, 2026, the page has 601 rows with a rule ID, carrying 593 distinct IDs, and 20 of those rows carry the flag NC ("not checked by DRC"). The other flags are explained in DRC is a spellchecker.

A deck restates a subset of those rows as code. The open SKY130 deck sky130A_mr.drc is written in the KLayout DRC language and is distributed with the efabless MPW precheck tools. Its first comment line says that it implements DRC "according to" the SkyWater periphery and layers pages. Each check ends in an output statement with a category name and a description. The rule ID connects the three forms of one rule:

Form m1.1 m1.3a and m1.3b
Row in the SkyWater manual "Width of metal1", 0.140 µm spacing of and to huge_met1, 0.280 µm each
Category in sky130A_mr.drc m1.1, "m1.1 : min. m1 width : 0.14um" one category m1.3ab, "m1.3ab : min. 3um.m1 spacing m1 : 0.28um"
Check in the LayoutEditor deck on this page check "m1.1", width(m1) < 0.14 um check "m1.3ab", sep(huge_m1, m1 - huge_m1) < 0.28 um

A marker can be acted on only if its category leads back to one row of the manual. A description that carries the value, as both decks do, lets a reader judge the marker without the manual open.

What a deck file contains

Deck languages differ between tools. The open decks still contain the same six parts, in this order:

Part Content In sky130A_mr.drc Statement in LayoutEditor .ledrc
Header source documents, license, release, change history periphery and layers pages; GPLv3; release = "2024.2.11_01.09"; dated history # comment lines
Parameters and switches input and report files, rule groups, process options input, report, feol, beol, offgrid, floating_met, sram_exclude; constants AL and CU for the back end select_checks, unselect_checks, include
Engine setup units, hierarchy mode, threads deep, 4 threads unless set units, grid, mode, threads, source
Layer map names bound to GDS layer/datatype pairs 89 bindings, for example metal 1 on 68/20 layer m1 = input(68, 20)
Derived layers booleans, sizing, selections huge metal, core areas, device regions layer name = expression
Checks and output one measurement per rule, one category per result 282 output statements check "id" "text" : expression

The layer map ties a deck to the layer and datatype numbers of one PDK. If a layout carries metal 1 on another datatype, the deck reads an empty layer, and every check on that layer passes.

Derived layers: huge metal

Some rules apply to shapes that no designer draws on a layer of their own. Rules m1.3a and m1.3b set a larger spacing for "huge_met1", but the periphery page gives no width that defines huge_met1. sky130A_mr.drc defines it in one line: shrink metal 1 by 1.5 µm, grow the result by the same amount, snap it to the manufacturing grid of 0.005 µm, and keep the part that lies on the original metal 1. A shape narrower than 3 µm disappears in the shrink; wider shapes return to their original outline. The deck then checks m1.2 only on edges of metal 1 that are not huge, and writes spacing violations of huge metal to all metal 1 into m1.3ab. The width threshold is a property of this deck; the label of its category, "3um.m1", states the same width. Derived layers also select device regions, core areas, and mask layers built from boolean operations.

Close-up in LayoutEditor: the amber strap edge on the left, blue wires ending near it, and a red wedge between the strap and the end of one wire

The close-up shows the strap edge from the first picture. The wire with the marker ends 0.200 µm from the strap. The wires above and below end exactly on the rule value and carry no marker. The marker is the area between the two measured edges: the full width of the wire end on one side, 0.532 µm of the strap edge on the other. The strap edge is longer because the check uses the euclidean distance, so strap points diagonal to the wire's corners are also within reach.

Manual rows and deck categories are not one-to-one

Counting the output statements of sky130A_mr.drc, release 2024.2.11_01.09, read on October 22, 2026:

Item Count
output statements 282
distinct category names 262
category names identical to a rule ID on the periphery page 93
per-layer grid and angle categories, for example nwell_OFFGRID with the description "x.1b : OFFGRID vertex on nwell" 75
categories with the prefix MR_, which the periphery page does not use 6

The differences have four causes. Some manual rows are merged into one category, as m1.3a and m1.3b are. One manual rule can be split into many categories: the grid rule x.1b becomes one category per layer, and its ID moves into the description. Some rows are not checks: NC rows, and rows that only give the window size or step of another rule, such as m1.pd.2a and m1.pd.2b. And some rules with a value are absent: this deck has no category for the metal 1 pattern-density rule m1.pd.1 (flags RR and AL), which density rules and fill describes.

A coverage list therefore compares the rule IDs of the manual with the category names and descriptions of the deck. Each manual ID ends in one of three states: checked under its own name, checked inside a merged or split category, or not checked. The third group is the list of rules that a clean report does not cover. A row counts as checked only when the check encodes its full condition: m1.5 asks for a 0.060 µm enclosure of mcon by metal 1 on one of two adjacent sides, which a plain 0.060 µm enclosure check over-reports, and checking m1.5, li.5, and via.5a in .ledrc writes it as one enc check with the rect_sides option.

Switches and deck variants

One process can have several valid rule sets. The README of the GF180MCU KLayout runset lists the combined options --gf180mcu=A, B, and C for 3, 4, and 5 metal levels, with top-metal thicknesses 30K, 11K, and 9K and MIM options A, B, and B. It also lists rule-group switches with their defaults: FEOL, BEOL, and OFFGRID on; connectivity, density, and antenna off. The checks are split into three deck files (main, antenna, density), started by the wrapper script run_drc.py, which writes a .lyrdb report. The SKY130 manual names switches inside rule descriptions: x.17 (floating labels) is "enabled by using switch floating_labels", and x.29 is "checked when switch nfet_in_dnwell is turned on".

Switch defaults decide what a run checks. The change history of sky130A_mr.drc has an entry dated 2024-08-15: "Fix defaults for arguments when they are not passed in the CLI". In the file as read, the parameters feol, beol, and offgrid default to "false" when they are not passed, and all 282 output statements sit inside the three blocks that those switches enable: 106 in FEOL blocks, 99 in BEOL, 77 in OFFGRID. The batch command in a comment of the same file passes only the input and report files. Read line by line, a run started with exactly that command writes a report without executing a single check. The release string also still reads 2024.2.11_01.09, while the history continues to September 1, 2024. A file name and a release string do not identify the rules that ran; the file content and the switch values do.

Magic keeps its deck inside the technology file, in a section named drc. The same file has a version section that the Magic maintainer's manual reserves for version control by the file's maintainers, and the manual recommends a fast style for interactive checking next to a complete style for sign-off.

User units and database units

A deck states rule values in the units of its language, and two languages used on open PDKs disagree. In the KLayout DRC language, a floating-point number is micrometers and an integer is database units; its manual adds "Not integer micron values!". In LayoutEditor's .ledrc, a bare number is a user unit set by the units line (units 1e-6 is one micrometer), and database units need the suffix dbu. The database unit itself comes from the layout file, not from the deck. A rule value typed as an integer therefore means a different length in each language. On the test layout further down, width(m1) < 140 returns 24 markers (each of the 12 rectangles is narrower than 140 µm in both directions), while width(m1) < 140 dbu returns one. A unit on every value removes the ambiguity.

Flat, hierarchical, and tiled runs

A deck also sets how the tool walks the layout. Flat mode merges the hierarchy into one cell. Deep (hierarchical) mode checks each unique cell once and then the interactions between placed cells. Tiled mode cuts the layout into rectangles with an overlap border and can process the work on several threads. KLayout and LayoutEditor both treat deep and tiled mode as mutually exclusive. The .ledrc reference states that a border at least as large as the check limit finds the same marker across a tile seam as flat mode, and uses the largest check limit as the border when none is given. sky130A_mr.drc runs deep; the GF180MCU wrapper defaults to flat. On the test layout below, the LayoutEditor deck in mode tiles 20 um, border 2 um returned the same six markers, case by case, as in flat mode.

A small deck in LayoutEditor

The deck below implements m1.1, m1.2, m1.3a/m1.3b, m1.6, and x.1b as a LayoutEditor .ledrc file. The layer map is a separate file, so that every deck of a project reads the same layer numbers:

layer mcon = input(67, 44)
layer m1   = input(68, 20)
layer via  = input(68, 44)

The main deck carries a version line and its sources, the setup, the include of the layer file, one derived layer, and one check per category:

# sky130_m1.ledrc  deck 1.0, 2026-10-22
# source: SKY130 periphery rules m1.1 m1.2 m1.3a m1.3b m1.6 x.1b
units 1e-6
grid 0.005 um
mode flat
include "sky130_layers.ledrc"

# derived layer: metal1 that survives a 1.5 um shrink and regrow
layer huge_m1 = sized(sized(m1, -1.5 um), 1.5 um) & m1

check "m1.1"   "m1.1 : met1 width >= 0.140 um"   : width(m1) < 0.14 um
check "m1.2"   "m1.2 : met1 spacing >= 0.140 um" : space(m1) < 0.14 um
check "m1.3ab" "m1.3ab : huge_met1 to met1 spacing >= 0.280 um" : sep(huge_m1, m1 - huge_m1) < 0.28 um
check "m1.6"   "m1.6 : met1 area >= 0.083 um2"   : area(m1) < 0.083 um2
check "x.1b"   "x.1b : met1 vertex on 0.005 um grid" : ongrid(m1) != 0.005 um

include inserts the named file at that line; the path is relative to the main deck. This deck checks m1.2 on all metal 1, so a gap below 0.140 µm next to huge metal produces two markers, m1.2 and m1.3ab. sky130A_mr.drc avoids that by excluding huge edges from m1.2. Both are valid encodings of the same two rows, with different marker counts.

LayoutEditor window with eight small metal 1 test cases in two rows, two amber plates, and red markers on a narrow strap, in a gap, beside a plate, and on a small square

The third picture shows the test layout, written with LayoutScript, after the run. Top row, left to right: a strap 0.120 µm wide (the m1.1 marker covers it), two straps 0.100 µm apart (m1.2 marker in the gap), two 0.5 µm straps with a 0.2 µm gap (no marker, neither is huge), and a 4 µm plate with a strap at the same 0.2 µm gap (m1.3ab marker). Bottom row: the same plate with the strap at the rule value (no marker), an island of 0.060 µm² (the m1.6 marker covers it), a strap whose left edge is 0.002 µm off the grid (two x.1b markers at its left corners, too small to see at this scale), and a clean strap. The deck runs from the command line:

layout --drc sky130_m1.ledrc deck_test.gds --outdir=drc_out

The report starts with the number of checks that ran and the number of markers, then one row per marker with the category, the two measured edges, and the measured distance in nanometers:

checks 5
errors 6
unsupported 0
m1.1    120,2000 120,0 | 0,0 0,2000  120
m1.2    10500,2000 10500,0 | 10600,0 10600,2000  100
m1.3ab  34000,4000 34000,0 | 34200,0 34200,4000  200
m1.6    50000,0 50200,0 | 50000,300 50200,300  0
x.1b    60002,2000 60002,2000 | 60002,2000 60002,2000  0
x.1b    60002,0 60002,0 | 60002,0 60002,0  0

The test script compares every case with a marker count written down in advance and fails on any difference.

A run that checked nothing

A deck variant can reuse the main deck and restrict it. select_checks takes a glob over check IDs:

select_checks "m1.3*"
include "sky130_m1.ledrc"

On the same test file this variant reports checks 1 and one m1.3ab marker. The glob is case-sensitive. With select_checks "M1.*", no ID matches, and the .ledrc reference states the result: "No match: no checks, not all of them."

full   exit 1  checks 5  errors 6  m1.1 1 m1.2 1 m1.3ab 1 m1.6 1 x.1b 2
huge   exit 1  checks 1  errors 1  m1.3ab 1
wrong  exit 0  checks 0  errors 0

The third run has exit status 0 and zero errors, the same as a clean layout. Only the checks line separates the two. The switch defaults of sky130A_mr.drc described above lead to the same state. A log that records only the error count cannot show it.

Deck versions

Decks change with the PDK. The history of sky130A_mr.drc for 2024-08-18 adds eight rules, among them rdl.1, rdl.2, and MR_li.WID.4, and renames the licon checks. A new rule can mark a layout that passed the previous release. A renamed category breaks every waiver and every script that matches the old name. What a PDK actually contains describes where decks sit among the other files of a kit.

Failure modes

Failure Effect Check
Rule-group switch off, or off by default categories absent; possibly no check at all checks count in the log; category list of the report
Wrong process option (metal stack, back end) rules of another option applied option recorded with the result (GF180MCU A/B/C; SKY130 AL/CU)
Layer map does not match the layout's datatypes layer read as empty; its checks pass a test layout with one violating shape per layer
Rule value written as an integer value read in another unit a unit on every value
Selection glob matches nothing zero checks, exit status 0 checks line
Tile border smaller than a check distance violations across tile seams can be missed border at least the largest check value
Manual row not in the deck (NC, descriptive, merged, absent) rule not verified by the run ID-to-category coverage list
Deck release differs from the manual or PDK revision rules added, renamed, or changed deck file and PDK revision in the sign-off record

A sign-off record for a DRC run names the deck file and its checksum, the PDK revision, every switch and option value, the number of checks that ran, and the coverage list of manual rule IDs that the deck does not check. With those five items, a report with zero markers can be compared with the manual row by row; without them, zero markers only shows that the categories which ran found nothing.

Continue exploring