Skip to content

debugger: trigger-based VCD waveform export (logic analyser for GTKWave)#198

Merged
LinuxJedi merged 2 commits into
mainfrom
feat/waveform-vcd-export
Jul 15, 2026
Merged

debugger: trigger-based VCD waveform export (logic analyser for GTKWave)#198
LinuxJedi merged 2 commits into
mainfrom
feat/waveform-vcd-export

Conversation

@LinuxJedi

Copy link
Copy Markdown
Owner

What

Records Copperline's internal hardware signals into a VCD file for GTKWave (or any VCD viewer), like a logic analyser probing the chip bus -- plus internal state no real probe could reach:

  • beam counters (vpos/hpos/frame)
  • chip-bus owner per colour clock, DMACON, the shared chip data bus latch
  • CPU chip-bus accesses (address, fetch/read/write/custom, arbitration wait)
  • Copper PC and state (run/wait/skip/jump/stop)
  • blitter busy, pipeline slot labels (A/B/C/D, line mode, fill), channel pointers
  • custom-register writes (offset, value, CPU/Copper attribution, strobe)
  • IPL as presented to the CPU, INTREQ, INTENA
  • audio DMA grants per channel

Captures are trigger-based and bounded so files stay small: arm, wait for now / pc=ADDR / beam=VPOS[:HPOS] / reg=OFF / time=SECS, record for a fixed window (cck/frames/ms/s, default one frame, hard-capped), finish the file. Signal groups are selectable.

Surfaces

  • CLI (works headless): --waveform out.vcd --wave-trigger pc=0x00C033C2 --wave-duration 20000cck --wave-signals cpu,bus,copper,blitter
  • Console (Cmd/Alt+K): WAVE START [PATH] [TRIGGER] [DURATION] [SIGNALS], WAVE STOP, WAVE -- arguments order-free, all optional
  • Debugger window: new Wave tab with Arm/Stop buttons driven by the shared entry box

How

The per-cck sampler joins the four existing gated instrumentation sinks at the chip-bus arbitration point (advance_one_chip_bus_quantum_limited); register writes and CPU grants tap their existing choke points. Every tap sits behind a plain wave_on bool: the hot path costs a single branch while nothing is armed, and a capture observes without changing emulated timing. One VCD time unit = one colour clock (declared $timescale 1 us, the closest legal unit), so GTKWave cursor deltas read directly in cck. Timestamps are relative to the trigger.

The hand-rolled change-only VCD writer, parsers, and capture state machine live in src/waveform.rs (no new dependencies); the bus-side taps in src/bus/wave.rs. Capture state is host-side observer state -- serde-skipped, no STATE_VERSION bump. FST output is documented via GTKWave's bundled vcd2fst rather than linking a C library.

Tests

  • VCD writer, id allocation, trigger/duration/signal parsing unit tests
  • Bus-level: beam/owner/blitter-label capture on an idle bus + a scheduled A->D blit; reg= trigger firing on the matching write; early stop + re-arm with a beam trigger
  • Console: full WAVE lifecycle including the pc= trigger firing on a stepped machine
  • GUI: Wave tab render case in panels_render_into_their_rects (preview PNG below), Arm/Stop through the full control dispatch
  • cargo test --lib (1447), clippy --all-targets, fmt --check, and the release golden-probe suite all clean -- the golden renders confirm no timing change

Verified end-to-end

Booting timing-test/ddfprobe.adf with --wave-trigger time=45 --wave-duration 2f produces a structurally valid VCD (monotonic stamps, exact window) showing bitplane DMA slots, per-frame Copper wait/run cycling, and the Copper's writes to BPLCONx, DIW/DDF, bitplane pointers, and COLORxx.

Docs

New chapter docs/debugger/waveform.md; command row in console.md; Wave tab in window.md; a workflows recipe; a pointer from the headless guide; README feature line.

Record internal hardware signals -- beam counters, chip-bus owner per
colour clock, CPU chip-bus accesses, Copper PC/state, blitter pipeline
slots and pointers, custom-register writes, IPL/INTREQ/INTENA, and
audio DMA grants -- into a VCD file for GTKWave, like a logic analyser
probing the chip bus.

A capture arms with an output path, a trigger (now, pc=ADDR,
beam=VPOS[:HPOS], reg=OFF, time=SECS), a bounded duration (cck, frames,
ms, s; default one frame, capped at 10 emulated seconds), and a signal
group selection. It is exposed three ways: --waveform/--wave-trigger/
--wave-duration/--wave-signals on the CLI (works headless), a WAVE
START/STOP console command, and a new Wave tab in the debugger window.

The sampler joins the existing gated instrumentation sinks at the
chip-bus arbitration point in advance_one_chip_bus_quantum_limited;
register writes and CPU grants tap their existing choke points. Every
tap sits behind a plain wave_on bool, so the hot path costs a single
branch while nothing is armed, and a capture observes without changing
timing (the golden probe renders are unaffected). One VCD time unit is
one colour clock, so GTKWave cursor deltas read directly in cck.

The hand-rolled change-only VCD writer lives in src/waveform.rs with
the trigger/duration/signal parsing and capture state machine; the
bus-side taps live in src/bus/wave.rs. Documented in
docs/debugger/waveform.md.
Copilot AI review requested due to automatic review settings July 15, 2026 21:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a trigger-based waveform capture facility that records internal chipset activity into a bounded VCD file for viewing in GTKWave, exposed consistently across CLI, console, and the debugger UI.

Changes:

  • Introduces a VCD writer + trigger/duration/signal parsing + capture state machine (src/waveform.rs) and bus-side sampling/trigger taps (src/bus/wave.rs).
  • Adds new user-facing surfaces: CLI flags (--waveform, --wave-trigger, --wave-duration, --wave-signals), console WAVE command, and a new debugger Wave tab with Arm/Stop.
  • Adds tests and documentation covering parsing, bus-level behavior, console lifecycle, and UI rendering.

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/waveform.rs New waveform capture core: options parsing, VCD writer, capture state machine, and unit tests.
src/bus/wave.rs New bus-side waveform hooks: arming/stopping, trigger checks, and per-quantum sampling.
src/bus.rs Adds bus fields for waveform capture state and wires the new wave module.
src/bus/dma_slots.rs Calls per-quantum sampler from the chip-bus arbitration hot path when armed/capturing.
src/bus/custom_regs.rs Hooks custom-register writes for reg= trigger and register-write sampling.
src/cpu.rs Adds UI-facing wave start/stop/status APIs and a per-instruction PC-trigger tap gate.
src/chipset/copper.rs Exposes a stable copper state label string for waveform export.
src/main.rs Adds CLI parsing + help text for waveform capture flags and arms capture at startup.
src/lib.rs Exposes the new waveform module publicly.
src/video/window/console.rs Adds WAVE console command and shared waveform status line formatting.
src/video/window.rs Hooks Wave tab Arm/Stop controls into the debugger dispatch and view rendering.
src/video/ui.rs Adds the Wave tab, UI controls, button layout/rendering, and entry-box character allowance tweaks.
src/video/window/tests.rs Adds integration-style tests for Wave tab dispatch and console WAVE lifecycle.
src/bus/tests.rs Adds bus-level waveform capture tests for sampling and triggers.
docs/debugger/waveform.md New documentation chapter for waveform export usage and reference.
docs/debugger/console.md Documents the new console WAVE command.
docs/debugger/window.md Documents the new debugger Wave tab behavior and entry syntax.
docs/debugger/workflows.md Adds a workflow recipe for using waveform capture to analyze bus interleaving.
docs/guide/headless.md Adds a headless waveform capture mention and example.
docs/myst.yml Adds the waveform chapter to the docs navigation.
README.md Mentions waveform export as part of the tooling feature set.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/waveform.rs
Comment thread src/waveform.rs
Comment thread src/waveform.rs Outdated
Comment thread src/waveform.rs
Comment thread src/waveform.rs
Comment thread src/waveform.rs
Comment thread src/video/ui.rs Outdated
- Reject odd reg= trigger offsets instead of silently rounding them
  down to the neighbouring word register.
- Latch VCD write errors in the writer: a failed writer emits nothing
  further, the capture aborts at its next expiry check (instead of
  running on while silently truncating the file), the status reports
  "failed (write error)", and the finish path logs a warning.
- Allow backslash in the debugger entry box so Windows paths can be
  typed on the Waveform tab.
@LinuxJedi LinuxJedi merged commit 1f7ead4 into main Jul 15, 2026
9 checks passed
@LinuxJedi LinuxJedi deleted the feat/waveform-vcd-export branch July 15, 2026 21:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants