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

ExtensionLetterDescriptionKey Instructions
IntegerIBase integer operations (always present)ADD, SUB, AND, OR, SLT, BEQ, JAL, LW, SW
MultiplyMInteger multiply and divideMUL, MULH, DIV, DIVU, REM
AtomicAAtomic memory operationsLR.W/D, SC.W/D, AMOSWAP, AMOADD, AMOAND
Float (single)FSingle-precision floating pointFADD.S, FMUL.S, FLW, FSW, FCVT
Float (double)DDouble-precision floating pointFADD.D, FMUL.D, FLD, FSD, FCVT
CompressedC16-bit instruction encodingC.ADD, C.LW, C.SW, C.BEQZ, C.JAL
VectorVSIMD vector operationsVADD, 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

CategoryRegistersCountWidth
Integer (GPR)x0 (zero), x1 (ra), x2 (sp), ... x313264-bit (RV64)
Floating Pointf0-f313264-bit (D ext)
Vectorv0-v3132VLEN bits
CSRmstatus, misa, satp, cycle, etc.~4096 space64-bit
Program Counterpc164-bit

πŸ” Narrated Walkthrough: Handling a Page Fault

  1. Access β€” A load instruction in U-mode accesses virtual address 0x1000_0000. The MMU walks the Sv39 page table starting from satp.ppn.
  2. TLB Miss β€” The TLB doesn't have a translation. The page table walker reads the 3-level page table from memory.
  3. Fault Detection β€” The PTE's Valid bit is 0. This triggers a Load Page Fault (cause = 13).
  4. Delegation Check β€” M-mode checks medeleg. If bit 13 is set, the fault is delegated to S-mode. Otherwise, M-mode handles it.
  5. Trap Entry β€” The processor saves pc β†’ sepc, cause β†’ scause (13), faulting address β†’ stval (0x1000_0000).
  6. 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 executes SRET to resume.

Key Components Reference

ComponentFilePurpose
Decoderdecoder.hh16/32-bit instruction decoder with C-extension support
RiscvISA::ISAisa.hhCSR register file and privilege mode state
RiscvMMURiscvMMU.pySv39/Sv48 page table walker
RiscvFaultfaults.hhException hierarchy with mcause/mtval
Interruptsinterrupts.hhPLIC/CLINT interrupt controller interface
PMPPMP.pyPhysical Memory Protection (16 entries)
PMACheckerPMAChecker.pyPhysical Memory Attributes checker
RiscvSystemRiscvSystem.pyRISC-V system configuration

Glossary

TermDefinition
RV64GCRISC-V 64-bit with General extensions (I+M+A+F+D) and Compressed (C)
CSRControl and Status Register β€” RISC-V's mechanism for system configuration
PMPPhysical Memory Protection β€” M-mode configurable memory access control
Sv39/Sv4839-bit/48-bit virtual address space page table schemes
ECALLEnvironment Call β€” instruction for system calls (traps to higher privilege)
PLICPlatform-Level Interrupt Controller β€” routes external interrupts to harts
CLINTCore-Local Interruptor β€” timer and software interrupt controller per hart
HartHardware Thread β€” RISC-V term for a hardware execution context