Contents

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:

Update of the write logic

https://github.com/openhwgroup/cva6/blob/master/core/csr_regfile.sv#L488

1
2
3
4
5
6
7
@@ -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
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
@@ -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
1
2
3
4
5
6
7
8
@@ -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.

1
2
3
4
5
6
7
@@ -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

1
2
3
4
5
@@ -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:

1
2
3
4
5
6
7
@@ -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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
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/

../img/verilator_custom.png