CVA6 - Adding a CSR and verifying the behavior in GTKwave
Introduction
The idea of this post is to explore how we can add a CSR in the CVA6 processor and how we can check its behavior in GTKwave. In this tutorial, we will try to add a CSR named dmpcfg
at address 0x3f0
.
Adding a CSR in the CVA6 HDL code
For the CVA6, CSRs are implemented in https://github.com/openhwgroup/cva6/blob/master/core/csr_regfile.sv. In this file, there are two important processes:
csr_read_process
: https://github.com/openhwgroup/cva6/blob/master/core/csr_regfile.sv#L188, the CSR read logic.csr_update
: https://github.com/openhwgroup/cva6/blob/master/core/csr_regfile.sv#L488, the CSR update/write logic.
Update of the write logic
https://github.com/openhwgroup/cva6/blob/master/core/csr_regfile.sv#L488
@@ -566,6 +571,9 @@ module csr_regfile import ariane_pkg::*; #(
en_ld_st_translation_d = en_ld_st_translation_q;
dirty_fp_state_csr = 1'b0;
+ // custom register - begin
+ dmpcfg_d = dmpcfg_q;
+ // custom register - end
@@ -1392,6 +1403,9 @@ module csr_regfile import ariane_pkg::*; #(
en_ld_st_translation_q <= 1'b0;
// wait for interrupt
wfi_q <= 1'b0;
+ // custom register - begin
+ dmpcfg_q <= 1'b0;
+ // custom register - end
// pmp
pmpcfg_q <= '0;
pmpaddr_q <= '0;
@@ -1437,6 +1451,9 @@ module csr_regfile import ariane_pkg::*; #(
en_ld_st_translation_q <= en_ld_st_translation_d;
// wait for interrupt
wfi_q <= wfi_d;
+ // custom register - begin
+ dmpcfg_q <= dmpcfg_d;
+ // custom register - end
@@ -149,7 +149,9 @@ module csr_regfile import ariane_pkg::*; #(
logic [63:0] cycle_q, cycle_d;
logic [63:0] instret_q, instret_d;
-
+ // custom register - begin
+ riscv::xlen_t dmpcfg_q, dmpcfg_d;
+ // custom register - end
The CSR variable goes through a D flip-flop, and can be reset in the related signal is raised: dmpcfg_q
and dmpcfg_d
are defined for this purpose.
@@ -847,6 +855,9 @@ module csr_regfile import ariane_pkg::*; #(
update_access_exception = 1'b1;
end
end
+ // custom register - begin
+ riscv::CSR_DMPCFG: dmpcfg_d = csr_wdata;
+ // custom register - end
When we want to write data, if the address is equal to CSR_DMPCFG
, csr_wdata
goes into dmpcfg_d
(similar process for other registers). CSR addresses are defined in https://github.com/openhwgroup/cva6/blob/master/core/include/riscv_pkg.sv
@@ -453,6 +453,7 @@ package riscv;
CSR_PMPADDR13 = 12'h3BD,
CSR_PMPADDR14 = 12'h3BE,
CSR_PMPADDR15 = 12'h3BF,
+ CSR_DMPCFG = 12'h3F0,
Update of the read logic
https://github.com/openhwgroup/cva6/blob/master/core/csr_regfile.sv#L188
More easier:
@@ -444,6 +446,9 @@ module csr_regfile import ariane_pkg::*; #(
read_access_exception = 1'b1;
end
end
+ // custom register - begin
+ riscv::CSR_DMPCFG: csr_rdata=dmpcfg_q;
+ // custom register - end
All modifications are also in this commit in a fork: https://github.com/pcotret/cva6/commit/b854721dc9214ff88075363af08acff9976ebbce
Verifying the new CSR in GTKwave
This small code is an example of write-then-read a custom CSR named dmpcfg
. In order to verify if the CSR can be accessed without recompiling a new toolchain, the code has been slightly modified:
int main()
{
printf("Write-then-read of a custom CSR, dmpcfg in this case\n");
write_csr(0x3f0, 0x1234ABCD);
uintptr_t ret_dmpcfg = read_csr(0x3f0);
if(ret_dmpcfg!=0x1234ABCD)
{
printf("dmpcfg W/R failed\n");
}
else
{
printf("dmpcfg W/R succeeded\n");
}
printf("Got: %" PRIxPTR "\n", ret_dmpcfg);
return 0;
}
We can finally checked this code in GTKWave as done in http://pcotret.gitlab.io/blog/cva6_vcd/