Write VCD or FST waveforms from a simulation and open them in a viewer.
There are two ways to get a waveform file:
--trace-vcd or --trace-fst. The model records
every signal in the design from time 0, with no change to the source.$dumpfile and $dumpvars from the testbench (IEEE 1800-2023
clause 21.7). These write VCD and need no compile option.Save the counter as counter.sv:
`timescale 1ns/1ps
module counter (
input logic clk,
input logic rst,
input logic en,
output logic [3:0] count
);
always_ff @(posedge clk)
if (rst) count <= '0;
else if (en) count <= count + 1'b1;
endmodule
and its testbench as tb.sv:
`timescale 1ns/1ps
module tb;
logic clk = 0, rst = 1, en = 0;
logic [3:0] count;
counter dut (.clk, .rst, .en, .count);
always #5 clk = ~clk;
initial begin
@(negedge clk) rst = 0;
en = 1;
repeat (3) @(negedge clk);
$display("count=%0d", count);
$finish;
end
endmodule
Compile with --trace-vcd and run the model:
ryusim compile --top tb --trace-vcd tb.sv counter.sv
obj_dir/build/tb_sim
The run writes trace.vcd in the current directory. Its header lists every
scope and signal:
sed -n '/^\$timescale/,/^\$enddefinitions/p' trace.vcd
$timescale 1ps $end
$scope module tb $end
$var wire 1 ! clk $end
$var wire 4 " count $end
$scope module dut $end
$var wire 1 # clk $end
$var wire 4 $ count $end
$var wire 1 % en $end
$var wire 1 & rst $end
$upscope $end
$var wire 1 ' en $end
$var wire 1 ( rst $end
$upscope $end
$enddefinitions $end
Times in the file are in the design's global time precision, here 1ps, so the first
clock edge at 5ns is #5000.
FST is a compressed binary format that GTKWave and Surfer read. Compile with
--trace-fst. This example also sets the file name:
ryusim compile --top tb --trace-fst --trace-fst-file counter.fst tb.sv counter.sv
obj_dir/build/tb_sim
ls counter.fst
Give both --trace-vcd and --trace-fst to write both files from one
run.
The options are compiled into the model. Change them and compile again.
| Option | Effect |
|---|---|
--trace-vcd | Write a VCD file. |
--trace-vcd-file <path> | VCD file name. Default trace.vcd, relative to the directory the simulation runs in. |
--trace-fst | Write an FST file. |
--trace-fst-file <path> | FST file name. Default trace.fst. |
--trace-depth <n> | Record only the top n levels of hierarchy. 1 keeps the top module's signals and drops dut. 0 (the default) records every level. |
--trace-max-width <n> | Leave out signals wider than n bits. 0 (the default) keeps all. |
ryusim compile --help gives the default file names as
<top_module>.vcd and <top_module>.fst. The files are
written as trace.vcd and trace.fst.
The testbench can choose what to dump and when. This version of the testbench dumps the
whole tb hierarchy to counter.vcd. Save it as
tb_dump.sv:
`timescale 1ns/1ps
module tb;
logic clk = 0, rst = 1, en = 0;
logic [3:0] count;
counter dut (.clk, .rst, .en, .count);
always #5 clk = ~clk;
initial begin
$dumpfile("counter.vcd");
$dumpvars(0, tb);
@(negedge clk) rst = 0;
en = 1;
repeat (3) @(negedge clk);
$finish;
end
endmodule
Compile it without any trace option and run it:
ryusim compile --top tb -o obj_dump tb_dump.sv counter.sv
obj_dump/build/tb_sim
grep '^\$scope' counter.vcd
$scope module tb $end
$scope module dut $end
The first argument of $dumpvars is the depth: $dumpvars(1, tb) dumps
the signals of tb and none of dut. $dumpoff writes every
signal as x and pauses the dump; $dumpon writes the current values
and resumes. Without $dumpfile the file is named dump.vcd.
$dumpfile always writes VCD, whatever the file extension.
WAVES=1 adds --trace-vcd. The
cocotb guide covers it for each flow, including where
trace.vcd lands. For FST, add COMPILE_ARGS += --trace-fst to the
Makefile, or add it to the Runner's build_args.
Open the file in GTKWave or
Surfer. Both read VCD and FST. On Ubuntu and
Debian, GTKWave is the gtkwave package:
sudo apt install gtkwave
gtkwave trace.vcd
These two blocks are not run in CI: GTKWave needs a display.