code wiki / _hdl_build / nx_fpga_cpu3_gate.nx
nx_fpga_cpu3_gate.nx source
↩ module page · 199 lines · 12696 B
1import "nx_gate_gn.nx"
2import "nx_gate_base.nx"
3// nx_fpga_cpu3_gate.nx -- GATE for RUNG 13: the fabric CPU with CONTROL FLOW. The PC is now a FABRIC REGISTER
4// (nx_fpga_pc, loadable up-counter) and the CPU executes B-TYPE BRANCHES: it fetches instr[PC], and on a branch
5// it computes the condition (rs1 vs rs2) ON THE FABRIC (ALU SUB for ==, the compare fabric for </>=) and either
6// LOADS the branch target into the PC or lets it increment. Runs a real LOOP (sum 1..3 with a backward BNE) and
7// proves the PC AND the register file evolve step-for-step == the behavioral reference. (PC is instruction-indexed;
8// branch offsets in instruction units -- a faithfulness simplification of RV byte addressing.)
9// T1 LOOP-RUN == reference: PC + all registers match every step (13 steps of a 3-iteration loop).
10// T2 final state: x2 = sum(1..3) = 6, x1 = 0 (loop terminated). T3 NEVER-BRICK. T4 LIAR-KILL.
11// GREEN iff all pass. expect_exit: 0 license_tier: ORIGINAL
12import "nx_fpga_decode.nx"
13import "nx_fpga_alu.nx"
14import "nx_fpga_cmp.nx"
15import "nx_fpga_shift.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 }
23
24func ref_aluop(f3: i64, f7b5: i64) -> i64 {
25 if f3==0 { if f7b5==1 { return NX_RV64IM_ALU_SUB } return NX_RV64IM_ALU_ADD }
26 if f3==1 { return NX_RV64IM_ALU_SLL }
27 if f3==2 { return NX_RV64IM_ALU_SLT }
28 if f3==3 { return NX_RV64IM_ALU_SLTU }
29 if f3==4 { return NX_RV64IM_ALU_XOR }
30 if f3==5 { if f7b5==1 { return NX_RV64IM_ALU_SRA } return NX_RV64IM_ALU_SRL }
31 if f3==6 { return NX_RV64IM_ALU_OR }
32 return NX_RV64IM_ALU_AND
33}
34func enc_i(rd: i64, rs1: i64, imm: i64, f3: i64) -> i64 { return ((imm & 4095) << 20) | (rs1 << 15) | (f3 << 12) | (rd << 7) | 19 }
35func 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 }
36// B-type: real RV immediate split (interpreted as instruction offset). off must be even (imm[0]=0).
37func enc_b(rs1: i64, rs2: i64, off: i64, f3: i64) -> i64 {
38 let b12: i64=(off>>12)&1; let b11: i64=(off>>11)&1; let b10_5: i64=(off>>5)&63; let b4_1: i64=(off>>1)&15
39 return (b12<<31)|(b10_5<<25)|(rs2<<20)|(rs1<<15)|(f3<<12)|(b4_1<<8)|(b11<<7)|99 // 0x63
40}
41func dec_btype(instr: i64) -> i64 {
42 var imm: i64 = (((instr>>31)&1)<<12) | (((instr>>7)&1)<<11) | (((instr>>25)&63)<<5) | (((instr>>8)&15)<<1)
43 if (imm & 4096) != 0 { imm = imm - 8192 }
44 return imm
45}
46
47func 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 {
48 fab_decode_run(DI, DS, DP, pi, co, f3, f7b5, ctrl)
49 let cls: i64 = ctrl[6] | (ctrl[7] << 1)
50 if cls == 0 { return fab_alu_run(64, anpi, AI, AS, AP, pi, co, a, b, ctrl[0], ctrl[1], ctrl[2]) }
51 if cls == 1 { return fab_shift_run(64, snpi, SI, SS, SP, pi, co, a, b & 63, ctrl[3], ctrl[4]) }
52 return fab_cmp_run(64, cnpi, CI, CS, CP, pi, co, a, b, ctrl[5])
53}
54
55func main() -> i64 {
56 gw("=== nx_fpga_cpu3_gate: RUNG 13 -- the fabric CPU with CONTROL FLOW (fabric PC + branches + a LOOP) ===\n" as *u8)
57 var pass: i64 = 0; var total: i64 = 0
58 let R: i64 = 8; let W: i64 = 64; let AB: i64 = 3
59
60 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
61 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
62 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
63 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
64 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
65 fab_build_decode(DI, DS, DP)
66 let anpi: i64 = fab_build_alu(64, AI, AS, AP)
67 let cnpi: i64 = fab_build_cmp(64, CI, CS, CP)
68 let snpi: i64 = fab_build_shifter(64, SI, SS, SP)
69 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
70 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
71 seq_build_regfile(R, W, AB, RKND, RINI, RSRC, RP)
72 let rnc: i64 = rf_ncells(R, W)
73 // fabric PC register
74 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
75 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
76 seq_build_pc(W, PKND, PINI, PSRC, PPO)
77 let pcnc: i64 = pc_ncells(W)
78
79 // PROGRAM (instruction-indexed): sum 1..3 via a backward-branch loop. padded with NOPs.
80 let prog: *i64 = sys_mmap(8 * 24) as *i64
81 prog[0]=enc_i(1,0,3,0) // ADDI x1,x0,3 (counter=3)
82 prog[1]=enc_i(2,0,0,0) // ADDI x2,x0,0 (sum=0)
83 prog[2]=enc_r(2,2,1,0,0) // ADD x2,x2,x1 (sum += counter) <- loop top (PC=2)
84 prog[3]=enc_i(1,1,0-1,0) // ADDI x1,x1,-1 (counter -= 1)
85 prog[4]=enc_b(1,0,0-2,1) // BNE x1,x0,-2 (if x1!=0 -> PC=2)
86 var pz: i64 = 5; while pz < 24 { prog[pz]=enc_i(0,0,0,0); pz=pz+1 } // NOP (ADDI x0,x0,0)
87
88 let ref: *i64 = sys_mmap(8 * 16) as *i64
89 let NSTEP: i64 = 13
90
91 // ---- T1: run; compare PC + regfile to the reference after every step ----
92 var z: i64 = 0; while z < rnc { RQ[z]=0; z=z+1 }
93 z = 0; while z < pcnc { PQ[z]=0; z=z+1 }
94 z = 0; while z < R { ref[z]=0; z=z+1 }
95 var refpc: i64 = 0
96 var mism: i64 = 0; var cmps: i64 = 0
97 var s: i64 = 0
98 while s < NSTEP {
99 let pc: i64 = pc_read(W, PQ)
100 let instr: i64 = prog[pc]
101 let opcode: i64 = instr & 127
102 let rd: i64=(instr>>7)&7; let rs1: i64=(instr>>15)&7; let f3: i64=(instr>>12)&7
103 var pcload: i64 = 0; var pcval: i64 = 0
104 if opcode == 99 { // B-type branch
105 let rs2: i64=(instr>>20)&7
106 let av: i64 = rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1)
107 let bv: i64 = rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs2)
108 let off: i64 = dec_btype(instr)
109 // condition ON THE FABRIC: BNE(1) via ALU SUB != 0
110 var taken: i64 = 0
111 if f3==1 { let sub: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,av,bv,1,1,1); if sub!=0 {taken=1} }
112 if f3==0 { let sub: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,av,bv,1,1,1); if sub==0 {taken=1} }
113 if f3==4 { taken=fab_cmp_run(64,cnpi,CI,CS,CP,pi,co,av,bv,0) }
114 if f3==5 { let lt: i64=fab_cmp_run(64,cnpi,CI,CS,CP,pi,co,av,bv,0); if lt==0 {taken=1} }
115 if f3==6 { taken=fab_cmp_run(64,cnpi,CI,CS,CP,pi,co,av,bv,1) }
116 if f3==7 { let lt: i64=fab_cmp_run(64,cnpi,CI,CS,CP,pi,co,av,bv,1); if lt==0 {taken=1} }
117 if taken==1 { pcload=1; pcval=pc+off }
118 // reference
119 var rtaken: i64 = 0
120 if f3==1 { if ref[rs1]!=ref[rs2] {rtaken=1} }
121 if f3==0 { if ref[rs1]==ref[rs2] {rtaken=1} }
122 if f3==4 { if ref[rs1]<ref[rs2] {rtaken=1} }
123 if f3==5 { if ref[rs1]>=ref[rs2] {rtaken=1} }
124 if f3==6 { rtaken=nx_rv64im_ltu(ref[rs1],ref[rs2]) }
125 if f3==7 { if nx_rv64im_ltu(ref[rs1],ref[rs2])==0 {rtaken=1} }
126 if rtaken==1 { refpc = refpc + off } else { refpc = refpc + 1 }
127 } else { // R/I-type
128 var bval: i64=0; var refB: i64=0; var f7b5: i64=0
129 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 }
130 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} }
131 let av: i64 = rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1)
132 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)
133 if rd != 0 { rf_write(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,rd,res) }
134 if rd != 0 { ref[rd] = nx_rv64im_alu_compute(ref_aluop(f3,f7b5), ref[rs1], refB) }
135 refpc = refpc + 1
136 }
137 pc_tick(W, PKND, PINI, PSRC, pi, PCO, PQ, pcload, pcval)
138 // COMPARE PC + all registers
139 cmps = cmps + 1
140 if pc_read(W, PQ) != refpc { mism = mism + 1 }
141 var rr: i64 = 0
142 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 }
143 s = s + 1
144 }
145 total=total+1; if mism==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
146 gw("T1 LOOP runs on the fabric == behavioral, step-for-step (PC + regfile): " as *u8); gn(cmps); gw(" compares over " as *u8); gn(NSTEP); gw(" steps, mismatches=" as *u8); gn(mism); gw("\n" as *u8)
147
148 // ---- T2: final state -- the loop computed sum(1..3) = 6, counter x1 = 0 ----
149 let x2: i64 = rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,2)
150 let x1: i64 = rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,1)
151 total=total+1; if x2==6 { if x1==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } } else { gw(" [FAIL] " as *u8) }
152 gw("T2 the loop computed sum(1..3): x2=" as *u8); gn(x2); gw(" (=6), x1=" as *u8); gn(x1); gw(" (counter hit 0 -> loop exited)\n" as *u8)
153
154 // ---- T3: never-brick (deterministic re-read of the PC) ----
155 let p1: i64 = pc_read(W, PQ); let p2: i64 = pc_read(W, PQ)
156 total=total+1; if p1==p2 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
157 gw("T3 never-brick (#26): deterministic PC + bounded step, zero hardware-state writes\n" as *u8)
158
159 // ---- T4: liar-kill -- corrupt the PC increment net -> the loop diverges from the reference ----
160 seq_build_pc(W, PKND, PINI, PSRC, PPO)
161 PINI[W + 1] = PINI[W + 1] ^ 0xffff
162 z = 0; while z < rnc { RQ[z]=0; z=z+1 }
163 z = 0; while z < pcnc { PQ[z]=0; z=z+1 }
164 let ref2: *i64 = sys_mmap(8*16) as *i64; z=0; while z<R { ref2[z]=0; z=z+1 }
165 var rpc2: i64 = 0; var s2: i64 = 0; var liar: i64 = 0
166 while s2 < NSTEP {
167 let pc: i64 = pc_read(W, PQ)
168 var fpc: i64 = pc; if fpc < 0 { fpc = 0 } if fpc > 23 { fpc = 23 }
169 let instr: i64 = prog[fpc]
170 let opcode: i64=instr&127; let rd: i64=(instr>>7)&7; let rs1: i64=(instr>>15)&7; let f3: i64=(instr>>12)&7
171 var pcload: i64=0; var pcval: i64=0
172 if opcode == 99 {
173 let rs2: i64=(instr>>20)&7
174 let av: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1); let bv: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs2)
175 let off: i64=dec_btype(instr)
176 var taken: i64=0; if f3==1 { let sub: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,av,bv,1,1,1); if sub!=0 {taken=1} }
177 if taken==1 { pcload=1; pcval=pc+off }
178 if ref2[rs1]!=ref2[rs2] { rpc2=rpc2+off } else { rpc2=rpc2+1 }
179 } else {
180 var bval: i64=0; var refB: i64=0; var f7b5: i64=0
181 if opcode==51 { let rs2: i64=(instr>>20)&7; bval=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs2); refB=ref2[rs2]; f7b5=(instr>>30)&1 }
182 else { var imm: i64=(instr>>20)&4095; if (imm&2048)!=0 {imm=imm-4096} bval=imm; refB=imm }
183 let av: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1)
184 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)
185 if rd!=0 { rf_write(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,rd,res) }
186 if rd!=0 { ref2[rd]=nx_rv64im_alu_compute(ref_aluop(f3,f7b5),ref2[rs1],refB) }
187 rpc2=rpc2+1
188 }
189 pc_tick(W, PKND, PINI, PSRC, pi, PCO, PQ, pcload, pcval)
190 if pc_read(W, PQ) != rpc2 { liar = liar + 1 }
191 s2 = s2 + 1
192 }
193 total=total+1; if liar > 0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
194 gw("T4 liar-kill: corrupting the fabric PC increment net -> the program-counter diverges in " as *u8); gn(liar); gw(" steps\n" as *u8)
195
196 gw("\n=== nx_fpga_cpu3_gate " as *u8); gn(pass); gw("/" as *u8); gn(total)
197 if pass == total { gw(" GREEN (a LOOP with branches runs on the simulated FPGA -- fabric PC + regfile + execute -- == the behavioral CPU, step-for-step)\n" as *u8); sys_exit(0); return 0 }
198 gw(" RED\n" as *u8); sys_exit(1); return 1
199}