code wiki / _hdl_build / nx_alu_emit_text_test.nx
nx_alu_emit_text_test.nx source
↩ module page · 96 lines · 3503 B
1// nx_alu_emit_text_test.nx -- SOVEREIGN gate (NishiLang verdict, no shell/grep):
2// drives the SHIPPING .nxgate emitter (nx_emit_alu_gates) and SELF-VERIFIES that
3// the emitted text carries the proven divider. The same builder the MEM verifier
4// proved at 21/7 runs here with a TEXT sink -> one source, two sinks.
5//
6// A stub ALU emits ~28 MUX / ~2 SUB / ~1 LTU cells; the divider-wired ALU emits
7// 4x64 of each. This test scans its OWN emitted buffer (no grep) and exits 0 IFF
8// the divider's signature is present + the .nxgate is structurally valid.
9// Verdict (exit code): 0 PROVEN; 1 MUX low; 2 SUB low; 3 LTU low; 4 no header;
10// 5 no .END; 20 emit failed.
11
12import "synth_emit_alu_gates.nx"
13
14const NX_ALU_MAX_SIG: i64 = 8192
15
16// Count non-overlapping occurrences of NUL-terminated `pat` in buf[0..used).
17func _count_sub(buf: *u8, used: i64, pat: *u8) -> i64 {
18 var plen: i64 = 0
19 while pat[plen] != (0 as u8) { plen = plen + 1 }
20 var c: i64 = 0
21 var i: i64 = 0
22 while i + plen <= used {
23 var hit: i64 = 1
24 var j: i64 = 0
25 while j < plen {
26 if buf[i + j] != pat[j] { hit = 0 }
27 j = j + 1
28 }
29 if hit == 1 { c = c + 1 }
30 i = i + 1
31 }
32 return c
33}
34
35func _emit_cstr(s: *u8) -> i64 {
36 var n: i64 = 0
37 while s[n] != (0 as u8) { n = n + 1 }
38 sys_write(1, s, n)
39 return 0
40}
41func _emit_dec(v: i64) -> i64 {
42 let b: *u8 = sys_mmap(28)
43 let t2: *u8 = sys_mmap(28)
44 var n: i64 = v
45 if n < 0 { n = 0 - n }
46 var t: i64 = 0
47 if n == 0 { t2[0] = 48; t = 1 }
48 while n > 0 { t2[t] = 48 + (n % 10); n = n / 10; t = t + 1 }
49 var i: i64 = 0
50 while i < t { b[i] = t2[t - 1 - i]; i = i + 1 }
51 sys_write(1, b, t)
52 return 0
53}
54
55func main() -> i64 {
56 let m: *NxHdlModule = sys_mmap(128) as *NxHdlModule
57 let sigs: *i64 = sys_mmap(8 * 4 * NX_ALU_MAX_SIG) as *i64
58 let npool: *u8 = sys_mmap(8192)
59 nx_hdl_module_init(m, "rv64im_alu" as *u8, 10, sigs, npool, 8192)
60
61 let ports: *NxRv64imAluPorts = sys_mmap(64) as *NxRv64imAluPorts
62 nx_rv64im_alu_build(m, ports)
63
64 let buf: *u8 = sys_mmap(2097152)
65 let s: *NxSynthSink = sys_mmap(64) as *NxSynthSink
66 nx_synth_sink_init(s, buf, 2097152)
67
68 let rc: i64 = nx_emit_alu_gates(s, m, ports)
69 if rc != NX_HDL_OK { sys_exit(20); return 20 }
70
71 let nmux: i64 = _count_sub(s.buf, s.used, "kind=MUX" as *u8)
72 let nsub: i64 = _count_sub(s.buf, s.used, "kind=SUB" as *u8)
73 let nltu: i64 = _count_sub(s.buf, s.used, "kind=LTU" as *u8)
74 let nmul: i64 = _count_sub(s.buf, s.used, "kind=MUL" as *u8)
75 let nhdr: i64 = _count_sub(s.buf, s.used, ".NXGATE 1" as *u8)
76 let nend: i64 = _count_sub(s.buf, s.used, ".END" as *u8)
77
78 _emit_cstr("emit-text: MUX=" as *u8); _emit_dec(nmux)
79 _emit_cstr(" SUB=" as *u8); _emit_dec(nsub)
80 _emit_cstr(" LTU=" as *u8); _emit_dec(nltu)
81 _emit_cstr(" MUL=" as *u8); _emit_dec(nmul)
82 _emit_cstr(" hdr=" as *u8); _emit_dec(nhdr)
83 _emit_cstr(" end=" as *u8); _emit_dec(nend)
84 _emit_cstr("\n" as *u8)
85
86 if nmux < 280 { sys_exit(1); return 1 }
87 if nsub < 250 { sys_exit(2); return 2 }
88 if nltu < 250 { sys_exit(3); return 3 }
89 if nhdr < 1 { sys_exit(4); return 4 }
90 if nend < 1 { sys_exit(5); return 5 }
91 // mulh shipped: each of MULH/MULHSU/MULHU emits a wide multiplier (4 MUL cells),
92 // so >= 12 MUL cells beyond the 2 single-MUL ops (MUL, MULW). A stub had ~5.
93 if nmul < 14 { sys_exit(6); return 6 }
94 sys_exit(0)
95 return 0
96}