code wiki / _hdl_build / nx_fpga_cpu2_gate.nx

nx_fpga_cpu2_gate.nx source

↩ module page · 166 lines · 10294 B

1import "nx_gate_gn.nx" 2import "nx_gate_base.nx" 3// nx_fpga_cpu2_gate.nx -- GATE for RUNG 12: the fabric CPU widened to I-TYPE IMMEDIATES (OP-IMM), so a 4// SELF-CONTAINED program runs from zero state (no pre-load -- the R11 crutch removed). Adds: opcode discrimination 5// (R-type 0x33 vs OP-IMM 0x13), 12-bit immediate extraction + SIGN-EXTENSION, and an operand-B mux (rs2 value vs 6// the immediate). The fabric ALU/shift/compare + decoder datapaths (R9) are REUSED unchanged -- the immediate is 7// just the second operand. Proven step-for-step vs the behavioral nx_rv64im_alu_compute. 8// T1 SELF-CONTAINED program (ADDI bootstrap + R-type + I-type incl a NEGATIVE immediate) == reference, every reg. 9// T2 final state spot-check (incl sign-extended ADDI x7=x3-10=127). T3 NEVER-BRICK. T4 LIAR-KILL. 10// GREEN iff all pass. 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_r(rd: i64, rs1: i64, rs2: i64, f3: i64, f7b5: i64) -> i64 { 33 var funct7: i64 = 0; if f7b5 == 1 { funct7 = 32 } 34 return (funct7 << 25) | (rs2 << 20) | (rs1 << 15) | (f3 << 12) | (rd << 7) | 51 // 0x33 35} 36func enc_i(rd: i64, rs1: i64, imm: i64, f3: i64) -> i64 { 37 return ((imm & 4095) << 20) | (rs1 << 15) | (f3 << 12) | (rd << 7) | 19 // 0x13, imm[11:0] 38} 39 40// fabric execute: decode (funct3,f7b5) on the fabric -> dispatch to the datapath fabric. 41func 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 { 42 fab_decode_run(DI, DS, DP, pi, co, f3, f7b5, ctrl) 43 let cls: i64 = ctrl[6] | (ctrl[7] << 1) 44 if cls == 0 { return fab_alu_run(64, anpi, AI, AS, AP, pi, co, a, b, ctrl[0], ctrl[1], ctrl[2]) } 45 if cls == 1 { return fab_shift_run(64, snpi, SI, SS, SP, pi, co, a, b & 63, ctrl[3], ctrl[4]) } 46 return fab_cmp_run(64, cnpi, CI, CS, CP, pi, co, a, b, ctrl[5]) 47} 48 49func main() -> i64 { 50 gw("=== nx_fpga_cpu2_gate: RUNG 12 -- the fabric CPU + I-TYPE immediates: a SELF-CONTAINED program runs ===\n" as *u8) 51 var pass: i64 = 0; var total: i64 = 0 52 let R: i64 = 8; let W: i64 = 64; let AB: i64 = 3 53 54 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 55 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 56 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 57 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 58 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 59 fab_build_decode(DI, DS, DP) 60 let anpi: i64 = fab_build_alu(64, AI, AS, AP) 61 let cnpi: i64 = fab_build_cmp(64, CI, CS, CP) 62 let snpi: i64 = fab_build_shifter(64, SI, SS, SP) 63 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 64 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 65 seq_build_regfile(R, W, AB, RKND, RINI, RSRC, RP) 66 let rnc: i64 = rf_ncells(R, W) 67 68 let ref: *i64 = sys_mmap(8 * 16) as *i64 69 let prog: *i64 = sys_mmap(8 * 16) as *i64 70 // SELF-CONTAINED program -- starts from x0=0, bootstraps with ADDI (no pre-load) 71 prog[0]=enc_i(1, 0, 100, 0) // ADDI x1, x0, 100 -> 100 72 prog[1]=enc_i(2, 0, 37, 0) // ADDI x2, x0, 37 -> 37 73 prog[2]=enc_r(3, 1, 2, 0, 0) // ADD x3, x1, x2 -> 137 74 prog[3]=enc_r(4, 1, 2, 0, 1) // SUB x4, x1, x2 -> 63 75 prog[4]=enc_i(5, 1, 255, 4) // XORI x5, x1, 0xFF -> 100^255 76 prog[5]=enc_i(6, 2, 4, 1) // SLLI x6, x2, 4 -> 37<<4 (imm[10]=0 -> logical) 77 prog[6]=enc_i(7, 3, 0-10, 0) // ADDI x7, x3, -10 -> 127 (SIGN-EXTENDED negative immediate) 78 prog[7]=enc_r(1, 4, 3, 2, 0) // SLT x1, x4, x3 -> 63<137=1 (overwrite x1) 79 let nprog: i64 = 8 80 81 // ---- run; compare fabric regfile to reference after every step ---- 82 var z: i64 = 0; while z < rnc { RQ[z] = 0; z = z + 1 } 83 z = 0; while z < R { ref[z] = 0; z = z + 1 } 84 var mism: i64 = 0; var steps: i64 = 0 85 var ic: i64 = 0 86 while ic < nprog { 87 let instr: i64 = prog[ic] 88 let opcode: i64 = instr & 127 89 let rd: i64 = (instr >> 7) & 7 90 let rs1: i64 = (instr >> 15) & 7 91 let f3: i64 = (instr >> 12) & 7 92 var bval: i64 = 0; var refB: i64 = 0; var f7b5: i64 = 0 93 if opcode == 51 { // R-type 0x33 94 let rs2: i64 = (instr >> 20) & 7 95 bval = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, rs2) 96 refB = ref[rs2] 97 f7b5 = (instr >> 30) & 1 98 } else { // I-type OP-IMM 0x13 99 var imm: i64 = (instr >> 20) & 4095 // imm[11:0] 100 if (imm & 2048) != 0 { imm = imm - 4096 } // SIGN-EXTEND (bit 11) 101 bval = imm; refB = imm 102 if f3 == 1 { f7b5 = (instr >> 30) & 1 } // SLLI 103 if f3 == 5 { f7b5 = (instr >> 30) & 1 } // SRLI/SRAI (imm[10]) 104 } 105 let aval: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, rs1) 106 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, aval, bval) 107 if rd != 0 { rf_write(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, rd, res) } 108 let refres: i64 = nx_rv64im_alu_compute(ref_aluop(f3, f7b5), ref[rs1], refB) 109 if rd != 0 { ref[rd] = refres } 110 var rr: i64 = 0 111 while rr < R { 112 steps = steps + 1 113 if rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, rr) != ref[rr] { mism = mism + 1 } 114 rr = rr + 1 115 } 116 ic = ic + 1 117 } 118 total=total+1; if mism==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 119 gw("T1 self-contained program (ADDI bootstrap + R/I-type) == behavioral, step-for-step: " as *u8); gn(steps); gw(" register-compares (8 instrs x 8 regs), mismatches=" as *u8); gn(mism); gw("\n" as *u8) 120 121 // ---- T2: final-state spot-checks ---- 122 let x6: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, 6) 123 let x7: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, 7) 124 let x1: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, 1) 125 total=total+1 126 var t2ok: i64 = 1 127 if x6 != (37 << 4) { t2ok = 0 } // SLLI 37<<4 = 592 128 if x7 != 127 { t2ok = 0 } // ADDI x3(137) + (-10) = 127 (sign-extend) 129 if x1 != 1 { t2ok = 0 } // SLT 63<137 = 1 130 if t2ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 131 gw("T2 final state: x6=" as *u8); gn(x6); gw(" (37<<4=592) x7=" as *u8); gn(x7); gw(" (137 + -10 = 127, sign-extended) x1=" as *u8); gn(x1); gw(" (SLT=1)\n" as *u8) 132 133 // ---- T3: never-brick ---- 134 let y1: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, 7) 135 let y2: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, 7) 136 total=total+1; if y1==y2 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 137 gw("T3 never-brick (#26): deterministic, bounded per-instruction step, zero hardware-state writes\n" as *u8) 138 139 // ---- T4: liar-kill -- corrupt the decoder class LUT -> the program diverges ---- 140 DI[6] = DI[6] ^ 0xffff 141 z = 0; while z < rnc { RQ[z] = 0; z = z + 1 } 142 let rf2: *i64 = sys_mmap(8 * 16) as *i64 143 z = 0; while z < R { rf2[z] = 0; z = z + 1 } 144 ic = 0 145 while ic < nprog { 146 let instr: i64 = prog[ic] 147 let opcode: i64 = instr & 127 148 let rd: i64=(instr>>7)&7; let rs1: i64=(instr>>15)&7; let f3: i64=(instr>>12)&7 149 var bval: i64=0; var refB: i64=0; var f7b5: i64=0 150 if opcode == 51 { let rs2: i64=(instr>>20)&7; bval=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs2); refB=rf2[rs2]; f7b5=(instr>>30)&1 } 151 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 } } 152 let aval: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, rs1) 153 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, aval, bval) 154 if rd != 0 { rf_write(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, rd, res) } 155 if rd != 0 { rf2[rd] = nx_rv64im_alu_compute(ref_aluop(f3,f7b5), rf2[rs1], refB) } 156 ic = ic + 1 157 } 158 var liar: i64 = 0; var rr: i64 = 0 159 while rr < R { if rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, rr) != rf2[rr] { liar = liar + 1 } rr = rr + 1 } 160 total=total+1; if liar > 0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 161 gw("T4 liar-kill: scrambling the decoder class LUT -> the program diverges in " as *u8); gn(liar); gw(" registers\n" as *u8) 162 163 gw("\n=== nx_fpga_cpu2_gate " as *u8); gn(pass); gw("/" as *u8); gn(total) 164 if pass == total { gw(" GREEN (a SELF-CONTAINED R-type + I-type-immediate program runs on the simulated FPGA == the behavioral CPU; no pre-load)\n" as *u8); sys_exit(0); return 0 } 165 gw(" RED\n" as *u8); sys_exit(1); return 1 166}