A C++14 re-implementation of the Fast Signal Trace (FST) waveform writer, originally designed for GtkWave.
This project provides a highly optimized, standard-compliant C++ implementation of the FST writer API. The core of this project is written in C++14 to ensure maximum compatibility with EDA tools and environments (which is usually a bit outdated), specifically targeting performance improvements for Verilator simulations.
The unittests are written in C++20.
- C++14: The core of this project is written in clean C++14 to maximize compatibility. Using
vectorandstringcan eliminate most resource management code compared to C. - High Performance: Optimized for speed to reduce simulation overhead (2x faster than the original
fstapiwhen used with Verilator). This is mainly because we process data as binary instead of strings used by the originalfstapi.c. - Drop-in Compatibility: Includes an optional C-compatible wrapper
fstapi.cpp, providing the same writer interface as the originalfstapi.c. - Robust Testing: Comprehensive unit tests written in C++20 to ensure correctness. Coverage is also generated and checked (85% line and 85% function coverage).
- Bit-true blocks: Integration tests require byte-identical corresponding blocks against the original
fstapi.c, allowing blocks of different types to appear in a different order.
We generate a detailed regression summary for every push on the main branch.
To view it:
- Go to the Commit Detail page (click the Commit SHA, usually above the files list).
- Look for a comment by
github-actions[bot]. - Click the link "Click Here to View Summary". This takes you to the Job Summary page of the Action run, where you can see the pass/fail status and coverage metrics.
fstcpp/: 🌟 MAIN Core C++ implementation, header, and unittests.fstcpp_writer.h: The new C++ API header.fstcpp_writer.cpp: The implementation.
integration_test/: 🧪 TESTS Integration tests generated by Verilator.fstapi.cpp: C-style wrapper for backward compatibility.verilator_share/*.patch: Patches for Verilator runtime.- other files: Copied from Verilator 5.046 runtime by
setup_runtime.sh.
- other folders: individual integration tests.
submodule/libfst/: Pristine upstream reference, pinned by the Git submodule.
- C++20 compatible compiler (GCC/Clang)
- CMake (3.10 or higher)
- Ninja (optional, recommended for speed)
- Verilator 5.046 (the CI version, using the C FST API for independent reference comparisons)
First, initialize the pinned reference (also done by run_regression.sh and CI):
git submodule update --init --recursiveThen, prepare and patch the Verilator runtime and libfst reference, and generate the integration test files. Rerun this after updating the submodule, patches, or Verilog files in tests/:
./integration_test/setup_runtime.shThen, to configure the project with debug symbols and prepare it for VS Code+clangd:
# Generate build files using Ninja
cmake -G Ninja -B build/debug -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .If you prefer running steps manually, our repository follows a very standard CMake workflow, here is an example:
cmake -G Ninja -B build/debug -DCMAKE_BUILD_TYPE=Debug .
cd build/debug
ninja -j$(nproc)
ctest -j$(nproc)Integration tests compare generated FST files using fst_block_compare. It matches
blocks by type and occurrence, checking every byte (including headers and compressed
payloads). Order within each block type must match; geometry and hierarchy blocks
may move relative to value-change blocks. This checks block-level byte equality,
not whole-file byte equality or decoded waveform equivalence.
Independent reference comparisons require a Verilator runtime using the C FST API (for example the original 5.046 runtime). Runtimes that include the C++ writer directly, such as 5.050, can also run the tests, but both integration binaries then use the C++ writer and do not validate it against the C reference.
The submodule/libfst reference is pinned to official
libfst commit 17f6a5d27b2f576d65b550114fbde3c035cc74a8.
integration_test/setup_runtime.sh copies fstapi.c, fstapi.h, and
fst_win_unistd.h into the ignored integration_test/verilator_share/gtkwave/
directory and applies integration_test/libfst.patch. The patch replaces only
the FastLZ and bundled LZ4 includes with the existing FastLZ-disable macros and
system <lz4.h> include. The submodule stays pristine; bundled compression
sources are never built. Setup fails if the patch no longer applies, so an
upstream update requires reviewing this adjustment. Both integration
writers use the same system LZ4 library; the runtime selects LZ4. FastLZ decoding
is unsupported by this patched reference.
To compare two files manually after building:
build/debug/fst_block_compare reference.fst output.fstTo run the full regression suite (build, test, and coverage) just like the CI server. The regression script automatically calls setup_runtime.sh:
./run_regression.sh --coverageBy default, it will create build/regression directory.
The local regression on 2026-10-26 used verilator/verilator:v5.046 with the
CI dependencies: all 10 CTest targets passed, including both independent strict
block comparisons. Coverage was 91.9% lines (1513/1647) and 94.6% functions
(369/390). Gcov confirmed execution of the C reference in both _c binaries;
all four integration binaries linked system LZ4.
There is no standard installation step now, just copy the fstcpp/ folder to your project, and remove *.test.cpp. If you want to use the C-style wrapper, also copy integration_test/fstapi.cpp and submodule/libfst/src/fstapi.h (place the header under gtkwave/ on your include path) to your project.
The dependencies are ZLIB and lz4, which are quite easy to install on most Linux distributions.
- FST Waveform Specification (Unofficial) - A great resource for understanding the FST format internals.
- Benchmark - Contains performance benchmarks.
The main source code of this repository is licensed under the MIT License. See the LICENSE file for more details.
The root directory of this project contains a mix of original code and redistributed files:
- MIT
fstcpp/: The core of this project.submodule/libfst/: Upstreamlibfst, under its own MIT license.integration_test/: Without explicitly mentioned, all SystemVerilog files and the testbench CPP files are part of this project.fstapi.cpp: A compatibility layer wrapping this project intolibfst's original C-interface.*/verilated/: Generated by Verilator 5.046. They are derivative works and inherit the original MIT license of the SystemVerilog source.
- LGPL v3
integration_test/verilator_share/: Copied from Verilator runtime bysetup_runtime.sh(patched for bit-true).
- Projects that we have cited:
AI usage notice: The files in this repository are assisted by AI agents.