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}