Schematex

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.

timing·§ WaveJSON
↘ preview
100%
SPI Transaction Digital timing diagram with 4 signals 0xAB0xCD0xEF0x010x020x030x04 CLK CS_N MOSI MISO SPI Transaction
UTF-8 · LF · 5 lines · 202 chars✓ parsed·0.4 ms·5.9 KB SVG

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:

timing·§ WaveJSON
↘ preview
100%
Timing Diagram Digital timing diagram with 3 signals AB CLK RST DATA
UTF-8 · LF · 4 lines · 70 chars✓ parsed·0.3 ms·3.9 KB SVG

Three rules cover 80% of usage:

  1. Start with the keyword timing, optionally followed by a quoted title and [hscale: N].
  2. Each signal is one line: NAME: <wave> — name, colon, then the waveform. The waveform can be:
    • clock N — a clock generator with N periods (add neg for 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.
  3. 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 N and rle make 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:

CharacterStateMeaning
0Logic lowSignal at GND / VSS
1Logic highSignal at VDD
xUnknownDon't-care, undefined, or uninitialized
zHigh-ZTri-state / high-impedance
pClock pulse (positive)Rising-edge-active clock; one p = one full period (low→high→low)
PClock pulse (positive, tall)Same as p, visually taller
nClock pulse (negative)Falling-edge-active; one n = one full period (high→low→high)
NClock pulse (negative, tall)Same as n, visually taller
=Bus dataParallel-bus segment; add labels via data: […]
29Named bus segmentSame as =, indexed into data: […] by position
.Hold / continueExtend the previous state for one more period
h / HHold highForce-high for this period
l / LHold lowForce-low for this period
uRising edgeDiagonal from low to high (transition only)
d / DFalling edgeDiagonal from high to low (transition only)
timing·§ WaveJSON
↘ preview
100%
Wave character reference Digital timing diagram with 9 signals ADDRDATA clk high low unkn hiz bus hold rise fall Wave character reference
UTF-8 · LF · 10 lines · 222 chars✓ parsed·0.3 ms·8.6 KB SVG

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 29) 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 0xFF
timing·§ WaveJSON
↘ preview
100%
I2C read burst Digital timing diagram with 2 signals ADDR+RACKD0D1D2D3D4 SCL SDA I2C read burst
UTF-8 · LF · 3 lines · 122 chars✓ parsed·0.2 ms·5.3 KB SVG

4. 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).

timing·§ WaveJSON
↘ preview
100%
UART frame Digital timing diagram with 4 signals STARTD0D1D2D3D4D5D6D7STOP D0D1D2D3D4 Clock & control CLK TX_EN Data lines TX RX UART frame
UTF-8 · LF · 8 lines · 246 chars✓ parsed·0.4 ms·8.0 KB SVG

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 timing keyword, quoted.
  • Comments: # at the start of a line (after leading whitespace).
timing "Demo"
# this is a comment
CLK: pppp    # ← inline trailing comment is NOT supported

7. Common mistakes

You wroteParser saysFix
CLK: p p p p (spaces in wave)Wave string parsed as p only; the rest is treated as data clauseRemove spaces: CLK: pppp
DATA: ===== with no data:Segments render as unlabeled bus cellsAdd data: ["A","B","C","D","E"]
Wave character s or rTimingParseError: Invalid wave stringOnly the characters listed in §2 are valid
CLK pppp (no colon)Line does not match signal pattern; silently skippedThe 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 fineSupported
hscale: 2 on its own lineNot 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 NEWLINE

Authoritative 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] and group "name" { } syntax
  • --- separator / group-close
  • hscale period-width multiplier
  • ⏳ Timing annotations (arrows between signal transitions, t_su, t_pd labels)
  • 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


11. Roadmap

Planned — not yet parseable. Do not use these in generated DSL today; the parser will ignore them.

  • Timing annotation arrowsannotate: block with A -> 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 optionsnarrow (compact) and lowkey (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.