code wiki / _hdl_build / nx_fpga_cpu4_gate.nx

nx_fpga_cpu4_gate.nx source

↩ module page · 151 lines · 10222 B

1import "nx_gate_gn.nx" 2import "nx_gate_base.nx" 3// nx_fpga_cpu4_gate.nx -- GATE for RUNG 14: MEMORY -- the fabric CPU gains LOADS/STORES (LW/SW) + a DATA MEMORY. 4// A data memory IS an addressed clocked RAM == the register file (R10), so ONE regfile fabric is built and given 5// TWO state arrays: RQ (the 8 registers) + DQ (an 8-word data memory). The load/store address (rs1 + imm) is 6// computed ON THE FABRIC ALU; the access reads/writes the DQ memory fabric. Proven: a store->load roundtrip 7// program leaves the register file AND the data memory == the behavioral reference, step-for-step. 8// T1 ROUNDTRIP == reference: SW 100->mem[3], 200->mem[5]; LW back to x4/x5; ADD x6=300 -- regfile + memory match. 9// T2 final state (x4=100, x5=200, x6=300; mem[3]=100, mem[5]=200). T3 NEVER-BRICK. T4 LIAR-KILL. 10// (Builds on R12 R/I-type; branches are R13 -- combined in R15. expect_exit: 0 license_tier: ORIGINAL) 11import "nx_fpga_decode.nx" 12import "nx_fpga_alu.nx" 13import "nx_fpga_cmp.nx" 14import "nx_fpga_shift.nx" 15import "nx_fpga_regfile.nx" 16import "rv64im_min_alu.nx" 17import "nx_syscalls.nx" 18 19func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw(" 20" as *u8); return ok } 21 22func ref_aluop(f3: i64, f7b5: i64) -> i64 { 23 if f3==0 { if f7b5==1 { return NX_RV64IM_ALU_SUB } return NX_RV64IM_ALU_ADD } 24 if f3==1 { return NX_RV64IM_ALU_SLL } 25 if f3==2 { return NX_RV64IM_ALU_SLT } 26 if f3==3 { return NX_RV64IM_ALU_SLTU } 27 if f3==4 { return NX_RV64IM_ALU_XOR } 28 if f3==5 { if f7b5==1 { return NX_RV64IM_ALU_SRA } return NX_RV64IM_ALU_SRL } 29 if f3==6 { return NX_RV64IM_ALU_OR } 30 return NX_RV64IM_ALU_AND 31} 32func enc_i(rd: i64, rs1: i64, imm: i64, f3: i64) -> i64 { return ((imm & 4095) << 20) | (rs1 << 15) | (f3 << 12) | (rd << 7) | 19 } 33func enc_r(rd: i64, rs1: i64, rs2: i64, f3: i64, f7b5: i64) -> i64 { var f7: i64=0; if f7b5==1 {f7=32} return (f7<<25)|(rs2<<20)|(rs1<<15)|(f3<<12)|(rd<<7)|51 } 34func enc_lw(rd: i64, rs1: i64, imm: i64) -> i64 { return ((imm & 4095) << 20) | (rs1 << 15) | (2 << 12) | (rd << 7) | 3 } // 0x03, funct3=2 35func enc_sw(rs1: i64, rs2: i64, imm: i64) -> i64 { return (((imm >> 5) & 127) << 25) | (rs2 << 20) | (rs1 << 15) | (2 << 12) | ((imm & 31) << 7) | 35 } // 0x23, funct3=2 36 37func cpu_exec(DI: *i64, DS: *i64, DP: *i64, AI: *i64, AS: *i64, AP: *i64, anpi: i64, CI: *i64, CS: *i64, CP: *i64, cnpi: i64, SI: *i64, SS: *i64, SP: *i64, snpi: i64, pi: *i64, co: *i64, ctrl: *i64, f3: i64, f7b5: i64, a: i64, b: i64) -> i64 { 38 fab_decode_run(DI, DS, DP, pi, co, f3, f7b5, ctrl) 39 let cls: i64 = ctrl[6] | (ctrl[7] << 1) 40 if cls == 0 { return fab_alu_run(64, anpi, AI, AS, AP, pi, co, a, b, ctrl[0], ctrl[1], ctrl[2]) } 41 if cls == 1 { return fab_shift_run(64, snpi, SI, SS, SP, pi, co, a, b & 63, ctrl[3], ctrl[4]) } 42 return fab_cmp_run(64, cnpi, CI, CS, CP, pi, co, a, b, ctrl[5]) 43} 44 45func main() -> i64 { 46 gw("=== nx_fpga_cpu4_gate: RUNG 14 -- MEMORY: the fabric CPU + LOADS/STORES (LW/SW) + a data-memory fabric ===\n" as *u8) 47 var pass: i64 = 0; var total: i64 = 0 48 let R: i64 = 8; let W: i64 = 64; let AB: i64 = 3 49 50 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 51 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 52 let CI: *i64=sys_mmap(8*256) as *i64; let CS: *i64=sys_mmap(8*1056) as *i64; let CP: *i64=sys_mmap(8*72) as *i64 53 let SI: *i64=sys_mmap(8*800) as *i64; let SS: *i64=sys_mmap(8*3200) as *i64; let SP: *i64=sys_mmap(8*72) as *i64 54 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 55 fab_build_decode(DI, DS, DP) 56 let anpi: i64 = fab_build_alu(64, AI, AS, AP) 57 let cnpi: i64 = fab_build_cmp(64, CI, CS, CP) 58 let snpi: i64 = fab_build_shifter(64, SI, SS, SP) 59 // ONE regfile fabric, TWO state arrays: RQ = registers, DQ = data memory 60 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 61 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 62 let DQ: *i64=sys_mmap(8*2048) as *i64 63 seq_build_regfile(R, W, AB, RKND, RINI, RSRC, RP) 64 let rnc: i64 = rf_ncells(R, W) 65 66 let ref: *i64 = sys_mmap(8 * 16) as *i64 67 let refmem: *i64 = sys_mmap(8 * 16) as *i64 68 let prog: *i64 = sys_mmap(8 * 16) as *i64 69 prog[0]=enc_i(1, 0, 100, 0) // ADDI x1,x0,100 70 prog[1]=enc_i(2, 0, 200, 0) // ADDI x2,x0,200 71 prog[2]=enc_sw(0, 1, 3) // SW x1, 3(x0) -> mem[3]=100 72 prog[3]=enc_sw(0, 2, 5) // SW x2, 5(x0) -> mem[5]=200 73 prog[4]=enc_lw(4, 0, 3) // LW x4, 3(x0) -> x4=mem[3]=100 74 prog[5]=enc_lw(5, 0, 5) // LW x5, 5(x0) -> x5=mem[5]=200 75 prog[6]=enc_r(6, 4, 5, 0, 0) // ADD x6,x4,x5 -> 300 (uses loaded values) 76 let nprog: i64 = 7 77 78 // ---- T1: run; compare regfile + data memory to the reference after every step ---- 79 var z: i64 = 0; while z < rnc { RQ[z]=0; DQ[z]=0; z=z+1 } 80 z = 0; while z < R { ref[z]=0; refmem[z]=0; z=z+1 } 81 var mism: i64 = 0; var cmps: i64 = 0 82 var ic: i64 = 0 83 while ic < nprog { 84 let instr: i64 = prog[ic] 85 let opcode: i64 = instr & 127 86 let rd: i64=(instr>>7)&7; let rs1: i64=(instr>>15)&7; let f3: i64=(instr>>12)&7 87 if opcode == 3 { // LW (load) 88 var imm: i64=(instr>>20)&4095; if (imm&2048)!=0 {imm=imm-4096} 89 let base: i64 = rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1) 90 let addr: i64 = fab_alu_run(64,anpi,AI,AS,AP,pi,co,base,imm,0,1,1) // addr = rs1 + imm (fabric ALU) 91 let loaded: i64 = rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,DQ,RP,addr) // data-memory read 92 if rd != 0 { rf_write(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,rd,loaded) } 93 if rd != 0 { ref[rd] = refmem[(ref[rs1]+imm)&7] } 94 } else { if opcode == 35 { // SW (store) 95 var imm: i64=(((instr>>25)&127)<<5)|((instr>>7)&31); if (imm&2048)!=0 {imm=imm-4096} 96 let rs2: i64=(instr>>20)&7 97 let base: i64 = rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1) 98 let val: i64 = rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs2) 99 let addr: i64 = fab_alu_run(64,anpi,AI,AS,AP,pi,co,base,imm,0,1,1) 100 rf_write(R,W,AB,RKND,RINI,RSRC,pi,RCO,DQ,addr,val) // data-memory write 101 refmem[(ref[rs1]+imm)&7] = ref[rs2] 102 } else { // R/I-type 103 var bval: i64=0; var refB: i64=0; var f7b5: i64=0 104 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 } 105 else { var imm: i64=(instr>>20)&4095; if (imm&2048)!=0 {imm=imm-4096} bval=imm; refB=imm; if f3==1 {f7b5=(instr>>30)&1} if f3==5 {f7b5=(instr>>30)&1} } 106 let av: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1) 107 let res: i64=cpu_exec(DI,DS,DP,AI,AS,AP,anpi,CI,CS,CP,cnpi,SI,SS,SP,snpi,pi,co,ctrl,f3,f7b5,av,bval) 108 if rd != 0 { rf_write(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,rd,res) } 109 if rd != 0 { ref[rd]=nx_rv64im_alu_compute(ref_aluop(f3,f7b5),ref[rs1],refB) } 110 } } 111 // compare registers + memory 112 var rr: i64 = 0 113 while rr < R { 114 cmps = cmps + 2 115 if rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rr) != ref[rr] { mism = mism + 1 } 116 if rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,DQ,RP,rr) != refmem[rr] { mism = mism + 1 } 117 rr = rr + 1 118 } 119 ic = ic + 1 120 } 121 total=total+1; if mism==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 122 gw("T1 store->load roundtrip == behavioral (regfile + data memory), step-for-step: " as *u8); gn(cmps); gw(" compares, mismatches=" as *u8); gn(mism); gw("\n" as *u8) 123 124 // ---- T2: final state ---- 125 let x4: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,4); let x5: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,5); let x6: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,6) 126 let m3: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,DQ,RP,3); let m5: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,DQ,RP,5) 127 total=total+1 128 var t2ok: i64 = 1 129 if x4!=100 {t2ok=0} if x5!=200 {t2ok=0} if x6!=300 {t2ok=0} if m3!=100 {t2ok=0} if m5!=200 {t2ok=0} 130 if t2ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 131 gw("T2 final: mem[3]=" as *u8); gn(m3); gw(" mem[5]=" as *u8); gn(m5); gw(" -> LW -> x4=" as *u8); gn(x4); gw(" x5=" as *u8); gn(x5); gw(" -> ADD x6=" as *u8); gn(x6); gw(" (=300)\n" as *u8) 132 133 // ---- T3: never-brick ---- 134 let y1: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,DQ,RP,3); let y2: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,DQ,RP,3) 135 total=total+1; if y1==y2 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 136 gw("T3 never-brick (#26): deterministic memory reads, bounded, zero hardware-state writes\n" as *u8) 137 138 // ---- T4: liar-kill -- corrupt a data-memory write-decode LUT -> a store lands wrong ---- 139 RINI[R*W + 1 + 3] = RINI[R*W + 1 + 3] ^ 0xffff // wsel LUT of memory word 3 (cell R*W+1+3) 140 z = 0; while z < rnc { RQ[z]=0; DQ[z]=0; z=z+1 } 141 let base0: i64=0 142 let a0: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,base0,3,0,1,1) 143 rf_write(R,W,AB,RKND,RINI,RSRC,pi,RCO,DQ,a0,12345) 144 let got: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,DQ,RP,3) 145 total=total+1; if got != 12345 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 146 gw("T4 liar-kill: corrupting a data-memory write-decode LUT -> store to mem[3] lands wrong (read=" as *u8); gn(got); gw(")\n" as *u8) 147 148 gw("\n=== nx_fpga_cpu4_gate " as *u8); gn(pass); gw("/" as *u8); gn(total) 149 if pass == total { gw(" GREEN (LW/SW + a data memory run on the simulated FPGA == the behavioral CPU; a program stores to memory and loads it back)\n" as *u8); sys_exit(0); return 0 } 150 gw(" RED\n" as *u8); sys_exit(1); return 1 151}