code wiki / _hdl_build / nx_rv64_m_gate.nx
nx_rv64_m_gate.nx source
↩ module page · 90 lines · 7131 B
1// nx_rv64_m_gate.nx -- GATE: the RV64 M EXTENSION (multiply/divide) -- so the emulator runs REAL programs (they
2// multiply/divide constantly). MUL/DIV/DIVU/REM/REMU decoded + interpreted with EXACT RV64 semantics (div-by-zero ->
3// -1 / dividend; INT_MIN/-1 overflow -> INT_MIN / 0; unsigned via long division). MUL is JIT-accelerated (imul);
4// DIV/REM fail-safe-tier to the interpreter. This is RV64I -> RV64IM (the real base ISA).
5// T1 signed div/rem semantics incl div-by-zero and INT_MIN/-1 overflow (the edge cases real ISAs define carefully).
6// T2 UNSIGNED div/rem (differs from signed on high-bit operands) + DIVU-by-zero.
7// T3 MUL/DIV/REM run end-to-end through the interpreter (a real program).
8// T4 JIT MUL == interpreter (imul-accelerated multiply is correct).
9// T5 a DIV program fail-safe-TIERS: the JIT declines (-1) but the interpreter computes it correctly.
10// expect_exit: 0
11import "nx_syscalls.nx"
12import "nx_rv64_fast.nx"
13import "nx_rv64_jit.nx"
14
15func 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 }
16func g_pn(v: i64) -> i64 { let b: *u8=sys_mmap(28); var x: i64=v; if x<0{b[0]=45;sys_write(1,b,1);x=0-x} 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 }
17func 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 }
18const MEMSZ: i64 = 4096
19
20// run a 3-op program [li x1,a; li x2,b; <kind> x3,x1,x2] on the interpreter; return reg[3].
21func run_m(kind: i64, a: i64, b: i64, opk: *i64, rd: *i64, rs1: *i64, rs2: *i64, imm: *i64, reg: *i64, mem: *u8) -> i64 {
22 opk[0]=FK_ADDI; rd[0]=1; rs1[0]=0; rs2[0]=0; imm[0]=a
23 opk[1]=FK_ADDI; rd[1]=2; rs1[1]=0; rs2[1]=0; imm[1]=b
24 opk[2]=kind; rd[2]=3; rs1[2]=1; rs2[2]=2; imm[2]=0
25 var z: i64=0; while z<32 { reg[z]=0; z=z+1 }
26 fk_run(opk, rd, rs1, rs2, imm, 3, reg, mem, MEMSZ, 100000, (0 as i64) as *NxVirtioMmio)
27 return reg[3]
28}
29
30func main() -> i64 {
31 g_puts("nx_rv64_m_gate (RV64 M extension: multiply/divide, exact semantics + JIT MUL + fail-safe DIV tiering)\n" as *u8)
32 var pass: i64=0; var total: i64=0
33 let opk: *i64=sys_mmap(64*8) as *i64; let rd: *i64=sys_mmap(64*8) as *i64; let rs1: *i64=sys_mmap(64*8) as *i64; let rs2: *i64=sys_mmap(64*8) as *i64; let imm: *i64=sys_mmap(64*8) as *i64
34 let reg: *i64=sys_mmap(32*8) as *i64; let mem: *u8=sys_mmap(MEMSZ)
35 let IMIN: i64 = 1<<63
36
37 // T1: signed div/rem, including the two RV64-defined edge cases.
38 var t1: i64=0
39 if sdiv64(20,3)==6 { if srem64(20,3)==2 { if sdiv64(0-20,3)==(0-6) { if srem64(0-20,3)==(0-2) {
40 if sdiv64(20,0)==(0-1) { if srem64(20,0)==20 { // div-by-zero: -1 / dividend
41 if sdiv64(IMIN,0-1)==IMIN { if srem64(IMIN,0-1)==0 { t1=1 } } } } } } } } // INT_MIN/-1 overflow: INT_MIN / 0
42 g_puts(" T1 signed: 20/3="); g_pn(sdiv64(20,3)); g_puts(" 20%3="); g_pn(srem64(20,3)); g_puts(" 20/0="); g_pn(sdiv64(20,0)); g_puts(" IMIN/-1="); g_pn(sdiv64(IMIN,0-1)); g_puts(" (=IMIN, no trap)\n" as *u8)
43 pass=pass+ck("T1: signed DIV/REM -- normal + div-by-zero(-1/dividend) + INT_MIN/-1 overflow(IMIN/0), the RV64 edge cases" as *u8, t1); total=total+1
44
45 // T2: unsigned div/rem differs from signed on high-bit operands. -1 (unsigned 2^64-1) / 2 = 2^63-1.
46 var t2: i64=0
47 if udiv_mod(0-1,2,0)==(IMIN-1) { if udiv_mod(100,7,0)==14 { if udiv_mod(100,7,1)==2 {
48 if udiv_mod(0-1,2,1)==1 { if sdiv64(0-1,2)==0 { t2=1 } } } } } // signed -1/2=0 != unsigned
49 g_puts(" T2 unsigned: (2^64-1)/2="); g_pn(udiv_mod(0-1,2,0)); g_puts(" (=2^63-1; signed -1/2="); g_pn(sdiv64(0-1,2)); g_puts(") 100/7="); g_pn(udiv_mod(100,7,0)); g_puts(" 100%7="); g_pn(udiv_mod(100,7,1)); g_puts("\n" as *u8)
50 pass=pass+ck("T2: UNSIGNED DIVU/REMU (long division) -- differs from signed on high-bit operands, correct" as *u8, t2); total=total+1
51
52 // T3: MUL/DIV/REM/DIVU end-to-end through the interpreter.
53 let mul: i64=run_m(FK_MUL,20,3,opk,rd,rs1,rs2,imm,reg,mem)
54 let dv: i64=run_m(FK_DIV,20,3,opk,rd,rs1,rs2,imm,reg,mem)
55 let rm: i64=run_m(FK_REM,20,3,opk,rd,rs1,rs2,imm,reg,mem)
56 let dvu0: i64=run_m(FK_DIVU,20,0,opk,rd,rs1,rs2,imm,reg,mem)
57 g_puts(" T3 interp: 20*3="); g_pn(mul); g_puts(" 20/3="); g_pn(dv); g_puts(" 20%3="); g_pn(rm); g_puts(" 20/0(u)="); g_pn(dvu0); g_puts(" (expect 60,6,2,-1)\n" as *u8)
58 var t3: i64=0; if mul==60 { if dv==6 { if rm==2 { if dvu0==(0-1) { t3=1 } } } }
59 pass=pass+ck("T3: MUL/DIV/REM/DIVU run END-TO-END through the interpreter (a real multiply/divide program)" as *u8, t3); total=total+1
60
61 // T4: JIT MUL == interpreter. compile the MUL program + run natively.
62 opk[0]=FK_ADDI; rd[0]=1; rs1[0]=0; rs2[0]=0; imm[0]=20
63 opk[1]=FK_ADDI; rd[1]=2; rs1[1]=0; rs2[1]=0; imm[1]=3
64 opk[2]=FK_MUL; rd[2]=3; rs1[2]=1; rs2[2]=2; imm[2]=0
65 let x86: *u8=sys_mmap(4096); let x86off: *i64=sys_mmap(64*8) as *i64
66 jit_set_membase(0, MEMSZ)
67 let xlen: i64=jit_compile(opk, rd, rs1, rs2, imm, 3, x86, x86off)
68 var rj: *i64=sys_mmap(32*8) as *i64; var z: i64=0; while z<32 { rj[z]=0; z=z+1 }
69 if xlen>0 { jit_run(x86, xlen, rj) }
70 g_puts(" T4 JIT MUL 20*3="); g_pn(rj[3]); g_puts(" (xlen="); g_pn(xlen); g_puts(", interp=60)\n" as *u8)
71 var t4: i64=0; if xlen>0 { if rj[3]==60 { t4=1 } }
72 pass=pass+ck("T4: JIT MUL (imul) == interpreter == 60 -- multiply is JIT-accelerated + correct" as *u8, t4); total=total+1
73
74 // T5: a DIV program fail-safe TIERS -- the JIT declines (DIV not in its set -> -1), interpreter computes it.
75 opk[2]=FK_DIV
76 let xlen2: i64=jit_compile(opk, rd, rs1, rs2, imm, 3, x86, x86off)
77 let interp_div: i64=run_m(FK_DIV,20,3,opk,rd,rs1,rs2,imm,reg,mem)
78 g_puts(" T5 DIV program: jit_compile rc="); g_pn(xlen2); g_puts(" (-1=JIT declines, tiers to interp) interp result="); g_pn(interp_div); g_puts("\n" as *u8)
79 var t5: i64=0; if xlen2==(0-1) { if interp_div==6 { t5=1 } }
80 pass=pass+ck("T5: a DIV program fail-safe TIERS -- JIT declines (-1), interpreter computes it correctly (never wrong)" as *u8, t5); total=total+1
81
82 var okall: i64=0; if pass==total { okall=1 }
83 g_puts("---- nx_rv64_m_gate: passed "); g_pn(pass); g_puts(" / "); g_pn(total); g_puts(" ----\n" as *u8)
84 if okall==1 {
85 let logf: i64=sys_openat_append("knowledge/status/rv64_m.log" as *u8, 420)
86 if logf>=0 { let z2: i64=sys_write(logf,"NXRV64M GREEN: RV64 M extension -- MUL/DIV/DIVU/REM/REMU with exact semantics (div-by-zero, INT_MIN/-1 overflow, unsigned long division); MUL JIT-accelerated (imul), DIV/REM fail-safe tier. RV64I -> RV64IM\n" as *u8,213); sys_close(logf) }
87 g_puts("verdict=GREEN (RV64 M extension: multiply/divide with exact RV64 semantics, MUL JIT-accelerated, DIV/REM fail-safe-tiered; the emulator is now RV64IM -- runs real multiply/divide code)\n" as *u8); sys_exit(0); return 0
88 }
89 g_puts("verdict=RED\n" as *u8); sys_exit(1); return 1
90}