code wiki / _hdl_build / nx_fpga_cpu8_gate.nx

nx_fpga_cpu8_gate.nx source

↩ module page · 138 lines · 11154 B

1import "nx_gate_gn.nx" 2import "nx_gate_base.nx" 3// nx_fpga_cpu8_gate.nx -- GATE for RUNG 19: the UNIFIED von Neumann CPU. ONE machine that FETCHES instructions from 4// an IMEM RAM fabric (R18) AND keeps its DATA in a DMEM RAM fabric (R17, a true RAM -- so data ADDRESS 0 works, the 5// end-to-end fix for R16's data-memory-can't-use-address-0 finding). Each step: instr = ram_read(IMEM, PC); decode; 6// dispatch (R/I -> ALU+regfile; SW -> ram_write(DMEM); LW -> ram_read(DMEM)); PC++. Both code and data live in 7// simulated memory fabrics; the machine reads code out of one and reads/writes data in the other. 8// Program: store a 2-element array to DMEM STARTING AT ADDRESS 0, load both back, sum them. 9// T1 the program (fetched from IMEM, data in DMEM) == behavioral (regfile + DMEM), every step. 10// T2 result x5 = DMEM[0]+DMEM[1] = 10+20 = 30, AND DMEM[0] (address 0) holds 10. 11// T3 NEVER-BRICK. T4 LIAR-KILL: corrupt IMEM word 2 (the SW to address 0) -> the store never happens -> diverges. 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 } 27 28func main() -> i64 { 29 gw("=== nx_fpga_cpu8_gate: RUNG 19 -- the UNIFIED von Neumann CPU (fetch from IMEM RAM + data in DMEM RAM) ===\n" as *u8) 30 var pass: i64 = 0; var total: i64 = 0 31 let R: i64=8; let W: i64=64; let AB: i64=3 32 let MR: i64=8; let MAB: i64=3 // DMEM: 8 words x 64-bit 33 let IR: i64=8; let IW: i64=32; let IAB: i64=3 // IMEM: 8 words x 32-bit 34 35 // IMEM (true RAM) 36 let IK: *i64=sys_mmap(8*1100) as *i64; let II: *i64=sys_mmap(8*1100) as *i64; let IS: *i64=sys_mmap(8*4400) as *i64 37 let IPO: *i64=sys_mmap(8*40) as *i64; let IQ: *i64=sys_mmap(8*1100) as *i64 38 seq_build_ram(IR, IW, IAB, IK, II, IS, IPO); let inc: i64=ram_ncells(IR, IW) 39 // DMEM (true RAM) 40 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 41 let MPO: *i64=sys_mmap(8*72) as *i64; let MQ: *i64=sys_mmap(8*2100) as *i64 42 seq_build_ram(MR, W, MAB, MK, MI, MS, MPO); let mnc: i64=ram_ncells(MR, W) 43 // datapath 44 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 45 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 46 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 47 fab_build_decode(DI, DS, DP); let anpi: i64=fab_build_alu(64, AI, AS, AP) 48 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 49 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 50 seq_build_regfile(R, W, AB, RKND, RINI, RSRC, RP); let rnc: i64=rf_ncells(R, W) 51 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 52 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 53 seq_build_pc(W, PKND, PINI, PSRC, PPO); let pcnc: i64=pc_ncells(W) 54 55 let prog: *i64=sys_mmap(8*16) as *i64 56 prog[0]=enc_i(1,0,10,0) // ADDI x1,x0,10 57 prog[1]=enc_i(2,0,20,0) // ADDI x2,x0,20 58 prog[2]=enc_sw(0,1,0) // SW x1,0(x0) DMEM[0]=10 <- DATA ADDRESS 0 (the R17 fix) 59 prog[3]=enc_sw(0,2,1) // SW x2,1(x0) DMEM[1]=20 60 prog[4]=enc_lw(3,0,0) // LW x3,0(x0) x3=DMEM[0]=10 61 prog[5]=enc_lw(4,0,1) // LW x4,1(x0) x4=DMEM[1]=20 62 prog[6]=enc_r(5,3,4,0) // ADD x5,x3,x4 = 30 63 prog[7]=enc_i(0,0,0,0) // NOP (halt-ish) 64 let NSTEP: i64=7 65 66 var z: i64=0; while z<inc { IQ[z]=0; z=z+1 } 67 var a: i64=0; while a < 8 { ram_write(IR,IW,IAB,IK,II,IS,pi,co,IQ,a,prog[a]); a=a+1 } 68 69 let ref: *i64=sys_mmap(8*16) as *i64; let refm: *i64=sys_mmap(8*16) as *i64 70 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 } 71 z=0; while z<R { ref[z]=0; z=z+1 } z=0; while z<MR { refm[z]=0; z=z+1 } 72 var mism: i64=0; var cmps: i64=0; var s: i64=0 73 while s < NSTEP { 74 let pc: i64=pc_read(W, PQ) 75 let instr: i64=ram_read(IR,IW,IAB,IK,II,IS,pi,co,IQ,IPO,pc) // FETCH from IMEM 76 let opcode: i64=instr&127; let rd: i64=(instr>>7)&7; let rs1: i64=(instr>>15)&7; let f3: i64=(instr>>12)&7 77 if opcode==3 { // LW 78 var imm: i64=(instr>>20)&4095; if (imm&2048)!=0 {imm=imm-4096} 79 let base: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1) 80 let addr: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,base,imm,0,1,1) 81 let ld: i64=ram_read(MR,W,MAB,MK,MI,MS,pi,co,MQ,MPO,addr) // LOAD from DMEM 82 if rd!=0 { rf_write(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,rd,ld); ref[rd]=refm[(ref[rs1]+imm)&7] } 83 } else { if opcode==35 { // SW 84 var imm: i64=(((instr>>25)&127)<<5)|((instr>>7)&31); if (imm&2048)!=0 {imm=imm-4096} 85 let rs2: i64=(instr>>20)&7 86 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) 87 let addr: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,base,imm,0,1,1) 88 ram_write(MR,W,MAB,MK,MI,MS,pi,co,MQ,addr,v); refm[(ref[rs1]+imm)&7]=ref[rs2] // STORE to DMEM 89 } else { // R/I ALU 90 var bval: i64=0; var refB: i64=0; var f7b5: i64=0 91 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 } 92 else { var imm: i64=(instr>>20)&4095; if (imm&2048)!=0 {imm=imm-4096} bval=imm; refB=imm } 93 let av: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1) 94 fab_decode_run(DI,DS,DP,pi,co,f3,f7b5,ctrl) 95 let res: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,av,bval,ctrl[0],ctrl[1],ctrl[2]) 96 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) } 97 } } 98 pc_tick(W,PKND,PINI,PSRC,pi,PCO,PQ,0,0) 99 var rr: i64=0; while rr<R { cmps=cmps+1; if rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rr)!=ref[rr] {mism=mism+1} rr=rr+1 } 100 var mm: i64=0; while mm<MR { cmps=cmps+1; if ram_read(MR,W,MAB,MK,MI,MS,pi,co,MQ,MPO,mm)!=refm[mm] {mism=mism+1} mm=mm+1 } 101 s=s+1 102 } 103 total=total+1; if mism==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 104 gw("T1 program FETCHED from IMEM + data in DMEM == behavioral (regfile + DMEM): " as *u8); gn(cmps); gw(" compares, mismatches=" as *u8); gn(mism); gw("\n" as *u8) 105 106 // T2: result + data address 0 107 let x5: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,5); let d0: i64=ram_read(MR,W,MAB,MK,MI,MS,pi,co,MQ,MPO,0) 108 total=total+1; var t2ok: i64=1; if x5!=30 {t2ok=0} if d0!=10 {t2ok=0} 109 if t2ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 110 gw("T2 x5 = DMEM[0]+DMEM[1] = " as *u8); gn(x5); gw(" (=30); DMEM address 0 holds " as *u8); gn(d0); gw(" (=10, stored+loaded at addr 0 via the RAM fabric)\n" as *u8) 111 112 // T3: never-brick 113 let q1: i64=pc_read(W,PQ); let q2: i64=pc_read(W,PQ) 114 total=total+1; if q1==q2 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 115 gw("T3 never-brick (#26): deterministic fetch+execute+memory, bounded step, zero hardware-state writes\n" as *u8) 116 117 // T4: liar-kill -- corrupt IMEM word 2 (the SW to address 0) into a NOP; the store never happens -> x5 wrong 118 z=0; while z<inc { IQ[z]=0; z=z+1 } a=0; while a<8 { ram_write(IR,IW,IAB,IK,II,IS,pi,co,IQ,a,prog[a]); a=a+1 } 119 ram_write(IR,IW,IAB,IK,II,IS,pi,co,IQ,2,enc_i(0,0,0,0)) // mem[2]: SW -> NOP (the store vanishes) 120 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 } 121 var s2: i64=0 122 while s2 < NSTEP { 123 let pc: i64=pc_read(W,PQ); let instr: i64=ram_read(IR,IW,IAB,IK,II,IS,pi,co,IQ,IPO,pc) 124 let opcode: i64=instr&127; let rd: i64=(instr>>7)&7; let rs1: i64=(instr>>15)&7; let f3: i64=(instr>>12)&7 125 if opcode==3 { var imm: i64=(instr>>20)&4095; if (imm&2048)!=0 {imm=imm-4096} let base: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1); let addr: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,base,imm,0,1,1); let ld: i64=ram_read(MR,W,MAB,MK,MI,MS,pi,co,MQ,MPO,addr); if rd!=0 {rf_write(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,rd,ld)} } 126 else { if opcode==35 { var imm: i64=(((instr>>25)&127)<<5)|((instr>>7)&31); if (imm&2048)!=0 {imm=imm-4096} let rs2: i64=(instr>>20)&7; 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); let addr: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,base,imm,0,1,1); ram_write(MR,W,MAB,MK,MI,MS,pi,co,MQ,addr,v) } 127 else { var bval: i64=0; var f7b5: i64=0; if opcode==51 {let rs2: i64=(instr>>20)&7; bval=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs2); f7b5=(instr>>30)&1} else {var imm: i64=(instr>>20)&4095; if (imm&2048)!=0 {imm=imm-4096} bval=imm} let av: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1); fab_decode_run(DI,DS,DP,pi,co,f3,f7b5,ctrl); let res: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,av,bval,ctrl[0],ctrl[1],ctrl[2]); if rd!=0 {rf_write(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,rd,res)} } } 128 pc_tick(W,PKND,PINI,PSRC,pi,PCO,PQ,0,0) 129 s2=s2+1 130 } 131 let bx5: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,5) 132 total=total+1; if bx5 != 30 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 133 gw("T4 liar-kill: corrupting IMEM word 2 (the store to addr 0) -> x5=" as *u8); gn(bx5); gw(" != 30 (the machine's result depends on what is in memory)\n" as *u8) 134 135 gw("\n=== nx_fpga_cpu8_gate " as *u8); gn(pass); gw("/" as *u8); gn(total) 136 if pass == total { gw(" GREEN (a UNIFIED von Neumann CPU: fetches code from an IMEM RAM fabric + stores/loads data in a DMEM RAM fabric incl ADDRESS 0 == behavioral)\n" as *u8); sys_exit(0); return 0 } 137 gw(" RED\n" as *u8); sys_exit(1); return 1 138}