code wiki / _hdl_build / synth_emit_regfile_gates_smoke.nx
synth_emit_regfile_gates_smoke.nx source
↩ module page · 97 lines · 3809 B
1// synth_emit_regfile_gates_smoke.nx -- structural smoke for the
2// regfile .nxgate emitter.
3//
4// Builds the rv64im_min regfile HDL module, runs nx_emit_regfile_gates
5// into a sink, prints the netlist (so progress is followable), then
6// asserts the structural invariants the emitter MUST satisfy:
7//
8// .NXGATE 1 present (format header)
9// .MODULE present (module declared)
10// .PORT x 9 (clk reset rs1_idx rs2_idx rd_idx rd_value write_en
11// rs1_data rs2_data)
12// .FLOP x 31 (x1..x31; x0 has no flop)
13// .CONST x 33 (31 shared index consts + 2 read-cascade zeros)
14// .CELL x 217 (per-reg EQ+AND+MUX write path = 93; dual read
15// EQ+MUX = 124)
16// .NET x 248 (every internal non-const net, width-declared)
17// .END present
18// UNKNOWN x 0 (no cell emitted an out-of-enum kind)
19//
20// Exit code 0 = all green. Non-zero = the first failed check (see
21// per-check codes). This is a CORRECTNESS gate (EXEMPT from the
22// NISHIBENCH winner-tier per the bench standard).
23//
24// Functional gate-sim equivalence vs the behavioural regfile is NOT
25// checked here -- that needs nishi-pnr's gate simulator (M5). This
26// smoke proves the netlist is well-formed + complete + on-spec.
27
28import "nx_syscalls.nx"
29import "nishi_hdl_primitives.nx"
30import "nishi_synth.nx"
31import "nishi_synth_gates.nx"
32import "rv64im_min_regfile.nx"
33import "synth_emit_regfile_gates.nx"
34
35func nx_rfsmoke_slen(p: *u8) -> i64 {
36 var n: i64 = 0
37 while p[n] != (0 as u8) { n = n + 1 }
38 return n
39}
40
41func nx_rfsmoke_puts(p: *u8) -> i64 {
42 return sys_write(1, p, nx_rfsmoke_slen(p))
43}
44
45// Count non-overlapping occurrences of NUL-terminated needle in buf[0..used).
46func nx_rfsmoke_count(buf: *u8, used: i64, needle: *u8) -> i64 {
47 let nlen: i64 = nx_rfsmoke_slen(needle)
48 if nlen == 0 { return 0 }
49 var c: i64 = 0
50 var i: i64 = 0
51 while i + nlen <= used {
52 var j: i64 = 0
53 var ok: i64 = 1
54 while j < nlen {
55 if buf[i + j] != needle[j] { ok = 0 }
56 j = j + 1
57 }
58 if ok == 1 { c = c + 1 }
59 i = i + 1
60 }
61 return c
62}
63
64func main() -> i64 {
65 // ----- allocate module + ports + sink -----
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: *NxRv64imRegfilePorts = (sys_mmap(128)) as *NxRv64imRegfilePorts
70 let buf: *u8 = sys_mmap(262144)
71 let s: *NxSynthSink = (sys_mmap(64)) as *NxSynthSink
72
73 nx_hdl_module_init(m, "rv64im_regfile" as *u8, 14, sigbuf, namepool, 256)
74 nx_rv64im_rf_build(m, ports)
75 nx_synth_sink_init(s, buf, 262144)
76
77 let rc: i64 = nx_emit_regfile_gates(s, m, ports)
78
79 // ----- print the netlist (follow-along) -----
80 sys_write(1, s.buf, s.used)
81
82 // ----- structural assertions -----
83 if rc != NX_HDL_OK { return 1 }
84 if s.used == 0 { return 2 }
85 if nx_rfsmoke_count(s.buf, s.used, ".NXGATE 1" as *u8) != 1 { return 3 }
86 if nx_rfsmoke_count(s.buf, s.used, ".MODULE " as *u8) != 1 { return 4 }
87 if nx_rfsmoke_count(s.buf, s.used, ".PORT " as *u8) != 9 { return 5 }
88 if nx_rfsmoke_count(s.buf, s.used, ".FLOP " as *u8) != 31 { return 6 }
89 if nx_rfsmoke_count(s.buf, s.used, ".CONST " as *u8) != 33 { return 7 }
90 if nx_rfsmoke_count(s.buf, s.used, ".CELL " as *u8) != 217 { return 8 }
91 if nx_rfsmoke_count(s.buf, s.used, ".NET " as *u8) != 248 { return 9 }
92 if nx_rfsmoke_count(s.buf, s.used, ".END" as *u8) != 1 { return 10 }
93 if nx_rfsmoke_count(s.buf, s.used, "UNKNOWN" as *u8) != 0 { return 11 }
94
95 nx_rfsmoke_puts("\nREGFILE .nxgate SMOKE PASS (31 flops, 9 ports, 217 cells, 33 consts, 248 nets)\n" as *u8)
96 return 0
97}