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}