"People. What a bunch of bastards." — Roy, The IT Crowd
But RISC-V instructions? Those we can work with.
The foundation. If you can't add numbers, you can't do anything.
- Immediate operations: addi, slti, sltiu, xori, ori, andi, slli, srli, srai
- Register operations: add, sub, sll, slt, sltu, xor, srl, sra, or, and
- Upper immediate: lui, auipc
Status: Complete. Tests passing. Tea consumed.
Because registers alone won't get you far.
- Loads: lb, lh, lw, ld (signed)
- Unsigned loads: lbu, lhu, lwu
- Stores: sb, sh, sw, sd
- Guest memory buffer: 64KB sandbox for RISC-V programmes
Status: Complete. Sign extension working properly. More tea.
Where things get interesting. Branches and jumps.
- Conditional branches: beq, bne, blt, bge, bltu, bgeu
- Unconditional jumps: jal, jalr
- Basic block detection: Stop translating at branch boundaries
- Branch target calculation: PC-relative addressing
- Block caching: 1024-entry cache with hash lookup
- Execute loop: Run multiple blocks in sequence
Status: Complete. Full block caching implemented. The code is jumping about properly now.
The bits that make it actually useful.
- ECALL/EBREAK: System call interface (exit syscall terminates execution)
- CSR instructions: Control and status registers (cycle, time, misa implemented via RDTSC)
- Fence instructions: Memory ordering (NOPs on x86, as predicted)
- High register fix: Displacement encoding for x16-x31 now uses 32-bit offsets
Status: Complete. The machine can now politely request to exit. Jolly good.
Load actual RISC-V binaries instead of hand-coded test cases.
- ELF64 parser: Read RISC-V executables (validates magic, class, endianness, machine type)
- Section loading: Map PT_LOAD segments into guest memory
- Symbol resolution: For debugging output (deferred - not essential)
- Entry point detection: Find where to start
- Real binary tests: Cross-compiled with riscv64-unknown-linux-gnu-gcc via Docker
Test Programs:
simple.S: Arithmetic (10+20+30=60) ✓fib.S: Fibonacci(10)=55 ✓
Status: Complete. We can now load and execute real cross-compiled RISC-V binaries. The dream is alive!
Make it fast. Or at least faster.
- Block caching: Don't re-translate the same code (moved to Phase 3)
- Block linking: Patch exits to jump directly between blocks
- Hot path detection: Identify frequently-executed blocks
- Register allocation: Map hot RISC-V regs to x86 regs
- Peephole optimisation: Combine common instruction sequences
Status: In progress. Block caching and linking complete. Blocks now jump directly to their successors, skipping the dispatch loop. The Fibonacci loop is now faster than a caffeinated rabbit.
The ultimate test.
- Run Doom: If it can run Doom, it's a proper computer
- Framebuffer support: Memory-mapped display output
- Input handling: Keyboard/mouse via memory-mapped I/O
Status: The dream. Every emulator must eventually run Doom. It is known.
Things that would be lovely but aren't essential:
- M extension: Multiply/divide instructions (MUL, MULH, MULHU, DIV, DIVU, REM, REMU)
- A extension: Atomic operations (LR/SC, AMO family)
- F/D extensions: Floating-point (single/double) - basic ops via SSE
- C extension: Compressed instructions
- [~] Linux syscall compatibility: Basic syscalls working (read, write, exit, brk, mmap, ioctl, fstat, close, openat)
- Self-hosting: Translate a RISC-V build of Conway itself
- Correctness first. A slow correct answer beats a fast wrong one.
- Test everything. If it's not tested, it's broken.
- Keep it simple. Clever code is hard to debug.
- Document as you go. Future you will thank present you.
- Have fun. This is a hobby project, not a job.
Last updated during Phase 6. Block linking now patches JMP instructions to skip the dispatch loop entirely. M extension (MUL, DIV, REM family) complete. F/D extensions (floating-point single/double) added via x86 SSE. A extension (atomics: LR/SC and all AMO ops) now implemented - mutex enthusiasts rejoice. Linux syscall compatibility expanding nicely. Also added OP-IMM-32 support (addiw et al.) after the compiler decided to use compressed instructions without asking first. Cheeky.