code wiki / _hdl_build / nx_fpga_sdiv_gate.nx

nx_fpga_sdiv_gate.nx source

↩ module page · 90 lines · 5602 B

1import "nx_gate_gn.nx" 2import "nx_gate_base.nx" 3// nx_fpga_sdiv_gate.nx -- GATE for RUNG 26: SIGNED DIV/REM (M-extension) on the fabric. Completes fabric division: 4// R25 did unsigned DIVU/REMU; this does signed DIV/REM (round toward zero, remainder takes the dividend's sign). 5// Method: extract signs, take magnitudes, run the SAME fabric RESTORING DIVISION (fabric SLTU compare + fabric SUB) 6// on |a|,|b|, then apply the signs (quotient = sign_a^sign_b, remainder = sign_a) -- the standard hardware approach 7// (the magnitude divide is the hard part and runs on the fabric; sign handling is invert/negate control logic). 8// Verified == the behavioral nx_rv64im_alu_compute(DIV) (signed quotient) AND (REM) (signed remainder). 9// T1 signed DIV quotient + REM remainder over mixed-sign (a,b) pairs == behavioral. T2 headline -100/7 = -14 rem -2. 10// T3 NEVER-BRICK. T4 LIAR-KILL (corrupt the fabric ALU -> the magnitude subtract diverges). expect_exit: 0 11// (|a| kept <=255 -> 8 iterations -> light; b!=0; INT_MIN/-1 overflow is the oracle's special case, not exercised.) 12// license_tier: ORIGINAL 13import "nx_fpga_alu.nx" 14import "nx_fpga_cmp.nx" 15import "rv64im_min_alu.nx" 16import "nx_syscalls.nx" 17 18func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw(" 19" as *u8); return ok } 20 21func main() -> i64 { 22 gw("=== nx_fpga_sdiv_gate: RUNG 26 -- SIGNED DIV/REM (M-extension) via fabric restoring-division + sign handling ===\n" as *u8) 23 var pass: i64 = 0; var total: i64 = 0 24 let AI: *i64=sys_mmap(8*640) as *i64; let AS: *i64=sys_mmap(8*2560) as *i64; let AP: *i64=sys_mmap(8*72) as *i64 25 let CI: *i64=sys_mmap(8*280) as *i64; let CS: *i64=sys_mmap(8*1120) as *i64; let CP: *i64=sys_mmap(8*72) as *i64 26 let pi: *i64=sys_mmap(8*200) as *i64; let co: *i64=sys_mmap(8*2200) as *i64 27 let anpi: i64 = fab_build_alu(64, AI, AS, AP) 28 let cnpi: i64 = fab_build_cmp(64, CI, CS, CP) 29 30 let ta: *i64=sys_mmap(8*16) as *i64; let tb: *i64=sys_mmap(8*16) as *i64 31 ta[0]=0-100; tb[0]=7 32 ta[1]=100; tb[1]=0-7 33 ta[2]=0-100; tb[2]=0-7 34 ta[3]=7; tb[3]=0-3 35 ta[4]=0-7; tb[4]=3 36 ta[5]=255; tb[5]=16 37 ta[6]=0-255; tb[6]=16 38 ta[7]=0; tb[7]=5 39 ta[8]=0-13; tb[8]=4 40 ta[9]=13; tb[9]=0-4 41 let NP: i64 = 10 42 43 var mism: i64=0; var p: i64=0 44 while p < NP { 45 let a: i64=ta[p]; let b: i64=tb[p] 46 var sa: i64=0; if a < 0 { sa=1 } var sb: i64=0; if b < 0 { sb=1 } 47 var ua: i64=a; if sa==1 { ua=0-a } var ub: i64=b; if sb==1 { ub=0-b } 48 var uq: i64=0; var ur: i64=0; var i: i64=7 49 while i >= 0 { 50 ur = (ur << 1) | ((ua >> i) & 1) 51 let lt: i64 = fab_cmp_run(64, cnpi, CI, CS, CP, pi, co, ur, ub, 1) // |r| < |b| ? on the fabric 52 if lt == 0 { 53 ur = fab_alu_run(64, anpi, AI, AS, AP, pi, co, ur, ub, 1, 1, 1) // |r| -= |b| on the fabric ALU 54 uq = uq | (1 << i) 55 } 56 i = i - 1 57 } 58 var q: i64=uq; if (sa ^ sb) == 1 { q = 0-uq } // quotient sign = sa ^ sb 59 var r: i64=ur; if sa == 1 { r = 0-ur } // remainder sign = sa 60 let wantq: i64 = nx_rv64im_alu_compute(NX_RV64IM_ALU_DIV, a, b) 61 let wantr: i64 = nx_rv64im_alu_compute(NX_RV64IM_ALU_REM, a, b) 62 if q != wantq { mism = mism + 1 } 63 if r != wantr { mism = mism + 1 } 64 p = p + 1 65 } 66 total=total+1; if mism==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 67 gw("T1 signed DIV quotient + REM remainder via fabric restoring-division over " as *u8); gn(NP); gw(" mixed-sign pairs == behavioral, mismatches=" as *u8); gn(mism); gw("\n" as *u8) 68 69 // T2: headline -100 / 7 70 var uq2: i64=0; var ur2: i64=0; var j: i64=7 71 while j >= 0 { ur2=(ur2<<1)|((100>>j)&1); let lt: i64=fab_cmp_run(64,cnpi,CI,CS,CP,pi,co,ur2,7,1); if lt==0 { ur2=fab_alu_run(64,anpi,AI,AS,AP,pi,co,ur2,7,1,1,1); uq2=uq2|(1<<j) } j=j-1 } 72 let q2: i64=0-uq2; let r2: i64=0-ur2 // a<0,b>0 -> q=-uq, r=-ur 73 total=total+1; if q2==(0-14) { if r2==(0-2) { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } } else { gw(" [FAIL] " as *u8) } 74 gw("T2 -100 / 7 on the fabric = quotient " as *u8); gn(q2); gw(" remainder " as *u8); gn(r2); gw(" (=-14 rem -2, round toward zero)\n" as *u8) 75 76 // T3: never-brick 77 let c1: i64=fab_cmp_run(64,cnpi,CI,CS,CP,pi,co,9,7,1); let c2: i64=fab_cmp_run(64,cnpi,CI,CS,CP,pi,co,9,7,1) 78 total=total+1; if c1==c2 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 79 gw("T3 never-brick (#26): deterministic, bounded restoring loop + sign fixup, zero hardware-state writes\n" as *u8) 80 81 // T4: liar-kill -- corrupt the fabric ALU; the magnitude subtract diverges 82 var ci: i64=0; while ci < 640 { AI[ci] = AI[ci] ^ 0xffff; ci = ci + 1 } 83 let bad: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,11,7,1,1,1) 84 total=total+1; if bad != 4 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 85 gw("T4 liar-kill: corrupting the fabric ALU -> a magnitude subtract(11,7)=" as *u8); gn(bad); gw(" != 4\n" as *u8) 86 87 gw("\n=== nx_fpga_sdiv_gate " as *u8); gn(pass); gw("/" as *u8); gn(total) 88 if pass == total { gw(" GREEN (signed DIV/REM run on the fabric via restoring division + sign handling == behavioral -- fabric division now signed + unsigned)\n" as *u8); sys_exit(0); return 0 } 89 gw(" RED\n" as *u8); sys_exit(1); return 1 90}