i-RISCV CPU Internals

The i-RISCV core is a single-issue, in-order processor. The following mechanisms are supported.

Pipeline

A six-stage pipeline (IF1/IF2/ID/EX/MEM/WB) with synchronous instruction and data memory access.

flowchart LR
    IF1["IF1<br/>PC gen"] --> IF2["IF2<br/>imem data phase"]
    IF2 --> ID["ID<br/>decode + reg read"]
    ID --> EX["EX<br/>ALU / branch resolve"]
    EX --> MEM["MEM<br/>dmem addr phase,<br/>CSR r/w, traps"]
    MEM --> WB["WB<br/>dmem data phase,<br/>regfile commit"]

Supported mechanisms:

  • Compressed (C) handling entirely within fetch: 16-bit RVC expansion to full-width instructions, self-correcting length prediction, and straddling-instruction splicing
  • Same-cycle result forwarding between stages for dependent instructions
  • Load-use / CSR-use / AMO-use hazard detection with a single-cycle consumer stall; the FP register file carries its own structurally identical check
  • Memory-system back-pressure handling: bus-arbitration waits, multi-cycle atomics, in-flight page-table walks (data-side and instruction-side)
  • Multi-cycle execution units: RV64M divide, RV64F/D divide/square-root, and the serial (one-element-per-cycle) vector engine
  • Vector load/store with per-element address translation, mid-instruction fault latching with vstart resume, and misaligned access splitting across two bus words
  • Vector load-use: any instruction in ID is stalled for one cycle while a vector load/store sits in EX, so neither a vector consumer of the load’s result nor a scalar consumer racing the store’s write landing can observe stale data
  • Branch/jump misprediction resolution in EX with a fixed squash of all younger instructions
  • Trap/MRET/SRET/FENCE.I/SFENCE.VMA redirects resolved at the commit point (MEM)
  • Synchronous exceptions take priority over pending interrupts sampled at the commit point

Branch Prediction

A trained fetch-address predictor, build-time optional (BPU_ENABLE):

  • 64-entry direct-mapped branch target buffer (BTB) remembering last-resolved targets
  • 256-entry pattern history table (PHT) with 2-bit saturating counters for conditional-branch direction
  • Return address stack (RAS, default 8 entries) giving call-site-specific predictions for shared ret instructions; push/pop only on resolved outcomes, never speculatively
  • Mispredictions corrected by the ordinary EX-stage redirect path, in both prediction directions

Spectre/Meltdown resistance. This core is not susceptible to Spectre-v1/v2 or Meltdown-class attacks:

  • Every mis-speculated instruction is squashed before it reaches MEM, the only stage that can touch memory/TLB – so a speculative load can never leave an observable cache/TLB footprint (the precondition both Spectre variants rely on)
  • All trained predictor state (BTB, PHT, and RAS) is unconditionally erased on every privilege-domain crossing (trap, MRET, SRET, FENCE.I), so no prediction history or call stack can survive across a privilege transition (closes the Spectre-v2 branch-target-injection setup at the source)
  • Meltdown requires a permission check deferred past speculative use of a faulting load; this core’s MMU translation and PMP permission checks are combinational and gate the real bus access in the same cycle, so no such path exists

MMU with PMP

The MMU implements Sv39/Sv48/Sv57 virtual memory plus H-extension two-stage (VS + G) translation. Supported mechanisms:

  • Variable-depth page-table walker (3/4/5 levels) for instruction and data accesses, including superpage support
  • H-extension two-stage translation with separate VS-stage and G-stage walkers/TLBs – see the Tagged TLB section for the shared TLB’s tagging and selective invalidation
  • Hardware A/D-bit management implementing both Svade and Svadu: a leaf PTE that would otherwise succeed but has A=0, or D=0 on a write/AMO, is either auto-updated in place by the walker (a real atomic read-modify-write under the cross-hart bus grant; a cached TLB entry whose A/D no longer match the current access is evicted and re-walked) when ADUE=1, or reported as a genuine page fault for software fixup when ADUE=0 – menvcfg.ADUE governs S-mode and G-stage translations, henvcfg.ADUE the VS stage (spec-forced to 0 while menvcfg.ADUE=0); both reset to 1

