Add phase-by-phase tutorial notes

Add a Tutorial tree that mirrors the roadmap from Phase 0 through Linux bring-up.
Each phase and subphase gets a short learning note with consistent sections for
context, goals, new concepts, mental model, learning tasks, pitfalls, tooling,
testing, and references.

The tutorial material is intentionally explanatory rather than implementation
code. It gives a systems-oriented learner enough FPGA, SystemVerilog, RISC-V,
firmware, and Linux bring-up context to approach each roadmap phase without
turning the notes into copy-paste RTL.
This commit is contained in:
2026-04-28 12:11:23 +02:00
parent 8edfc86027
commit b008b37d49
43 changed files with 2110 additions and 0 deletions
@@ -0,0 +1,49 @@
# Phase 8.1 - Linker Script + Startup Code
## Context
C programs assume a runtime environment. Bare metal provides none unless you create it:
memory layout, stack pointer, zeroed globals, and entry point.
## Goals
- Place code and read-only data in instruction memory.
- Place writable data, BSS, and stack in data memory.
- Understand what startup code must do before calling `main`.
## New Concepts
- Section: named region of an object file, such as `.text` or `.bss`.
- Load address: where bytes are stored in the image.
- Virtual/runtime address: where code expects them at execution.
- Stack pointer: register pointing to top of current stack frame.
## How To Think About It
The linker script is the contract between memory hardware and compiled software. If it
lies, the CPU may be correct and the program will still fail.
## Learning Tasks
- Draw the memory layout from reset PC through stack top.
- Identify which sections need initial contents and which are zero-filled.
- Understand why `.bss` must be cleared.
## Pitfalls
- Placing stack where it collides with `.bss` or data.
- Forgetting alignment requirements.
- Using library code that expects syscalls or a full C runtime.
## Tooling And Testing
- Inspect ELF sections and symbols with binutils.
- Disassemble startup code and confirm the first instructions are supported.
- Create a C program with global initialized and uninitialized variables.
## References
- GNU ld scripts: https://sourceware.org/binutils/docs/ld/Scripts.html
- RISC-V ELF psABI: https://github.com/riscv-non-isa/riscv-elf-psabi-doc
- OSDev bare bones concepts: https://wiki.osdev.org/Bare_Bones
@@ -0,0 +1,49 @@
# Phase 8.2 - First GCC Program
## Context
The first compiled program proves your hardware can execute compiler-generated code, not
just carefully hand-authored assembly.
## Goals
- Compile a tiny C firmware for `rv32im`.
- Convert the ELF into a memory image.
- Print through UART MMIO from C.
## New Concepts
- `-march`: compiler ISA target string.
- `-mabi`: ABI selection, here `ilp32` for 32-bit integer/long/pointer.
- objcopy: tool that converts ELF into raw binary or other formats.
- Disassembly: readable assembly representation of generated machine code.
## How To Think About It
Treat the compiler as an external producer of instructions. Your job is to verify that
every emitted instruction is implemented or fails loudly.
## Learning Tasks
- Compare C source to generated assembly.
- Identify every load/store used for UART access.
- Confirm no CSR or `fence.i` instructions appear before Phase 9.
## Pitfalls
- Using the wrong `-march` and accidentally generating unsupported instructions.
- Forgetting `volatile` on MMIO accesses in firmware.
- Assuming the compiler will preserve simple-looking loops exactly.
## Tooling And Testing
- Always inspect early firmware with objdump.
- Build at low optimization first, then compare optimized output later.
- Keep firmware small enough to single-step mentally.
## References
- GCC RISC-V options: https://gcc.gnu.org/onlinedocs/gcc/RISC-V-Options.html
- RISC-V ELF psABI: https://github.com/riscv-non-isa/riscv-elf-psabi-doc
- GNU objcopy: https://sourceware.org/binutils/docs/binutils/objcopy.html
@@ -0,0 +1,49 @@
# Phase 8.3 - Fill Remaining RV32I Gaps
## Context
Compiler output will expose missing instructions and edge cases. This subphase closes
the base ISA gaps before moving into traps and privilege.
## Goals
- Implement remaining RV32I instructions required by compiler output.
- Decode `fence` as safe in a cacheless design.
- Make unsupported system instructions halt visibly.
## New Concepts
- `fence`: memory-ordering instruction.
- `fence.i`: instruction-stream synchronization instruction.
- `ecall`: environment call, later a trap.
- `ebreak`: breakpoint instruction, later a trap.
## How To Think About It
Incomplete ISA behavior should be loud. A clean halt with PC and instruction word is far
better than silent execution through an unsupported instruction.
## Learning Tasks
- Make a list of every RV32I instruction and current support status.
- Disassemble increasingly complex C programs and mark new instructions.
- Understand why `fence` can be harmless without caches while `fence.i` still needs decode policy.
## Pitfalls
- Treating `ecall` or `ebreak` as NOPs.
- Missing uncommon instructions emitted by switch statements or stack setup.
- Debugging firmware before checking the disassembly.
## Tooling And Testing
- Add illegal-instruction tests.
- Keep a cycle limit in simulations to catch hangs.
- Use compiler output as a test source, not a proof of correctness.
## References
- RISC-V unprivileged ISA: https://riscv.org/technical/specifications/
- GCC RISC-V options: https://gcc.gnu.org/onlinedocs/gcc/RISC-V-Options.html
- RISC-V assembly manual: https://github.com/riscv-non-isa/riscv-asm-manual
@@ -0,0 +1,49 @@
# Phase 8.4 - Meaningful C Program
## Context
After minimal C works, write a program large enough to exercise stack, branches, calls,
arrays, strings, and UART interaction.
## Goals
- Run an interactive or semi-interactive firmware.
- Exercise real C control flow and memory behavior.
- Build confidence before adding privilege and traps.
## New Concepts
- Stack frame: per-call storage for return address, locals, and saved registers.
- Recursion: function calling itself, useful for stressing stack behavior.
- Jump table: compiler-generated table for some switch statements.
- Serial monitor: small firmware command interface over UART.
## How To Think About It
This is a system test, not a unit test. Failures can come from CPU, memory, compiler
assumptions, or firmware bugs. Use it after smaller tests pass.
## Learning Tasks
- Trace one function call through prologue and epilogue.
- Observe stack growth and confirm it stays within data memory.
- Add one feature at a time to firmware and inspect generated assembly.
## Pitfalls
- Pulling in library functions accidentally.
- Overflowing the tiny BRAM-backed stack.
- Debugging optimized code before unoptimized code works.
## Tooling And Testing
- Use map files to understand memory usage.
- Add firmware-visible test results through UART.
- Keep a known-good simple firmware for regression comparisons.
## References
- RISC-V ELF psABI: https://github.com/riscv-non-isa/riscv-elf-psabi-doc
- GNU ld map files: https://sourceware.org/binutils/docs/ld/Options.html
- Embedded Artistry bare-metal articles: https://embeddedartistry.com/
@@ -0,0 +1,49 @@
# Phase 8.5 - riscv-tests Compliance
## Context
Official instruction tests catch ISA bugs that ad hoc tests miss. Run them before adding
trap, interrupt, and privilege complexity.
## Goals
- Build and run `rv32ui-p-*` and `rv32um-p-*`.
- Create a simulation harness that loads test programs.
- Establish regression coverage for later phases.
## New Concepts
- Compliance test: focused program checking architectural behavior.
- Harness: wrapper that provides memory, stop condition, and pass/fail reporting.
- Signature region: memory region where tests record results.
- Regression: test suite run repeatedly to catch breakage.
## How To Think About It
Do not treat compliance tests as optional polish. They are how you avoid stacking new
features on top of unknown ISA bugs.
## Learning Tasks
- Understand how a riscv-test indicates pass/fail.
- Learn how ELF sections map into your BRAM model.
- Categorize failures by decode, execute, memory, or control-flow likely cause.
## Pitfalls
- Running tests with the wrong ISA target.
- Assuming the test harness memory layout matches your hardware automatically.
- Ignoring one failing test because normal firmware seems to work.
## Tooling And Testing
- Automate running all tests once the harness exists.
- Keep failing waveforms short and reproducible.
- Re-run the suite after every meaningful datapath change.
## References
- riscv-tests repository: https://github.com/riscv-software-src/riscv-tests
- RISC-V architectural tests: https://github.com/riscv-non-isa/riscv-arch-test
- RISC-V unprivileged ISA: https://riscv.org/technical/specifications/
@@ -0,0 +1,49 @@
# Phase 8 - GCC Toolchain Integration
## Context
This phase moves from hand-written assembly to compiled C. The CPU must now satisfy the
expectations of a real compiler, linker, and runtime startup.
## Goals
- Create linker script and startup code.
- Compile simple C programs for the implemented ISA.
- Run RISC-V compliance-style tests.
## New Concepts
- Linker script: file controlling where sections are placed in memory.
- crt0: startup code that prepares stack and globals before `main`.
- ELF: executable/linkable file format used by toolchains.
- ABI: software binary contract for registers, stack, calls, and data layout.
## How To Think About It
GCC is an unforgiving test generator. It will use legal instruction combinations you did
not think to test manually. That is exactly why this phase matters.
## Learning Tasks
- Understand sections: `.text`, `.rodata`, `.data`, `.bss`, and stack.
- Learn how ELF becomes a BRAM initialization image.
- Compare disassembly with your implemented instruction list.
## Pitfalls
- Advertising ISA extensions before hardware decodes them.
- Forgetting to initialize stack or zero `.bss`.
- Assuming "simple C" means "simple instruction stream."
## Tooling And Testing
- Use objdump for every early firmware image.
- Keep `-nostdlib` until you deliberately provide runtime support.
- Run compliance tests before adding traps and privilege complexity.
## References
- RISC-V ELF psABI: https://github.com/riscv-non-isa/riscv-elf-psabi-doc
- GNU linker scripts: https://sourceware.org/binutils/docs/ld/Scripts.html
- riscv-tests: https://github.com/riscv-software-src/riscv-tests