RISCV ISA
Exported from Notion, may not be well-organized.
RISCV Extensions
In RISC-V, extensions are optional instruction sets that extend the base ISA (RV32I, 32-bit integer instructions) to add extra functionality.
Some extensions are listed here:
| Extension | Meaning | Purpose |
|---|---|---|
| M | Integer Multiplication & Division | Adds mul, div, rem instructions |
| A | Atomic Instructions | Adds atomic memory operations (e.g., amoadd.w) |
| F | Single-Precision Floating Point | Supports float (32-bit) operations |
| D | Double-Precision Floating Point | Supports double (64-bit) operations |
| C | Compressed Instructions | Reduces code size (e.g., c.add, c.sw) |
For example, RV32IMAC → A 32-bit RISC-V CPU with Integer (I), Multiply (M), Atomic (A), and Compressed (C) extensions. RV32IMAFD can be reduced to written as RV32G.
Zicsr: Z (Standard), I (Integer), CSR (Support read and write to CSRs)
指令类型
ALU 运算
One category of instructions is arithmetic operations (abbr. aluop), which is just doing things between GPRs.
Commonly Used aluop instructions:
lui t0, 0x40000 ;t0 = 0x40000 << 12 (load upper 20 bits of the imm) add t0, t1, t2 ;t0 = t1 + t2 sub t0, t1, t2 ;t0 = t1 - t2 (no imm version) or t0, t1, t2 ;t0 = t1 | t2 and t0, t1, t2 ;t0 = t1 & t2 xor t0, t1, t2 ;t0 = t1 ^ t2 addi t0, t1, 10 ;t0 = t1 + 10 (decimal) ori t0, t1, 0xF ;t0 = t1 | 0xF andi t0, t1, 0xF ;t0 = t1 & 0xF xori t0, t1, 0xF ;t0 = t1 ^ 0xF sll t0, t1, t2 ;t0 = t1 << t2 (shift left logical) srl t0, t1, t2 ;t0 = t1 >> t2 (shift right logical) sra t0, t1, t2 ;t0 = t1 >> t2 (shift right arithmetic, preserve sign) slli t0, t1, 2 ;t0 = t1 << 2 srli t0, t1, 2 ;t0 = t1 >> 2 srai t0, t1, 2 ;t0 = t1 >> 2 (preserve sign) slt t0, t1, t2 ;t0 = (t1 < t2) (set if less than signed) sltu t0, t1, t2 ;t0 = (t1 < t2) (set if less than unsigned) slti t0, t1, -5 ;t0 = (t1 < -5) (imm signed) sltiu t0, t1, 10 ;t0 = (t1 < 10) (imm unsigned)
CSR 寄存器及其操作
Introduction
CSR (Control and Status Registers)
Are accessed using CSR instructions, not via memory-mapped I/O like GPIO registers.
GPRs can be accessed at any privilege level, while CSRs are defined at a specific privilege level and can only be accessed by that level and any levels of higher privilege.
Every CSR has a unique address, each 32 bits share one address (instead of 8 bits).
CSR addresses are 12-bits, meaning that up to 4,096 CSRs can be implemented (\(2^12 = 4096\)). The bits in a CSR address define its accessibility, use, and CSR number.

While GPRs are used for storing data used to perform operations, CSRs typically modify the behavior of a hart (i.e. “Control”) or inform of its state and attributes (i.e. “Status”), or both.
WARL(Write any, read legal): Some field in a CPU register that allows any value to be written, but when read back, it returns only a valid (legal) value. For example, inMPP[12:11]field inmstatusregister, we have:
| Write Attempt (MPP) | Stored Value (MPP field) |
|---|---|
| 00 (User) | ✅ 00 (User mode) |
| 11 (Machine) | ✅ 11 (Machine mode) |
| 01 (Illegal) | 🔄 Returns 00 or 11 (Legal) |
| 10 (Illegal) | 🔄 Returns 00 or 11 (Legal) |
- CSRs related intimitely to interrupts and exceptions (interrupts are external (“asynchronise”), exceptions are internal (“synchronise”, usually through software or timer), some place confuse them though, but it’s okay).
Commonly Used CSRs and their sub-fields
The registers are labelled in this format: reg (addr, reset_val).