Physical Memory Protection (PMP), build-time optional (PMP_ENABLE; at 0 the pmpcfg/pmpaddr CSRs raise illegal-instruction and every check passes unconditionally):

  • 64 entries restricting S/U-mode physical read/write/exec access, orthogonal to page-table permissions
  • TOR/NA4/NAPOT address matching with lowest-index-wins priority; addresses WARL-masked to the 54-bit address >> 2 width of this design’s 56-bit physical address space
  • Per-entry r/w/x permissions; M-mode bypasses unlocked entries but not locked ones
  • No-match default: M-mode is always granted, S/U-mode denied – so merely having PMP present (all entries still A=OFF) denies every S/U-mode access until firmware configures at least one permissive entry before entering S-mode
  • Entry locking (config and address read-only until reset), including the locked-TOR lower-bound rule
  • Enforcement on every physical bus access: instruction fetch, load, store, and page-table-walker PTE reads; a denial reports the ordinary access-fault cause of the original access

Smepmp (Enhanced PMP) is layered directly on top via three mseccfg bits:

  • MML (Machine Mode Lockdown): replaces the per-entry permission rule with a fixed 16-row table over {L,R,W,X} – M-mode-only, S/U-mode-only (which removes the base rule’s own M-mode bypass), and shared-region patterns; sticky-set until reset
  • MMWP (Machine-mode Whitelist Policy): flips the M-mode no-match default from granted to denied; sticky-set until reset
  • RLB (Rule Locking Bypass): while set, locked entries’ config/address become writable again; cannot be set once any entry is already locked (stuck at 0 until reset)

Tagged TLB

The MMU’s translation lookaside buffer is tagged so that cached translations remain valid across address-space switches and can be invalidated selectively instead of wholesale. Supported mechanisms:

  • 16-entry TLB whose entries are tagged with the active ASID (full 16-bit satp.ASID width) and the PTE’s global bit
  • Global mappings hit under every address space; non-global entries only match their own ASID, so a satp write needs no flush – a new address space can never match stale entries installed under another ASID
  • Selective invalidation via the 4-case SFENCE.VMA rs1, rs2 predicate: whole-TLB, per-ASID, per-address (a superpage entry matches any address within its range), or per-address-and-ASID; global mappings are exempt only when an ASID is named
  • Svinval: SINVAL.VMA provides identical selectivity to SFENCE.VMA; the SFENCE.W.INVAL/SFENCE.INVAL.IR ordering fences are architecturally no-ops on this in-order core
  • H extension: separate VS-stage and G-stage TLBs; HFENCE.VVMA invalidates the ASID-tagged VS-stage entries with the same 4-case predicate, HFENCE.GVMA the G-stage entries – which are tagged by hgatp.VMID (14 bits) instead of an ASID, so a VMID-scoped flush touches only that guest’s cached translations and two guests under different VMIDs can switch without any intervening flush

Privilege Levels and Traps

M/S/U privilege levels with reset into M-mode; MRET restores the level from mstatus.MPP (resetting it to U), SRET from sstatus.SPP. The H extension layers an orthogonal virtualization bit on top of these – see the Hypervisor page.

