Bare-metal RV32 support and a qemu smoke test - #24
Closed
pawlex wants to merge 1 commit into
Closed
Conversation
Runs the i386 core on a bare-metal 32-bit RISC-V target -- no OS, no
heap, no host libc beyond picolibc. Verified under qemu-system-riscv32
with `make -C rv32 run`.
Three changes to i386.c, all conditional. Default builds are unaffected:
with no new macros defined and on a non-RISC-V target, i386.c compiles
exactly as before.
-DI386_DISABLE_FPU x87 becomes opt-OUT rather than always on. The
integer core uses no floating point (fpu.c
holds the project's only FP references), so
this avoids pulling soft-float into targets
without an FPU. Stubs for the disabled case
already existed.
__riscv && xlen == 32 get_nticks() reads the 64-bit cycle counter via
rdcycle/rdcycleh instead of clock_gettime,
which bare metal does not have. This feeds the
emulated RDTSC, and counting CPU cycles is
arguably closer to real x86 TSC semantics than
the host build's nanoseconds. Note the `cycle`
CSR is optional in RISC-V.
-DTINY386_STATIC_ALLOC the two mallocs become static (CPUI386 512 B,
TLB table 12 KB). Assumes a single CPU
instance.
baremetal_stubs.c adds usleep(), called on an idle path at i386.c:5030;
a no-op suffices for a functional test, though an embedded integration
would make it a WFI or a yield. Nothing else was needed -- picolibc's
semihosting crt0 supplies stdout/stderr/_exit, so no fprintf or abort
stubs are required and printf works under qemu.
rv32/ holds the smoke test: a small flat-32-bit payload whose every
emitted value is COMPUTED rather than constant, so the output cannot be
produced by anything but real execution -- squares via IMUL and a
decrementing ECX through LOOP, a memory round-trip that survives an
XOR EAX,EAX clobber, and a byte store read back with MOVZX.
Footprint (-Os -DNDEBUG, FPU off, picolibc):
rv32im .text 159,361 B
rv32imc .text 119,917 B
x86-64 .text 140,422 B (host reference, with x87)
plus ~12 KB writable state excluding guest RAM.
The Makefile defaults to rv32im rather than rv32imc despite compressed
instructions being 25% smaller. Measured against VexRiscv on a Lattice
ECP5 LFE5U-85F (yosys 0.68 + nextpnr-ecp5, out-of-context): the RVC
decompressor lands on the critical path, costing 40% of Fmax (57.43 MHz
vs 96.55) and 16% more logic. Smaller code helps I-cache hit rate but
would have to be worth 68% to break even, which for a throughput-bound
interpreter it is not. Override with `make ARCH=rv32imc` where compressed
support is cheap. rv32/README.md carries the full variant table.
Not covered by the test, and documented as such: rdcycle is unexercised
(the payload never executes RDTSC), interrupts are untouched, and the
payload runs flat 32-bit via cpui386_reset_pm rather than real mode.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Owner
|
There is no longer a hardcoded For other changes, consider adding |
Author
|
understood -- realized after PR this was working with a stale branch. If there is interest from upstream, I will re-generate after integration is complete. |
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.
Runs the i386 core on a bare-metal 32-bit RISC-V target — no OS, no heap,
no host libc beyond picolibc. Verified under
qemu-system-riscv32.Default builds are unaffected. With no new macros defined and on a
non-RISC-V target,
i386.ccompiles exactly as before — the threechanges are all behind guards.
Changes to
i386.c-DI386_DISABLE_FPUfpu.cholds the project's only FP references. Dropping it avoids pulling soft-float into targets without an FPU. Stubs for the disabled case already existed.get_nticks()usesrdcycle/rdcycleh#if defined(__riscv) && __riscv_xlen == 32clock_gettime. Feeds the emulatedRDTSC; counting CPU cycles is arguably closer to real x86 TSC semantics than the host build's nanoseconds.mallocs become static-DTINY386_STATIC_ALLOCCPUI386512 B + 12 KB TLB. Assumes a single CPU instance.Plus
baremetal_stubs.cforusleep(), called on the idle path ati386.c:5030. Nothing else was needed — picolibc's semihosting crt0supplies
stdout/stderr/_exit, so nofprintf/abortstubs andprintfworks under qemu.Smoke test
rv32/holds a small flat-32-bit payload whose every emitted value iscomputed rather than constant, so the output can't be produced by
anything but real execution — squares via
IMULand a decrementingECXthrough
LOOP, a memory round-trip surviving anXOR EAX,EAXclobber,and a byte store read back with
MOVZX.Footprint
-Os -DNDEBUG, FPU off, picolibc:.textrv32imrv32imcplus ~12 KB writable state excluding guest RAM.
Why the Makefile defaults to
rv32imCompressed instructions are 25% smaller, which looks decisive until the
core running it is measured. Tested against VexRiscv on a Lattice
ECP5 LFE5U-85F (yosys 0.68 + nextpnr-ecp5, out-of-context):
VexRiscv_FullVexRiscv_IMAC(RVC)The decompressor lands on the critical path — 40% of the clock for 25%
of the code. Smaller code helps I-cache hit rate but would need to be
worth 68% to break even. Override with
make ARCH=rv32imcwherecompressed support is cheap.
rv32/README.mdhas the full variant table.Not covered
rdcycleis unexercised (the payload never runsRDTSC), interrupts areuntouched, and the payload is flat 32-bit via
cpui386_reset_pm()ratherthan real mode.