Contents

Rocket RISC-V processor - Adding a custom CSR, software point of view

Introduction

In the context of a research project related to RIMI [1], we need to add a new CSR (Control & Status Register) in the Rocket processor [2] in order to store new security settings. There are obviously modifications to do in the hardware description of the processor (it will be the topic of a future article). However, we also need to modify a few lines of the software stack.

Software stack for Rocket Chip

rocket-tools [3] is the reference repository given by Rocket Chip maintainers. It contains:

  • The cross-compiler : riscv-gnu-toolchain

  • The simulator : riscv-isa-sim (also known as Spike)

  • An on-chip debugger : riscv-openocd

  • A proxy kernel : riscv-pk

  • Several tests : riscv-tests

Adding a custom CSR - Use case

Initial configuration

Let’s say we want to add a custom CSR labeled dmpcfg at address 0x308 (CSR ID isn’t used by any existing register).

Modifications in the software toolchain

It turns out that we have to modify a few lines in fsf-binutils-gdb @ ffea142:

1
2
3
4
// Define CSR ID
#define CSR_DMPCFG 0x308
// Creating the CSR
DECLARE_CSR(dmpcfg, CSR_DMPCFG)

This repository contains several tools such as objdump, the linker and the assembler. Modifying binutils source code didn’t seem trivial at first sight.

Why is this modification needed?

If we want to access this new CSR with a very simple C code with a default toolchain, an error appears:

1
2
3
./read_write_dmpcfg/read_write_dmpcfg.c: Assembler messages:
./read_write_dmpcfg/read_write_dmpcfg.c:14: Error: unknown CSR `dmpcfg'
./read_write_dmpcfg/read_write_dmpcfg.c:15: Error: unknown CSR `dmpcfg'
  • Yes, the assembler is involved here.

  • It seems that the dmpcfg is unknown to the software toolchain.

This error comes from a function called check_absolute_expr which call graph is as follows:

1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4

The description of riscv_ip is interesting:

This routine assembles an instruction into its binary format.

When looking at the code related to CSR (csrrw instruction):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
case 'Z':           /* CSRRxI immediate.  */
  my_getExpression (imm_expr, s);
  check_absolute_expr (ip, imm_expr, FALSE);
  if ((unsigned long) imm_expr->X_add_number > 31)
    as_bad (_("Improper CSRxI immediate (%lu)"),
            (unsigned long) imm_expr->X_add_number);
  INSERT_OPERAND (RS1, *ip, imm_expr->X_add_number);
  imm_expr->X_op = O_absent;
  s = expr_end;
  continue;

case 'E':           /* Control register.  */
  if (reg_lookup (&s, RCLASS_CSR, &regno))
    INSERT_OPERAND (CSR, *ip, regno);
  else
    {
      my_getExpression (imm_expr, s);
      check_absolute_expr (ip, imm_expr, TRUE);
      if ((unsigned long) imm_expr->X_add_number > 0xfff)
        as_bad (_("Improper CSR address (%lu)"),
                (unsigned long) imm_expr->X_add_number);
      INSERT_OPERAND (CSR, *ip, imm_expr->X_add_number);
      imm_expr->X_op = O_absent;
      s = expr_end;
    }
  continue;

It turns out the GNU assembler is checking the CSR name before assembling the binary!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
/* [...] MAYBE_CSR is true if the symbol may be an unrecognized CSR name. <= This comment !  */

static void
check_absolute_expr (struct riscv_cl_insn *ip, expressionS *ex,
                     bfd_boolean maybe_csr)
{
  if (ex->X_op == O_big)
    as_bad (_("unsupported large constant"));
  else if (maybe_csr && ex->X_op == O_symbol)
    as_bad (_("unknown CSR `%s'"),
            S_GET_NAME (ex->X_add_symbol));
  else if (ex->X_op != O_constant)
    as_bad (_("Instruction %s requires absolute expression"),
            ip->insn_mo->name);
  normalize_constant_expr (ex);
}

Once the CSR ID has been correctly in the GNU assembler (fsf-binutils-gdb submodule of [3]), the C code given in [4] is compiled without error.

References

  1. RIMI: instruction-level memory isolation for embedded systems on RISC-V
  2. GitHub - chipsalliance/rocket-chip: Rocket Chip Generator
  3. GitHub - chipsalliance/rocket-tools: Software tools that support rocket-chip
  4. Custom C simple C code