mstatus (0x300, 0x00001800): Machine Status (lower 32 bits), controls global interrupt enable and privilege modes.
mstatus.MPP[12:11]: Machine Previous Priviledge mode. When an mret is executed, the privilege mode is change to this value.mstatus.MIE[3]: Machine (global) Interrupt Enable.mstatus.MPIE[7]: Machine previous Interrupt Enable. When an interrupt occurs, the content inmstatus.MIEis loaded into this bit (and for simplicity,mstatus.MIEis changed to 0, so no other interrupts is allowed to come in), and after the interrupt is processed (aftermret), this bit is restored intomstatus.MIEagain.
misa (0x301, depends on RV32 and M_EXT):mie (0x304, 0x00000000): Machine Interrupt Enable, enables specific interrupts (not global). Also you should have a look atmip (0x344).mip (0x344): Machine Interrupt Pending Register, indicates which specific interrupts are pending.
MSIP/MSIE[3]: Machine Software Interrupt Pending/EnableMTIP/MTIE[7]: Machine Timer Interrupt Pending/EnableMEIP/MEIE[11]: Machine External Interrupt Pending/Enable
mtvec (0x305, ): Machine Trap-Handler Base Address, specifies where the CPU jumps on an interrupt/exception.
MODE[1:0]:- 00: Direct. All traps (either interrupts or exceptions) set
PCdirectly toBASE. - 01: Vectored. Exceptions will set
PCdirectly toBASE, while (asynchronous) interrupts will setPCtoBASE+4*mcause.Exception Code(Seemcauseregister.) - others: invalid.
- 00: Direct. All traps (either interrupts or exceptions) set
mepc (0x341, 0x00000000): Machine Exception Program Counter, saves the address of the interrupted instruction.- When an interrupt occurs, the current PC + 1 is saved in
mepc. - When an exception is encountered, the current PC is saved in
mepc. (Why? The exception may triggered by the instruction at the current PC, maybe we solve the exception in the interrupt handler, so give it another chance to execute that instruction again.)
and the core jumps to the exception address. When a
mretinstruction is executed, the value frommepcreplaces the current program counter.- When an interrupt occurs, the current PC + 1 is saved in
mcause (0x342): Machine Trap Cause, identifies the cause of the interrupt/exception.
Interrupt[31]:- 1: Exceptions
- 0: Interrupts
Exception Code[30:0]: (pay special attention to the number 3/7/11)Interrupt[31]Exception Code[30:0]Description 1 0, 2, 4, 6, 8, 10, 12, 14-15 Reserved 1 1 / 3 Supervisor/Machine software interrupt 1 5 / 7 Supervisor/Machine timer interrupt 1 9 / 11 Supervisor/Machine external interrupt 1 13 Counter-overflow interrupt 1 ≥16 Designated for platform use 0 0 Instruction address misaligned 0 1 Instruction access fault 0 2 Illegal instruction 0 3 Breakpoint 0 4 Load address misaligned 0 5 Load access fault 0 6 / 7 Store/AMO address/access fault 0 8 / 9 / 11 Environment call from U/S/M-mode 0 10, 14, 17, 20-23, 32-47, ≥64 Reserved 0 12 Instruction page fault 0 13 Load page fault 0 15 Store/AMO page fault 0 16 Double trap 0 18 Software check 0 19 Hardware error 0 24-31, 48-63 Designated for custom use
mtval (0x343): Machine Trap Value, provides extra information about exceptions (their addresses and so on)
Commonly Used CSR instructions
;register version:
csrrw x5, mstatus, x10 ;x5 = mstatus (read), mstatus = x10 (write)
csrw mtvec, t0 ;mtvec = t0 (write only)
csrrs x5, mie, x10 ;x5 = mie (read), mie |= x10 (set)
csrrc x5, mie, x10 ;x5 = mie (read), mie &= x10 (clear)
;imm version:
csrrwi x5, mstatus, 0x1 ;x5 = mstatus (read), mstatus = 0x1 (write imm)
csrrsi x5, mie, 0x1 ;x5 = mie (read), mie |= 0x1 (set imm)
csrrc x5, mie, 0x1 ;x5 = mie (read), mie &= 0x1 (clear imm)
Convenient pseudo-instructions:
csrr rd, csr ;csrrs rd, csr, x0
csrw csr, rs ;csrrw x0, csr, rs
csrs csr, rs ;csrrs x0, csr, rs
csrc csr, rs ;csrrc x0, csr, rs
csrwi csr, imm ;csrrwi x0, csr, imm
csrsi csr, imm ;csrrsi x0, csr, imm
csrci csr, imm ;csrrci x0, csr, imm
GPRs 通用寄存器
Introduction
The 32 registers in RISC-V are called general-purpose registers (GPRs, or “integer registers”). They are used for various purposes, such as holding data, addresses, or temporary values during program execution. These registers are 32 bits wide in the RV32I ISA and are identified as x0 to x31.
Each register has a conventional name that indicates its intended usage, although these names are just conventions, and you can use them for other purposes if needed.

