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}