code wiki / _hdl_build / nx_nofloat_mxfp4_gate.nx
nx_nofloat_mxfp4_gate.nx source
↩ module page · 59 lines · 2888 B
1// nx_nofloat_mxfp4_gate.nx -- gate for the no-float MXFP4 dequant (authored ON nx_gate_verdict).
2// Proves OCP MX v1.0 conformance in pure integer: E2M1 magnitude table, sign, E8M0 power-of-2 scale,
3// full 32-elem block, determinism.
4// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
5import "nx_nofloat_mxfp4.nx"
6import "nx_gate_verdict.nx"
7import "nx_syscalls.nx"
8
9func main() -> i64 {
10 let ctr: *i64 = gv_ctr()
11 gv_head("nx_nofloat_mxfp4 gate -- OCP MXFP4 (E2M1 + E8M0 shared scale) dequant, pure integer" as *u8)
12
13 // scale e=127 -> 2^0 = 1.0
14 // T1 magnitude table: 0010(idx2)=1.0=65536 ; 0111(idx7)=6.0=393216 ; 0001(idx1)=0.5=32768 ; 0000=0
15 var t1: i64 = 0
16 if mx_e2m1(2, 127) == 65536 { if mx_e2m1(7, 127) == 393216 { if mx_e2m1(1, 127) == 32768 { if mx_e2m1(0, 127) == 0 { t1 = 1 } } } }
17 gv_check("T1 E2M1 magnitude table {0,.5,1,1.5,2,3,4,6} exact in Q16" as *u8, t1, ctr)
18
19 // T2 sign bit: 1010 (sign=1, idx2=1.0) -> -65536
20 var t2: i64 = 0
21 if mx_e2m1(10, 127) == (0 - 65536) { if mx_e2m1(15, 127) == (0 - 393216) { t2 = 1 } }
22 gv_check("T2 sign bit negates (1010 -> -1.0, 1111 -> -6.0)" as *u8, t2, ctr)
23
24 // T3 E8M0 scale: e=128 (2^1) doubles 1.0->2.0=131072 ; e=126 (2^-1) halves 1.0->0.5=32768 ; e=129 -> 4.0
25 var t3: i64 = 0
26 if mx_e2m1(2, 128) == 131072 { if mx_e2m1(2, 126) == 32768 { if mx_e2m1(2, 129) == 262144 { t3 = 1 } } }
27 gv_check("T3 E8M0 shared scale = power-of-2 shift (e-127): doubles/halves correctly" as *u8, t3, ctr)
28
29 // T3b NaN scale (0xFF) -> 0 (uninitialised block)
30 var t3b: i64 = 0
31 if mx_e2m1(2, 255) == 0 { t3b = 1 }
32 gv_check("T3b E8M0 NaN scale (0xFF) -> 0 (fail-safe uninitialised)" as *u8, t3b, ctr)
33
34 // T4 full 32-elem block: 16 bytes each 0x21 (low nib 1=0.5, high nib 2=1.0), scale e=127
35 let buf: *u8 = sys_mmap(64)
36 var i: i64 = 0
37 while i < 16 { buf[i] = 0x21 as u8; i = i + 1 }
38 buf[16] = 127 as u8
39 let out: *i64 = sys_mmap(MX_BLK * 8) as *i64
40 mx_block(buf, 0, 16, out)
41 var t4: i64 = 0
42 // even idx = low nib (1 -> 0.5 = 32768), odd idx = high nib (2 -> 1.0 = 65536)
43 if out[0] == 32768 { if out[1] == 65536 { if out[30] == 32768 { if out[31] == 65536 { t4 = 1 } } } }
44 gv_check("T4 full 32-element block dequant (16 packed bytes + E8M0 scale)" as *u8, t4, ctr)
45
46 // T5 deterministic re-run
47 let out2: *i64 = sys_mmap(MX_BLK * 8) as *i64
48 mx_block(buf, 0, 16, out2)
49 var t5: i64 = 0
50 var d: i64 = 0
51 var k: i64 = 0
52 while k < MX_BLK { if out[k] != out2[k] { d = 1 } k = k + 1 }
53 if d == 0 { t5 = 1 }
54 gv_check("T5 deterministic (two block dequants bit-identical)" as *u8, t5, ctr)
55
56 let rc: i64 = gv_verdict("NOFLOAT-MXFP4-GATE" as *u8, ctr, "OCP MXFP4 E2M1+E8M0 pure-integer dequant: magnitude table, sign, power-of-2 scale, block, deterministic" as *u8)
57 sys_exit(rc)
58 return rc
59}