code wiki / _hdl_build / synth_emit_alu_gates_smoke.nx

synth_emit_alu_gates_smoke.nx source

↩ module page · 109 lines · 5197 B

1// synth_emit_alu_gates_smoke.nx -- structural smoke for the ALU .nxgate emitter. 2// 3// ROOT-CAUSE FIX (2026-06-20): synth_emit_alu_gates.nx is a LIBRARY (no main); building it 4// standalone fails "UNDEFINED label: main" -- that was a build-as-executable mistake, NOT an nxasm 5// regression. A library organ is verified by its SMOKE GATE (with main), exactly like 6// synth_emit_regfile_gates_smoke.nx. This is that missing tool: it builds the rv64im_min ALU HDL 7// module, runs nx_emit_alu_gates into a sink, prints the netlist, then asserts the structural 8// invariants the emitter MUST satisfy -- well-formed (.NXGATE/.MODULE/.END), complete (4 ports, 9// ~4125 cells, divider-backed), and ON-ENUM (UNKNOWN x 0 = no cell emitted an out-of-enum kind). 10// .PORT x 4 (op_in, a_in, b_in, result) 11// .CELL ~4125 (divider-backed: full restoring divider for DIV/DIVU/REM/REMU + 29-op cascade) 12// .CONST ~498 (opcode + divider/widening constants) 13// .NET ~4623 (width-complete: every cell drives a declared net; cells <= nets) 14// UNKNOWN x 0 (the correctness invariant: no out-of-enum cell kind) 15// NOTE: output is ~270KB -> the sink buffer must be MB-scale (an earlier 262KB buf silently dropped 16// all cells because nx_synth_emit_bytes is all-or-nothing). Exact cell count tracks the emitter; the 17// gate floors at >100 + checks ports/end/unknown/width-completeness. Exit 0 = green. CORRECTNESS gate. 18// Mirrors the proven regfile smoke (same import set, dedup-safe). 100% sovereign. 19// license_tier: ORIGINAL expect_exit: 0 20import "nx_syscalls.nx" 21import "nishi_hdl_primitives.nx" 22import "nishi_synth.nx" 23import "nishi_synth_gates.nx" 24import "rv64im_min_alu.nx" 25import "synth_emit_alu_gates.nx" 26 27func nx_alusmoke_slen(p: *u8) -> i64 { 28 var n: i64 = 0 29 while p[n] != (0 as u8) { n = n + 1 } 30 return n 31} 32func nx_alusmoke_puts(p: *u8) -> i64 { 33 return sys_write(1, p, nx_alusmoke_slen(p)) 34} 35func nx_alusmoke_putn(v: i64) -> i64 { 36 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 } 37 var m: i64 = v 38 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 39 let d: *u8 = sys_mmap(24); var k: i64 = 0 40 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 41 let o: *u8 = sys_mmap(24); var i: i64 = 0 42 while i < k { o[i] = d[k - 1 - i]; i = i + 1 } 43 sys_write(1, o, k); return 0 44} 45 46// Count non-overlapping occurrences of NUL-terminated needle in buf[0..used). 47func nx_alusmoke_count(buf: *u8, used: i64, needle: *u8) -> i64 { 48 let nlen: i64 = nx_alusmoke_slen(needle) 49 if nlen == 0 { return 0 } 50 var c: i64 = 0 51 var i: i64 = 0 52 while i + nlen <= used { 53 var j: i64 = 0 54 var ok: i64 = 1 55 while j < nlen { 56 if buf[i + j] != needle[j] { ok = 0 } 57 j = j + 1 58 } 59 if ok == 1 { c = c + 1 } 60 i = i + 1 61 } 62 return c 63} 64 65func main() -> i64 { 66 let sigbuf: *i64 = (sys_mmap(NX_HDL_MODULE_MAX_SIGNALS * 32)) as *i64 67 let namepool: *u8 = sys_mmap(256) 68 let m: *NxHdlModule = (sys_mmap(64)) as *NxHdlModule 69 let ports: *NxRv64imAluPorts = (sys_mmap(128)) as *NxRv64imAluPorts 70 let buf: *u8 = sys_mmap(8388608) 71 let s: *NxSynthSink = (sys_mmap(64)) as *NxSynthSink 72 73 nx_hdl_module_init(m, "rv64im_alu" as *u8, 10, sigbuf, namepool, 256) 74 nx_rv64im_alu_build(m, ports) 75 nx_synth_sink_init(s, buf, 8388608) 76 77 let rc: i64 = nx_emit_alu_gates(s, m, ports) 78 79 // print the netlist (follow-along) 80 sys_write(1, s.buf, s.used) 81 82 // observed counts (printed so the real emitter output is visible) 83 let n_port: i64 = nx_alusmoke_count(s.buf, s.used, ".PORT " as *u8) 84 let n_cell: i64 = nx_alusmoke_count(s.buf, s.used, ".CELL " as *u8) 85 let n_const: i64 = nx_alusmoke_count(s.buf, s.used, ".CONST " as *u8) 86 let n_net: i64 = nx_alusmoke_count(s.buf, s.used, ".NET " as *u8) 87 let n_unk: i64 = nx_alusmoke_count(s.buf, s.used, "UNKNOWN" as *u8) 88 nx_alusmoke_puts("\nALU emit counts: ports=" as *u8); nx_alusmoke_putn(n_port) 89 nx_alusmoke_puts(" cells=" as *u8); nx_alusmoke_putn(n_cell) 90 nx_alusmoke_puts(" consts=" as *u8); nx_alusmoke_putn(n_const) 91 nx_alusmoke_puts(" nets=" as *u8); nx_alusmoke_putn(n_net) 92 nx_alusmoke_puts(" unknown=" as *u8); nx_alusmoke_putn(n_unk); nx_alusmoke_puts("\n" as *u8) 93 94 // structural assertions 95 if rc != NX_HDL_OK { return 1 } 96 if s.used == 0 { return 2 } 97 if nx_alusmoke_count(s.buf, s.used, ".NXGATE 1" as *u8) != 1 { return 3 } 98 if nx_alusmoke_count(s.buf, s.used, ".MODULE " as *u8) != 1 { return 4 } 99 if n_port != 4 { return 5 } 100 if n_cell < 100 { return 6 } // divider-backed ALU = thousands of cells; floor, not exact 101 if n_const < 1 { return 7 } 102 if nx_alusmoke_count(s.buf, s.used, ".END" as *u8) != 1 { return 8 } 103 if n_unk != 0 { return 9 } // the correctness invariant: no out-of-enum cell kind 104 if n_net <= 0 { return 10 } 105 if n_cell > n_net { return 11 } // every cell drives a declared net (width-complete) 106 107 nx_alusmoke_puts("ALU .nxgate SMOKE PASS (divider-backed; 4 ports, on-enum, cells+nets width-complete; counts above)\n" as *u8) 108 return 0 109}