Timing diagram
About timing diagrams
A timing diagram shows how digital signals change over time — clock pulses, bus transitions, data values, and high-impedance states — drawn as a set of horizontal waveform bands with a shared time axis. Hardware engineers use them to specify protocol behavior, verify setup and hold constraints, and document chip interfaces. They appear in datasheets, HDL simulation reports, and digital systems textbooks.
Schematex uses a WaveDrom-compatible signal notation — the same wave characters (0, 1, x, z, p, =, …) and data label syntax that WaveDrom pioneered — so existing WaveDrom DSL transfers directly. This page documents what the parser accepts today.
1. Your first timing diagram
The smallest useful timing diagram: a clock and one data signal. The friendliest way to write it avoids counting characters entirely:
Three rules cover 80% of usage:
- Start with the keyword
timing, optionally followed by a quoted title and[hscale: N]. - Each signal is one line:
NAME: <wave>— name, colon, then the waveform. The waveform can be:clock N— a clock generator withNperiods (addnegfor a negedge clock). No character-counting.rle <state>*<count> …— run-length segments, e.g.rle 1*2 0*6=11000000. Auto-aligns length.- a raw WaveDrom wave string — a contiguous run of state characters (no internal spaces) for fine control.
- Add
data: ["val1", "val2"]after a raw wave string to label bus segments.
Tip for alignment: the #1 cause of a broken timing diagram is signals of unequal length.
clock Nandrlemake every signal's cell count explicit, so they line up. Use raw wave strings only when you need per-cell control.
Comments must start with
#on their own line.
2. Wave characters
The wave string is a sequence of characters, one per time period. The parser accepts these:
| Character | State | Meaning |
|---|---|---|
0 | Logic low | Signal at GND / VSS |
1 | Logic high | Signal at VDD |
x | Unknown | Don't-care, undefined, or uninitialized |
z | High-Z | Tri-state / high-impedance |
p | Clock pulse (positive) | Rising-edge-active clock; one p = one full period (low→high→low) |
P | Clock pulse (positive, tall) | Same as p, visually taller |
n | Clock pulse (negative) | Falling-edge-active; one n = one full period (high→low→high) |
N | Clock pulse (negative, tall) | Same as n, visually taller |
= | Bus data | Parallel-bus segment; add labels via data: […] |
2–9 | Named bus segment | Same as =, indexed into data: […] by position |
. | Hold / continue | Extend the previous state for one more period |
h / H | Hold high | Force-high for this period |
l / L | Hold low | Force-low for this period |
u | Rising edge | Diagonal from low to high (transition only) |
d / D | Falling edge | Diagonal from high to low (transition only) |
3. Data labels
When a signal carries a bus value, tag the wave with data: ["label1", "label2", …]. Each non-empty quoted string is placed inside the corresponding = (or 2–9) segment.
MOSI: x======= data: ["0xAB","0xCD","0xEF","0x01","0x02","0x03","0x04","0x05"]Empty strings "" leave a segment unlabeled (useful for segments that extend a previous value).
MISO: zzzz==== data: ["","","","","0xFF","0x12","0x34","0x56"]
# first four z-periods have no label; four = segments get labels starting at 0xFF4. Grouping signals
Wrap related signals in a [GroupName] block. A --- line closes the group and also acts as a visual separator between groups.
[Control]
CLK: pppppppp
CS_N: 10000001
---
[Data]
MOSI: x======= data: ["0xAB","0xCD","0xEF","0x01","0x02","0x03","0x04","0x05"]
MISO: zzzz==== data: ["","","","","0xFF","0x12","0x34","0x56"]Alternative group "name" { … } syntax is also accepted (closing } closes the group).
5. Title and hscale
Title: timing "SPI Transaction" — appears at the top of the diagram.
hscale: timing "title" [hscale: 2] — scales the width of each time period. Default is 1. Use 2 for wider periods when data labels need more room.
timing "Wide bus" [hscale: 2]
CLK: pppp
DATA: ==== data: ["long label here","another","third","fourth"]6. Labels & comments
- Signal name: anything before the first
:on a signal line. Names with spaces are fine — the colon is the delimiter. - Data labels:
data: ["a", "b"]after the wave string. - Title: first token after
timingkeyword, quoted. - Comments:
#at the start of a line (after leading whitespace).
timing "Demo"
# this is a comment
CLK: pppp # ← inline trailing comment is NOT supported7. Common mistakes
| You wrote | Parser says | Fix |
|---|---|---|
CLK: p p p p (spaces in wave) | Wave string parsed as p only; the rest is treated as data clause | Remove spaces: CLK: pppp |
DATA: ===== with no data: | Segments render as unlabeled bus cells | Add data: ["A","B","C","D","E"] |
Wave character s or r | TimingParseError: Invalid wave string | Only the characters listed in §2 are valid |
CLK pppp (no colon) | Line does not match signal pattern; silently skipped | The colon after the signal name is required |
data: [A, B, C] (unquoted) | Values not recognized — parser looks for "…" | Quote each value: data: ["A","B","C"] |
[Group Name with spaces] | Group label is Group Name with spaces — parsed fine | Supported |
hscale: 2 on its own line | Not recognized (hscale goes on the header line) | timing "title" [hscale: 2] |
8. Grammar (EBNF)
document = header (blank | comment | group-open | group-close | separator | signal)*
header = "timing" ( WS quoted-string )? ( WS "[" "hscale:" number "]" )? NEWLINE
quoted-string = '"' any-char-but-quote* '"'
group-open = "[" label "]" NEWLINE
| "group" WS quoted-string WS "{"? NEWLINE
group-close = "}" NEWLINE
separator = "---" NEWLINE
signal = name ":" WS wave-string ( WS data-clause )? NEWLINE
name = any text before the first ":"
wave-string = wave-char+
wave-char = "0"|"1"|"x"|"z"
| "p"|"P"|"n"|"N"
| "h"|"H"|"l"|"L"
| "u"|"d"|"D"
| "="|"."|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"
data-clause = "data:" WS ( "[" quoted-string ("," quoted-string)* "]"
| quoted-string+ )
comment = "#" any NEWLINEAuthoritative source: src/diagrams/timing/parser.ts. If this diverges from the parser, the parser wins — please open an issue.
9. Standard compliance
Schematex timing diagrams follow the WaveDrom WaveJSON signal notation for wave characters and data labels — the same set used by WaveDrom's online editor, making Schematex DSL largely interchangeable with WaveDrom input. The hscale option, group syntax, and data label format are all compatible.
What is implemented today:
- ✅ All core wave characters:
0 1 x z p P n N h H l L u d D = . 2–9 - ✅ Data labels via
data: ["…"] - ✅ Group blocks:
[Name]andgroup "name" { }syntax - ✅
---separator / group-close - ✅
hscaleperiod-width multiplier - ⏳ Timing annotations (arrows between signal transitions,
t_su,t_pdlabels) - ⏳
phase:offset per signal (fractional cycle shift) - ⏳ WaveDrom
node:/edge:annotation blocks - ⏳ Skin / theme (
default,narrow,lowkey)
References:
- WaveDrom — https://wavedrom.com (WaveJSON specification)
- IEEE Std 1364 (Verilog HDL) — digital timing simulation concepts
- IEEE Std 1497 (Standard Delay Format) — timing annotation conventions
10. Related examples
11. Roadmap
Planned — not yet parseable. Do not use these in generated DSL today; the parser will ignore them.
- Timing annotation arrows —
annotate:block withA -> B [label: "t_su = 5ns"]syntax to draw setup/hold and propagation-delay spans between signal transitions. phase:per signal — fractional-cycle offset so signals can start part-way through a period.- WaveDrom
node:/edge:— full WaveDrom annotation block compatibility. - Skin options —
narrow(compact) andlowkey(muted palette) rendering themes. - Time axis — optional numeric time axis at the bottom (ns, µs, ps units).
Track in the GitHub issues if you need any of these sooner.