code wiki / _hdl_build / nx_nishi_riscv_emit.nx

nx_nishi_riscv_emit.nx source

↩ module page · 82 lines · 6192 B

1// nx_nishi_riscv_emit.nx -- THE PRODUCT LOOP: NishiLang -> RISC-V, run on the QEMU-validated emulator. Invokes the 2// SOVEREIGN NishiLang RISC-V codegen (nx_riscv_lib `lower`) on a real IR program (triangular sum 1..N), keeps its 3// computation (result in a0), and swaps the codegen's Linux ecall-exit for a bare-metal UART-emit + SiFive-finisher 4// epilogue (assembled by the sovereign nx_rv64_asm). Writes the flat binary to knowledge/hw/nishi_rv.bin, to be run on 5// the QEMU-validated golden sim (nx_rv64_run_bin) AND real qemu-system-riscv64 (the liar-killer). N=5 -> sum 15 = 0x0f. 6// This closes the loop: NishiLang -> sovereign RISC-V codegen -> QEMU-validated emulator, C/QEMU as the liar-killer. 7// expect_exit: 0 Sovereign: nx_riscv_lib (codegen) + nx_rv64_asm (assembler) + nx_syscalls. 8import "nx_riscv_lib.nx" 9import "nx_rv64_asm.nx" 10import "nx_syscalls.nx" 11const K_MAGIC_4096: i64 = 4096 12 13func g_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 14func g_pn(v: i64) -> i64 { let b: *u8=sys_mmap(28); var x: i64=v; if x==0{b[0]=48;sys_write(1,b,1);return 0} var d: i64=0; var y: i64=x; while y>0{d=d+1;y=y/10} var i: i64=d-1; y=x; while i>=0{b[i]=(48+(y%10)) as u8;y=y/10;i=i-1} sys_write(1,b,d); return 0 } 15func ck(name: *u8, c: i64) -> i64 { if c==1 { g_puts(" PASS " as *u8) } else { g_puts(" FAIL " as *u8) } g_puts(name); g_puts("\n" as *u8); return c } 16 17// the IR program: acc=0; i=1; L0: acc += i; i += 1; if i <= N goto L0; return acc (op 0=CONST 2=ADD 8=ADDI 6=LABEL 7=BLE 5=RET) 18func build_loop_ir(irop: *i64, irdst: *i64, irs1: *i64, irs2: *i64, irimm: *i64, N: i64) -> i64 { 19 irop[0]=0; irdst[0]=0; irimm[0]=0 20 irop[1]=0; irdst[1]=1; irimm[1]=1 21 irop[2]=0; irdst[2]=2; irimm[2]=N 22 irop[3]=6; irimm[3]=0 23 irop[4]=2; irdst[4]=0; irs1[4]=0; irs2[4]=1 24 irop[5]=8; irdst[5]=1; irs1[5]=1; irimm[5]=1 25 irop[6]=7; irs1[6]=1; irs2[6]=2; irimm[6]=0 26 irop[7]=5; irs1[7]=0 27 return 8 28} 29 30func main() -> i64 { 31 g_puts("nx_nishi_riscv_emit (NishiLang IR -> SOVEREIGN RISC-V codegen -> bare-metal binary for the QEMU-validated emulator)\n" as *u8) 32 var pass: i64=0; var total: i64=0 33 let irop: *i64=sys_mmap(16*8) as *i64; let irdst: *i64=sys_mmap(16*8) as *i64; let irs1: *i64=sys_mmap(16*8) as *i64 34 let irs2: *i64=sys_mmap(16*8) as *i64; let irimm: *i64=sys_mmap(16*8) as *i64; let labelpos: *i64=sys_mmap(16*8) as *i64 35 let preg: *i64=sys_mmap(8*8) as *i64; preg[0]=5; preg[1]=6; preg[2]=7 // t0,t1,t2 36 37 let n: i64=build_loop_ir(irop, irdst, irs1, irs2, irimm, 5) 38 let m: *u8=sys_mmap(0x20000) 39 // INVOKE the sovereign NishiLang RISC-V codegen: lower IR -> machine-code words at m[0]. 40 let nw: i64=lower(m, 0, irop, irdst, irs1, irs2, irimm, n, preg, labelpos) 41 g_puts(" sovereign codegen lowered the IR -> "); g_pn(nw); g_puts(" RISC-V words\n" as *u8) 42 // the codegen's exit convention is `li a7,93; ecall` (last 2 words); the computation ends with `mv a0,acc` (result 43 // in a0). keep words [0, nw-2); assert the last word is ecall (0x73). 44 let lastop: i64=(m[(nw-1)*4] as i64)&0x7f 45 var t1: i64=0; if lastop==0x73 { if nw>=3 { t1=1 } } 46 pass=pass+ck("T1: the sovereign NishiLang codegen emitted a real RISC-V loop ending in ecall (result in a0)" as *u8, t1); total=total+1 47 let compbytes: i64=(nw-2)*4 // drop `li a7,93; ecall`; keep the computation (result in a0) 48 49 // bare-metal epilogue (assembled by the SOVEREIGN nx_rv64_asm): emit a0's low byte to UART + sentinel + finisher halt. 50 let epi: *u8=sys_mmap(K_MAGIC_4096) 51 let en: i64=rvasm_assemble_str(" lui ra, 0x10000\n sb a0, 0(ra)\n li t3, 0x2a\n sb t3, 0(ra)\n lui t4, 0x100\n lui t5, 0x5\n addi t5, t5, 0x555\n sw t5, 0(t4)\nspin:\n j spin\n" as *u8, epi, K_MAGIC_4096) 52 var t2: i64=0; if en>0 { t2=1 } 53 pass=pass+ck("T2: the bare-metal epilogue assembled by the sovereign nx_rv64_asm (UART-emit a0 + finisher halt)" as *u8, t2); total=total+1 54 55 // concatenate: [codegen computation][epilogue] -> flat binary at 0x80000000. 56 let out: *u8=sys_mmap(0x20000); var i: i64=0 57 while i<compbytes { out[i]=m[i]; i=i+1 } 58 var j: i64=0; while j<en { out[compbytes+j]=epi[j]; j=j+1 } 59 let total_bytes: i64=compbytes+en 60 let fd: i64=sys_openat_wr("knowledge/hw/nishi_rv.bin" as *u8, 420) 61 var t3: i64=0; if fd>=0 { let wn: i64=sys_write(fd, out, total_bytes); sys_close(fd); if wn==total_bytes { t3=1 } } 62 g_puts(" wrote knowledge/hw/nishi_rv.bin (N=5): "); g_pn(compbytes); g_puts(" codegen bytes + "); g_pn(en); g_puts(" epilogue bytes = "); g_pn(total_bytes); g_puts(" total\n" as *u8) 63 pass=pass+ck("T3: flat binary (NishiLang-codegen loop + epilogue) written for the QEMU-validated emulator + QEMU liar-killer" as *u8, t3); total=total+1 64 65 // rigor: a SECOND value (N=10 -> sum 55 = 0x37) from the SAME sovereign codegen -> nishi_rv10.bin. kills "hardcoded 15". 66 let n2: i64=build_loop_ir(irop, irdst, irs1, irs2, irimm, 10) 67 let m2: *u8=sys_mmap(0x20000) 68 let nw2: i64=lower(m2, 0, irop, irdst, irs1, irs2, irimm, n2, preg, labelpos) 69 let cb2: i64=(nw2-2)*4 70 let out2: *u8=sys_mmap(0x20000); var i2: i64=0 71 while i2<cb2 { out2[i2]=m2[i2]; i2=i2+1 } 72 var j2: i64=0; while j2<en { out2[cb2+j2]=epi[j2]; j2=j2+1 } 73 let fd2: i64=sys_openat_wr("knowledge/hw/nishi_rv10.bin" as *u8, 420) 74 var t4: i64=0; if fd2>=0 { let wn2: i64=sys_write(fd2, out2, cb2+en); sys_close(fd2); if wn2==(cb2+en) { t4=1 } } 75 g_puts(" wrote knowledge/hw/nishi_rv10.bin (N=10, expect UART 37 2a = sum 1..10 = 55)\n" as *u8) 76 pass=pass+ck("T4 (rigor): a SECOND value (N=10) from the same sovereign codegen written -- kills the hardcoded-constant doubt" as *u8, t4); total=total+1 77 78 var okall: i64=0; if pass==total { okall=1 } 79 g_puts("---- nx_nishi_riscv_emit: passed "); g_pn(pass); g_puts(" / "); g_pn(total); g_puts(" ----\n" as *u8) 80 if okall==1 { g_puts("verdict=GREEN (NishiLang -> sovereign RISC-V codegen -> bare-metal binary emitted; run nishi_rv.bin on the golden sim + QEMU, expect UART 0f 2a = sum 1..5 = 15)\n" as *u8); sys_exit(0); return 0 } 81 g_puts("verdict=RED\n" as *u8); sys_exit(1); return 1 82}