code wiki / _hdl_build / nx_nofloat_mxfp8_gate.nx
nx_nofloat_mxfp8_gate.nx source
↩ module page · 71 lines · 3502 B
1// nx_nofloat_mxfp8_gate.nx -- gate: MXFP8 (OCP E4M3 + E5M2) dequant to Q16, EXACT known values.
2// T1 E4M3 normals decode to exact Q16 (1.0, 1.5, 2.0, 0.5, -1.0)
3// T2 E4M3 subnormal (2^-7) + NaN (E=1111,M=111) -> 0
4// T3 E5M2 normals decode to exact Q16 (1.0, 1.25, 0.5)
5// T4 E5M2 subnormal (2^-16) + inf (E=11111,M=0) -> 0
6// T5 E8M0 shared block scale: same element, scale 2^+1 doubles, 2^-1 halves
7// T6 block decode: 32-element E4M3 block all decode + bit-identical on a second pass (deterministic)
8// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
9import "nx_nofloat_mxfp8.nx"
10import "nx_gate_verdict.nx"
11import "nx_syscalls.nx"
12
13const G8_S0: i64 = 127 // E8M0 scale exponent for 2^0 = 1
14
15func main() -> i64 {
16 let ctr: *i64 = gv_ctr()
17 gv_head("nx_nofloat_mxfp8 gate -- OCP E4M3 + E5M2 dequant to Q16, exact known values" as *u8)
18
19 // T1: E4M3 normals (scale 2^0)
20 var t1: i64 = 1
21 if mx8_e4m3(56, G8_S0) != 65536 { t1 = 0 } // 0x38 = 1.0
22 if mx8_e4m3(60, G8_S0) != 98304 { t1 = 0 } // 0x3C = 1.5
23 if mx8_e4m3(64, G8_S0) != 131072 { t1 = 0 } // 0x40 = 2.0
24 if mx8_e4m3(48, G8_S0) != 32768 { t1 = 0 } // 0x30 = 0.5
25 if mx8_e4m3(184, G8_S0) != (0 - 65536) { t1 = 0 } // 0xB8 = -1.0
26 gv_check("T1 E4M3 normals -> exact Q16 (1.0, 1.5, 2.0, 0.5, -1.0)" as *u8, t1, ctr)
27
28 // T2: E4M3 subnormal + NaN
29 var t2: i64 = 1
30 if mx8_e4m3(4, G8_S0) != 512 { t2 = 0 } // 0x04 = 2^-7 = 512 Q16
31 if mx8_e4m3(127, G8_S0) != 0 { t2 = 0 } // 0x7F = NaN -> 0
32 gv_check("T2 E4M3 subnormal (2^-7=512) + NaN -> 0" as *u8, t2, ctr)
33
34 // T3: E5M2 normals
35 var t3: i64 = 1
36 if mx8_e5m2(60, G8_S0) != 65536 { t3 = 0 } // 0x3C = 1.0
37 if mx8_e5m2(61, G8_S0) != 81920 { t3 = 0 } // 0x3D = 1.25
38 if mx8_e5m2(56, G8_S0) != 32768 { t3 = 0 } // 0x38 = 0.5
39 gv_check("T3 E5M2 normals -> exact Q16 (1.0, 1.25, 0.5)" as *u8, t3, ctr)
40
41 // T4: E5M2 subnormal + inf
42 var t4: i64 = 1
43 if mx8_e5m2(1, G8_S0) != 1 { t4 = 0 } // 0x01 = 2^-16 = 1 Q16
44 if mx8_e5m2(124, G8_S0) != 0 { t4 = 0 } // 0x7C = inf -> 0
45 gv_check("T4 E5M2 subnormal (2^-16=1) + inf -> 0" as *u8, t4, ctr)
46
47 // T5: E8M0 block scale doubles/halves
48 var t5: i64 = 1
49 if mx8_e4m3(56, 128) != 131072 { t5 = 0 } // 1.0 * 2^1 = 2.0
50 if mx8_e4m3(56, 126) != 32768 { t5 = 0 } // 1.0 * 2^-1 = 0.5
51 if mx8_e5m2(60, 128) != 131072 { t5 = 0 } // 1.0 * 2^1 = 2.0
52 gv_check("T5 E8M0 shared block scale: 2^+1 doubles, 2^-1 halves" as *u8, t5, ctr)
53
54 // T6: block decode + determinism (32-elem E4M3 block all 0x38=1.0, scale byte 127)
55 let buf: *u8 = sys_mmap(64) as *u8
56 var i: i64 = 0
57 while i < 32 { buf[i] = 56 as u8; i = i + 1 } // 32 bytes of 0x38
58 buf[32] = 127 as u8 // E8M0 scale at soff=32
59 let out: *i64 = sys_mmap(64*8) as *i64
60 let out2: *i64 = sys_mmap(64*8) as *i64
61 mx8_block_e4m3(buf, 0, 32, out)
62 mx8_block_e4m3(buf, 0, 32, out2)
63 var t6: i64 = 1
64 i = 0
65 while i < 32 { if out[i] != 65536 { t6 = 0 } if out2[i] != out[i] { t6 = 0 } i = i + 1 }
66 gv_check("T6 block decode: 32 E4M3 elements all 1.0, bit-identical on re-decode" as *u8, t6, ctr)
67
68 let rc: i64 = gv_verdict("NOFLOAT-MXFP8-GATE" as *u8, ctr, "MXFP8 OCP E4M3+E5M2 dequant to Q16: exact normals/subnormals, NaN/inf guarded, E8M0 block scale, deterministic no-float" as *u8)
69 sys_exit(rc)
70 return rc
71}