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}