Partial Explanations
raPurpose: Stores the return address for function calls.
jal ra, function_label # Jump to function_label and store return address in ra ret # Return to the address in raspPurpose: Points to the top of the stack (used for dynamic memory allocation during function calls).
addi sp, sp, -16 # Allocate 16 bytes on the stack sw t0, 0(sp) # Store t0 at the top of the stack lw t0, 0(sp) # Retrieve t0 from the stack addi sp, sp, 16 # Deallocate 16 bytesgpPurpose: Points to global and static data in memory.
lw t0, 0(gp) # Load a value from the global data sectiontpPurpose: Points to thread-local storage (used in multi-threaded programs).
lw t0, 0(tp) # Load a thread-specific valuet0-t6Purpose: Temporary values, not preserved across function calls.
跳转指令
Introduction
One category of instructions is jump operations (abbr. jmpop), which is just changing the value of PC (or some GPRs by the way)
Commonly Used aluop instructions
; unconditional:
jal ra, 0x10 ;ra = PC + 4, PC += 0x10 (link and jump, should be laj)
jalr ra, 8(t0) ;ra = PC + 4, PC += t0+8 (wrt a register)
; conditional:
beq t0, t1, 0x8 ;PC += 0x8 if t0 == t1 (branch if equal)
bne t0, t1, 0x8 ;PC += 0x8 if t0 != t1 (branch if not equal)
blt t0, t1, 0x8 ;PC += 0x8 if t0 < t1 (signed less than)
bge t0, t1, 0x8 ;PC += 0x8 if t0 >= t1 (signed greater or equal)
bltu t0, t1, 0x8 ;PC += 0x8 if t0 < t1 (unsigned less than)
bgeu t0, t1, 0x8 ;PC += 0x8 if t0 >= t1 (unsigned greater or equal)
auipc t0, 0x1000 ;t0 = PC + (0x1000 << 12) (add upper imm and PC to a reg)
Notes
load:
lbu a1, 0(t1)
sb a1, 0(t2)
addi t1, t1, 1
addi t2, t2, 1
bltu t2, t3, load
If lbu a1, 0(t1) is at location 0x8000001a, then this line: bltu t2, t3, load does NOT mean
PC += 0x8000001a if t2 < t3
but
PC = 0x8000001a if t2 < t3
(done by the smart compiler!)
Machine Mode
Introduction
One category of instructions is machine operations (abbr. machineop), which is a set of privileged instructions in the RISC-V privileged architecture. These instructions are all related to the CSRs, so make sure you are familiar with those registers first.
RISCV Privilege Levels from High to Low
- Debug (D)
- Machine (M): “must-have”
- Supervisor (S)
- Hypervisor-extended Supervisor (HS)
- Virtual Supervisor (VS)
- Virtual User (VU)
- User (U)
Commonly Used machineop instructions
mret: Return from Machine-mode to Supervisor-mode (or User-mode). Steps:- Restore the privilege mode:
- The processor sets the current privilege mode based on MPP from mstatus.
- MPP is cleared to user mode (00) or supervisor mode (01) if applicable.
- Restore the interrupt enable status:
- The MIE bit in mstatus is set to MPIE.
- The MPIE bit is cleared (0).
- Restore the program counter (PC):
- The PC is set to the value stored in mepc, resuming execution where it was interrupted.
- Restore the privilege mode:
内存操作
Introduction
One category of instructions is memory operations (abbr. memop), which is just exchanging data between GPRs to memory locations.
So naturally, these signals are crucial for storing a data into memory:
WE: Write enable. Whenever a memop intruction is detected, the memory block needs to be enabled.[31:0] data_mem: the 32-bit data to be stored.[31:0] mem_addr: where to be stored.[3:0] storebytes_size: Store a byte (0001), half word (0011), or a word (1111)?
Commonly Used memop instructions
lui t0, 0x40000 ;t0 = 0x40000 << 12b (load unsigned imm)
lb t0, 1(a0) ;t0 = mem[a0 + 1] (load byte)
lh t0, 2(a0) ;t0 = mem[a0 + 2] (load half word)
lw t0, 4(a0) ;t0 = mem[a0 + 4] (load word)
lbu t0, 1(a0) ;unsigned (zero extending)
lhu t0, 2(a0) ;unsigned (zero extending)
sb t0, 1(a0) ;mem[a0 + 1] = t0 (store byte)
sh t0, 2(a0) ;mem[a0 + 2] = t0 (store half word)
sw t0, 4(a0) ;mem[a0 + 4] = t0 (store word)