Add BIOS and tiny kernel roadmap phases

This commit is contained in:
2026-04-28 13:23:03 +02:00
parent 07dd8e21f0
commit e8631501e8
18 changed files with 344 additions and 77 deletions
+19 -19
View File
@@ -29,8 +29,8 @@ See ROADMAP.md for the full phased plan.
- Firmware source: `fw/` directory. Built with `riscv64-unknown-elf-gcc`
(multilib build required). March string evolves with the implemented ISA:
- Phase 8 (pre-CSR bare-metal): `-march=rv32im -mabi=ilp32`
- Phase 9+ (CSRs/Zifencei decoded): `-march=rv32im_zicsr_zifencei -mabi=ilp32`
- Phase 12+ (atomics): `-march=rv32ima_zicsr_zifencei -mabi=ilp32`
- Phase 12+ (CSRs/Zifencei decoded): `-march=rv32im_zicsr_zifencei -mabi=ilp32`
- Phase 15+ (atomics): `-march=rv32ima_zicsr_zifencei -mabi=ilp32`
Don't advertise an extension before its ops are decoded — the compiler is
free to emit them, and "trap as illegal" early is much better than NOPing.
@@ -55,14 +55,14 @@ End target: **RV32IMA + Zicsr + Zifencei + M/S/U privilege + Sv32** (Linux-capab
Extensions land incrementally:
- RV32IM base — Phases 1-8
- Zicsr (CSR instructions) + M-mode trap handling — Phase 9
- Zifencei (`fence.i`) — decoded but NOP until caches exist (Phase 14+)
- A (atomics: LR/SC + AMO) — Phase 12 (required for mainline Linux)
- S-mode + U-mode + Sv32 — Phase 15
- Zicsr (CSR instructions) + M-mode trap handling — Phase 12
- Zifencei (`fence.i`) — decoded but NOP until caches exist (Phase 17+)
- A (atomics: LR/SC + AMO) — Phase 15 (required for mainline Linux)
- S-mode + U-mode + Sv32 — Phase 18
## Key Design Decisions
- Single-cycle first, pipeline later (Phase 13, optional). Stages are separated
- Single-cycle first, pipeline later (Phase 16, optional). Stages are separated
in the code even without pipeline registers between them.
- "Single-cycle" is a logical model, not a literal one cycle per instruction.
BRAM has a 1-cycle read latency, so fetch is registered and loads take 2
@@ -82,10 +82,10 @@ Extensions land incrementally:
```
0x0000_0000 0x0FFF_FFFF reserved boot aperture (256 MB decode region)
actual SPI flash device is 16 MB (Arty A7),
mapped at 0x0000_00000x00FF_FFFF in Phase 14
mapped at 0x0000_00000x00FF_FFFF in Phase 17
0x1000_0000 0x1000_0FFF MMIO (UART; later: timer, PLIC)
0x2000_0000 0x2000_FFFF instruction BRAM (64 KB)
0x8000_0000 0x8000_FFFF data BRAM (64 KB) → grows to DRAM 0x8000_00000x8FFF_FFFF in Phase 14
0x8000_0000 0x8000_FFFF data BRAM (64 KB) → grows to DRAM 0x8000_00000x8FFF_FFFF in Phase 17
```
Reset PC = `0x2000_0000`. Linker script anchors text/rodata at `0x2000_0000`
@@ -99,7 +99,7 @@ UART register layout (split, not 16550-style):
```
This is fine for bare-metal firmware but is *not* directly Linux-compatible:
the in-tree `8250/16550` driver expects a different register layout. Phase 16
the in-tree `8250/16550` driver expects a different register layout. Phase 19
(Linux Boot Contract) revisits this — either add a 16550-compatible wrapper
or write a custom Linux serial driver + device-tree binding.
@@ -123,7 +123,7 @@ typedef struct packed {
logic [1:0] size; // 00=byte, 01=halfword, 10=word
logic [31:0] wdata; // lane-aligned per wstrb
logic [3:0] wstrb; // byte enables (writes only)
logic [3:0] amo; // AMO op encoding (D-bus only, Phase 12+)
logic [3:0] amo; // AMO op encoding (D-bus only, Phase 15+)
} mem_req_t;
// Payload — slave → master
@@ -153,7 +153,7 @@ Handshake notes:
producing a response (BRAM = 1 cycle, DRAM = many).
- `wstrb` is mandatory from Phase 6.2 onward (sub-word stores). For
Phase 6.1 (word-only), tie strobes to `4'b1111` on stores.
- `amo` is unused (drive `4'h0`) until Phase 12; on the I-bus it is always
- `amo` is unused (drive `4'h0`) until Phase 15; on the I-bus it is always
unused.
- `err` is **only** raised by a slave to report access faults it owns:
unmapped address, peripheral-access violation, eventually DRAM ECC fault.
@@ -173,8 +173,8 @@ separately. Per-phase progression:
| 4 | CPU fetch ↔ instruction BRAM | (none yet) |
| 6 | unchanged | LSU ↔ data BRAM (single slave) |
| 7 | unchanged | LSU ↔ decoder → {data BRAM, UART MMIO} |
| 9-12 | unchanged | + timer (Phase 10), PLIC (Phase 11) |
| 14 | I-bus → arbiter → DRAM | D-bus → arbiter → DRAM (or MIG dual-port) |
| 12-15 | unchanged | + timer (Phase 13), PLIC (Phase 14) |
| 17 | I-bus → arbiter → DRAM | D-bus → arbiter → DRAM (or MIG dual-port) |
Both buses can fault independently; classification happens in the masters
(see below).
@@ -195,17 +195,17 @@ transaction adds context to produce the precise architectural cause:
| Store/AMO address misaligned | 6 | LSU (size + addr LSBs, pre-issue) |
| Store/AMO access fault | 7 | LSU (D-bus `rsp.err` on write) |
| Ecall from M-mode | 11 | decoder |
| Instruction page fault | 12 | I-side MMU (Phase 15) |
| Load page fault | 13 | D-side MMU (Phase 15) |
| Store/AMO page fault | 15 | D-side MMU (Phase 15) |
| Instruction page fault | 12 | I-side MMU (Phase 18) |
| Load page fault | 13 | D-side MMU (Phase 18) |
| Store/AMO page fault | 15 | D-side MMU (Phase 18) |
Two consequences:
- The LSU detects misalignment **before** issuing a bus request — never
send a request you already know will trap.
- Page faults (Phase 15) are raised by the MMU during translation,
- Page faults (Phase 18) are raised by the MMU during translation,
before the (translated) request hits the bus.
### Atomics (Phase 12)
### Atomics (Phase 15)
LR/SC and AMO use the `amo` field of `mem_req_t` (D-bus only) rather than
a separate bus. Single-hart reservation tracking lives in the LSU.