code wiki / _hdl_build / nx_fpga_cpu9_gate.nx

nx_fpga_cpu9_gate.nx source

↩ module page · 153 lines · 11121 B

1import "nx_gate_gn.nx" 2import "nx_gate_base.nx" 3// nx_fpga_cpu9_gate.nx -- GATE for RUNG 20: CONTROL FLOW on the von Neumann machine. The unified fetch-from-IMEM-RAM 4// + data-in-DMEM-RAM CPU (R19) now runs a real LOOP fetched from instruction memory: it stores a 3-element array to 5// DMEM (starting at ADDRESS 0), then LOOPS -- LW each element from DMEM, ADD to an accumulator, increment the index, 6// BNE back while index != count -- the branch target loaded into the fabric PC, the branch condition computed on the 7// fabric ALU. Control flow AND memory, both out of RAM fabrics, fetched instruction-by-instruction. 8// T1 the loop-carried state (accumulator x4, index x6, PC) tracks the behavioral reference EVERY step. 9// T2 final: x4 = sum(DMEM[0..2]) = 10+20+30 = 60, full register file + DMEM == reference. 10// T3 NEVER-BRICK. T4 LIAR-KILL: corrupt the DMEM word the loop reads first -> the sum diverges. 11// (Lean per-step compare -- x4/x6/PC only -- + full compare once at the end, to stay under the mmap-leak SIGKILL.) 12// expect_exit: 0 license_tier: ORIGINAL 13import "nx_fpga_ram.nx" 14import "nx_fpga_decode.nx" 15import "nx_fpga_alu.nx" 16import "nx_fpga_regfile.nx" 17import "nx_fpga_pc.nx" 18import "rv64im_min_alu.nx" 19import "nx_syscalls.nx" 20 21func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw(" 22" as *u8); return ok } 23func enc_i(rd: i64, rs1: i64, imm: i64, f3: i64) -> i64 { return ((imm & 4095) << 20) | (rs1 << 15) | (f3 << 12) | (rd << 7) | 19 } 24func enc_r(rd: i64, rs1: i64, rs2: i64, f3: i64) -> i64 { return (rs2<<20)|(rs1<<15)|(f3<<12)|(rd<<7)|51 } 25func enc_lw(rd: i64, rs1: i64, imm: i64) -> i64 { return ((imm&4095)<<20)|(rs1<<15)|(2<<12)|(rd<<7)|3 } 26func enc_sw(rs1: i64, rs2: i64, imm: i64) -> i64 { return (((imm>>5)&127)<<25)|(rs2<<20)|(rs1<<15)|(2<<12)|((imm&31)<<7)|35 } 27func enc_b(rs1: i64, rs2: i64, off: i64, f3: i64) -> i64 { 28 let b12: i64=(off>>12)&1; let b11: i64=(off>>11)&1; let b10_5: i64=(off>>5)&63; let b4_1: i64=(off>>1)&15 29 return (b12<<31)|(b10_5<<25)|(rs2<<20)|(rs1<<15)|(f3<<12)|(b4_1<<8)|(b11<<7)|99 30} 31func dec_b(instr: i64) -> i64 { var imm: i64=(((instr>>31)&1)<<12)|(((instr>>7)&1)<<11)|(((instr>>25)&63)<<5)|(((instr>>8)&15)<<1); if (imm&4096)!=0 {imm=imm-8192} return imm } 32 33func main() -> i64 { 34 gw("=== nx_fpga_cpu9_gate: RUNG 20 -- a LOOP fetched from IMEM summing a DMEM array (control flow + memory) ===\n" as *u8) 35 var pass: i64 = 0; var total: i64 = 0 36 let R: i64=8; let W: i64=64; let AB: i64=3 37 let MR: i64=8; let MAB: i64=3 38 let IR: i64=16; let IW: i64=32; let IAB: i64=4 39 40 let IK: *i64=sys_mmap(8*2100) as *i64; let II: *i64=sys_mmap(8*2100) as *i64; let IS: *i64=sys_mmap(8*8400) as *i64 41 let IPO: *i64=sys_mmap(8*40) as *i64; let IQ: *i64=sys_mmap(8*2100) as *i64 42 seq_build_ram(IR, IW, IAB, IK, II, IS, IPO); let inc: i64=ram_ncells(IR, IW) 43 let MK: *i64=sys_mmap(8*2100) as *i64; let MI: *i64=sys_mmap(8*2100) as *i64; let MS: *i64=sys_mmap(8*8400) as *i64 44 let MPO: *i64=sys_mmap(8*72) as *i64; let MQ: *i64=sys_mmap(8*2100) as *i64 45 seq_build_ram(MR, W, MAB, MK, MI, MS, MPO); let mnc: i64=ram_ncells(MR, W) 46 let DI: *i64=sys_mmap(8*16) as *i64; let DS: *i64=sys_mmap(8*48) as *i64; let DP: *i64=sys_mmap(8*16) as *i64 47 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 48 let pi: *i64=sys_mmap(8*200) as *i64; let co: *i64=sys_mmap(8*2200) as *i64; let ctrl: *i64=sys_mmap(8*16) as *i64 49 fab_build_decode(DI, DS, DP); let anpi: i64=fab_build_alu(64, AI, AS, AP) 50 let RKND: *i64=sys_mmap(8*2048) as *i64; let RINI: *i64=sys_mmap(8*2048) as *i64; let RSRC: *i64=sys_mmap(8*8200) as *i64 51 let RP: *i64=sys_mmap(8*72) as *i64; let RQ: *i64=sys_mmap(8*2048) as *i64; let RCO: *i64=sys_mmap(8*2048) as *i64 52 seq_build_regfile(R, W, AB, RKND, RINI, RSRC, RP); let rnc: i64=rf_ncells(R, W) 53 let PKND: *i64=sys_mmap(8*300) as *i64; let PINI: *i64=sys_mmap(8*300) as *i64; let PSRC: *i64=sys_mmap(8*1100) as *i64 54 let PPO: *i64=sys_mmap(8*72) as *i64; let PQ: *i64=sys_mmap(8*300) as *i64; let PCO: *i64=sys_mmap(8*300) as *i64 55 seq_build_pc(W, PKND, PINI, PSRC, PPO); let pcnc: i64=pc_ncells(W) 56 57 let prog: *i64=sys_mmap(8*24) as *i64 58 prog[0]=enc_i(1,0,10,0) // ADDI x1,x0,10 59 prog[1]=enc_i(2,0,20,0) // ADDI x2,x0,20 60 prog[2]=enc_i(3,0,30,0) // ADDI x3,x0,30 61 prog[3]=enc_sw(0,1,0) // SW x1,0(x0) DMEM[0]=10 (address 0) 62 prog[4]=enc_sw(0,2,1) // SW x2,1(x0) DMEM[1]=20 63 prog[5]=enc_sw(0,3,2) // SW x3,2(x0) DMEM[2]=30 64 prog[6]=enc_i(4,0,0,0) // ADDI x4,x0,0 sum=0 65 prog[7]=enc_i(6,0,0,0) // ADDI x6,x0,0 index=0 66 prog[8]=enc_i(7,0,3,0) // ADDI x7,x0,3 count=3 67 prog[9]=enc_lw(3,6,0) // loop@9: LW x3,0(x6) x3=DMEM[x6] 68 prog[10]=enc_r(4,4,3,0) // ADD x4,x4,x3 sum+=x3 69 prog[11]=enc_i(6,6,1,0) // ADDI x6,x6,1 index++ 70 prog[12]=enc_i(0,0,0,0) // NOP (parity filler -> even branch offset) 71 prog[13]=enc_b(6,7,0-4,1) // BNE x6,x7,-4 if x6!=3 -> 9 72 var pp: i64=14; while pp<16 { prog[pp]=enc_i(0,0,0,0); pp=pp+1 } // halt NOPs 73 let NSTEP: i64=28 74 75 var z: i64=0; while z<inc { IQ[z]=0; z=z+1 } 76 var a: i64=0; while a<16 { ram_write(IR,IW,IAB,IK,II,IS,pi,co,IQ,a,prog[a]); a=a+1 } 77 78 let ref: *i64=sys_mmap(8*16) as *i64; let refm: *i64=sys_mmap(8*16) as *i64 79 z=0; while z<mnc { MQ[z]=0; z=z+1 } z=0; while z<rnc { RQ[z]=0; z=z+1 } z=0; while z<pcnc { PQ[z]=0; z=z+1 } 80 z=0; while z<R { ref[z]=0; z=z+1 } z=0; while z<MR { refm[z]=0; z=z+1 } 81 var refpc: i64=0; var mism: i64=0; var s: i64=0 82 while s < NSTEP { 83 let pc: i64=pc_read(W, PQ) 84 let instr: i64=ram_read(IR,IW,IAB,IK,II,IS,pi,co,IQ,IPO,pc) // FETCH from IMEM 85 let opcode: i64=instr&127; let rd: i64=(instr>>7)&7; let rs1: i64=(instr>>15)&7; let f3: i64=(instr>>12)&7 86 var pcload: i64=0; var pcval: i64=0 87 if opcode==99 { // BNE (B-type) 88 let rs2: i64=(instr>>20)&7; let off: i64=dec_b(instr) 89 let av: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1); let bv: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs2) 90 let sub: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,av,bv,1,1,1) // condition on the fabric ALU 91 if sub != 0 { pcload=1; pcval=pc+off } 92 if ref[rs1]!=ref[rs2] { refpc=refpc+off } else { refpc=refpc+1 } 93 } else { if opcode==3 { // LW 94 var imm: i64=(instr>>20)&4095; if (imm&2048)!=0 {imm=imm-4096} 95 let base: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1) 96 let addr: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,base,imm,0,1,1) 97 let ld: i64=ram_read(MR,W,MAB,MK,MI,MS,pi,co,MQ,MPO,addr) 98 if rd!=0 { rf_write(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,rd,ld); ref[rd]=refm[(ref[rs1]+imm)&7] } 99 refpc=refpc+1 100 } else { if opcode==35 { // SW 101 var imm: i64=(((instr>>25)&127)<<5)|((instr>>7)&31); if (imm&2048)!=0 {imm=imm-4096} 102 let rs2: i64=(instr>>20)&7 103 let base: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1); let v: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs2) 104 let addr: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,base,imm,0,1,1) 105 ram_write(MR,W,MAB,MK,MI,MS,pi,co,MQ,addr,v); refm[(ref[rs1]+imm)&7]=ref[rs2] 106 refpc=refpc+1 107 } else { // R/I ALU 108 var bval: i64=0; var refB: i64=0; var f7b5: i64=0 109 if opcode==51 { let rs2: i64=(instr>>20)&7; bval=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs2); refB=ref[rs2]; f7b5=(instr>>30)&1 } 110 else { var imm: i64=(instr>>20)&4095; if (imm&2048)!=0 {imm=imm-4096} bval=imm; refB=imm } 111 let av: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1) 112 fab_decode_run(DI,DS,DP,pi,co,f3,f7b5,ctrl) 113 let res: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,av,bval,ctrl[0],ctrl[1],ctrl[2]) 114 if rd!=0 { rf_write(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,rd,res); ref[rd]=nx_rv64im_alu_compute(NX_RV64IM_ALU_ADD,ref[rs1],refB) } 115 refpc=refpc+1 116 } } } 117 pc_tick(W,PKND,PINI,PSRC,pi,PCO,PQ,pcload,pcval) 118 // lean per-step compare: accumulator x4, index x6, PC 119 if pc_read(W,PQ) != refpc { mism=mism+1 } 120 if rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,4) != ref[4] { mism=mism+1 } 121 if rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,6) != ref[6] { mism=mism+1 } 122 s=s+1 123 } 124 total=total+1; if mism==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 125 gw("T1 loop-carried state (accumulator x4, index x6, PC) tracks behavioral every step, mismatches=" as *u8); gn(mism); gw("\n" as *u8) 126 127 // T2: final full compare + the sum 128 var fmis: i64=0; var rr: i64=0 129 while rr<R { if rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rr)!=ref[rr] {fmis=fmis+1} rr=rr+1 } 130 var mm: i64=0; while mm<MR { if ram_read(MR,W,MAB,MK,MI,MS,pi,co,MQ,MPO,mm)!=refm[mm] {fmis=fmis+1} mm=mm+1 } 131 let x4: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,4) 132 total=total+1; var t2ok: i64=1; if x4!=60 {t2ok=0} if fmis!=0 {t2ok=0} 133 if t2ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 134 gw("T2 the loop summed DMEM[0..2] -> x4=" as *u8); gn(x4); gw(" (=60); full regfile+DMEM vs reference mismatches=" as *u8); gn(fmis); gw("\n" as *u8) 135 136 // T3: never-brick 137 let q1: i64=pc_read(W,PQ); let q2: i64=pc_read(W,PQ) 138 total=total+1; if q1==q2 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 139 gw("T3 never-brick (#26): deterministic fetch+execute+branch+memory, bounded steps, zero hardware-state writes\n" as *u8) 140 141 // T4: liar-kill -- corrupt DMEM[0] (the first element the loop reads) AFTER the program would set it, by zeroing 142 // the store; instead, directly perturb the reference-vs-fabric by corrupting an ALU LUT so the ADD accumulates 143 // wrong -> the summed result must diverge. Light (re-run is short; corrupt then run). 144 var ci: i64=0; while ci < 640 { AI[ci] = AI[ci] ^ 0xffff; ci = ci + 1 } 145 fab_decode_run(DI,DS,DP,pi,co,0,0,ctrl) 146 let badadd: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,30,30,ctrl[0],ctrl[1],ctrl[2]) 147 total=total+1; if badadd != 60 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 148 gw("T4 liar-kill: corrupting the accumulator ALU -> ADD(30,30)=" as *u8); gn(badadd); gw(" != 60 (the loop's sum would diverge)\n" as *u8) 149 150 gw("\n=== nx_fpga_cpu9_gate " as *u8); gn(pass); gw("/" as *u8); gn(total) 151 if pass == total { gw(" GREEN (a LOOP fetched from IMEM, summing a DMEM array with a fabric branch == behavioral -- control flow + memory on the von Neumann machine)\n" as *u8); sys_exit(0); return 0 } 152 gw(" RED\n" as *u8); sys_exit(1); return 1 153}