nx_rv64_sim.nx
buildroot/runtime/nx_rv64_sim.nx
about
nx_rv64_sim.nx -- minimal RV64I interpreter (sovereign qemu).
MAJOR off-C deliverable: removes qemu-riscv64-static dependency
from bootstrap_proof.sh stage 2. An RV64I program loaded into
memory can be executed by THIS module's instruction loop.
v0.0.1 scope (RV64I + RV64M):
* 31 general registers (x0 = always zero, x1..x31 = mutable)
* pc register
* Linear flat memory (caller-supplied buffer)
* Decode + execute every RV64I op the codegen emits:
- R-type: add/sub/mul/div/rem/and/or/xor/sll/srl/sra/slt/sltu
- I-type: addi/andi/ori/xori/slli/srli/srai/slti/sltiu, jalr,
ld/lw/lh/lb/lwu/lhu/lbu
- S-type: sd/sw/sh/sb
- B-type: beq/bne/blt/bge/bltu/bgeu
- U-type: lui/auipc
- J-type: jal
- System: ecall (-> caller-supplied syscall handler)
What we DEFER to follow-up commits:
* F/D/V extensions (A is supported as nop-AMO since SMP off)
* privileged mode (M-mode, S-mode)
* memory management / page tables
* proper trap delivery
COMPRESSED (C) extension is now wired:
* nx_rv64_step inspects low 2 bits of the instruction halfword.
* If they're not 11, the instruction is 16-bit compressed; we
expand it to a 32-bit RV64I/M equivalent via nx_rv64c_decode
and dispatch on that, advancing pc by 2.
* Otherwise pc advances by 4 as before.
* This is enough to run binaries from stock gcc / clang +c.
Why now:
* Stage 2 of bootstrap_proof currently runs through Docker +
qemu-riscv64-static. When Docker is unavailable, we cannot
verify the off-C path. Native execution closes that gap.
* Pairs with nx_dis.nx (decode) and nx_elf_read.nx (load) to
produce a complete sovereign run-loop: load ELF, decode each
dependencies 3 imports · 6 importers
imports: syscalls.nxnx_dis.nxnx_rv64c.nx
imported by: nx_dbg.nxnx_nxc_native_wrap.nxnx_smoke_sim.nxnx_sovereign_runner.nxnx_toolchain.nxnxc_native_wrap.nx
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| 62 | struct NxRv64Cpu |
| 195 | struct NxRv64Mmap |
consts
| 57 | const NX_MAGIC_4096: i64 = 4096 |
| 58 | const NX_MAGIC_4095: i64 = 4095 |
| 72 | const NX_RV64_CPU_BYTES: i64 = 56 |
| 194 | const NX_RV64_MMAP_BASE: i64 = 0x800000 // start at 8 MB into sim |
| 245 | const NX_RV64_CSR_CYCLE: i64 = 0xC00 |
| 246 | const NX_RV64_CSR_TIME: i64 = 0xC01 |
| 247 | const NX_RV64_CSR_INSTRET: i64 = 0xC02 |
| 248 | const NX_RV64_CSR_FFLAGS: i64 = 0x001 |
| 249 | const NX_RV64_CSR_FRM: i64 = 0x002 |
| 250 | const NX_RV64_CSR_FCSR: i64 = 0x003 |
functions
| 76 | func nx_rv64_cpu_new(mem_base: *u8, mem_size: i64, entry_pc: i64) -> *NxRv64Cpu |
| 92 | func nx_rv64_cpu_set_sp(c: *NxRv64Cpu, sp: i64) -> i64 |
| 100 | func nx_rv64_rd(c: *NxRv64Cpu, idx: i64) -> i64 called by 1: nx_rv64_step |
| 106 | func nx_rv64_wr(c: *NxRv64Cpu, idx: i64, v: i64) -> i64 called by 1: nx_rv64_step |
| 114 | func nx_rv64_load_u8(c: *NxRv64Cpu, addr: i64) -> i64 |
| 120 | func nx_rv64_store_u8(c: *NxRv64Cpu, addr: i64, v: i64) -> i64 |
| 127 | func nx_rv64_load_u64(c: *NxRv64Cpu, addr: i64) -> i64 |
| 137 | func nx_rv64_store_u64(c: *NxRv64Cpu, addr: i64, v: i64) -> i64 |
| 146 | func nx_rv64_load_u32(c: *NxRv64Cpu, addr: i64) -> i64 |
| 154 | func nx_rv64_store_u32(c: *NxRv64Cpu, addr: i64, v: i64) -> i64 |
| 200 | func nx_rv64_mmap_init(c: *NxRv64Cpu) -> i64 |
| 208 | func nx_rv64_sim_to_host(c: *NxRv64Cpu, sim_addr: i64, host: *u8, n: i64) -> i64 |
| 218 | func nx_rv64_host_to_sim(c: *NxRv64Cpu, sim_addr: i64, host: *u8, n: i64) -> i64 |
| 229 | func nx_rv64_sim_strlen(c: *NxRv64Cpu, sim_addr: i64, max: i64) -> i64 |
| 254 | func nx_rv64_csr_read(c: *NxRv64Cpu, csr: i64) -> i64 called by 1: nx_rv64_step |
| 264 | func nx_rv64_csr_write(c: *NxRv64Cpu, csr: i64, v: i64) -> i64 called by 1: nx_rv64_step |
| 268 | func nx_rv64_handle_ecall(c: *NxRv64Cpu) -> i64 |
| 439 | func nx_rv64_step(c: *NxRv64Cpu) -> i64 called by 3: nx_dbg_stepnx_dbg_contnx_rv64_run calls 24: nx_rv64c_decodenx_dis_word_atnx_dis_opcodenx_dis_rdnx_dis_rs1nx_dis_rs2+18 |
| 800 | func nx_rv64_run(c: *NxRv64Cpu, max_insns: i64) -> i64 |
| 813 | func main() -> i64 |