feat(riscv): bare-metal startup + linker script generators#89
Merged
Conversation
9e891b1 to
0abbecb
Compare
6a7df86 to
6e25fef
Compare
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
4eac182 to
adb57b1
Compare
Track B3 — adds the runtime infrastructure that turns synth's RISC-V .text into a bootable firmware ELF. ## startup.rs — RiscVStartupGenerator Emits C source (with inline RISC-V asm) that: 1. Disables interrupts (mie, mip = 0) 2. Sets sp/gp/s11 (linear-memory base) from linker symbols 3. Installs `_trap_entry` into mtvec (direct mode) 4. Optionally enables the FPU via mstatus.FS = 1 5. Copies .data from flash to RAM 6. Zeroes .bss 7. Calls main(); spins via `wfi` if main returns The trap entry saves the AAPCS-style caller-saved set (ra, t0..t6, a0..a7), marshals mcause/mepc/mtval into a0/a1/a2, and dispatches to a weak C function `synth_trap_handler` that the firmware can override. `StartupConfig` exposes three knobs: external_irq_count (PLIC wiring), trap_returns (mret vs spin in default), enable_fpu (mstatus FPU enable). ## linker_script.rs — RiscVLinkerScriptGenerator Emits a GNU-`ld` script that: - Places `.text._reset` at the entry point so the reset vector is at the start of flash. - Aligns `.text._trap_entry` to 64 bytes (works for both mtvec direct and vectored modes — vectored requires 64-byte alignment). - Splits `.data` between flash (load address) and RAM (run address) so the startup copy loop has well-defined bounds. - Provides `_stack_top`, `_data_start`/`_data_end`/`_data_load`, `_bss_start`/`_bss_end`, `__linear_memory_base`/`__linear_memory_end`, and `__global_pointer$` (= `_data_start + 0x800`, the standard RV small-data anchor). - `LinkerScriptConfig` configures flash/ram origins, linear-memory size, and stack size. ## Memory model The wasm linear-memory base lives in **s11** — chosen because the RV psABI marks it callee-saved, so all selector-emitted load/store sequences (`add tmp, s11, addr; lw rd, offset(tmp)`) work without per-callee re-loading. The startup code pre-loads s11 from `__linear_memory_base`, which the linker script positions in RAM. ## Test summary * 16 new tests (8 in startup, 8 in linker_script). Total RISC-V tests now 98 (was 82). * All workspace tests still pass. * `cargo clippy --workspace --all-targets -- -D warnings` clean. ## Out of scope (B4) * CLI integration of `--link` for RISC-V (riscv64-unknown-elf-gcc invocation) * PLIC wiring (external_irq_count is exposed but not yet emitted) * Calculator demo running on Renode RV32 with full firmware * Kiln-builtins-style host bridge for RV32 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
adb57b1 to
08203f9
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Track B3 — adds the runtime infrastructure that turns synth's RISC-V .text into a bootable firmware ELF. Stacked on #88.
What this adds
`startup.rs` — `RiscVStartupGenerator`
Emits C source (with inline RISC-V asm) that:
Trap entry saves caller-saved registers, marshals mcause/mepc/mtval into a0/a1/a2, dispatches to a weak `synth_trap_handler` (firmware-overridable).
`linker_script.rs` — `RiscVLinkerScriptGenerator`
Emits a GNU-`ld` script that:
Memory model
The wasm linear-memory base lives in s11 — chosen because the RV psABI marks it callee-saved, so all selector load/store sequences (`add tmp, s11, addr; lw rd, offset(tmp)`) work without per-callee re-loading.
Test summary
Out of scope (B4)
🤖 Generated with Claude Code