Classroom Glossary Public page

Lab 14: Capstone Integration Week

1,086 words

Total points: See CAPSTONE.md (Tier 1 + Tier 2 scoring)
Estimated time: Open-ended (recommended 8-12 hours over the final two weeks)
Prerequisites: Labs 1-13 complete (all six gates require specific prior labs)


Overview

Lab 14 is not a prescribed sequence of parts -- it is an integration sprint. You are assembling all CSA-201 modules into a single running system: Virtus OS v2 on DE10-Nano. The deliverable is the capstone package described in CAPSTONE.md.

Read CAPSTONE.md in full before starting this lab. The six Tier 1 gates are the primary pass/fail criteria. Tier 2 scoring depends on passing all six gates first.

This document is a pre-submission checklist and debugging reference. Work through it top to bottom before submitting.


Pre-flight: gate-by-gate prerequisite map

Before attempting a gate, confirm the listed lab artifacts are working on hardware (not just in Verilator):

Gate Gate requirement Required lab
Gate 1: OS boots Cold boot, OLED shows boot message within 10 s Labs 11, 12
Gate 2: U/S transition ECALL flips priv bit; MRET restores it Lab 2
Gate 3: Page-fault handler Unmapped access handled cleanly Lab 7 (Part C)
Gate 4: PMP W^X Write to code page faults; OS handles Lab 8 (Part C)
Gate 5: Round-robin scheduler Two tasks advance concurrently on OLED Lab 11 (Part C)
Gate 6: SSD1306 live output OS version + process names + live counter Lab 12 (Part C)

If any prerequisite lab is incomplete, finish it before attempting the corresponding gate.


Integration checklist

Work through these items in order. Check each off as you verify it on DE10-Nano hardware.

Boot and initialization order

  • clint_init() called before scheduler_start(); mtimecmp set before MIE enabled
  • mmu_init() called before any user process spawns; satp written before MRET to U-mode
  • pmp_init() called before switching to U-mode; at minimum entry 0 (code R+X) and entry 1 (data R+W) set
  • oled_init() called before first display write; sd_init() called before first FAT access
  • Heap initialized for both BRAM and DDR3 regions before Memory.alloc is called
  • __stack_chk_guard initialized before any user function runs

MMU + PMP interaction (common source of silent failures)

  • After every page-table modification, SFENCE.VMA executed before the next memory access to the modified VA
  • PMP entries cover exactly the physical ranges you intend; virtual addresses must be translated to physical before PMP checks them
  • If using the Sv32 MMU, PMP checks physical addresses (post-translation). Test with a code page that has both a valid PTE and a PMP W=0 entry; a store should fault even if the PTE has W=1

Scheduler + GC interaction

  • Memory_gc() calls scheduler_stop() (disables timer interrupt) at entry and scheduler_resume() at exit
  • If a context switch fires during the mark phase (before stop-the-world), the GC state will be corrupted. Verify timer interrupt is disabled before gc_mark() executes
  • After GC completes and scheduler resumes, the first timer interrupt fires normally; verify by counting interrupts in the first 100 ms after GC

Context-switch register file integrity

  • All 32 registers are saved and restored (x0-x31); do not skip x0 (it must read as zero but the slot must be consistent)
  • mepc saved and restored correctly; the interrupted instruction re-executes correctly after MRET
  • satp saved and restored per process (if processes have different address spaces -- even if they share the same page table, save satp in case you later add per-process tables)
  • mstatus.MPP set to U (=00) before MRET to user process; set to M (=11) only when returning to kernel

Driver timing

  • I2C SCL does not exceed the SSD1306's maximum clock rate (400 kHz fast mode, or 100 kHz standard mode)
  • SD card SPI clock rate at or below 400 kHz during init sequence (CMD0 through ACMD41); can increase to 25 MHz after initialization
  • No SPI transaction starts while CS is high; CS must be asserted (low) before the first clock edge and de-asserted after the last

Common last-minute failures and fixes

Gate 1: OLED shows nothing after boot.

  • Most common cause: oled_init() not called before oled_draw_string().
  • Second most common: I2C address wrong (try 0x3C and 0x3D).
  • Third: pull-up resistors missing on SDA/SCL lines (SSD1306 is open-drain; needs external 4.7k ohm to VCC).

Gate 3: Page fault handler fires but process does not resume.

  • Check that MRET returns to the faulting address (mepc = faulting instruction VA, not mepc + 4).
  • Check that SFENCE.VMA is called after installing the new PTE.
  • Check that alloc_page() returns a non-zero physical address; if the free list is exhausted, the PTE install writes address 0, which is likely already mapped to kernel code.

Gate 4: Store to code page does not fault; "write succeeded" appears on OLED.

  • Check that the PMP entry for the code region has W=0. The pmpcfg byte should have bit 1 (W) = 0.
  • Check that the U-mode program is actually running in U-mode (priv = 00). If it is running in M-mode due to a MRET bug, PMP W=0 with L=0 does not apply to M-mode.
  • Check priority: if a later PMP entry has W=1 and matches the same address, it will not override entry 0 (higher number = lower priority); but verify your CPU's priority cascade is correct.

Gate 5: One task advances but the other freezes.

  • Most likely: the context switch is restoring registers to the wrong process. Check that the process table index used for save and restore is consistent.
  • Second most likely: timer is not reprogrammed after context switch. reprogram_timer(500000) must execute before MRET in the timer handler.
  • Third: the new process's sp was initialized to a valid stack address in sys_spawn(); if sp is 0 or uninitialized, the process will fault on first push.

Gate 5: Context-switch cycle count is far above 150 cycles.

  • Cause: memcpy is not optimized; word-by-word copy is slower than expected.
  • Fix: implement an unrolled 32-register save using sw x1, 4(a0); sw x2, 8(a0); ... (32 explicit stores); no loop overhead.

Gate 6: OLED shows garbled output.

  • Check page/column cursor is set before each string write; successive writes without cursor reset will run off the end of the page.
  • Check that oled_draw_string does not write past column 128; add a bounds check.

Deliverable package reminder

csa201-capstone-{your-name}.zip
├── bitstream/
│   └── virtus-os-v2-de10nano.sof
├── hdl/
├── firmware/
├── compiler/
├── measurements/
├── demo/
│   └── capstone-demo.mp4      (3-5 minutes)
└── writeup.pdf                (6-8 pages, six sections per CAPSTONE.md)

SHA-256 all binaries and include checksums.txt.

Submit to the course LMS before the deadline. Late submissions lose 10% per day. Gate demonstrations must be live on hardware (not Verilator) to count for Tier 1.


Grading

See CAPSTONE.md for the complete rubric.

Component Points
Tier 1: Six gates (pass/fail; must pass all for Tier 2 credit) Pass/Fail
Tier 2 / Mitigation depth 40% of Tier 2
Tier 2 / Measurement quality 30% of Tier 2
Tier 2 / Demo and write-up 30% of Tier 2

B- minimum on Tier 2 (>= 70%) required for the VCA-CSA-201 Certificate of Completion.