Skip to content

Add FST waveform output support (--fst) #17

@thomasnormal

Description

@thomasnormal

Motivation

VCD files are ASCII text and grow very large for non-trivial simulations. FST (Fast Signal Trace) is a binary format that achieves ~50x compression over VCD while supporting the same signal types.

Currently crun/circt-sim support --vcd <file>. Adding --fst <file> would make waveform dumps practical for larger designs.

Format comparison

VCD FST SHM (Xcelium)
Format ASCII text Binary (LZ4/gzip) Proprietary binary
Compression vs VCD 1x (baseline) ~50x smaller ~20-50x smaller
Open spec Yes (IEEE 1364) Yes (community) No (Cadence proprietary)
Viewers Everything GTKWave, Surfer, VaporView SimVision only
Write library Trivial Drop-in C lib Cadence PLI/VPI only
4-state support Yes Yes Yes
Real/string types Limited Yes Yes
Random access No (sequential) Yes (block index) Yes

FST and SHM are roughly comparable in compression. FST's advantage is that it's open and has random access (seek to any time without reading from the start). SHM's advantage is tight SimVision integration and streaming during simulation.

For our use case, FST is the clear choice — it's the open-source standard that all the modern viewers support. Users who need SimVision would use --vcd and convert, or run on Xcelium directly.

FST ecosystem

Viewers that support FST:

  • GTKWave (originator of the format)
  • Surfer (modern Rust-based viewer)
  • VaporView (VSCode extension)

Simulators that dump FST:

  • Verilator (native)
  • Icarus Verilog
  • GHDL
  • NVC

NOT supported by commercial tools — Verdi uses FSDB, SimVision uses SHM, DVE uses VPD. Users of those tools would continue using --vcd and converting.

Compression

Typical 50x reduction over VCD (delta encoding + LZ4/gzip). Concrete data point: 2GB VCD → 20-50MB FST (from Verilator issue #3168).

Implementation

FST has a self-contained C library: fstapi.h + fstapi.c + fastlz.c (~4K lines total). Drop-in, no external dependencies.

Write-side API:

void *ctx = fstWriterCreate("output.fst", 1);
fstWriterSetTimescale(ctx, -9);  // 1ns
fstHandle h = fstWriterCreateVar(ctx, FST_VT_VCD_WIRE, FST_VD_OUTPUT, width, "name", 0);
fstWriterEmitTimeChange(ctx, time);
fstWriterEmitValueChange(ctx, h, "10110100");
fstWriterClose(ctx);

Integration points

  • Register signals during SimulationContext::initialize() (same as VCD)
  • Emit value changes in the signal-drive path (same as VCD)
  • Add --fst <file> cl::opt alongside existing --vcd
  • Estimated effort: ~200-300 lines of glue code

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions