code wiki / _hdl_build / nx_nofloat_mxfp8.nx
nx_nofloat_mxfp8.nx source
↩ module page · 75 lines · 3316 B
1// nx_nofloat_mxfp8.nx -- SOVEREIGN no-float MXFP8 dequant (K3 F406; operator 2026-07-19 "state of the art").
2// Completes the OCP Microscaling (MX v1.0) story begun in nx_nofloat_mxfp4: Kimi K3 uses MXFP4 WEIGHTS +
3// MXFP8 ACTIVATIONS. An MX block = 32 elements, each an 8-bit float sharing ONE E8M0 scale byte (value =
4// 2^(e-127), 0xFF=NaN). Two OCP FP8 element formats:
5// E4M3: sign(1) exp(4,bias 7) mant(3) -- NO inf; max 448; NaN = E=1111,M=111; subnormal when E=0
6// E5M2: sign(1) exp(5,bias 15) mant(2) -- inf at E=11111,M=00; NaN at E=11111,M!=0; subnormal when E=0
7// Dequant is PURE INTEGER Q16: implicit-1 mantissa (1 + M/2^m) as Q16 + a combined power-of-2 shift of
8// (E - bias) + (scale_e - 127), sign applied. No float touches weights OR activations -> deterministic, the
9// novel no-float treatment. Grounded: OCP MX v1.0; arXiv 2310.10537. license_tier: ORIGINAL No hw (Rule 26).
10import "nx_syscalls.nx"
11
12const MX8_Q: i64 = 65536
13const MX8_NAN_SCALE: i64 = 255 // E8M0 0xFF = NaN block scale
14const MX8_SBIAS: i64 = 127 // E8M0 bias
15const MX8_BLK: i64 = 32
16
17// apply a signed power-of-2 shift to a Q16 magnitude (sh>=0 left, else right)
18func mx8_shift(v: i64, sh: i64) -> i64 {
19 if sh >= 0 { return v << sh }
20 return v >> (0 - sh)
21}
22// decode one E4M3 byte with block scale exponent scale_e -> Q16 value. NaN/NaN-scale -> 0.
23func mx8_e4m3(byte: i64, scale_e: i64) -> i64 {
24 if scale_e == MX8_NAN_SCALE { return 0 }
25 let sign: i64 = (byte >> 7) & 1
26 let e: i64 = (byte >> 3) & 15
27 let m: i64 = byte & 7
28 if e == 15 { if m == 7 { return 0 } } // NaN
29 var mant: i64 = 0
30 var esh: i64 = 0
31 if e == 0 {
32 mant = (m << 16) / 8 // subnormal: M/8 (no implicit 1), Q16
33 esh = 1 - 7
34 } else {
35 mant = MX8_Q + ((m << 16) / 8) // normal: (1 + M/8) Q16
36 esh = e - 7
37 }
38 var v: i64 = mx8_shift(mant, esh + (scale_e - MX8_SBIAS))
39 if sign == 1 { v = 0 - v }
40 return v
41}
42// decode one E5M2 byte with block scale exponent scale_e -> Q16 value. inf/NaN/NaN-scale -> 0.
43func mx8_e5m2(byte: i64, scale_e: i64) -> i64 {
44 if scale_e == MX8_NAN_SCALE { return 0 }
45 let sign: i64 = (byte >> 7) & 1
46 let e: i64 = (byte >> 2) & 31
47 let m: i64 = byte & 3
48 if e == 31 { return 0 } // inf (m==0) or NaN (m!=0)
49 var mant: i64 = 0
50 var esh: i64 = 0
51 if e == 0 {
52 mant = (m << 16) / 4 // subnormal: M/4 Q16
53 esh = 1 - 15
54 } else {
55 mant = MX8_Q + ((m << 16) / 4) // normal: (1 + M/4) Q16
56 esh = e - 15
57 }
58 var v: i64 = mx8_shift(mant, esh + (scale_e - MX8_SBIAS))
59 if sign == 1 { v = 0 - v }
60 return v
61}
62// dequant one E4M3 MX block: 32 element bytes at boff + 1 E8M0 scale byte at soff -> 32 Q16 ints.
63func mx8_block_e4m3(buf: *u8, boff: i64, soff: i64, out: *i64) -> i64 {
64 let e: i64 = buf[soff] as i64
65 var i: i64 = 0
66 while i < MX8_BLK { out[i] = mx8_e4m3(buf[boff + i] as i64, e); i = i + 1 }
67 return 0
68}
69// dequant one E5M2 MX block.
70func mx8_block_e5m2(buf: *u8, boff: i64, soff: i64, out: *i64) -> i64 {
71 let e: i64 = buf[soff] as i64
72 var i: i64 = 0
73 while i < MX8_BLK { out[i] = mx8_e5m2(buf[boff + i] as i64, e); i = i + 1 }
74 return 0
75}