code wiki / _hdl_build / nx_fpga_div_gate.nx
nx_fpga_div_gate.nx source
↩ module page · 85 lines · 5213 B
1import "nx_gate_gn.nx"
2import "nx_gate_base.nx"
3// nx_fpga_div_gate.nx -- GATE for RUNG 25: DIVU + REMU (the M-extension division) on the fabric via RESTORING DIVISION.
4// Classic sequential divider: process the dividend MSB->LSB; each step shift the next bit into the partial remainder r,
5// COMPARE r to the divisor b on the fabric (SLTU via nx_fpga_cmp), and if r>=b SUBTRACT b on the fabric ALU
6// (nx_fpga_alu) and set the quotient bit. The arithmetic (compare + subtract) runs on the proven fabric datapath.
7// Verified == the behavioral nx_rv64im_alu_compute(DIVU) (quotient) AND (REMU) (remainder). With MUL (R24) this
8// completes the rv64i**M** integer set in sim.
9// T1 DIVU quotient AND REMU remainder over representative (a,b) pairs == behavioral. T2 headline 100/7 = 14 rem 2.
10// T3 NEVER-BRICK. T4 LIAR-KILL (corrupt the fabric ALU -> the subtract diverges -> wrong quotient).
11// (Dividend kept <=255 -> 8 iterations -> light; b>=1, division-by-zero is the oracle's special case, not tested here.)
12// expect_exit: 0 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_div_gate: RUNG 25 -- DIVU/REMU (M-extension) via fabric RESTORING DIVISION (cmp + subtract) ===\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]=100; tb[0]=7
32 ta[1]=255; tb[1]=16
33 ta[2]=0; tb[2]=5
34 ta[3]=255; tb[3]=255
35 ta[4]=200; tb[4]=1
36 ta[5]=13; tb[5]=4
37 ta[6]=255; tb[6]=2
38 ta[7]=100; tb[7]=100
39 ta[8]=7; tb[8]=13
40 ta[9]=250; tb[9]=25
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 q: i64=0; var r: i64=0; var i: i64=7
47 while i >= 0 {
48 r = (r << 1) | ((a >> i) & 1) // bring down the next dividend bit
49 let lt: i64 = fab_cmp_run(64, cnpi, CI, CS, CP, pi, co, r, b, 1) // r < b ? (unsigned) on the fabric
50 if lt == 0 { // r >= b
51 r = fab_alu_run(64, anpi, AI, AS, AP, pi, co, r, b, 1, 1, 1) // r = r - b on the fabric ALU
52 q = q | (1 << i) // set quotient bit i
53 }
54 i = i - 1
55 }
56 let wantq: i64 = nx_rv64im_alu_compute(NX_RV64IM_ALU_DIVU, a, b)
57 let wantr: i64 = nx_rv64im_alu_compute(NX_RV64IM_ALU_REMU, a, b)
58 if q != wantq { mism = mism + 1 }
59 if r != wantr { mism = mism + 1 }
60 p = p + 1
61 }
62 total=total+1; if mism==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
63 gw("T1 DIVU quotient + REMU remainder via fabric restoring-division over " as *u8); gn(NP); gw(" pairs == behavioral, mismatches=" as *u8); gn(mism); gw("\n" as *u8)
64
65 // T2: headline 100 / 7
66 var q2: i64=0; var r2: i64=0; var j: i64=7
67 while j >= 0 { r2=(r2<<1)|((100>>j)&1); let lt: i64=fab_cmp_run(64,cnpi,CI,CS,CP,pi,co,r2,7,1); if lt==0 { r2=fab_alu_run(64,anpi,AI,AS,AP,pi,co,r2,7,1,1,1); q2=q2|(1<<j) } j=j-1 }
68 total=total+1; if q2==14 { if r2==2 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } } else { gw(" [FAIL] " as *u8) }
69 gw("T2 100 / 7 on the fabric = quotient " as *u8); gn(q2); gw(" remainder " as *u8); gn(r2); gw(" (=14 rem 2)\n" as *u8)
70
71 // T3: never-brick
72 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)
73 total=total+1; if c1==c2 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
74 gw("T3 never-brick (#26): deterministic, bounded restoring loop, pure-integer, zero hardware-state writes\n" as *u8)
75
76 // T4: liar-kill -- corrupt the fabric ALU; the divider's subtract diverges
77 var ci: i64=0; while ci < 640 { AI[ci] = AI[ci] ^ 0xffff; ci = ci + 1 }
78 let bad: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,11,7,1,1,1)
79 total=total+1; if bad != 4 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
80 gw("T4 liar-kill: corrupting the fabric ALU -> a divider subtract(11,7)=" as *u8); gn(bad); gw(" != 4\n" as *u8)
81
82 gw("\n=== nx_fpga_div_gate " as *u8); gn(pass); gw("/" as *u8); gn(total)
83 if pass == total { gw(" GREEN (DIVU/REMU run on the fabric via restoring division (compare + subtract) == behavioral -- with MUL, the rv64iM integer set is complete in sim)\n" as *u8); sys_exit(0); return 0 }
84 gw(" RED\n" as *u8); sys_exit(1); return 1
85}