Contents

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 and rd 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

../img/test3.jpg

  • 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 to rs1, nothing is generated

  • 899 ps : rd operand

    Test 4 3+7=0xA

    ../img/test4.jpg

  • reg(@1)+reg(@2)=reg(@E)

  • Values: 3 + 7 = 0xA

  • 917 ps : rs1 operand

  • 919 ps : rs2 operand

  • 921 ps : rd operand