code wiki / _hdl_build / nx_lwq24_probe.nx
nx_lwq24_probe.nx source
↩ module page · 146 lines · 5045 B
1// nx_lwq24_probe.nx -- LAYERED probe for the LWC-2 FILL FAIL (2026-08-01).
2// P1: fq4m_fill_q24 + fq4m_rows_cached_q24 SERIALLY (no pool, no lazy-weight) vs the scalar oracle.
3// P2: the full nx_f32_lazy_matmul dispatch on the same data.
4// Whichever layer first diverges owns the bug. Same exact-regime synthesis as nx_lw_cache_gate
5// (d=1.0 f16, dmin=0, sc=1 -> dequant == q4 integers; int activations).
6// expect_exit: 0 license_tier: ORIGINAL No hw writes (Rule 26).
7import "nx_f32_lazy_weight.nx"
8import "nx_fmt.nx"
9const PB_MAGIC_1103515245: i64 = 1103515245
10const PB_MAGIC_12345: i64 = 12345
11const PB_MAGIC_2147483647: i64 = 2147483647
12const PB_MAGIC_20260708: i64 = 20260708
13const PB_MAGIC_424242: i64 = 424242
14
15const PB_M: i64 = 3
16const PB_K: i64 = 512
17const PB_N: i64 = 37
18
19func p_lcg(s: i64) -> i64 {
20 var v: i64 = s * PB_MAGIC_1103515245 + PB_MAGIC_12345
21 v = v & PB_MAGIC_2147483647
22 return v
23}
24func p_block_dense(buf: *u8, off: i64, seed: i64) -> i64 {
25 buf[off + 0] = 0x00 as u8
26 buf[off + 1] = 0x3C as u8
27 buf[off + 2] = 0 as u8
28 buf[off + 3] = 0 as u8
29 var i: i64 = 0
30 while i < 4 {
31 buf[off + 4 + i] = 0x01 as u8
32 buf[off + 8 + i] = 0x00 as u8
33 buf[off + 12 + i] = 0x01 as u8
34 i = i + 1
35 }
36 var s: i64 = seed
37 var z: i64 = 0
38 while z < 128 {
39 s = p_lcg(s)
40 buf[off + 16 + z] = (s & 255) as u8
41 z = z + 1
42 }
43 return off + 144
44}
45func p_fill_weights(buf: *u8, n_rows: i64, k: i64, seed: i64) -> i64 {
46 let bpr: i64 = (k / 256) * 144
47 var s: i64 = seed
48 var r: i64 = 0
49 while r < n_rows {
50 var b: i64 = 0
51 while b < k / 256 {
52 s = p_lcg(s)
53 p_block_dense(buf, r * bpr + b * 144, s)
54 b = b + 1
55 }
56 r = r + 1
57 }
58 return 0
59}
60func p_fill_a(p: *i64, count: i64, seed: i64, half: i64) -> i64 {
61 var s: i64 = seed
62 var i: i64 = 0
63 while i < count {
64 s = p_lcg(s)
65 let v: i64 = (s % (half + half)) - half
66 p[i] = nx_i32_to_f32(v)
67 i = i + 1
68 }
69 return 0
70}
71// first differing index, or -1
72func p_diff(a: *i64, b: *i64, count: i64) -> i64 {
73 var i: i64 = 0
74 while i < count {
75 if a[i] != b[i] { return i }
76 i = i + 1
77 }
78 return 0 - 1
79}
80
81func main() -> i64 {
82 let a_n: i64 = PB_M * PB_K
83 let b_n: i64 = PB_N * (PB_K / 256) * 144
84 let c_n: i64 = PB_M * PB_N
85 let A: *i64 = sys_mmap(a_n * 8) as *i64
86 let B: *u8 = sys_mmap(b_n)
87 let Cs: *i64 = sys_mmap(c_n * 8) as *i64
88 let Cq: *i64 = sys_mmap(c_n * 8) as *i64
89 p_fill_a(A, a_n, PB_MAGIC_20260708, 5)
90 p_fill_weights(B, PB_N, PB_K, PB_MAGIC_424242)
91
92 let v1: nx_int = nx_f32_q4k_matmul(A, B, 0, Cs, PB_M, PB_K, PB_N)
93 fmt_puts("P0 scalar rc=" as *u8); fmt_putn(v1); fmt_puts("\n" as *u8)
94
95 // ---- P1: serial fill + serial cached dot, NO pool, NO lazy-weight ----
96 let cache: *u8 = sys_mmap(PB_N * PB_K * 4)
97 let fr: i64 = fq4m_fill_q24(cache, B, 0, PB_K, PB_N, 0, PB_N)
98 fmt_puts("P1 fill rc=" as *u8); fmt_putn(fr)
99 fmt_puts(" cache[0..3]=" as *u8)
100 fmt_putn(_fq4m_q24_at(cache, 0)); fmt_puts("," as *u8)
101 fmt_putn(_fq4m_q24_at(cache, 1)); fmt_puts("," as *u8)
102 fmt_putn(_fq4m_q24_at(cache, 2)); fmt_puts("," as *u8)
103 fmt_putn(_fq4m_q24_at(cache, 3)); fmt_puts("\n" as *u8)
104
105 let pq: *i64 = sys_mmap(a_n * 8) as *i64
106 _fq4m_pack_q10(A, a_n, pq)
107 let cr: i64 = fq4m_rows_cached_q24(pq, cache, Cq, PB_M, PB_K, PB_N, 0, PB_N)
108 let d1: i64 = p_diff(Cq, Cs, c_n)
109 fmt_puts("P1 cached-serial rc=" as *u8); fmt_putn(cr)
110 fmt_puts(" first_diff=" as *u8); fmt_putn(d1)
111 if d1 >= 0 {
112 fmt_puts(" got=" as *u8); fmt_putn(Cq[d1])
113 fmt_puts(" want=" as *u8); fmt_putn(Cs[d1])
114 }
115 fmt_puts("\n" as *u8)
116
117 // ---- P1b: the streamed fused oracle on the same data ----
118 let Cf: *i64 = sys_mmap(c_n * 8) as *i64
119 let vf: nx_int = nx_f32_q4k_matmul_fused(A, B, 0, Cf, PB_M, PB_K, PB_N)
120 let df: i64 = p_diff(Cf, Cs, c_n)
121 fmt_puts("P1b fused-serial rc=" as *u8); fmt_putn(vf)
122 fmt_puts(" first_diff_vs_scalar=" as *u8); fmt_putn(df)
123 if df >= 0 {
124 fmt_puts(" got=" as *u8); fmt_putn(Cf[df])
125 fmt_puts(" want=" as *u8); fmt_putn(Cs[df])
126 }
127 let dqf: i64 = p_diff(Cq, Cf, c_n)
128 fmt_puts(" cached_vs_fused_diff=" as *u8); fmt_putn(dqf)
129 fmt_puts("\n" as *u8)
130
131 // ---- P2: the full lazy dispatch ----
132 let W: *NxF32LazyWeight = nx_f32_lazy_weight_new_q4k(B, 0, PB_K, PB_N)
133 let Cd: *i64 = sys_mmap(c_n * 8) as *i64
134 let v2: nx_int = nx_f32_lazy_matmul(A, W, Cd, PB_M, PB_K, PB_N)
135 let d2: i64 = p_diff(Cd, Cs, c_n)
136 fmt_puts("P2 lazy rc=" as *u8); fmt_putn(v2)
137 fmt_puts(" pk_state=" as *u8); fmt_putn(W.pk_state)
138 fmt_puts(" used=" as *u8); fmt_putn(nx_lw_cache_used())
139 fmt_puts(" first_diff=" as *u8); fmt_putn(d2)
140 if d2 >= 0 {
141 fmt_puts(" got=" as *u8); fmt_putn(Cd[d2])
142 fmt_puts(" want=" as *u8); fmt_putn(Cs[d2])
143 }
144 fmt_puts("\n" as *u8)
145 return 0
146}