Supported mechanisms:

  • Full machine CSR set (read-only identification CSRs mvendorid/marchid/mimpid/mhartid/mconfigptr, plus mstatus, self-describing misa, medeleg/mideleg, mie/mip, mtvec Direct + Vectored, mcounteren, mscratch, mepc/mcause/mtval, mcycle/minstret) and supervisor CSR set (sstatus as a masked view of mstatus, sie/sip, stvec, scounteren, sscratch, sepc/scause/stval, satp WARL-limited to Bare/Sv39/Sv48/Sv57)
  • CSRRS/CSRRC implement the spec’s own strict rs1==x0 no-write rule – a real (non-x0) register holding 0 is still a genuine write attempt
  • mstatus.MXR/SUM are real bits consumed by the MMU’s permission check (SUM never applies to instruction fetch); FS and VS are likewise real, reset to Off (any F/D or vector instruction traps as illegal-instruction until software enables them), and auto-transition to Dirty in hardware on the first state-modifying commit – the vector floating-point forms specifically are gated by both FS and VS at once
  • mstatus.MPRV/MPP/MPV are real and consulted by the data-side translation (the full six-row truth table), never affecting instruction fetch or HLV/HSV
  • Zicfilp forward-edge CFI: a non-exempt JALR arms an expected-landing-pad state; the next fetched instruction must be a label-matching LPAD or a software-check exception (mcause=18, mtval=2) fires – enabled per privilege via menvcfg.LPE/henvcfg.LPE/senvcfg.LPE/mseccfg.MLPE, with the state trap-preserved in xPELP
  • Zicfiss backward-edge CFI: a dedicated shadow stack (ssp CSR) with SSPUSH/SSPOPCHK; a mismatched pop raises the same software-check exception (mtval=3), and the shadow-stack’s own pages use a new PTE encoding that only the SS instructions may write – any other write is a fatal access fault
  • Ssdbltrp/Smdbltrp double-trap detection: per-level sticky trap-in-flight bits (mstatus.MDT, sstatus.SDT, vsstatus.SDT); an unexpected trap into a level already in flight redirects one level up as mcause=16 with the suppressed cause in mtval2, and an unexpected trap targeting M-mode halts the hart in a permanent critical-error state
  • Unprivileged counters (cycle/time/instret) and F/D’s fflags/frm/fcsr; RV32’s high-half shadow CSRs are illegal instructions on this RV64 core
  • Synchronous exceptions: instruction/load/store misaligned access, illegal instruction, breakpoint, ECALL from U/S/M, and instruction/load/store page faults once paging is active; the H extension adds VS-mode ECALL (cause 10), virtual-instruction (22), and guest-page-fault causes (20/21/23)
  • Interrupts: machine/supervisor x {software, timer, external}; MSIP/MTIP/MEIP are hardware-driven from the CLINT/CLINT/PLIC; SEIP becomes a read-only view of the IMSIC S-file’s delivery signal when AIA’s mvien.SEIE is set (the PLIC’s own dedicated S-mode context is ORed in unconditionally); STIP becomes the real mtime >= stimecmp comparator once Sstc’s menvcfg.STCE is enabled
  • Interrupt priority: external > software > timer, machine level before supervisor level; the H extension adds a VS tier below both and AIA adds SGEIP (bit 12) to the same scheme
  • menvcfg/henvcfg/senvcfg: real STCE (Sstc), PBMTE (Svpbmt), ADUE (Svade/Svadu), FIOM, CBZE/CBCFE/CBIE (Zicboz/Zicbom), and LPE/SSE/DTE (Zicfilp/Zicfiss/Ssdbltrp) fields – henvcfg mirrors them for VS-stage (ADUE/SSE/DTE spec-forced to 0 whenever their menvcfg counterpart clears), and senvcfg mirrors the U-mode subset
  • WFI genuinely stalls fetch/issue until an individually-enabled-and-pending interrupt is observed – independent of the global enable bits – with mstatus.TW/hstatus.VTW timeout-wait and the U-mode/VU-mode rules enforced via a bounded hardware timer

Documented simplifications. Not silent scope cuts:

  • XS/UBE read a constant 0 – unimplemented; nothing in this design needs them yet
  • Every remaining menvcfg/henvcfg/senvcfg field is WPRI and reads 0

Synchronized Timer

A single shared high-resolution timer, synchronized across all harts by construction:

  • Exactly one mtime register in the whole design (the CLINT), incrementing every core clock cycle – e.g. 10 ns resolution at a 100 MHz core clock; every hart’s time CSR (rdtime) observes the literal same value in the same cycle, with no per-core replica to resynchronize and no drift to bound
  • Per-hart state is only mtimecmp[hart] and msip[hart]; the register layout matches the SiFive/QEMU “virt” CLINT, so an unmodified OpenSBI/Linux driver works against it
  • Sstc: a real per-hart stimecmp CSR compared against the same shared mtime, gated by M-mode’s menvcfg.STCE – once enabled, S-mode programs its own timer interrupt directly with no CLINT MMIO access and no M-mode relay; while disabled, S-mode access to stimecmp traps illegal-instruction (the mechanism firmware uses to detect whether the hand-off is safe)