VCD Waveform Analyzer — Agent Skill
What this tool does
vcd_analyzer.py is a single-file, zero-dependency Python CLI that parses IEEE 1364 VCD files and exposes seven query commands. It reads VCD files in streaming mode (constant memory regardless of file size), handles QuestaSim bit-exploded buses, Extended VCD port states, and malformed/hostile inputs safely.
All commands support --json for structured output. Always use --json when calling from an agent.
Setup (one-time)
curl -fsSL https://raw.githubusercontent.com/neveltyc/VCD_ANALYZER/v1.3.12/vcd_analyzer.py -o vcd_analyzer.py
python3 vcd_analyzer.py --version # expect: vcd_analyzer 1.3.12
No pip install, no virtualenv, no dependencies. Python 3.9+.
Decision tree: which command to use
User wants to know...
├─ "What's in this VCD file?"
│ └─ info → file overview, signal count, time span, scopes
├─ "What signals exist?" / "Find signals matching X"
│ └─ list → signal paths with width and type
├─ "What happened between T1 and T2?"
│ └─ dump → raw value-change events in time order
├─ "Which signals are active/static?"
│ └─ summary → per-signal change count, rise/fall edges, unique values
├─ "What is the value of X at time T?"
│ └─ snapshot → all known signal values at one time point
├─ "What changed between T1 and T2?"
│ └─ compare → diff of signal values at two time points
├─ "When does condition C hold?" / "Find handshakes" / "Find state=X"
│ └─ search → condition-based search with three sub-modes:
│ ├─ interval → time ranges where condition is true (no --show)
│ ├─ segment → intervals + observed signal values (with --show)
│ └─ event → per-change snapshots (with --changed)
Command reference
Universal options (apply to every command)
| Option | Effect |
|---|---|
--json |
Always use this. Compact JSON to stdout. |
--limit N |
Max results. Default 200. --limit 0 = unlimited. |
--verbose |
Extra fields (width, type, raw values). Disables default limit. |
Time argument format
Bare integer = raw VCD ticks. With unit suffix = converted using the file's $timescale.
Valid: 0, 100ns, 17.5us, 1ms, 500ps, 200fs, .5ns
Invalid: 10.5 (ambiguous — use 10.5ns), 5 ns (no space allowed)
Filter pattern format (--filter)
Comma-separated. Plain text = case-insensitive substring match. * and ? = glob (but [ is literal, safe for bus ranges like data[7:0]).
--filter clk,rst # substring: matches tb.clk, tb.rst_n
--filter '*_valid,*_ready' # glob: matches any signal ending in _valid or _ready
--filter 'top.u_dma.*' # glob: all signals under top.u_dma scope
1. info — file overview
python3 vcd_analyzer.py --json info <file>
Key JSON fields: signal_count, time_min_ticks, time_max_ticks, duration_h, timescale, scopes[], version (simulator ID), var_types (wire/reg/real counts), synthesized_buses (auto-reassembled bit-exploded buses).
Use first on any new VCD file to learn the time range, signal count, scope hierarchy, and timescale before issuing further commands.
2. list — find signals
python3 vcd_analyzer.py --json list <file> [--filter K1,K2]
Key JSON fields: signals[].path, signals[].width, signals[].type.
Signal paths use dot-separated scope hierarchy: tb.u_cpu.u_alu.result[31:0].
3. dump — raw value changes
python3 vcd_analyzer.py --json dump <file> [--begin T] [--end T] [--filter K1,K2]
Key JSON fields: events[].time_ticks, events[].time_h, events[].path, events[].value.
Values are formatted: scalars as 0/1/x/z, vectors as decimal (0xhex), 4-state vectors as b01xz, reals as float strings, events as triggered.
Always provide --begin and --end to avoid dumping the entire file. Always provide --filter to avoid flooding output with every signal.
4. summary — signal activity overview
python3 vcd_analyzer.py --json summary <file> [--begin T] [--end T] [--filter K1,K2]
Key JSON fields: rows[].path, rows[].kind (active/static), rows[].changes, rows[].rise_count/fall_count (1-bit signals only), rows[].init, rows[].last, rows[].unique.
Use to quickly identify which signals are toggling in a time window and which are stuck.
5. snapshot — signal values at a point
python3 vcd_analyzer.py --json snapshot <file> --at T [--filter K1,K2]
Key JSON fields: signals[].path, signals[].value. Also known (how many have values) and undefined (selected but never assigned).
6. compare — diff between two times
python3 vcd_analyzer.py --json compare <file> --at T1,T2 [--filter K1,K2]
Key JSON fields: diffs[].path, diffs[].at_t1, diffs[].at_t2. Only signals whose value differs are included.
7. search — condition-based query (three modes)
This is the most powerful command. Mode is selected by which options are present:
Interval mode (no --show, no --changed)
"When is the condition true?"
python3 vcd_analyzer.py --json search <file> --condition "state=5" [--begin T] [--end T]
python3 vcd_analyzer.py --json search <file> --condition "valid=1,ready=1" [--begin T] [--end T]
Returns intervals[] with begin_ticks, begin_h, end_ticks, end_h.
Segment mode (with --show)
"When is the condition true, and what are the observed signal values during each sub-interval?"
python3 vcd_analyzer.py --json search <file> --condition "arvalid=1,arready=1" --show araddr,arlen,arid
Returns segments[] with begin_h, end_h, values: {path: formatted_value}. A new segment starts whenever any --show signal changes value while the condition remains true.
This is the primary tool for protocol transaction extraction — e.g., capturing every AXI handshake with its address and length.
Important: the JSON output key differs by mode — intervals (no --show/--changed), segments (with --show), events (with --changed). Always check the mode field.
Event mode (with --changed)
"Show me a snapshot each time a specific signal changes, while the condition holds."
python3 vcd_analyzer.py --json search <file> --changed data_out --condition "valid=1" --show data_out,valid
Returns events[] with time_ticks, time_h, values: {path: formatted_value}.
Each event fires when the --changed signal genuinely transitions (not initial assignment, not same-value re-dump). If --show is omitted, the changed signal itself becomes the show list.
Condition syntax
Comma-separated AND list. Each item: SIGNAL=VALUE, SIGNAL==VALUE, or SIGNAL!=VALUE.
- Signal pattern must match exactly one signal (use
listfirst to find the right path). - Values: decimal (
5,255), hex (0xff), binary (b1010,0b1010), 4-state (b1x0z), or the literalx/z. !=does not matchx/z/undefined. Unknown is not evidence of difference. To find unknowns, usesignal=x.- No OR operator. To search for
state=3 OR state=5, run two searches and merge results.
Workflow patterns
Pattern 1: First contact with a VCD file
1. info → learn time range, signal count, scopes, timescale
2. list → find signals of interest (use --filter to narrow)
3. summary → identify active vs static signals in the relevant window
4. dump or search → drill into specifics
Pattern 2: "What happened at time T?"
1. snapshot --at T → see all values at that moment
2. dump --begin T-delta --end T+delta → see what changed around T
3. compare --at T-delta,T+delta → diff view of the window
Pattern 3: Protocol transaction extraction (e.g., AXI)
1. list --filter '*valid,*ready,*addr,*data,*len' → find channel signals
2. search --condition "arvalid=1,arready=1" --show araddr,arlen
→ extract all read-address handshakes with address and burst length
3. search --condition "wvalid=1,wready=1" --show wdata,wstrb
→ extract all write-data beats
Pattern 4: Find when a signal enters an unexpected state
1. search --condition "state=x" → find when state goes unknown
2. search --condition "error!=0" → find when error is asserted (excludes x/z)
3. snapshot --at <first_hit_time> → see full system state at that moment
4. dump --begin <before_hit> --end <first_hit> --filter relevant_signals
→ trace what led to the bad state
Pattern 5: Clock and reset sanity check
1. summary --filter clk,rst,reset → check toggle counts and rise/fall edges
→ clk should be active with balanced rise/fall
→ rst should be static after initial assertion
Environment variables
For exceptionally large VCD files, tune resource limits:
| Variable | Default | Effect |
|---|---|---|
VCD_ANALYZER_MAX_VARS |
1,000,000 | Max $var declarations |
VCD_ANALYZER_MAX_REASSEMBLE_BITS |
65,536 | Max bits per bit-exploded bus |
Increase if the tool reports too many $var declarations or bit-exploded group has more than N bits.
Important behaviors to know
--json placement
--json can appear before or after the subcommand:
python3 vcd_analyzer.py --json info sim.vcd
python3 vcd_analyzer.py info sim.vcd --json
Output truncation
Default --limit is 200 results. If truncated: true appears in JSON output, there are more results. Use --limit 0 for unlimited, or increase the limit. The total_is_exact field tells you whether total is the true count or a lower bound (streaming commands stop counting after the first unshown result).
Time fields in JSON
Every time value appears in three forms:
*_ticks: integer, raw VCD timestamp (use for computation)*_h: human-readable string with unit (use for display to user)- Some legacy fields without suffix equal
*_ticks
Value formatting
- 1-bit:
0,1,x,z - Multi-bit clean:
decimal (0xhex)— e.g.,255 (0xff) - Multi-bit with unknowns:
b01xzprefix notation - Real/realtime: float string as-is from simulator
- Event type:
triggered
Filter vs condition signal matching
--filter allows multiple matches (substring/glob, returns all hits).
--condition signal patterns must resolve to exactly one signal. If ambiguous, the error message lists matching candidates — use a more specific path.
Bit-exploded bus reassembly
QuestaSim writes a 32-bit bus as 32 separate 1-bit $var declarations with [N] suffixes. The tool auto-reassembles these into a single bus[31:0] signal. The info command reports synthesized_buses count. This is transparent — reassembled buses appear as normal multi-bit signals in all commands.
Error handling
Errors go to stderr and exit with code 1. The error message is a single human-readable line starting with Error:. Common errors:
| Error | Cause | Fix |
|---|---|---|
condition signal pattern 'X' matches no signals |
Signal name not found | Use list to find correct path |
condition signal pattern 'X' matches N signals |
Ambiguous pattern | Use full path from list output |
end time must be >= begin time |
Reversed time range | Swap begin/end |
cannot open VCD file |
File not found | Check path |
VCD data section contains no value changes |
Empty or header-only VCD | File may be incomplete |
What this tool does NOT do
- Does not read FSDB, SHM, WLF, or any non-VCD format (convert to VCD first using vendor tools)
- Does not modify or write VCD files
- Does not support OR in conditions (use multiple searches)
- Does not support arithmetic expressions in conditions (no
addr > 0xff) - Does not support bit-select in show/condition (no
data[7:4]=0xF— filter by the full signal) - Does not provide waveform visualization (text/JSON only)
- Default limit is 200 — always check
truncatedfield and increase--limitif needed