T0 · At a glance
What the RNL language looks like
The notation below is that of language standard 0.3: 46 keywords; written as standard sentences, statements read as prose, and they can be written in Chinese too. The toolkit’s runtime implements every keyword. Versions 0.x promise no compatibility with each other; tools still read files of 0.2.
Anatomy of a statement
Two ways to write one statement
Free text is only for people, so one statement can be bare notation or a standard sentence. Machines read exactly the same thing, and tools can convert between the styles either way.
Reference sigils
Tell at a glance what belongs to the netlist and what belongs to RNL.
Instance in the netlistreferenced, never createdNeta node in the netlistTerminalby name, or by position such as #M1:1 (from 1)Port of this subcircuitdefined by .subckt; a lone # is the subcircuit itselfName on this levelbound once per level, visible only thereDefinitiona symbol, style, definition or set; inherited downwardRole in a definitionfilled by objects when applied; in a symbol, a lone ? is the instance drawn with itPoint“_” leaves that axis to the solver; %j = (10, 10) is a named pointSetordered; spreads one level inside another set, while {{…}} stays one memberBusa group of nets or instances with indices, such as #XI<3:0>Child objectsuch as a label named with keyPipepasses a result on to the next part; => %x names itStatement shapes
Puts M1 at (10, 20). One axis is fine too, as in @PLACE(x=10); the other is left to the solver.
Braces hold an ordered group of objects: M1 and M2 share the same y.
Parentheses right after an object say which role of the definition it fills; “and” and “are treated” are free text.
Names the object the statement makes, so %g0 can be used later, for example to place it; => %g0 at the end does the same.
Each part passes its result to the next: place it first, then mirror it left to right.
One record, with statements separated by semicolons. The record head applies to every statement inside: author records who wrote it, and priority sets the default priority (except for AS and ATTACH, which inherit the record’s priority only when it is "disabled").
Keyword families
The 46 keywords fall into nine families. Click one to see what it does and its standard sentence.
Five layout constraints
All layout intent comes down to these relations: the first four act on x or y coordinates, the fifth on orientations. A constraint that names only an axis fixes no direction; a direction such as "left-to-right" fixes which comes first.
Align: same y, in one row.
Order: strictly along x. With only the axis, forward and reverse both satisfy it; "left-to-right" fixes the direction.
Distribute: equal steps between neighbors, for example to center the tail.
Distance: B at least 3 units right of A; with "x" as the direction, either may come first.
Orientation relation: B is A mirrored left to right; which way each one faces is up to the solver.
How one level of a circuit takes effect
Once a whole level is read, it is processed in nine fixed phases. That is why a name can be used before it is defined and a bad statement affects only itself; objects generated by rules, such as the grounds the standard package adds, still get symbols and positions.
Language tourNine hands-on sections: sentences, definitions, the standard package’s defaults, sets and selections, wires, text, orientation, priority and the header.T1 · Sentences
Statements read as facts: notation and sentences
Machines read only the notation: references starting with # & % $, keywords starting with @, parameters in parentheses, braces, semicolons and =>. The words between them are free text, there or not. The standard sentences give every keyword its words, so statements of one kind read the same everywhere; the Chinese alias package turns the same sentences into Chinese.
- Machines read
- Reads as
How the standard sentences are written
- Facts, not commandsA statement says what holds in the drawing, not an action to take. Objects are the subject, the keyword is the verb or noun, parameters are its values; only linking words such as is, are, has and there is are added.
- No more than it saysNo words that claim more than the statement, such as must, only or required: readers believe them, and machines ignore them.
- A glossA code or axis can be followed by “, i.e., …” saying what it means:
#M2 @ORIENT("MX"), i.e., flipped upside down. - What free text may containOutside parentheses, anything except @ # & % $ ? " ; = { } ( ) [ ] < > may sit between tokens, including punctuation; a space goes before every @.
Four common slips
A reference inside free text is still a reference, while a name without its prefix becomes free text.
The free text M3 has the same name as instance #M3; is a prefix missing?
M3 has no #, so it is free text: only M1 and M2 are aligned.
No message: this is perfectly valid.
#M2 is an object even inside the “explanation”: PLACE receives two objects and places each, so M2 also lands on x = 0. Put mere remarks in /* */.
A reference is followed by . and a name: terminals use :, so .d here is free text.
This refers to M1 itself, not its drain; CURRENT takes only terminals, so the statement fails. Write #M1:d.
A reference is followed by !: a name containing it must be quoted, as in &"vdd!".
Unquoted, this is the net vdd plus the free text “!”, and this level has no net vdd.
A whole file
The five-transistor OTA from the introduction, showing the complete file at Step 2.
T2 · Definitions
AS says what things are; ATTACH says what is added to them
A definition (@DEFINE) has roles, parameters and a body. Applying it with AS or ATTACH makes a usage: an object that can be named and selected. Differential pairs, mirrored pairs, grounds and port tags all come about this way, and their definitions live in the standard package.
The objects together form the thing. The definition comes last, and the objects fill its roles: M1 fills in_p, M2 fills in_n.
The thing is added onto the objects. The definition comes first: a ground is added on net vss; it exists only for display and makes no connection.
What things are, and how they are drawn
$CURRENT_MIRROR has an empty body: applying it records “this is a current mirror” and changes nothing in the drawing. $MIRRORED has constraints in its body; when it is applied, the roles are replaced by the objects and the constraints expand into this level. $DIFFERENTIAL_PAIR has both: it records a differential pair, and its body puts the tail under the middle of the pair. The constraints in the bodies of the standard package are all of priority low: what the author writes comes first, and PRIORITY on a usage turns them off.
Write your own
In the body, roles are written ?a and parameters ?gap. Parameters go in the parentheses of AS when applying it; without them the default applies. Drag the slider to change gap and watch the file and the drawing change together.
min=?gap is a minimum: a solver may space them further; this drawing shows the tightest arrangement.
Definitions in the standard package
The language itself knows nothing of differential pairs. These are ordinary definitions the standard package writes in RNL; click one to see it. A definition of the same name in a file hides them.
T3 · Defaults
Write nothing, and it still draws
The standard package is an RNL file containing default symbols, styles, definitions, and fill rules. It is loaded before every file, so anything a file writes can override it; see the standard package gallery for the contents of each package. The common-emitter stage below starts as a bare netlist; step through the two presets to add three RNL lines and see how the standard package’s automatic fill changes (shown in gray).
Default symbols
In a SPICE netlist, symbols are chosen first by the first letter of the instance name, then by the model’s type; in a Spectre netlist, by the master and the model’s type. SET-SYMBOL in a file comes later, so it overrides them.
| Instances | Symbol | Terminals |
|---|---|---|
R* C* L* | $RESISTOR $CAPACITOR $INDUCTOR | p n |
V* I* | $VOLTAGE_SOURCE $CURRENT_SOURCE | p n |
D* | $DIODE | a k |
E* G* | $VCVS_4TERM $VCCS_4TERM | p n cp cn |
M* | $NMOS_4TERM; type pmos $PMOS_4TERM | d g s b |
Q* | $NPN; type pnp $PNP | c b e |
The symbols of the other elements, such as F, H, B, S, W, J, T and U, and how every symbol looks, are in the gallery of the standard packages.
Fill rules (excerpt)
The standard package is RNL itself. A few sets are the hooks for a file: add to them or take from them, and the fill follows.
T4 · Sets and selections
Sets spread one level; selections are rules
Braces write an ordered set. A set referenced inside another set contributes its members; to keep it as one member, wrap it in another pair of braces. Objects picked by a selection form a set too, and a selection is evaluated on its own level and once on each level below.
Spread, or one member
Suppose %s1 = {#M1 #M2} and %s2 = {#M3 #M4}. In our LLM writing benchmark, about 15 runs produced the left form when intending the right one. Press “Another arrangement” to see which arrangements each allows.
Members: M1 M2 M3 M4
Four instances ordered one by one: only M1 M2 M3 M4, or the reverse.
Members: {M1 M2} {M3 M4}
The two groups are ordered by their centers; inside each group any order holds.
Selecting by condition
A selection picks objects from a scope by condition: with #, the scope is the whole level; with a net, the scope is the objects connected to that net. Click a statement to see what it picks.
Once on every level
A rule is treated like a definition: written at the top, it is evaluated on the top level and once in every subcircuit below, each time looking only at that level’s objects. With recursive=false it takes effect only on its own level.
T5 · Wires
Only a shared point joins wires
WIRE takes a net and an ordered list of points, each a terminal or a point object. The net is only a note; connections are still defined by the netlist. Whether drawn wires join depends only on whether they share the same point object or terminal.
Six routing modes
Every point in the list is visited; how a wire goes between neighbors is set by mode. Apart from auto, each mode is a strict rule that viewers follow. Click anywhere in the drawing to move the end point.
Buses, taps and bundles
Netlists have no buses: a bus is only a way of drawing several nets as one thick line. A single wire sharing a point with the bus is a tap. A bundle (BUNDLE) draws a group of instances as one symbol, whose pins stand for the members’ terminals of the same name.
To avoid writing the route, &D<1> @ROUTE hands the whole net to the solver: branches, paths and dots are up to it.
T6 · Text
Text on an object is a label; on a point, an annotation
What TEXT attaches to decides three things: whose properties ${…} reads, where the text goes by default, and, with a key, whose child object it is. The text’s own position is separate; PLACE or dx and dy can set it.
Text markup
Text markup uses a small subset of LaTeX that language models know well. Subscripts and superscripts need braces, so g_m shows as is; ${…} reads properties of the object the text is attached to, here M1 (W=2u L=0.5u). An unknown command shows as written with a warning, and the text stays valid.
T7 · Orientation
x right, y up; eight orientation codes
Coordinates are grid units with y up, as in Virtuoso. An orientation acts about the symbol’s origin: pin positions and wire directions change with it, the terminals they belong to do not. Only these eight codes are accepted; R90 turns counterclockwise, and MYR90 and MXR90 mirror first, then turn.
Orientation relations
ORIENT-RELATION fixes no direction, only the relation: B’s orientation is A’s followed by this transform. $MIRRORED uses "MY": however A turns, B is its left-right mirror image.
T8 · Priority
Conflicts are not errors: priority first, then order
Every geometric fact has a priority: disabled, low, normal (the default) or high. Facts are taken in order of priority, highest first, and within one priority the later-written first; each is kept unless it contradicts those already kept. A PLACE is two facts, x and y, which can be dropped separately; facts expanded from a usage take the position in statement order of the statement that creates the usage.
How three records get along
Semantics and constraints, normal by default. Edited at will.
Coordinates and wires, high. Replaced as a whole on each solve; hash records the input it solved.
Manual edits are appended after it, also high: within one priority the later wins, so they override the solver.
When the input changes and the hash no longer matches, the old result still displays; the viewer only suggests solving again, with no error. On the next solve, the editor’s high coordinates are fixed positions and everything else adjusts.
T9 · Header
The header record: version, alias packages, device terminals
The header record is optional; if written, it is the first record of the file, outside any subcircuit, and there is at most one. It is always read in standard spelling, without aliases. Without it, the file is read with the tool’s default version, and tools add the header when they save the file.
Terminal names for PDK devices
A subcircuit not defined in the netlist, such as sky130_fd_pr__nfet_01v8 from a PDK, has no known terminal names, so its terminals can only be referenced by position index (such as :1). @DEVICE declares its terminal names, matching instances by name and model patterns.
E · Examples
A few small examples
The file is on the left, the drawing on the right. Hover over a line to see which part of the drawing it controls; hover over a part of the drawing to mark the lines that refer to it.