code wiki / _hdl_build / nx_fpga_cpu_gate.nx

nx_fpga_cpu_gate.nx source

↩ module page · 172 lines · 10298 B

1import "nx_gate_gn.nx" 2import "nx_gate_base.nx" 3// nx_fpga_cpu_gate.nx -- GATE for RUNG 11: a RUNNING CPU on the simulated FPGA. Composes the fabric REGISTER 4// FILE (R10, real DFF state) + the R9 DECODE + ALU/shift/compare datapaths into a per-instruction step: 5// fetch instr[PC] -> decode fields (rd,rs1,rs2,funct3,funct7b5) -> read reg[rs1],reg[rs2] FROM THE FABRIC -> 6// execute ON THE FABRIC (decode->ALU/shift/cmp) -> writeback reg[rd] TO THE FABRIC (clocked, x0 ignored) -> PC++. 7// Runs a multi-instruction R-type program (incl DATA DEPENDENCIES) and proves the fabric register file evolves 8// STEP-FOR-STEP identically to the behavioral reference (decode -> nx_rv64im_alu_compute). The register STATE and 9// the EXECUTE run on the fabric; fetch/PC/field-extract are the orchestration (the monolithic single-fabric fold 10// is the R9b/R11-mono follow-on). R=8 registers (x0-x7), W=64. 11// T1 PROGRAM-RUN == reference, every register every step. T2 final state spot-check (incl a data-dependency). 12// T3 NEVER-BRICK. T4 LIAR-KILL -- corrupt the fabric ALU -> the run diverges from the reference. 13// GREEN iff all pass. expect_exit: 0 license_tier: ORIGINAL 14import "nx_fpga_decode.nx" 15import "nx_fpga_alu.nx" 16import "nx_fpga_cmp.nx" 17import "nx_fpga_shift.nx" 18import "nx_fpga_regfile.nx" 19import "rv64im_min_alu.nx" 20import "nx_syscalls.nx" 21 22func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw(" 23" as *u8); return ok } 24 25func enc(rd: i64, rs1: i64, rs2: i64, f3: i64, f7b5: i64) -> i64 { 26 var funct7: i64 = 0 27 if f7b5 == 1 { funct7 = 32 } // 0x20 (bit 5 set) 28 return (funct7 << 25) | (rs2 << 20) | (rs1 << 15) | (f3 << 12) | (rd << 7) | 51 // opcode 0x33 29} 30func ref_aluop(f3: i64, f7b5: i64) -> i64 { 31 if f3==0 { if f7b5==1 { return NX_RV64IM_ALU_SUB } return NX_RV64IM_ALU_ADD } 32 if f3==1 { return NX_RV64IM_ALU_SLL } 33 if f3==2 { return NX_RV64IM_ALU_SLT } 34 if f3==3 { return NX_RV64IM_ALU_SLTU } 35 if f3==4 { return NX_RV64IM_ALU_XOR } 36 if f3==5 { if f7b5==1 { return NX_RV64IM_ALU_SRA } return NX_RV64IM_ALU_SRL } 37 if f3==6 { return NX_RV64IM_ALU_OR } 38 return NX_RV64IM_ALU_AND 39} 40 41// fabric execute: decode (funct3,f7b5) on the fabric -> dispatch to the right datapath fabric. ctx-free globals via params. 42func 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 { 43 fab_decode_run(DI, DS, DP, pi, co, f3, f7b5, ctrl) 44 let cls: i64 = ctrl[6] | (ctrl[7] << 1) 45 if cls == 0 { return fab_alu_run(64, anpi, AI, AS, AP, pi, co, a, b, ctrl[0], ctrl[1], ctrl[2]) } 46 if cls == 1 { return fab_shift_run(64, snpi, SI, SS, SP, pi, co, a, b & 63, ctrl[3], ctrl[4]) } 47 return fab_cmp_run(64, cnpi, CI, CS, CP, pi, co, a, b, ctrl[5]) 48} 49 50func main() -> i64 { 51 gw("=== nx_fpga_cpu_gate: RUNG 11 -- a RUNNING CPU on the simulated FPGA (fabric regfile + decode/execute) ===\n" as *u8) 52 var pass: i64 = 0; var total: i64 = 0 53 let R: i64 = 8; let W: i64 = 64; let AB: i64 = 3 54 55 // datapath fabrics 56 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 57 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 58 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 59 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 60 let pi: *i64=sys_mmap(8*160) as *i64; let co: *i64=sys_mmap(8*2200) as *i64; let ctrl: *i64=sys_mmap(8*16) as *i64 61 fab_build_decode(DI, DS, DP) 62 let anpi: i64 = fab_build_alu(64, AI, AS, AP) 63 let cnpi: i64 = fab_build_cmp(64, CI, CS, CP) 64 let snpi: i64 = fab_build_shifter(64, SI, SS, SP) 65 // register file fabric (R=8 x W=64) + its persistent state q 66 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 67 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 68 let rnpi: i64 = seq_build_regfile(R, W, AB, RKND, RINI, RSRC, RP) 69 let rnc: i64 = rf_ncells(R, W) 70 var z: i64 = 0 71 while z < rnc { RQ[z] = 0; z = z + 1 } 72 73 // reference register file (software) 74 let ref: *i64 = sys_mmap(8 * 16) as *i64 75 z = 0; while z < R { ref[z] = 0; z = z + 1 } 76 77 // PRELOAD x1..x4 (both fabric + reference) -- the program's initial register state 78 let pa: *i64 = sys_mmap(8*8) as *i64; let pv: *i64 = sys_mmap(8*8) as *i64 79 pa[0]=1; pv[0]=100; pa[1]=2; pv[1]=37; pa[2]=3; pv[2]=255; pa[3]=4; pv[3]=4 80 var p: i64 = 0 81 while p < 4 { 82 rf_write(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, pa[p], pv[p]) 83 ref[pa[p]] = pv[p] 84 p = p + 1 85 } 86 87 // PROGRAM (R-type): rd, rs1, rs2, funct3, funct7b5 88 let prog: *i64 = sys_mmap(8 * 16) as *i64 89 prog[0]=enc(5,1,2,0,0) // x5 = x1 + x2 (ADD) 90 prog[1]=enc(6,1,3,4,0) // x6 = x1 ^ x3 (XOR) 91 prog[2]=enc(7,5,6,0,0) // x7 = x5 + x6 (ADD -- DATA DEPENDENCY on prior writes) 92 prog[3]=enc(5,2,4,1,0) // x5 = x2 << x4 (SLL, shamt=4 -- overwrite x5) 93 prog[4]=enc(6,1,2,2,0) // x6 = x1 < x2 (SLT signed = 0) 94 prog[5]=enc(7,3,4,5,0) // x7 = x3 >> x4 (SRL) 95 let nprog: i64 = 6 96 97 // ---- T1: run the program; compare the fabric regfile to the reference after EVERY step ---- 98 var mism: i64 = 0; var steps: i64 = 0 99 var ipc: i64 = 0 100 while ipc < nprog { 101 let instr: i64 = prog[ipc] 102 let rd: i64 = (instr >> 7) & 7 // R=8 -> low 3 bits 103 let rs1: i64 = (instr >> 15) & 7 104 let rs2: i64 = (instr >> 20) & 7 105 let f3: i64 = (instr >> 12) & 7 106 let f7b5: i64 = (instr >> 30) & 1 107 // FABRIC: read operands, execute, writeback 108 let a: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, rs1) 109 let b: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, rs2) 110 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, a, b) 111 if rd != 0 { rf_write(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, rd, res) } 112 // REFERENCE 113 let refres: i64 = nx_rv64im_alu_compute(ref_aluop(f3, f7b5), ref[rs1], ref[rs2]) 114 if rd != 0 { ref[rd] = refres } 115 // COMPARE all R registers 116 var rr: i64 = 0 117 while rr < R { 118 steps = steps + 1 119 if rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, rr) != ref[rr] { mism = mism + 1 } 120 rr = rr + 1 121 } 122 ipc = ipc + 1 123 } 124 total=total+1; if mism==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 125 gw("T1 program-run on fabric == behavioral reference: " as *u8); gn(steps); gw(" register-compares (6 instrs x 8 regs), mismatches=" as *u8); gn(mism); gw("\n" as *u8) 126 127 // ---- T2: final-state spot-checks (incl the data dependency x7=x5+x6 from step 3) ---- 128 let x5: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, 5) 129 let x6: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, 6) 130 let x7: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, 7) 131 total=total+1 132 var t2ok: i64 = 1 133 if x5 != ref[5] { t2ok = 0 } 134 if x6 != ref[6] { t2ok = 0 } 135 if x7 != ref[7] { t2ok = 0 } 136 if x7 != ((255 >> 4)) { t2ok = 0 } // final x7 = x3>>x4 = 255>>4 = 15 137 if t2ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 138 gw("T2 final state: x5=" as *u8); gn(x5); gw(" x6=" as *u8); gn(x6); gw(" x7=" as *u8); gn(x7); gw(" (x7 = x3>>x4 = 15) == reference\n" as *u8) 139 140 // ---- T3: never-brick (deterministic re-read) ---- 141 let y1: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, 5) 142 let y2: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, 5) 143 total=total+1; if y1==y2 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 144 gw("T3 never-brick (#26): deterministic, bounded per-instruction step, zero hardware-state writes\n" as *u8) 145 146 // ---- T4: liar-kill -- corrupt the DECODER's class LUT -> instructions mis-dispatch -> the program diverges ---- 147 DI[6] = DI[6] ^ 0xffff // scramble the decoder class0 LUT (R9 proved -> 8/10 mis-dispatch) 148 z = 0; while z < rnc { RQ[z] = 0; z = z + 1 } // reset regfile 149 let rf2: *i64 = sys_mmap(8 * 16) as *i64 150 z = 0; while z < R { rf2[z] = 0; z = z + 1 } 151 p = 0; while p < 4 { rf_write(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, pa[p], pv[p]); rf2[pa[p]] = pv[p]; p = p + 1 } 152 var liar_div: i64 = 0 153 ipc = 0 154 while ipc < nprog { 155 let instr: i64 = prog[ipc] 156 let rd: i64=(instr>>7)&7; let rs1: i64=(instr>>15)&7; let rs2: i64=(instr>>20)&7; let f3: i64=(instr>>12)&7; let f7b5: i64=(instr>>30)&1 157 let a: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, rs1) 158 let b: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, rs2) 159 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, a, b) 160 if rd != 0 { rf_write(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, rd, res) } 161 if rd != 0 { rf2[rd] = nx_rv64im_alu_compute(ref_aluop(f3,f7b5), rf2[rs1], rf2[rs2]) } 162 ipc = ipc + 1 163 } 164 var rr: i64 = 0 165 while rr < R { if rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, rr) != rf2[rr] { liar_div = liar_div + 1 } rr = rr + 1 } 166 total=total+1; if liar_div > 0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 167 gw("T4 liar-kill: scrambling the decoder class LUT mis-dispatches -> the program diverges in " as *u8); gn(liar_div); gw(" registers\n" as *u8) 168 169 gw("\n=== nx_fpga_cpu_gate " as *u8); gn(pass); gw("/" as *u8); gn(total) 170 if pass == total { gw(" GREEN (a multi-instruction R-type program RUNS on the simulated FPGA -- fabric regfile + decode/execute -- == the behavioral CPU, step-for-step)\n" as *u8); sys_exit(0); return 0 } 171 gw(" RED\n" as *u8); sys_exit(1); return 1 172}