code wiki / _hdl_build / nx_fpga_alu_verilog_gate.nx
nx_fpga_alu_verilog_gate.nx source
↩ module page · 83 lines · 6438 B
1import "nx_gate_gn.nx"
2import "nx_gate_base.nx"
3// nx_fpga_alu_verilog_gate.nx -- GATE for RUNG 29: emit a REAL CPU DATAPATH to Verilog. R27/R28 proved the synth
4// bridge on toy fabrics (4-bit adder, 3-bit counter); this emits the full 64-bit RV64I ALU (nx_fpga_alu, 576 LUT4
5// cells -- AND/OR/XOR + add/sub + result-MUX) to a Yosys-synthesizable Verilog gate-netlist via the emitter lib, and
6// proves the emitted netlist, re-parsed, computes the SAME results as the behavioral oracle. This is a substantial
7// CPU datapath (not a toy) serialized to the interchange Yosys/nextpnr consume toward an ECP5 bitstream.
8// T1 the emitted 576-cell ALU netlist re-parses to the SAME fabric (kind/init/src/po byte-identical).
9// T2 the RE-PARSED ALU netlist (fab_alu_run) computes ADD/SUB/AND/OR/XOR over several (a,b) == behavioral oracle.
10// T3 NEVER-BRICK. T4 LIAR-KILL (corrupt an ALU LUT -> emitted+reparsed netlist computes wrong). expect_exit: 0
11// license_tier: ORIGINAL
12import "nx_fpga_verilog.nx"
13import "nx_fpga_alu.nx"
14import "rv64im_min_alu.nx"
15import "nx_syscalls.nx"
16
17func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("
18" as *u8); return ok }
19
20func main() -> i64 {
21 gw("=== nx_fpga_alu_verilog_gate: RUNG 29 -- emit the REAL 64-bit ALU datapath (576 cells) to Verilog ===\n" as *u8)
22 var pass: i64 = 0; var total: i64 = 0
23 let W: i64 = 64
24 let AI: *i64=sys_mmap(8*640) as *i64; let AS: *i64=sys_mmap(8*2560) as *i64; let AP: *i64=sys_mmap(8*72) as *i64
25 let kind: *i64=sys_mmap(8*640) as *i64
26 let npi: i64 = fab_build_alu(W, AI, AS, AP)
27 let ncells: i64 = 9*W; let npo: i64 = W
28 var z: i64=0; while z < ncells { kind[z]=0; z=z+1 } // ALU is purely combinational (all LUT cells)
29
30 let buf: *u8 = sys_mmap(131072)
31 let len: i64 = fab_emit_verilog_seq(buf, ncells, npi, npo, kind, AI, AS, AP)
32 buf[len]=0 as u8
33 // print just the header + first ~5 lines (the full 576-cell netlist is large)
34 var cut: i64=0; var nl: i64=0
35 while cut < len { if buf[cut]==(10 as u8) { nl=nl+1; if nl==6 { cut=cut+1; z=cut } } cut=cut+1 }
36 let save: u8 = buf[z]; buf[z]=0 as u8
37 gw("--- emitted ALU Verilog (head; full netlist = \x00" as *u8); gn(len); gw(" bytes, \x00" as *u8); gn(ncells); gw(" cells) ---\n" as *u8); gw(buf); buf[z]=save
38 gw(" ... [+\x00" as *u8); gn(ncells-5); gw(" more cells] ... endmodule\n--- end ---\n" as *u8)
39
40 // T1: round-trip
41 let rk: *i64=sys_mmap(8*640) as *i64; let ri: *i64=sys_mmap(8*640) as *i64; let rs: *i64=sys_mmap(8*2560) as *i64; let rp: *i64=sys_mmap(8*72) as *i64
42 let pnpi: *i64=sys_mmap(16) as *i64; let pnpo: *i64=sys_mmap(16) as *i64
43 let rnc: i64=fab_parse_seq(buf, len, rk, ri, rs, rp, pnpi, pnpo)
44 var diff: i64=0
45 if rnc!=ncells {diff=diff+1} if pnpi[0]!=npi {diff=diff+1} if pnpo[0]!=npo {diff=diff+1}
46 var k: i64=0; while k<ncells { if rk[k]!=kind[k] {diff=diff+1} if ri[k]!=AI[k] {diff=diff+1} var j: i64=0; while j<4 { if rs[k*4+j]!=AS[k*4+j] {diff=diff+1} j=j+1 } k=k+1 }
47 var p: i64=0; while p<npo { if rp[p]!=AP[p] {diff=diff+1} p=p+1 }
48 total=total+1; if diff==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
49 gw("T1 the emitted 576-cell ALU netlist re-parses to the SAME fabric (kind/init/src/po), differences=" as *u8); gn(diff); gw("\n" as *u8)
50
51 // T2: the re-parsed ALU netlist computes ADD/SUB/AND/OR/XOR == behavioral oracle
52 let pi: *i64=sys_mmap(8*200) as *i64; let co: *i64=sys_mmap(8*2200) as *i64
53 var amis: i64=0
54 // (a, b, sub, m0, m1, oracle-op)
55 let av: i64=5; let bv: i64=7
56 if fab_alu_run(W,pnpi[0],ri,rs,rp,pi,co,av,bv,0,1,1) != nx_rv64im_alu_compute(NX_RV64IM_ALU_ADD,av,bv) { amis=amis+1 }
57 if fab_alu_run(W,pnpi[0],ri,rs,rp,pi,co,20,8,1,1,1) != nx_rv64im_alu_compute(NX_RV64IM_ALU_SUB,20,8) { amis=amis+1 }
58 if fab_alu_run(W,pnpi[0],ri,rs,rp,pi,co,12,10,0,0,0) != nx_rv64im_alu_compute(NX_RV64IM_ALU_AND,12,10) { amis=amis+1 }
59 if fab_alu_run(W,pnpi[0],ri,rs,rp,pi,co,12,10,0,1,0) != nx_rv64im_alu_compute(NX_RV64IM_ALU_OR,12,10) { amis=amis+1 }
60 if fab_alu_run(W,pnpi[0],ri,rs,rp,pi,co,12,10,0,0,1) != nx_rv64im_alu_compute(NX_RV64IM_ALU_XOR,12,10) { amis=amis+1 }
61 total=total+1; if amis==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
62 gw("T2 the RE-PARSED ALU netlist computes ADD(5,7)=\x00" as *u8); gn(fab_alu_run(W,pnpi[0],ri,rs,rp,pi,co,5,7,0,1,1)); gw(" SUB(20,8)=\x00" as *u8); gn(fab_alu_run(W,pnpi[0],ri,rs,rp,pi,co,20,8,1,1,1)); gw(" XOR(12,10)=\x00" as *u8); gn(fab_alu_run(W,pnpi[0],ri,rs,rp,pi,co,12,10,0,0,1)); gw(" all == oracle, mismatches=" as *u8); gn(amis); gw("\n" as *u8)
63
64 // T3: never-brick
65 let l2: i64=fab_emit_verilog_seq(buf, ncells, npi, npo, kind, AI, AS, AP)
66 total=total+1; if l2==len { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
67 gw("T3 never-brick (#26): deterministic text emit, bounded, zero hardware-state writes\n" as *u8)
68
69 // T4: liar-kill -- corrupt the WHOLE ALU LUT config (cell 0 alone is an AND-gate ADD never selects), re-emit+
70 // re-parse; the netlist must compute WRONG (proves the emitted Verilog carries the actual LUT contents)
71 var cc: i64=0; while cc < ncells { AI[cc] = AI[cc] ^ 0xffff; cc=cc+1 }
72 let buf2: *u8=sys_mmap(131072); let len2: i64=fab_emit_verilog_seq(buf2, ncells, npi, npo, kind, AI, AS, AP); buf2[len2]=0 as u8
73 let k2: *i64=sys_mmap(8*640) as *i64; let i2: *i64=sys_mmap(8*640) as *i64; let s2: *i64=sys_mmap(8*2560) as *i64; let p2: *i64=sys_mmap(8*72) as *i64
74 let pn2: *i64=sys_mmap(16) as *i64; let po2: *i64=sys_mmap(16) as *i64
75 let rnc2: i64=fab_parse_seq(buf2, len2, k2, i2, s2, p2, pn2, po2)
76 let bad: i64=fab_alu_run(W,pn2[0],i2,s2,p2,pi,co,5,7,0,1,1)
77 total=total+1; if bad != 12 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
78 gw("T4 liar-kill: corrupting an ALU LUT -> emitted+reparsed netlist computes ADD(5,7)=\x00" as *u8); gn(bad); gw(" != 12\n" as *u8)
79
80 gw("\n=== nx_fpga_alu_verilog_gate " as *u8); gn(pass); gw("/" as *u8); gn(total)
81 if pass == total { gw(" GREEN (a REAL 64-bit CPU ALU datapath serializes to a Yosys-synthesizable Verilog gate-netlist + round-trips == behavioral -- the synth bridge carries real CPU logic)\n" as *u8); sys_exit(0); return 0 }
82 gw(" RED\n" as *u8); sys_exit(1); return 1
83}