Computer Architecture MOC
A map of the concepts behind a small RISC-V system on a chip and the microkernel that runs on it. This MOC organizes everything below the operating-system boundary: the instruction set architecture (ISA) that the CPU speaks, the microarchitecture that executes it (pipeline, hazards, forwarding, branch prediction), the memory protection and virtual memory that isolate processes, the privilege model and trap machinery that turns hardware events into software handlers, the SoC fabric and peripherals (bus, timer, interrupt controller, UART) that surround the core, and the kernel-level primitives (microkernel, scheduling, IPC) that sit just above the metal. Each section has a paragraph of framing and a list of atomic leaf notes. Read this MOC top-to-bottom for the layered picture; then dive into a leaf for depth.
This MOC is the technical companion to the definitely-not-esp32 project: a year-long, from-scratch RV32IMC SoC and Rust microkernel, developed in Verilator simulation first and then ported to a Tang Nano 20K FPGA, benchmarked honestly against a real ESP32-C3. The leaf notes here are concept references; the project’s own repo holds the spec, the RTL, the kernel code, and the blog series.
How the Pieces Fit Together
flowchart TB subgraph SW["Software"] USER["User processes (U-mode)"] KERN["Microkernel (M-mode)"] USER -- "ecall" --> KERN end subgraph CPU["CPU core"] ISA["RV32IMC + Zicsr"] PIPE["5-stage pipeline<br/>IF · ID · EX · MEM · WB"] HAZ["Hazard unit:<br/>forwarding, stalls, flush"] BP["2-bit branch predictor"] CSR["CSRs (mtvec, mepc, ...)"] TRAP["Trap handler entry"] PMP["PMP / MMU"] ISA --> PIPE PIPE <--> HAZ PIPE <--> BP PIPE <--> CSR CSR --> TRAP TRAP --> PMP end KERN -.->|"runs on"| CPU subgraph SOC["SoC fabric"] BUS{"Bus (Wishbone)"} ROM["Boot ROM"] RAM["Main RAM"] UART["UART"] CLINT["CLINT<br/>timer + sw IRQ"] PLIC["PLIC<br/>external IRQ"] BUS <--> ROM BUS <--> RAM BUS <--> UART BUS <--> CLINT BUS <--> PLIC end CPU <--> BUS CLINT -. "timer / sw IRQ" .-> TRAP PLIC -. "external IRQ" .-> TRAP UART -. "RX IRQ" .-> PLIC
The layered architecture covered by this MOC. What it shows: a single CPU core executes a fixed ISA through a 5-stage pipeline with hazard handling and branch prediction; CSRs and a trap handler turn hardware events into software dispatch; the core sits on a small bus that fans out to memory, a UART, and two interrupt controllers (CLINT for timer and software IRQs, PLIC for external IRQs); a microkernel in M-mode multiplexes user processes in U-mode, talking to the hardware through traps. The insight to take: every other section of this MOC is a zoom into one of these blocks.
1. Instruction Set Architecture
The contract between hardware and software. The ISA is the part the compiler and assembler target; the microarchitecture is how a specific CPU implements it. RISC-V is the modular open ISA used here. The base integer set (I) is fixed; M (multiply / divide), C (compressed), Zicsr (CSR access), and the privilege levels are optional extensions that get bolted on.
- Instruction Set Architecture
- RISC-V Instruction Set Architecture
- RV32IMC
- Zicsr Extension
- RISC-V Privilege Modes
- RISC-V Instruction Formats — R/I/S/B/U/J and the compressed set, at bit accuracy
2. Building a Core: Datapath, Control, and the First Processor
Before a pipeline there has to be something to pipeline. These are the blocks a from-scratch RV32 core is actually made of, and the single-cycle machine that assembles them — correct, slow, and the golden reference model every later microarchitecture is differentially tested against.
- Instruction Decode — turning 32 bits into control signals, including expanding the compressed set
- The Register File — 2R1W,
x0as a mux, and the write-during-read question - The Arithmetic Logic Unit — the ten operations RV32I requires, and why RISC-V has no flags register
- Datapath and Control — the split that organizes every processor design
- The Single-Cycle Processor — CPI exactly 1, Fmax set by
lw, and the reference model for everything after
2. Pipeline Mechanics
How a single ISA instruction actually flows through the CPU. The textbook 5-stage pipeline (Instruction Fetch, Decode, Execute, Memory, Writeback) is the lingua franca of computer architecture teaching. Pipelining buys parallelism, but introduces data and control hazards that have to be resolved with forwarding, stalls, and flushes. The effective performance metric is cycles per instruction (CPI), which the pipeline drives down and the hazards push back up.
- Classic Five-Stage Pipeline
- Pipeline Hazards
- Operand Forwarding
- Load-Use Hazard
- Cycles Per Instruction
3. Branch Prediction and Simulation Tooling
Branches are control hazards: the CPU does not know the next instruction’s address until the branch resolves. A predictor guesses, the pipeline speculates, and a misprediction flushes the in-flight work. A 2-bit saturating counter is the smallest predictor that does meaningfully better than always-taken. The tooling section pairs this with the simulator (Verilator) and FPGA target (Tang Nano 20K) used to verify the design, plus the abstraction level (register-transfer level, or RTL) at which the RTL is written.
- Branch Prediction
- Two-Bit Saturating Counter
- Field-Programmable Gate Array
- Verilator
- Register-Transfer Level
- Testbenches and RTL Verification — driving a design and checking it; the golden-reference discipline
- Waveform Debugging — VCD vs FST measured, and finding the first cycle where reality diverges
- The RISC-V Cross-Compilation Toolchain —
-march/-mabi,-nostdlib, and verifying the compiler did what you asked - The riscv-tests Suite — the official tests, the
tohostprotocol, and why your own tests are not enough - Timing Closure and Fmax — critical path, slack, and reading a synthesis report
4. Memory Protection and Virtual Memory
Two different mechanisms for keeping processes from stomping on each other. Physical Memory Protection (PMP) is a small bank of hardware comparators against physical addresses, cheap and sufficient for a microkernel. A Memory Management Unit (MMU) walks page tables to translate virtual addresses to physical ones, giving every process its own address space. Sv32 is the 32-bit RISC-V virtual memory scheme; the TLB caches translations; the PTE is the leaf entry in the page table. The project ships PMP in v1.0; MMU is a stretch.
- Physical Memory Protection
- Memory Management Unit
- Sv32 Virtual Memory
- Translation Lookaside Buffer
- Page Table Entry
5. Privilege, Traps, and System Calls
How the hardware switches privilege levels and hands control to software on events (interrupts, exceptions, syscalls). Control and Status Registers (CSRs) hold the trap vector, the saved PC, the cause, and the interrupt enable bits. The trap handler is the kernel entry point. The ecall instruction is the explicit “I want a syscall” trap. Trap delegation lets M-mode hand certain traps directly to S-mode without a round trip; the Supervisor Binary Interface (SBI) is the standard ABI between the M-mode firmware and an S-mode kernel.
- Control and Status Registers
- RISC-V Trap Handling
- ecall Instruction
- RISC-V Trap Delegation
- Supervisor Binary Interface
6. SoC Fabric and Peripherals
The hardware around the core. A SoC is “system on a chip”: CPU plus memories plus peripherals on one die, glued by a bus. Wishbone is the open bus standard used here. CLINT is the standard RISC-V Core Local Interruptor (machine timer plus software interrupt). PLIC is the Platform-Level Interrupt Controller that prioritizes and routes external IRQs. UART is the venerable serial port that doubles as the kernel’s console.
- System on a Chip
- Wishbone Bus
- Core Local Interruptor
- Platform-Level Interrupt Controller
- Universal Asynchronous Receiver-Transmitter
- The SoC Memory Map — the contract between the address decoder, the linker script, and the software
- Boot ROM and the Reset Vector — where the very first instruction comes from
- Linker Scripts and Memory Layout — LMA vs VMA, and why
.datamust be copied at boot
7. Kernel-Level Primitives
The smallest set of OS concepts the microkernel needs. A microkernel keeps only the unavoidable parts (traps, scheduling, IPC, address-space protection) in privileged mode and pushes everything else into user processes. Round-robin scheduling is the simplest fair scheduler. Synchronous IPC (rendezvous) is the simplest message-passing primitive: sender blocks until receiver is ready, no buffering. Both are the v1.0 defaults; priority scheduling and async channels are stretches.
- Microkernel
- Round-Robin Scheduling
- Synchronous IPC
- Bare-Metal Rust —
no_std, the panic handler, and volatile MMIO under Rust’s aliasing rules - Context Switching in a Microkernel — 31 registers plus
mepc, themscratchtrick, and the real cycle cost
8. Reference Hardware
The reference point the project benchmarks against, and the FPGA target the design ports to.
Project Link
This MOC is part of definitely-not-esp32: a from-scratch RV32IMC SoC plus Rust microkernel, simulated in Verilator and ported to a Tang Nano 20K FPGA, benchmarked against an ESP32-C3. The project repo (spec, roadmap, RTL, kernel) lives outside this vault.
Open Threads
Round 2 leaves: complete
All five round-2 leaves are now written and verified:
Stretch and future leaves
- Stretch-goal concepts once the project reaches that phase: Direct-Mapped Cache, Set-Associative Cache, Asynchronous IPC, Priority Preemptive Scheduling, Sv39 Virtual Memory.
- SoC implementation notes once Phase 5 lands: Wishbone Pipelined Mode, Bus Arbitration.
- Cross-link to the Linux MOC entries on Linux scheduling and interrupts for comparison after the kernel posts ship.
Uncertainty triage — resolved 2026-08-08
A four-agent pass closed 16 of 17 open [!warning] Uncertain callouts across these leaves. Each resolution now sits inline in its note as a [!success] Resolved 2026-08-08 callout with primary citations. This list is rebuilt from a disk scan, not maintained by hand — re-scan before trusting it.
Resolved — the claim was true, now cited:
- RISC-V Instruction Set Architecture: RV32E/RV64E are Ratified at v2.0. The stale “v1.9 Draft” datum survives only inside the archived 20191213 preface, which the manual reproduces verbatim. Version bumped 1.95→2.0 in commit
fefbe61, 2023-01-25. - RISC-V Privilege Modes: N extension removed in privileged release
20211203(Priv ISA 1.12).src/n.texdeleted 2021-07-06, commitb6cade07, Andrew Waterman. - Memory Management Unit · Page Table Entry: no profile mandates Svadu. RVA20/22/23S64 all mandate Svade; RVA23S64 adds Svadu as an optional expansion option. The Svade/Svadu names were minted by the profiles WG (renamed from
Ssptead, 2023-04-02) and only absorbed into the privileged manual at release20241017. - Supervisor Binary Interface: SBI v3.0 ratified 2025-07-16. OpenSBI has reported SBI 3.0 since v1.7 (2025-06-30).
- Verilator: 5.048 released 2026-04-26 (from the
Changesfile and the annotated tag). - RV32IMC: Rust
riscv32imc-unknown-none-elfis Tier 2 (Rust 1.97.1). - Physical Memory Protection: ARM PMSAv7/v8 bit layouts now read from the actual Architecture Reference Manuals.
- Microkernel: Liedtke’s minimality principle now quoted verbatim from the 1995 SOSP paper (§2, p. 2).
Resolved — the claim was WRONG or unsourced, and the note was corrected:
- Classic Five-Stage Pipeline · ESP32-C3: the SiFive E2 lineage claim is unsourced. Zero occurrences of “SiFive” in TRM v1.4 or Datasheet v2.4; the core hardwires Espressif’s own
mvendorid=0x612/marchid=0x80000001(SiFive’s registered ID is0x489). The rumour traces to a reader’s forum post of 2020-11-21 whose sole argument (“it has an FPU, so it must be the E24”) is false —misahardwiresF=D=0— and was corrected in-thread by SiFive’s Jim Wilson. - Branch Prediction: the ESP32-C3 has no branch predictor. No “predict”/“BTB”/“speculat” in the TRM;
mpcerexposes a jump-hazard counter and no mispredict counter; ESP-IDF definesSOC_BRANCH_PREDICTOR_SUPPORTEDfor the P4/C5 but not the C3. - Branch Prediction: the Intel TAGE claim is vendor-UNDISCLOSED. Zero standalone “TAGE” hits in Intel’s Optimization Reference Manual 248966-050US. The claim rests on third-party reverse engineering (Half&Half, IEEE S&P 2023; Pathfinder, ASPLOS 2024) and is now attributed as such, bounded to Raptor Lake (2022) — the newest core with published reconstruction.
- RISC-V Privilege Modes: the note’s
medeleg/mideleg“read-as-zero” claim was wrong — Priv v1.10 §3.1.12 says they should not exist in M+U-without-N systems; read-as-zero was the pre-1.10 convention. - System on a Chip: the M4 Max transistor count is unpublished. Apple states 28 billion for the base M4 and zero times for the Pro/Max. The circulating ~95 billion is an unsourced extrapolation.
- Field-Programmable Gate Array: the Tang Nano 20K has no citable list price; recorded as a dated range (USD 25–40, 2026-08-08) with an evidence table.
Still open (1):
- RISC-V Privilege Modes: whether any N-extension revival proposal is currently active. Deliberately left open — absence of a task-group proposal is a negative the spec repo cannot prove. To resolve: RVI task-group roster +
tech-announcearchive.
Corrections worth carrying to other notes
- Espressif contradicts itself in print: Datasheet v2.4 §4.1.1.1 says “32 vectored interrupts at seven priority levels”; TRM v1.4 §1.5 says 31 (IDs 1–31) at 15 levels.
- The C3’s PMP is not fully compliant (TRM §1.8.1): no static priority, so overlapping entries fail open; max NAPOT region 1 GB.
- PMSAv8-M forbids overlapping MPU regions (a MemManage fault, rule
RLLLP) — so the three designs are three distinct points: RISC-V lowest-index-wins, PMSAv7 highest-index-wins, PMSAv8-M no-overlap. - Do not cite OpenSBI’s README for spec support — it still claims “fully supports SBI specification v0.2”, contradicting its own version macro.
- RV128I no longer exists in the manual; removed as unratified content in the
20240411release.