Generate cycle-accurate SystemVerilog testbenches from VCD waveforms
Project description
wave2tb-generator
Generate a cycle-based SystemVerilog testbench from a captured VCD waveform and DUT RTL.
Why This Project Matters
- Small design team using Chisel can keep their verification written in svsim.
- Outsourced backend/PD teams usually need plain, static SV testbenches for GLS handoff.
- This tool bridges both worlds by converting captured VCD behavior into deterministic, standalone SV TB code (no Chisel runtime dependency).
- It reduces manual TB rewrite effort and lowers handoff risk between frontend and backend flows.
Workflow
- Parse DUT ports from RTL in Python (
tree-sitter-verilog). - Read VCD waveform and auto-match one DUT scope.
- Build a JSON IR containing per-cycle input stimulus and expected outputs.
- Emit a standalone SystemVerilog testbench that:
- drives the same per-cycle stimulus (only emits changed input assignments),
- steps the DUT clock,
- checks expected outputs every cycle.
Install
uv sync
After uv sync, run CLI commands with uv run (recommended), for example:
uv run wave2tb --help
If you prefer not to use uv run each time, activate the venv first:
source .venv/bin/activate
wave2tb --help
CLI
Generate testbench in one step from VCD + RTL:
uv run wave2tb vcd-to-tb \
--vcd test/out/reference.vcd \
--rtl test/data/sample_dut.sv \
--top-module sample_dut \
--clock clk \
--tb-out test/out/generated_tb.sv \
--ir-out test/out/generated.ir.json
Generate IR and testbench (legacy two-output command):
uv run wave2tb from-vcd \
--vcd test/out/reference.vcd \
--rtl test/data/sample_dut.sv \
--top-module sample_dut \
--clock clk \
--ir-out test/out/generated.ir.json \
--tb-out test/out/generated_tb.sv
Generate testbench from an existing IR:
uv run wave2tb ir-to-tb \
--ir test/out/generated.ir.json \
--tb-out test/out/generated_tb.sv
Optional external equivalence verification:
uv run wave2tb vcd-to-tb \
--vcd test/out/reference.vcd \
--rtl test/data/sample_dut.sv \
--top-module sample_dut \
--clock clk \
--tb-out test/out/generated_tb.sv \
--verify-with-verilator
End-to-End Test
Run:
bash test/run_e2e.sh
Note: the optional --verify-with-verilator flow and test/run_e2e.sh require external Verilator.
Generated Output Examples
generated.ir.json (delta IR)
generated.ir.json uses encoding: "delta" and is the intermediate format consumed by the toolchain. Core rules:
- Top-level metadata includes
schema_version,encoding,top_module,scope,timescale,clock_name, andclock_edge. - The
portsarray stores the DUT port list; each item hasdirection,name, andwidth. - The
cyclesarray is time-ordered; each entry hasindex,time,inputs, andoutputs. inputs/outputsonly store signals that changed relative to the previous cycle; an empty object means no changes in that direction for this cycle.- When loading IR, the tool performs carry-forward expansion to reconstruct full per-cycle vectors before TB generation.
generated_tb.sv (generated SystemVerilog TB)
Below is the key excerpt copied from the real test artifact test/out/generated_tb.sv: the statements inside initial begin ... end.
clk = CLK_IDLE;
rst_n = '0;
clear = '0;
en = '0;
din = '0;
mode = '0;
// cycle 0, source_time=5 (1ps)
step_to_edge();
`CHECK_EQ(accum, 6'b000000, 0, "accum");
`CHECK_EQ(dout, 4'b0000, 0, "dout");
`CHECK_EQ(valid, 1'b0, 0, "valid");
`CHECK_EQ(parity, 1'b0, 0, "parity");
step_to_idle();
// cycle 1, source_time=15 (1ps)
rst_n = 1'b1;
en = 1'b1;
din = 4'b0011;
step_to_edge();
`CHECK_EQ(accum, 6'b000011, 1, "accum");
`CHECK_EQ(dout, 4'b0011, 1, "dout");
`CHECK_EQ(valid, 1'b1, 1, "valid");
`CHECK_EQ(parity, 1'b1, 1, "parity");
step_to_idle();
$display("PASS: %0d cycles checked for sample_dut from scope reference_wave_tb.u_dut", NUM_CYCLES);
$finish;
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file wave2tb_generator-0.1.0.tar.gz.
File metadata
- Download URL: wave2tb_generator-0.1.0.tar.gz
- Upload date:
- Size: 17.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.25 {"installer":{"name":"uv","version":"0.9.25","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f563ea156924d653e510aef2ba60ded15c19746330803b4aa1b9648088ceb60f
|
|
| MD5 |
f813a769972ddcf1a6c1631ccf3df547
|
|
| BLAKE2b-256 |
e6d261848f2ccee7c6d43aa0818d9b73017152b230ef24ad4b67ee5b1ee71665
|
File details
Details for the file wave2tb_generator-0.1.0-py3-none-any.whl.
File metadata
- Download URL: wave2tb_generator-0.1.0-py3-none-any.whl
- Upload date:
- Size: 18.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.25 {"installer":{"name":"uv","version":"0.9.25","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0e23a6c49b3908aafafc385ea454bc9b56d78128f3ef7e738fd25bcdf9492d8d
|
|
| MD5 |
767be9ddfb80c52cecf83d59828aef2c
|
|
| BLAKE2b-256 |
dacd717b069aeb18517aa2a85f146d0fae09ba5796f72433c48e38ef995139f0
|