nx_q6_k_to_f32_test.nx source
↩ module page · 54 lines · 1861 B
1// nx_q6_k_to_f32_test.nx -- KAT for ggml-correct Q6_K dequant.
2//
3// Block layout: ql:128 + qh:64 + scales:16 + d:2 = 210 bytes.
4// Per ggml dequantize_row_q6_K, super-block produces 256 values via
5// two 128-value chunks. Within each chunk, l=0..31 emits to
6// positions [l, l+32, l+64, l+96] using ql[l], ql[l+32], qh[l].
7//
8// Synthetic block:
9// d = 1.0 (f16=0x3C00)
10// All scales = 1 (i8)
11// ql[0] = 0x32 (low=2, high=3)
12// qh[0] = 0x01 (bits01=1, bits23=0, bits45=0, bits67=0)
13// Everything else zero.
14//
15// Expected for chunk c=0, l=0:
16// y[0] = (ql[0].low | bits01<<4) - 32 = (2|16)-32 = -14 -> 0xC1600000
17// y[32] = (ql[32].low | bits23<<4) - 32 = (0|0) - 32 = -32 -> 0xC2000000
18// y[64] = (ql[0].high | bits45<<4) - 32 = (3|0)-32 = -29 -> 0xC1E80000
19// y[96] = (ql[32].high | bits67<<4) - 32 = (0|0)-32 = -32 -> 0xC2000000
20
21import "nx_syscalls.nx"
22import "nx_tier.nx"
23import "nx_le.nx"
24import "nx_f32.nx"
25import "nx_q6_k_to_f32.nx"
26
27func main() -> i64 {
28 let buf: *u8 = sys_mmap(256)
29 var z: i64 = 0
30 while z < 210 { buf[z] = 0 as u8; z = z + 1 }
31
32 buf[0] = 0x32 as u8
33 buf[128] = 0x01 as u8
34 var s: i64 = 0
35 while s < 16 { buf[192 + s] = 1 as u8; s = s + 1 }
36 nx_le_write_u16(buf, 208, 0x3C00)
37
38 let out: *i64 = sys_mmap(256 * 8) as *i64
39 nx_q6_k_to_f32(buf, 0, 256, out)
40
41 // c=0, l=0 emits at y[0], y[32], y[64], y[96]
42 if out[0] != 0xC1600000 { return 10 } // -14
43 if out[32] != 0xC2000000 { return 11 } // -32
44 if out[64] != 0xC1E80000 { return 12 } // -29
45 if out[96] != 0xC2000000 { return 13 } // -32
46
47 // Other positions: ql/qh all zero -> q6=0, signed=-32, value=-32
48 if out[1] != 0xC2000000 { return 20 }
49 if out[33] != 0xC2000000 { return 21 }
50 if out[128] != 0xC2000000 { return 22 }
51 if out[255] != 0xC2000000 { return 23 }
52
53 return 0
54}