Intro
- The CSRs that are available are implementation dependent
- CSRs are generally accessed via special instructions into a 4096 entry register space, but may be memory mapped (e.g. mtime).
- CSRs have a defined priviledge level at which they can be accessed.
- CSRs may be unique per hart, or share a common value for all harts.
Example Code
The quick reference on this blog is generated from a YAML description (csr.yaml). Using that with a web template engine script (generators/yaml_jinja.py) and a template (templates/riscv-csr.h) code can be easily generated.
The C is code is include/riscv-csr.h, and there is an example examples/test_csr.c.
Accessing CSRs
The instructions to modifiy CSRs are listed here Some examples are shown below.
- Read a CSR. For example read the vendor ID mvendorid.
uint32_t vendorid;
__asm__ volatile ("csrr %0, mvendorid"
: "=r" (vendorid) /* output : register */
: /* input : none */
: /* clobbers: none */);
- Write a CSR. For example set the machine mode interrupt vector base address mtvec.
uint32_t new_mtvec = 0x10000000;
__asm__ volatile ("csrw mtvec, %0"
: /* output: none */
: "r" (new_mtvec) /* input : from register */
: /* clobbers: none */);
- Set a bit or bits via a register value. The zero register is used to discard the previous value. For example enable an interrupt via mie.
uint32_t value = 0x80; /* timer interrupt mtie */
__asm__ volatile ("csrrs zero, mie, %0"
: /* output: none */
: "r" (value) /* input : register */
: /* clobbers: none */);
- Atomically read and set a bit or bits via a register value. For example enable an interrupt via mie and save the previous enabled interrupts.
uint32_t prev_enabled;
uint32_t new_enable = 0x880; /* timer and external */
__asm__ volatile ("csrrs %0, mie, %1" /* read and write atomically */
: "=r" (prev_enabled) /* output: register %0 */
: "r" (new_enable) /* input: register %1 */
: /* clobbers: none */);
- Set a bit or bits via a immediate mask. The mask can be a constant. For example MASK=0x8 will set (mstatus.mie ) to enable machine interrupts..
#define MASK 0x08
__asm__ volatile (" csrsi mstatus, %0"
: /* output: none */
: "i" (MASK) /* input : constant immediate MASK */
: /* clobbers: none */);
- Clear a bit or bits via a immediate mask to mstatus. The mask can be a constant. For example MASK=0x8 will clear (mstatus.mie ) to disable machine interrupts..
#define MASK 0x08
__asm__ volatile (" csrci mstatus, %0"
: /* output: none */
: "i" (MASK) /* input : constant immediate MASK */
: /* clobbers: none */);