Jack Ku
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.

      Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Explore these features while you wait
      Complete general settings
      Bookmark and like published notes
      Write a few more notes
      Complete general settings
      Write a few more notes
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.

    Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Explore these features while you wait
    Complete general settings
    Bookmark and like published notes
    Write a few more notes
    Complete general settings
    Write a few more notes
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Implement MMU (Sv32) for MyCPU Report >This is for report full develop log here: https://hackmd.io/@sysprog/SyCApAcWWg ## Goals * The provided pipelined RISC-V design (`4-soc`) is currently a physical-address-only core. Extending it to support Sv32 (32-bit page-based virtual memory) requires substantial hardware changes. * CSR implementation (Privileged Specification): * Implementation of `satp` (Supervisor Address Translation and Protection), which controls paging mode, ASID, and the physical page number of the root page table. * Correct handling of `mstatus` and `sstatus`, including privilege mode tracking (MPP/SPP) and permission-related bits such as SUM and MXR. * Support for the `sfence.vma` instruction, which flushes TLB entries and requires logic to invalidate selected or all TLB entries. * Address translation logic: * Translation Lookaside Buffers (TLB): * Engineering challenge: Designing separate instruction and data TLBs (I-TLB and D-TLB). These must be set-associative or fully associative to maintain reasonable performance. * Critical-path concern: TLB lookup sits directly in the instruction-fetch and memory stages. Careful Chisel design is required to avoid degrading the maximum clock frequency. * Page Table Walker (PTW): * Requires a hardware finite-state machine that walks the two-level Sv32 page table (Level 1 then Level 0) in physical memory when a TLB miss occurs. * The PTW must arbitrate memory access with the rest of the pipeline, typically stalling the core while it fetches and processes Page Table Entries (PTEs). * Hardware page updates (A/D bits): * The hardware must check and update the Accessed (A) and Dirty (D) bits in PTEs during the walk. When a page is accessed or written, these bits must be set atomically in memory, which increases the complexity of the PTW’s memory operations. * Integrating the MMU into the MyCPU pipeline is one of the most error-prone aspects of the project: * Pipeline stalling: The core must correctly stall the Fetch stage on an I-TLB miss and the Memory stage on a D-TLB miss while the PTW completes translation. * Exception handling: * Precise detection of Instruction Page Faults, Load Page Faults, and Store/AMO Page Faults. * Correctly writing the faulting virtual address into `stval` (or `mtval`) and transferring control to the trap handler (`stvec`), with proper privilege-mode switching. * Verification: Ensure that the [mmu-test suite](https://github.com/sysprog21/rv32emu/tree/master/tests/system/mmu) runs correctly and that all translations, exceptions, and corner cases behave as expected. --- ## What is SV32? ### Sv32 Virtual Memory Overview Sv32 is the 32-bit virtual memory paging scheme defined in the RISC-V privileged specification. It translates a 32-bit virtual address (VA) into a physical address (PA) using a two-level page table structure. Sv32 uses 4 KiB pages, and the virtual address is divided as follows: ``` 31 22 21 12 11 0 +---------------+---------------+---------------+ | VPN[1] | VPN[0] | page offset | +---------------+---------------+---------------+ 10 bits 10 bits 12 bits ``` - VPN[1]: Index into the Level-1 page table - VPN[0]: Index into the Level-0 page table - page offset: Offset within a 4 KiB page After translation, the physical address is formed as: ``` PA = [ PPN (from PTE) | page offset ] ``` ### satp Register and Paging Enable Paging in Sv32 is controlled by the satp CSR (Supervisor Address Translation and Protection). In Sv32 mode, satp contains: • MODE: Enables Sv32 paging • ASID: Address Space Identifier (not implement yet) • PPN: Physical Page Number of the root (Level-1) page table When satp.MODE enables Sv32, all instruction fetches and data accesses use virtual addresses and must go through the MMU for VA→PA translation. ### Page Table Walk (PTW) On a TLB miss, requires a two-step page table walk: 1. Level-1 Lookup ``` PTE1_addr = satp.PPN * 4096 + VPN[1] * 4 ``` 2. Level-0 Lookup ``` PTE0_addr = PTE1.PPN * 4096 + VPN[0] * 4 ``` If any PTE is invalid or permission checks fail, the MMU must raise: - Instruction Page Fault - Load Page Fault - Store/AMO Page Fault --- ## Supervisor-mode CSR + Trap Infrastructure (Implemented) ### Why implement S-mode first? Before MMU/PTW becomes meaningful, the core must be able to *enter and run Supervisor mode correctly*, because in a typical Sv32 system the operating system runs in S-mode and controls virtual memory through S-mode CSRs (e.g., `satp`, `stvec`, `sstatus`). So I implemented the S-mode CSR set and the trap/return path first, to make sure page table control and page-fault delivery can later work end-to-end in Supervisor context. --- ### 1) What I implemented - Added Supervisor CSRs in the CSR module: - `satp`, `stvec`, `sscratch`, `sepc`, `scause`, `stval`, and the supervisor-visible status view `sstatus`. - Added a privilege mode state (`priv_mode`) in CSR to track the current execution mode (M or S). - Extended CLINT to handle trap entry / return and to commit CSR updates via a direct-write interface. - Implemented exception delegation via `medeleg` (exceptions only; interrupt delegation via `mideleg` is not implemented in this stage). --- ### 2) How it is implemented (hardware behavior) #### 2.1 CSR storage + `sstatus` behavior - Keep one physical `mstatus` register. - Expose `sstatus` as a masked view of `mstatus`: - read: `sstatus = mstatus & SSTATUS_MASK` - Writes to `sstatus` only update the masked bits in `mstatus`, preserving all other fields. - This ensures S-mode status fields (`SPP`, `SIE`, `SPIE`, etc.) are stored physically in `mstatus` while still behaving like `sstatus` architecturally. #### 2.2 Trap commit path (atomic CSR updates) - CSR module provides a “direct write” commit path from CLINT: - `direct_write_enable` (M target) - `direct_write_enable_s` (S target) - When CLINT asserts these enables, CSR updates commit atomically in one place: - M target writes: `mstatus/mepc/mcause/mtval` - S target writes: `sepc/scause/stval` plus `sstatus` effect through the masked write path - `priv_mode` is updated through a dedicated interface (`priv_write_enable/priv_write_data`) to make privilege transitions explicit and easy to debug in waveforms. #### 2.3 Trap entry and return (CLINT) - CLINT determines whether to take a trap (exceptions + optional interrupts). - On trap entry, it records the faulting PC into `*epc`, writes `*cause`, then redirects PC to `*tvec`: - If handled in M-mode: - jump to `mtvec` - write `mepc/mcause/mtval` - set `priv_mode = M` - If handled in S-mode: - jump to `stvec` - write `sepc/scause/stval` - set `priv_mode = S` - Return instructions: - `mret`: PC <- `mepc`, and `priv_mode` is restored from `mstatus.MPP` (supports M→S transition) - `sret`: PC <- `sepc`, return to S (current design has no U-mode yet) #### 2.4 Exception delegation via `medeleg` (exceptions only) - Delegation decision is explicit and per-cause: - `delegatedToS = (cur_priv != M) && trap_is_exception && medeleg[cause]` - If delegated: - use S-mode CSRs (`sepc/scause/stval`) and jump to `stvec` - If not delegated: - default to M-mode CSRs (`mepc/mcause/mtval`) and jump to `mtvec` - Interrupt delegation via `mideleg` is intentionally not implemented at this stage. --- ### 3) How I verified it (waveform checkpoints) :::spoiler testcode here ```asm= .section .text .globl main .option norvc main: # ===== M-mode checkpoint ===== # Write a known value to mscratch to mark execution in M-mode li t0, 0x4D300001 csrw mscratch, t0 # ===== Configure MRET target and set MPP = S ===== # Prepare mstatus so that MRET returns to Supervisor mode csrr t1, mstatus li t0, ~(3 << 11) # Clear MPP[12:11] and t1, t1, t0 li t0, (1 << 11) # Set MPP = 01 (Supervisor mode) or t1, t1, t0 csrw mstatus, t1 # Set return address for MRET la t0, s_main csrw mepc, t0 # Second M-mode checkpoint before MRET li t0, 0x4D300002 csrw mscratch, t0 # Return from M-mode to S-mode mret # ========================= # S-mode trap handler # ========================= .align 4 s_trap: # Trap entry checkpoint li t0, 0x5330EE01 csrw sscratch, t0 # Advance SEPC to skip the faulting ECALL instruction csrr t1, sepc addi t1, t1, 4 csrw sepc, t1 # Trap exit checkpoint before SRET li t0, 0x5330EE02 csrw sscratch, t0 # Return from Supervisor trap sret # --- Insert a large gap to make PC jumps clearly visible in waveforms --- .align 4 .space 1024 # Can be increased (e.g., 4096) for clearer separation # ========================= # S-mode main # ========================= .align 4 s_main: # Write the current PC into sscratch for easy identification in waveforms auipc t2, 0 csrw sscratch, t2 # sscratch = PC of s_main # Configure Supervisor trap vector to point to s_trap # This is intentionally done in S-mode la t0, s_trap csrw stvec, t0 # S-mode execution checkpoint before ECALL li t0, 0x53300002 csrw sscratch, t0 # Trigger Supervisor-mode ECALL ecall after_ecall: # Checkpoint indicating successful return from SRET li t0, 0x53300003 csrw sscratch, t0 done: # Infinite loop to keep execution observable j done ``` ::: #### 3.1 M→S transition via `mret` - Test sets `mstatus.MPP = S` and `mepc = s_main`, then executes `mret`. - Expected waveform: - PC jumps to `s_main` - `priv_mode` switches from M to S ![截圖 2026-01-06 凌晨12.21.32](https://hackmd.io/_uploads/BkYfrvYEbe.png) #### 3.2 S-mode `ecall` trap + `sret` return - In S-mode, set `stvec = s_trap`, execute `ecall`. - Handler increments `sepc` by 4 then executes `sret`. - Expected waveform: - `sepc` captures the faulting PC - `scause = 9` (ECALL from S-mode) - PC jumps to `stvec` - `sret` returns to the instruction after `ecall` ![截圖 2026-01-06 凌晨12.22.46](https://hackmd.io/_uploads/rkHwrPYVZl.png) ![截圖 2026-01-06 凌晨12.25.22](https://hackmd.io/_uploads/SkbW8vt4Ze.png) #### 3.3 `medeleg` behavior (delegated vs non-delegated) - Run the same S-mode `ecall`, but toggle `medeleg[9]`: - `medeleg[9] = 1`: - trap stays in S-mode - PC jumps to `stvec` - writes `sepc/scause` ![截圖 2026-01-09 晚上8.25.21](https://hackmd.io/_uploads/S1AnXd0VWx.png) - `medeleg[9] = 0`: - trap escalates to M-mode (default behavior) - PC jumps to `mtvec` - writes `mepc/mcause` - `priv_mode` transitions S → M ![截圖 2026-01-09 晚上8.31.01](https://hackmd.io/_uploads/SyffSdA4-e.png) --- ## PTW + TLB (Full Version Only) ### 1) What I implemented To support Sv32 VA→PA translation, I implemented inside the MMU: - **Separate ITLB / DTLB** - **8 sets × 2 ways** (16 entries) each - Cache translations for **4KB pages** and **4MB superpages** - Per-set **round-robin replacement** (waveform-friendly and deterministic) - **A shared PTW (Page Table Walker) FSM** - Performs a **full 2-level Sv32 walk**: - L1 PTE fetch → (if non-leaf) L0 PTE fetch - Produces either: - **A leaf translation** → fills ITLB/DTLB - **A fault** → raises I/D fault signals (full trap plumbing is the next step) - **Pipeline stall + bus arbitration** - PTW must fetch PTEs via the **same AXI/bus** that the core MEM stage uses - So I added a PTW memory port and used **mutual exclusion**: - When PTW is active, **stall the whole core** (reuse `mem_stall`) - Block MEM stage from issuing requests during MMU stall - Use a **MUX** controlled by `ptw_active` to route bus request/response to either **PTW** or **normal MEM stage** --- ### 2) How the TLB works (high level) Each (I/D) TLB entry stores: - `valid` - `tag` - `ppn` (PA[31:12]) - `isSuper` (distinguish 4KB vs 4MB superpage entry) Lookup: - **4KB page** lookup uses **VPN0-based set** and a 4KB tag - **4MB superpage** lookup uses **VPN1-based set** and a superpage tag - `isSuper` prevents matching the wrong page size On hit: - output `PA = (PPN << 12) | page_offset` On PTW completion: - fill the selected set/way - update per-set RR victim pointer --- ### 3) How the PTW works (full Sv32 walk) ![image](https://hackmd.io/_uploads/HkTXWnnHbx.png) The PTW FSM contains the following states: - **sIdle** The PTW is inactive and the pipeline is not stalled by the MMU. When Sv32 is enabled and an instruction/data access misses in the corresponding TLB, the MMU latches the faulting virtual address and access type (I-side fetch vs D-side load/store), then starts a page table walk. - **sL1Req** Issues a memory read request for the level-1 PTE (L1 PTE). The requested physical address is computed from `satp.ppn` (root page table base) and `VPN[1]` extracted from the latched VA. - **sL1Wait** Waits for the memory response containing the L1 PTE. Once the response arrives, the PTW checks: 1) validity and illegal encoding (e.g., `V=0` or `R=0 && W=1`), 2) whether the entry is a **leaf** (translation terminates here) or a **pointer** (must continue to level-0), 3) if it is an L1 leaf (superpage/4MB mapping), it also checks alignment constraints (Sv32 requires `PPN0 == 0` for a superpage leaf). If the L1 PTE is a valid leaf, the walk completes and transitions to `sLeaf`. If it is a valid non-leaf pointer, the PTW proceeds to fetch the L0 PTE. - **sL0Req** Issues a memory read request for the level-0 PTE (L0 PTE). The base address is derived from the PPN in the L1 PTE, and the index comes from `VPN[0]` of the latched VA. - **sL0Wait** Waits for the memory response containing the L0 PTE. When the response arrives, the PTW validates the PTE similarly: - invalid or illegal encoding → page fault (`sFault`) - leaf entry → translation complete (`sLeaf`) - non-leaf entry at L0 → page fault (`sFault`) because Sv32 has only two levels - **sLeaf** Finalization state for a successful translation. In this state the PTW: 1) checks access permissions based on the request type: - instruction fetch requires `X` - load requires `R` - store requires `W` 2) constructs the final translated PPN: - for a normal 4KB page, PPN comes directly from the L0 leaf PTE - for a 4MB superpage, the PPN is formed by combining `PPN1` from the L1 leaf PTE with `VPN0` from the VA 3) fills the appropriate TLB (ITLB or DTLB), including replacement selection (2-way set-associative with per-set round-robin victim) After filling the TLB, the PTW returns to `sIdle` so the stalled request can be retried using the translated physical address. - **sFault** Terminal state for translation failure. The MMU reports a fault to either the I-side or D-side depending on which request triggered the walk, then returns to `sIdle`. *(Note: fault signaling to the IF stage and writing the corresponding `scause` are not implemented yet and will be added later.)* > Note: A/D-bit update is **not implemented yet** (I currently pre-set A/D in the test PTEs). --- ### 4) How I verified it Because the full mmu-test requires fault delivery + other missing pieces, I validated PTW/TLB behavior using a **standalone Sv32 assembly test** that: - Builds page tables in memory at fixed, aligned physical addresses - Enables `satp` - Triggers controlled accesses that force: - **L1 leaf (4MB superpage)** translations - **L1 pointer → L0 leaf (4KB)** translations :::spoiler ```asm= .section .text .globl main .equ L1_PT_PA, 0x00005000 # 4KB aligned .equ L0_PT0_PA, 0x00006000 # vpn1=0 -> VA 0x0000_0000 ~ 0x003F_FFFF .equ PTE_PTR, 0x001 # V=1, R=W=X=0 (pointer) .equ PTE_LEAF, 0x0CF # V|R|W|X|A|D main: # 1) mtvec point to trap entry la t0, __trap_entry csrw mtvec, t0 # --------------------------------------------------- # 2) clear L1 + L0 tables (only tables we use) # --------------------------------------------------- li t2, 0 # clear L1 page table @ L1_PT_PA li t0, L1_PT_PA li t1, 1024 1: sw t2, 0(t0) addi t0, t0, 4 addi t1, t1, -1 bnez t1, 1b # clear L0_PT0 @ L0_PT0_PA li t0, L0_PT0_PA li t1, 1024 2: sw t2, 0(t0) addi t0, t0, 4 addi t1, t1, -1 bnez t1, 2b # --------------------------------------------------- # 3) L1[0] -> L0_PT0 (pointer) # L1[1] = superpage leaf (4MB) for VA 0x0040_0000~0x007F_FFFF # --------------------------------------------------- li t0, L1_PT_PA # L1[0] pointer -> L0_PT0 li t1, (L0_PT0_PA >> 12) slli t1, t1, 10 ori t1, t1, PTE_PTR sw t1, 0(t0) # entry vpn1=0 # L1[1] superpage leaf: # PPN1 = 1, and PPN0 must be 0 => just put (1<<20) into PTE[31:20] li t2, (1 << 20) # PPN1 goes to bits [31:20] ori t2, t2, PTE_LEAF sw t2, 4(t0) # entry vpn1=1 (superpage leaf) # --------------------------------------------------- # 4) Fill L0_PT0: identity map 0~4MB (vpn1=0 chunk) # --------------------------------------------------- li t0, L0_PT0_PA li t1, 0 # vpn0 4: slli t2, t1, 12 # va within vpn1=0 region srli t3, t2, 12 # ppn = va>>12 (identity) slli t3, t3, 10 ori t3, t3, PTE_LEAF sw t3, 0(t0) addi t0, t0, 4 addi t1, t1, 1 li t4, 1024 blt t1, t4, 4b # --------------------------------------------------- # 5) Enter S-mode # --------------------------------------------------- csrr t0, mstatus li t1, ~(3 << 11) and t0, t0, t1 li t1, (1 << 11) # MPP=S or t0, t0, t1 csrw mstatus, t0 la t0, s_main csrw mepc, t0 mret # ===================================================== # S-mode main # ===================================================== .align 4 s_main: li t0, (1 << 31) | (L1_PT_PA >> 12) csrw satp, t0 li s0, 0 # error accumulator (0 = pass) # =================================================== # (A) Superpage region (vpn1=1 megapage) # touch a few addresses: base + 0x1000*k + small offset # =================================================== li s1, 0x00400000 # superpage base li s2, 0xA0000000 # seed # A0: [0x00401000] li t1, 0x00401000 li t2, 0xA0000001 sw t2, 0(t1) lw t3, 0(t1) xor t4, t2, t3 or s0, s0, t4 # A1: [0x00402004] li t1, 0x00402004 li t2, 0xA0000002 sw t2, 0(t1) lw t3, 0(t1) xor t4, t2, t3 or s0, s0, t4 # A2: [0x00403008] li t1, 0x00403008 li t2, 0xA0000003 sw t2, 0(t1) lw t3, 0(t1) xor t4, t2, t3 or s0, s0, t4 # A3: [0x0040400C] li t1, 0x0040400C li t2, 0xA0000004 sw t2, 0(t1) lw t3, 0(t1) xor t4, t2, t3 or s0, s0, t4 # =================================================== # (B) 4KB region (vpn1=0 via L0) # Force SAME set conflicts: # base = 0x00001000 keeps VA[14:12]=001 # stride = 0x8000 changes VA[21:15] (tag) but keeps set # Touch 6 distinct pages => must evict in 2-way # =================================================== li s4, 0xCAFE0000 # B0: 0x00001000 li t1, 0x00001000 li t2, 0xCAFE1000 sw t2, 0(t1) lw t3, 0(t1) xor t4, t2, t3 or s0, s0, t4 # B1: 0x00009000 li t1, 0x00009000 li t2, 0xCAFE1001 sw t2, 0(t1) lw t3, 0(t1) xor t4, t2, t3 or s0, s0, t4 # B2: 0x00011000 li t1, 0x00011000 li t2, 0xCAFE1002 sw t2, 0(t1) lw t3, 0(t1) xor t4, t2, t3 or s0, s0, t4 # B3: 0x00019000 li t1, 0x00019000 li t2, 0xCAFE1003 sw t2, 0(t1) lw t3, 0(t1) xor t4, t2, t3 or s0, s0, t4 # B4: 0x00021000 li t1, 0x00021000 li t2, 0xCAFE1004 sw t2, 0(t1) lw t3, 0(t1) xor t4, t2, t3 or s0, s0, t4 # B5: 0x00029000 li t1, 0x00029000 li t2, 0xCAFE1005 sw t2, 0(t1) lw t3, 0(t1) xor t4, t2, t3 or s0, s0, t4 # =================================================== # (C) Re-touch first two addresses again # If replacement is working, at least one should miss/refill # =================================================== # C0: 0x00001000 again li t1, 0x00001000 li t2, 0xDEAD0000 sw t2, 0(t1) lw t3, 0(t1) xor t4, t2, t3 or s0, s0, t4 # C1: 0x00009000 again li t1, 0x00009000 li t2, 0xDEAD0001 sw t2, 0(t1) lw t3, 0(t1) xor t4, t2, t3 or s0, s0, t4 done: j done ``` ::: Waveforms confirm the PTW/TLB loop works end-to-end: - **I-side (Instruction fetch)** - On an iTLB miss, the PTW performs the expected Sv32 walk and then fills the **ITLB**. - 4KB case: `L1 fetch → L0 fetch → leaf → ITLB fill` - (If the VA maps to a superpage) 4MB case: `L1 fetch → leaf → ITLB fill` - After the fill, the same fetch is retried and **hits in ITLB**. ![截圖 2026-01-18 晚上7.04.27](https://hackmd.io/_uploads/H1KHAE9SZe.png) - **D-side (Load/Store)** - I used **two waveforms** to cover both translation patterns: 1) **D-side 1-stage (superpage / 4MB)** - `L1 fetch → leaf → DTLB fill` - The retried load/store then **hits in DTLB**. ![截圖 2026-01-18 晚上11.22.15](https://hackmd.io/_uploads/rkEh5_qBZe.png) 2) **D-side 2-stage (normal 4KB)** - `L1 fetch → L0 fetch → leaf → DTLB fill` - The retried load/store then **hits in DTLB**. ![截圖 2026-01-19 凌晨12.00.01](https://hackmd.io/_uploads/S1aK7t9S-l.png) --- ### 5) Current limitation (next work) I can raise `i_fault/d_fault` from PTW, but **end-to-end page fault handling is not complete yet**, mainly because: - In a pipeline, faults must be **precise** (only the correct-path instruction should trap) - If the pipeline keeps presenting the same faulting request, PTW can re-walk repeatedly unless the core **kills the request + redirects PC** to the handler - The final integration step is: - carry fault info to the right stage, - flush/redirect correctly, - write `stval/scause/sepc` via the trap path. ## Next work / Not finished yet There are still several missing pieces before the Sv32 MMU is “complete” and OS-ready: - **Run the official `mmu-test` suite** - I currently cannot pass the full test suite because the remaining exception/fault plumbing is incomplete (see below). - Target: make the core pass the `rv32emu mmu-test` end-to-end (translation + faults + corner cases). - **Precise page fault handling (end-to-end)** - PTW can raise `i_fault/d_fault`, but I still need to: - generate the correct fault type (`Instruction/Load/Store Page Fault`) and write **`scause`** - write the faulting VA into **`stval`** - ensure faults are **precise** in a pipelined core (only correct-path instructions trap) - correctly **flush/kill** the faulting request and **redirect PC** to the trap handler (`stvec`) to avoid infinite re-walk loops. - **A/D bit update in hardware** - Current tests pre-set `A/D` in PTEs; PTW is read-only. - Target: implement atomic A/D updates (including the extra memory write sequence and corner cases). - **`sfence.vma` support** - TLB flush/invalidate behavior is still pending. - Target: implement `sfence.vma` and verify selective + global invalidation.

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password
    or
    Sign in via Google Sign in via Facebook Sign in via X(Twitter) Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    By signing in, you agree to our terms of service.

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully