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}