Skip to content

About

FST writer library

Resources

Stars

7 stars

Watchers

2 watching

Forks

Repository files navigation

High-Performance FST Waveform Writer

A C++14 re-implementation of the Fast Signal Trace (FST) waveform writer, originally designed for GtkWave.

🚀 Overview

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.

Key Features

  • C++14: The core of this project is written in clean C++14 to maximize compatibility. Using vector and string can eliminate most resource management code compared to C.
  • High Performance: Optimized for speed to reduce simulation overhead (2x faster than the original fstapi when used with Verilator). This is mainly because we process data as binary instead of strings used by the original fstapi.c.
  • Drop-in Compatibility: Includes an optional C-compatible wrapper fstapi.cpp, providing the same writer interface as the original fstapi.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.

Regression Reports (WIP due to GitHub Actions permission issue)

We generate a detailed regression summary for every push on the main branch. To view it:

  1. Go to the Commit Detail page (click the Commit SHA, usually above the files list).
  2. Look for a comment by github-actions[bot].
  3. 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.

📂 Project Structure

  • 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.

🛠️ Build & Testing & Installation

Prerequisites

  • 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)

Setup for Development

First, initialize the pinned reference (also done by run_regression.sh and CI):

git submodule update --init --recursive

Then, 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.sh

Then, 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 .

Manual Build for Development (No coverage test)

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)

Testing and Verification

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.fst

To 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 --coverage

By 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.

Installation

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.


📚 References

📄 License

The main source code of this repository is licensed under the MIT License. See the LICENSE file for more details.

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/: Upstream libfst, 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 into libfst'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 by setup_runtime.sh (patched for bit-true).
  • Projects that we have cited:

AI usage notice: The files in this repository are assisted by AI agents.

About

FST writer library

Resources

Stars

7 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages