CVA6 - Verilator model and VCD generation
Introduction
CVA6 is a processor from the OpenHW Group: 64-bit, Linux-capable and written in SystemVerilog.
git clone https://github.com/openhwgroup/cva6
cd cva6
git submodule update --init --recursive
Toolchain
Then, you need a toolchain as explained here. Just follow the Prerequisites and Getting started sections in util/toolchain-builder
directory.
Simulators
cd <cva6_repo_root>
cd verif/regress
# Install Verilator
./install-verilator.sh
# Install Spike
./install-spike.sh
Standalone simulations
# Toolchain path
$ export RISCV=/opt/riscv_cva6
# Set environment variables
$ source verif/sim/setup-env.sh
# If needed
# export NUM_JOBS=
# Which simulator to be used, Verilator here
$ export DV_SIMULATORS=veri-testharness
# Launch default hello world simulation for cv32a65x variant
$ cd ./verif/sim
Default simulation - Hello world
$ python3 cva6.py --target cv32a65x --iss=$DV_SIMULATORS --iss_yaml=cva6.yaml \
--c_tests ../tests/custom/hello_world/hello_world.c \
--linker=../../config/gen_from_riscv_config/linker/link.ld \
--gcc_opts="-static -mcmodel=medany -fvisibility=hidden -nostdlib \
-nostartfiles -g ../tests/custom/common/syscalls.c \
../tests/custom/common/crt.S -lgcc \
-I../tests/custom/env -I../tests/custom/common"
GCC Version: 13.1.0
Spike Version: 1.1.1-dev 60e57248
Verilator Version: Verilator 5.008 2023-03-04 rev v5.008 (mod)
Creating output directory: /home/user/cva6/verif/sim/out_2025-07-25
Iteration number: 1
Compiling test: ../tests/custom/hello_world/hello_world.c
Compilation cmd: /opt/riscv_cva6/bin/riscv-none-elf-gcc ../tests/custom/hello_world/hello_world.c -I/home/user/cva6/verif/sim/dv/user_extension -T../../config/gen_from_riscv_config/linker/link.ld -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles -g ../tests/custom/common/syscalls.c ../tests/custom/common/crt.S -lgcc -I../tests/custom/env -I../tests/custom/common -o /home/user/cva6/verif/sim/out_2025-07-25/directed_tests/hello_world.o -march=rv32imc_zba_zbb_zbs_zbc_zicsr_zifencei -mabi=ilp32
Processing ISS setup file: cva6.yaml
Found matching ISS: veri-testharness
Target: cv32a65x
ISA rv32imc_zba_zbb_zbs_zbc_zicsr_zifencei
/home/user/cva6/verif/sim/out_2025-07-25/directed_tests/hello_world.o
[veri-testharness] Running ISS simulation: make veri-testharness target=cv32a65x variant=rv32imc_zba_zbb_zbs_zbc_zicsr_zifencei elf=/home/user/cva6/verif/sim/out_2025-07-25/directed_tests/hello_world.o path_var=/home/user/cva6/ tool_path=/home/user/cva6/tools/spike/bin isscomp_opts="" issrun_opts="+debug_disable=1 +ntb_random_seed=787586395" isspostrun_opts="0x0000000080000000" log=/home/user/cva6/verif/sim/out_2025-07-25/veri-testharness_sim/hello_world.cv32a65x.log &> /home/user/cva6/verif/sim/out_2025-07-25/veri-testharness_sim/hello_world.cv32a65x.log.iss
[veri-testharness] Running ISS simulation: /home/user/cva6/verif/sim/out_2025-07-25/directed_tests/hello_world.o ...done
Processing ISS setup file: cva6.yaml
Found matching ISS: veri-testharness
Target: cv32a65x
ISA rv32imc_zba_zbb_zbs_zbc_zicsr_zifencei
veri-testharness sim log dir: /home/user/cva6/verif/sim/out_2025-07-25/veri-testharness_sim
Simulation and VCD exploitation
Before launching the Python script, you just need to export TRACE_FAST=1
$ export TRACE_FAST=1
$ python3 cva6.py --target cv32a65x --iss=$DV_SIMULATORS --iss_yaml=cva6.yaml \
--c_tests ../tests/custom/hello_world/hello_world.c \
--linker=../../config/gen_from_riscv_config/linker/link.ld \
--gcc_opts="-static -mcmodel=medany -fvisibility=hidden -nostdlib \
-nostartfiles -g ../tests/custom/common/syscalls.c \
../tests/custom/common/crt.S -lgcc \
-I../tests/custom/env -I../tests/custom/common"
It will generate a VCD file in out_2025-07-25/veri-testharness_sim
which can be analyzed with GTKWave.
Default simulation - Assembly test
Running the script
$ export TRACE_FAST=1
$ python3 cva6.py --target cv32a65x --iss=$DV_SIMULATORS --iss_yaml=cva6.yaml \
--asm_tests ../tests/custom/hello_world/custom_test_template.S \
--linker=../../config/gen_from_riscv_config/linker/link.ld \
--gcc_opts="-static -mcmodel=medany -fvisibility=hidden -nostdlib \
-nostartfiles -g ../tests/custom/common/syscalls.c \
../tests/custom/common/crt.S -lgcc \
-I../tests/custom/env -I../tests/custom/common"
GCC Version: 13.1.0
Spike Version: 1.1.1-dev 60e57248
Verilator Version: Verilator 5.008 2023-03-04 rev v5.008 (mod)
Creating output directory: /home/pascal/Documents/ensta/work/test/cva6/verif/sim/out_2025-07-25
Iteration number: 1
Compiling test: ../tests/custom/hello_world/custom_test_template.S
Compilation cmd: /opt/riscv_cva6/bin/riscv-none-elf-gcc ../tests/custom/hello_world/custom_test_template.S -I/home/pascal/Documents/ensta/work/test/cva6/verif/sim/dv/user_extension -T../../config/gen_from_riscv_config/linker/link.ld -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles -g ../tests/custom/common/syscalls.c ../tests/custom/common/crt.S -lgcc -I../tests/custom/env -I../tests/custom/common -o /home/pascal/Documents/ensta/work/test/cva6/verif/sim/out_2025-07-25/directed_tests/custom_test_template.o -march=rv32imc_zba_zbb_zbs_zbc_zicsr_zifencei -mabi=ilp32
Processing ISS setup file: cva6.yaml
Found matching ISS: veri-testharness
Target: cv32a65x
ISA rv32imc_zba_zbb_zbs_zbc_zicsr_zifencei
/home/pascal/Documents/ensta/work/test/cva6/verif/sim/out_2025-07-25/directed_tests/custom_test_template.o
[veri-testharness] Running ISS simulation: make veri-testharness target=cv32a65x variant=rv32imc_zba_zbb_zbs_zbc_zicsr_zifencei elf=/home/pascal/Documents/ensta/work/test/cva6/verif/sim/out_2025-07-25/directed_tests/custom_test_template.o path_var=/home/pascal/Documents/ensta/work/test/cva6/ tool_path=/home/pascal/Documents/ensta/work/test/cva6/tools/spike/bin isscomp_opts="" issrun_opts="+debug_disable=1 +ntb_random_seed=313885687" isspostrun_opts="0x0000000080000000" log=/home/pascal/Documents/ensta/work/test/cva6/verif/sim/out_2025-07-25/veri-testharness_sim/custom_test_template.cv32a65x.log &> /home/pascal/Documents/ensta/work/test/cva6/verif/sim/out_2025-07-25/veri-testharness_sim/custom_test_template.cv32a65x.log.iss
[veri-testharness] Running ISS simulation: /home/pascal/Documents/ensta/work/test/cva6/verif/sim/out_2025-07-25/directed_tests/custom_test_template.o ...done
Processing ISS setup file: cva6.yaml
Found matching ISS: veri-testharness
Target: cv32a65x
ISA rv32imc_zba_zbb_zbs_zbc_zicsr_zifencei
veri-testharness sim log dir: /home/pascal/Documents/ensta/work/test/cva6/verif/sim/out_2025-07-25/veri-testharness_sim
Waveform analysis
todo
Example of CVA6 and GTKWave on a simple test
cd work-ver
./Variane_testharness -v rv64ui-p-add.vcd riscv-tests/isa/rv64ui-p-add
gtkwave rv64ui-p-add.vcd
Let’s say we want to analyze/check the tests 3 and 4 of rv64ui-p-add
.
In GTKWave, we will watch:
- The instruction address.
- The instruction value.
- Register addresses (
rs1
,rs2
andrd
as we check a R-type instruction). - Result of the ALU.
Reading the dump of the test, we will look at this part:
000000008000010c <test_3>:
8000010c: 00100093 li ra,1
80000110: 00100113 li sp,1
80000114: 00208733 add a4,ra,sp
80000118: 00200393 li t2,2
8000011c: 00300193 li gp,3
80000120: 4c771463 bne a4,t2,800005e8 <fail>
0000000080000124 <test_4>:
80000124: 00300093 li ra,3
80000128: 00700113 li sp,7
8000012c: 00208733 add a4,ra,sp
80000130: 00a00393 li t2,10
80000134: 00400193 li gp,4
80000138: 4a771863 bne a4,t2,800005e8 <fail>
TEST_RR_OP( 3, add, 0x00000002, 0x00000001, 0x00000001 );
TEST_RR_OP( 4, add, 0x0000000a, 0x00000003, 0x00000007 );
Signals observed in GTKWave
Note: sometimes, it’s helpful to have the Vivado project opened. Much easier to explore the CPU hierarchy
TOP.ariane_testharness.i_ariane.i_cva6.id_stage_i.fetch_entry_i.address[63:0]
TOP.ariane_testharness.i_ariane.i_cva6.id_stage_i.fetch_entry_i.instruction[31:0]
TOP.ariane_testharness.i_ariane.i_cva6.id_stage_i.decoder_i.instr.rtype.rs1[19:15]
TOP.ariane_testharness.i_ariane.i_cva6.id_stage_i.decoder_i.instr.rtype.rs2[24:20]
TOP.ariane_testharness.i_ariane.i_cva6.id_stage_i.decoder_i.instr.rtype.rd[11:7]
TOP.ariane_testharness.i_ariane.i_cva6.ex_stage_i.alu_i.result_o[63:0]
RISC-V register values can be found at: https://en.wikichip.org/wiki/risc-v/registers
Test 3 1+1=2
-
reg(@1)+reg(@2)=reg(@E)
-
Values: 1 + 1 = 2
-
895 ps :
rs1
operand -
897 ps : it should be
rs2
operand. However, as it’s equal tors1
, nothing is generated -
899 ps :
rd
operandTest 4 3+7=0xA
-
reg(@1)+reg(@2)=reg(@E)
-
Values: 3 + 7 = 0xA
-
917 ps :
rs1
operand -
919 ps :
rs2
operand -
921 ps :
rd
operand