riscv β RISC-V ISA Implementation
Modular RISC-V instruction set support with standard extensions (M/A/F/D/C/V), privilege modes, PMP/PMA security, and compressed instruction decoding.
📚 What is this & why does it exist?
π‘ Think of it likeβ¦RISC-V is like a LEGO set. The base integer ISA (RV64I) is the starter kit β simple, clean, and complete on its own. Each extension snaps on like an expansion pack: M (multiply/divide), A (atomic ops), F/D (floating point), C (compressed instructions for code density), and V (vector processing). gem5 assembles whatever combination you configure, with the decoder automatically handling 16-bit compressed and 32-bit standard instructions.
Architecture Overview
gem5's RISC-V implementation supports the full RV64GC profile (I+M+A+F+D+C) plus the V (vector) extension. The clean, modular RISC-V design results in a relatively simple decoder compared to x86 or AArch32, AArch64, TrustZone security extensions, SVE/SVE2 vector processing, PMU, and hardware transactional memory." href="../arm/index.html">ARM, making it an excellent ISA for architecture research.
graph TB
subgraph "Decoder"
RvDec["RiscvISA::Decoder"]
C16["Compressed (16-bit)\nC extension"]
Std32["Standard (32-bit)\nRV64I base"]
end
subgraph "Extensions"
M["M: Multiply/Divide"]
A["A: Atomics (LR/SC, AMO)"]
F["F: Single-Precision FP"]
D["D: Double-Precision FP"]
V["V: Vector Processing"]
end
subgraph "Privilege"
U["U-mode (User)"]
S["S-mode (Supervisor)"]
Machine["M-mode (Machine)"]
PMP["PMP (Physical Memory Protection)"]
PMA["PMA (Physical Memory Attributes)"]
end
RvDec --> C16
RvDec --> Std32
Std32 --> M
Std32 --> A
Std32 --> F
Std32 --> D
Std32 --> V
Machine --> S --> U
Machine --> PMP
Machine --> PMA
Instruction Decoder
The RISC-V decoder is comparatively simple β instructions are either 16-bit (compressed) or 32-bit (standard). The two lowest bits of the instruction determine the length: 00, 01, or 10 = compressed (16-bit); 11 = standard (32-bit).
namespace RiscvISA {
class Decoder : public InstDecoder
{
public:
void moreBytes(const PCStateBase &pc, Addr fetchPC) override;
bool instReady() const override;
StaticInstPtr decode(PCStateBase &nextPC) override;
private:
bool aligned; // Instruction alignment state
MachInst machInst; // Current raw instruction
// Determine instruction length from first 2 bits
bool isCompressed(MachInst inst) const {
return (inst & 0x3) != 0x3;
}
// Expand compressed instruction to 32-bit equivalent
MachInst expandCompressed(MachInst inst) const;
// Decode 32-bit instruction by major opcode
StaticInstPtr decodeInst(MachInst mach_inst);
};
Standard Extensions
| Extension | Letter | Description | Key Instructions |
|---|---|---|---|
| Integer | I | Base integer operations (always present) | ADD, SUB, AND, OR, SLT, BEQ, JAL, LW, SW |
| Multiply | M | Integer multiply and divide | MUL, MULH, DIV, DIVU, REM |
| Atomic | A | Atomic memory operations | LR.W/D, SC.W/D, AMOSWAP, AMOADD, AMOAND |
| Float (single) | F | Single-precision floating point | FADD.S, FMUL.S, FLW, FSW, FCVT |
| Float (double) | D | Double-precision floating point | FADD.D, FMUL.D, FLD, FSD, FCVT |
| Compressed | C | 16-bit instruction encoding | C.ADD, C.LW, C.SW, C.BEQZ, C.JAL |
| Vector | V | SIMD vector operations | VADD, VMUL, VLE, VSE, VFADD |
Privilege Modes
RISC-V defines three privilege modes, each with increasing levels of access to the hardware:
Machine Mode (M-mode)
The most privileged mode β always present. Handles hardware initialization, interrupt routing, and provides the foundation for all other modes. Has direct access to all CSRs and physical memory.
Supervisor Mode (S-mode)
Operating system kernel mode. Manages virtual memory (Sv39/Sv48 page tables), handles page faults, and provides system call interface for user mode.
User Mode (U-mode)
Unprivileged application mode. Cannot access M/S-mode CSRs or execute privileged instructions. Memory access is controlled by S-mode page tables.
namespace RiscvISA {
// Privilege levels
enum PrivilegeMode : uint8_t {
PRV_U = 0, // User
PRV_S = 1, // Supervisor
PRV_M = 3 // Machine
};
// Key CSRs (Control and Status Registers)
enum CSRIndex {
// Machine-level
CSR_MSTATUS = 0x300,
CSR_MISA = 0x301, // ISA extensions present
CSR_MEDELEG = 0x302, // Exception delegation
CSR_MIDELEG = 0x303, // Interrupt delegation
CSR_MIE = 0x304, // Interrupt enable
CSR_MTVEC = 0x305, // Trap vector base
CSR_MEPC = 0x341, // Exception PC
CSR_MCAUSE = 0x342, // Exception cause
CSR_MTVAL = 0x343, // Trap value
// Supervisor-level
CSR_SSTATUS = 0x100,
CSR_SATP = 0x180, // Page table base (Sv39/Sv48)
// Performance counters
CSR_CYCLE = 0xC00,
CSR_INSTRET = 0xC02,
};
} // namespace RiscvISA
PMP and PMA
RISC-V provides two hardware security mechanisms for memory protection:
Physical Memory Protection (PMP)
PMP allows M-mode to restrict physical memory access for S/U modes. Up to 16 PMP entries define address regions with read/write/execute permissions.
// PMP configuration
struct PMPEntry {
enum AddrMatch { OFF, TOR, NA4, NAPOT };
AddrMatch addressMatching;
bool locked;
bool readable;
bool writable;
bool executable;
Addr address;
};
class PMP : public SimObject
{
public:
static const int MAX_PMP_ENTRIES = 16;
// Check access permission
Fault checkAccess(Addr addr, int size,
BaseMMU::Mode mode,
PrivilegeMode priv) const;
private:
PMPEntry entries[MAX_PMP_ENTRIES];
};
Physical Memory Attributes (PMA)
PMA defines hardware attributes for memory regions β cacheability, atomicity support, and memory ordering. This ensures correct behavior for MMIO regions vs. normal memory.
Fault Handling
namespace RiscvISA {
class RiscvFault : public FaultBase
{
protected:
ExceptionCode _code; // mcause value
Addr _trapValue; // mtval value
public:
void invoke(ThreadContext *tc, const StaticInstPtr &inst) override;
// Determine trap handler: M-mode or S-mode?
PrivilegeMode targetMode(ThreadContext *tc) const;
};
// Exception codes (mcause values)
enum ExceptionCode {
INST_ADDR_MISALIGNED = 0,
INST_ACCESS_FAULT = 1,
ILLEGAL_INST = 2,
BREAKPOINT = 3,
LOAD_ADDR_MISALIGNED = 4,
LOAD_ACCESS_FAULT = 5,
STORE_ADDR_MISALIGNED = 6,
STORE_ACCESS_FAULT = 7,
ECALL_FROM_U = 8,
ECALL_FROM_S = 9,
ECALL_FROM_M = 11,
INST_PAGE_FAULT = 12,
LOAD_PAGE_FAULT = 13,
STORE_PAGE_FAULT = 15,
};
} // namespace RiscvISA
Register File
| Category | Registers | Count | Width |
|---|---|---|---|
| Integer (GPR) | x0 (zero), x1 (ra), x2 (sp), ... x31 | 32 | 64-bit (RV64) |
| Floating Point | f0-f31 | 32 | 64-bit (D ext) |
| Vector | v0-v31 | 32 | VLEN bits |
| CSR | mstatus, misa, satp, cycle, etc. | ~4096 space | 64-bit |
| Program Counter | pc | 1 | 64-bit |
π Narrated Walkthrough: Handling a Page Fault
- Access β A load instruction in U-mode accesses virtual address
0x1000_0000. The MMU walks the Sv39 page table starting fromsatp.ppn. - TLB Miss β The TLB doesn't have a translation. The page table walker reads the 3-level page table from memory.
- Fault Detection β The PTE's Valid bit is 0. This triggers a Load Page Fault (cause = 13).
- Delegation Check β M-mode checks
medeleg. If bit 13 is set, the fault is delegated to S-mode. Otherwise, M-mode handles it. - Trap Entry β The processor saves
pcβsepc,causeβscause(13), faulting address βstval(0x1000_0000). - Handler Jump β PC is set to
stvec(S-mode trap vector). The OS page fault handler allocates a physical page, updates the page table, and executesSRETto resume.
Key Components Reference
| Component | File | Purpose |
|---|---|---|
Decoder | decoder.hh | 16/32-bit instruction decoder with C-extension support |
RiscvISA::ISA | isa.hh | CSR register file and privilege mode state |
RiscvMMU | RiscvMMU.py | Sv39/Sv48 page table walker |
RiscvFault | faults.hh | Exception hierarchy with mcause/mtval |
Interrupts | interrupts.hh | PLIC/CLINT interrupt controller interface |
PMP | PMP.py | Physical Memory Protection (16 entries) |
PMAChecker | PMAChecker.py | Physical Memory Attributes checker |
RiscvSystem | RiscvSystem.py | RISC-V system configuration |
Glossary
| Term | Definition |
|---|---|
| RV64GC | RISC-V 64-bit with General extensions (I+M+A+F+D) and Compressed (C) |
| CSR | Control and Status Register β RISC-V's mechanism for system configuration |
| PMP | Physical Memory Protection β M-mode configurable memory access control |
| Sv39/Sv48 | 39-bit/48-bit virtual address space page table schemes |
| ECALL | Environment Call β instruction for system calls (traps to higher privilege) |
| PLIC | Platform-Level Interrupt Controller β routes external interrupts to harts |
| CLINT | Core-Local Interruptor β timer and software interrupt controller per hart |
| Hart | Hardware Thread β RISC-V term for a hardware execution context |