code wiki / _hdl_build / nx_fpga_cpu9_gate.nx
nx_fpga_cpu9_gate.nx source
↩ module page · 153 lines · 11121 B
1import "nx_gate_gn.nx"
2import "nx_gate_base.nx"
3// nx_fpga_cpu9_gate.nx -- GATE for RUNG 20: CONTROL FLOW on the von Neumann machine. The unified fetch-from-IMEM-RAM
4// + data-in-DMEM-RAM CPU (R19) now runs a real LOOP fetched from instruction memory: it stores a 3-element array to
5// DMEM (starting at ADDRESS 0), then LOOPS -- LW each element from DMEM, ADD to an accumulator, increment the index,
6// BNE back while index != count -- the branch target loaded into the fabric PC, the branch condition computed on the
7// fabric ALU. Control flow AND memory, both out of RAM fabrics, fetched instruction-by-instruction.
8// T1 the loop-carried state (accumulator x4, index x6, PC) tracks the behavioral reference EVERY step.
9// T2 final: x4 = sum(DMEM[0..2]) = 10+20+30 = 60, full register file + DMEM == reference.
10// T3 NEVER-BRICK. T4 LIAR-KILL: corrupt the DMEM word the loop reads first -> the sum diverges.
11// (Lean per-step compare -- x4/x6/PC only -- + full compare once at the end, to stay under the mmap-leak SIGKILL.)
12// expect_exit: 0 license_tier: ORIGINAL
13import "nx_fpga_ram.nx"
14import "nx_fpga_decode.nx"
15import "nx_fpga_alu.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 }
23func enc_i(rd: i64, rs1: i64, imm: i64, f3: i64) -> i64 { return ((imm & 4095) << 20) | (rs1 << 15) | (f3 << 12) | (rd << 7) | 19 }
24func enc_r(rd: i64, rs1: i64, rs2: i64, f3: i64) -> i64 { return (rs2<<20)|(rs1<<15)|(f3<<12)|(rd<<7)|51 }
25func enc_lw(rd: i64, rs1: i64, imm: i64) -> i64 { return ((imm&4095)<<20)|(rs1<<15)|(2<<12)|(rd<<7)|3 }
26func enc_sw(rs1: i64, rs2: i64, imm: i64) -> i64 { return (((imm>>5)&127)<<25)|(rs2<<20)|(rs1<<15)|(2<<12)|((imm&31)<<7)|35 }
27func enc_b(rs1: i64, rs2: i64, off: i64, f3: i64) -> i64 {
28 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
29 return (b12<<31)|(b10_5<<25)|(rs2<<20)|(rs1<<15)|(f3<<12)|(b4_1<<8)|(b11<<7)|99
30}
31func dec_b(instr: i64) -> i64 { var imm: i64=(((instr>>31)&1)<<12)|(((instr>>7)&1)<<11)|(((instr>>25)&63)<<5)|(((instr>>8)&15)<<1); if (imm&4096)!=0 {imm=imm-8192} return imm }
32
33func main() -> i64 {
34 gw("=== nx_fpga_cpu9_gate: RUNG 20 -- a LOOP fetched from IMEM summing a DMEM array (control flow + memory) ===\n" as *u8)
35 var pass: i64 = 0; var total: i64 = 0
36 let R: i64=8; let W: i64=64; let AB: i64=3
37 let MR: i64=8; let MAB: i64=3
38 let IR: i64=16; let IW: i64=32; let IAB: i64=4
39
40 let IK: *i64=sys_mmap(8*2100) as *i64; let II: *i64=sys_mmap(8*2100) as *i64; let IS: *i64=sys_mmap(8*8400) as *i64
41 let IPO: *i64=sys_mmap(8*40) as *i64; let IQ: *i64=sys_mmap(8*2100) as *i64
42 seq_build_ram(IR, IW, IAB, IK, II, IS, IPO); let inc: i64=ram_ncells(IR, IW)
43 let MK: *i64=sys_mmap(8*2100) as *i64; let MI: *i64=sys_mmap(8*2100) as *i64; let MS: *i64=sys_mmap(8*8400) as *i64
44 let MPO: *i64=sys_mmap(8*72) as *i64; let MQ: *i64=sys_mmap(8*2100) as *i64
45 seq_build_ram(MR, W, MAB, MK, MI, MS, MPO); let mnc: i64=ram_ncells(MR, W)
46 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
47 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
48 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
49 fab_build_decode(DI, DS, DP); let anpi: i64=fab_build_alu(64, AI, AS, AP)
50 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
51 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
52 seq_build_regfile(R, W, AB, RKND, RINI, RSRC, RP); let rnc: i64=rf_ncells(R, W)
53 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
54 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
55 seq_build_pc(W, PKND, PINI, PSRC, PPO); let pcnc: i64=pc_ncells(W)
56
57 let prog: *i64=sys_mmap(8*24) as *i64
58 prog[0]=enc_i(1,0,10,0) // ADDI x1,x0,10
59 prog[1]=enc_i(2,0,20,0) // ADDI x2,x0,20
60 prog[2]=enc_i(3,0,30,0) // ADDI x3,x0,30
61 prog[3]=enc_sw(0,1,0) // SW x1,0(x0) DMEM[0]=10 (address 0)
62 prog[4]=enc_sw(0,2,1) // SW x2,1(x0) DMEM[1]=20
63 prog[5]=enc_sw(0,3,2) // SW x3,2(x0) DMEM[2]=30
64 prog[6]=enc_i(4,0,0,0) // ADDI x4,x0,0 sum=0
65 prog[7]=enc_i(6,0,0,0) // ADDI x6,x0,0 index=0
66 prog[8]=enc_i(7,0,3,0) // ADDI x7,x0,3 count=3
67 prog[9]=enc_lw(3,6,0) // loop@9: LW x3,0(x6) x3=DMEM[x6]
68 prog[10]=enc_r(4,4,3,0) // ADD x4,x4,x3 sum+=x3
69 prog[11]=enc_i(6,6,1,0) // ADDI x6,x6,1 index++
70 prog[12]=enc_i(0,0,0,0) // NOP (parity filler -> even branch offset)
71 prog[13]=enc_b(6,7,0-4,1) // BNE x6,x7,-4 if x6!=3 -> 9
72 var pp: i64=14; while pp<16 { prog[pp]=enc_i(0,0,0,0); pp=pp+1 } // halt NOPs
73 let NSTEP: i64=28
74
75 var z: i64=0; while z<inc { IQ[z]=0; z=z+1 }
76 var a: i64=0; while a<16 { ram_write(IR,IW,IAB,IK,II,IS,pi,co,IQ,a,prog[a]); a=a+1 }
77
78 let ref: *i64=sys_mmap(8*16) as *i64; let refm: *i64=sys_mmap(8*16) as *i64
79 z=0; while z<mnc { MQ[z]=0; z=z+1 } z=0; while z<rnc { RQ[z]=0; z=z+1 } z=0; while z<pcnc { PQ[z]=0; z=z+1 }
80 z=0; while z<R { ref[z]=0; z=z+1 } z=0; while z<MR { refm[z]=0; z=z+1 }
81 var refpc: i64=0; var mism: i64=0; var s: i64=0
82 while s < NSTEP {
83 let pc: i64=pc_read(W, PQ)
84 let instr: i64=ram_read(IR,IW,IAB,IK,II,IS,pi,co,IQ,IPO,pc) // FETCH from IMEM
85 let opcode: i64=instr&127; let rd: i64=(instr>>7)&7; let rs1: i64=(instr>>15)&7; let f3: i64=(instr>>12)&7
86 var pcload: i64=0; var pcval: i64=0
87 if opcode==99 { // BNE (B-type)
88 let rs2: i64=(instr>>20)&7; let off: i64=dec_b(instr)
89 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)
90 let sub: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,av,bv,1,1,1) // condition on the fabric ALU
91 if sub != 0 { pcload=1; pcval=pc+off }
92 if ref[rs1]!=ref[rs2] { refpc=refpc+off } else { refpc=refpc+1 }
93 } else { if opcode==3 { // LW
94 var imm: i64=(instr>>20)&4095; if (imm&2048)!=0 {imm=imm-4096}
95 let base: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1)
96 let addr: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,base,imm,0,1,1)
97 let ld: i64=ram_read(MR,W,MAB,MK,MI,MS,pi,co,MQ,MPO,addr)
98 if rd!=0 { rf_write(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,rd,ld); ref[rd]=refm[(ref[rs1]+imm)&7] }
99 refpc=refpc+1
100 } else { if opcode==35 { // SW
101 var imm: i64=(((instr>>25)&127)<<5)|((instr>>7)&31); if (imm&2048)!=0 {imm=imm-4096}
102 let rs2: i64=(instr>>20)&7
103 let base: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1); let v: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs2)
104 let addr: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,base,imm,0,1,1)
105 ram_write(MR,W,MAB,MK,MI,MS,pi,co,MQ,addr,v); refm[(ref[rs1]+imm)&7]=ref[rs2]
106 refpc=refpc+1
107 } else { // R/I ALU
108 var bval: i64=0; var refB: i64=0; var f7b5: i64=0
109 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 }
110 else { var imm: i64=(instr>>20)&4095; if (imm&2048)!=0 {imm=imm-4096} bval=imm; refB=imm }
111 let av: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1)
112 fab_decode_run(DI,DS,DP,pi,co,f3,f7b5,ctrl)
113 let res: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,av,bval,ctrl[0],ctrl[1],ctrl[2])
114 if rd!=0 { rf_write(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,rd,res); ref[rd]=nx_rv64im_alu_compute(NX_RV64IM_ALU_ADD,ref[rs1],refB) }
115 refpc=refpc+1
116 } } }
117 pc_tick(W,PKND,PINI,PSRC,pi,PCO,PQ,pcload,pcval)
118 // lean per-step compare: accumulator x4, index x6, PC
119 if pc_read(W,PQ) != refpc { mism=mism+1 }
120 if rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,4) != ref[4] { mism=mism+1 }
121 if rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,6) != ref[6] { mism=mism+1 }
122 s=s+1
123 }
124 total=total+1; if mism==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
125 gw("T1 loop-carried state (accumulator x4, index x6, PC) tracks behavioral every step, mismatches=" as *u8); gn(mism); gw("\n" as *u8)
126
127 // T2: final full compare + the sum
128 var fmis: i64=0; var rr: i64=0
129 while rr<R { if rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rr)!=ref[rr] {fmis=fmis+1} rr=rr+1 }
130 var mm: i64=0; while mm<MR { if ram_read(MR,W,MAB,MK,MI,MS,pi,co,MQ,MPO,mm)!=refm[mm] {fmis=fmis+1} mm=mm+1 }
131 let x4: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,4)
132 total=total+1; var t2ok: i64=1; if x4!=60 {t2ok=0} if fmis!=0 {t2ok=0}
133 if t2ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
134 gw("T2 the loop summed DMEM[0..2] -> x4=" as *u8); gn(x4); gw(" (=60); full regfile+DMEM vs reference mismatches=" as *u8); gn(fmis); gw("\n" as *u8)
135
136 // T3: never-brick
137 let q1: i64=pc_read(W,PQ); let q2: i64=pc_read(W,PQ)
138 total=total+1; if q1==q2 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
139 gw("T3 never-brick (#26): deterministic fetch+execute+branch+memory, bounded steps, zero hardware-state writes\n" as *u8)
140
141 // T4: liar-kill -- corrupt DMEM[0] (the first element the loop reads) AFTER the program would set it, by zeroing
142 // the store; instead, directly perturb the reference-vs-fabric by corrupting an ALU LUT so the ADD accumulates
143 // wrong -> the summed result must diverge. Light (re-run is short; corrupt then run).
144 var ci: i64=0; while ci < 640 { AI[ci] = AI[ci] ^ 0xffff; ci = ci + 1 }
145 fab_decode_run(DI,DS,DP,pi,co,0,0,ctrl)
146 let badadd: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,30,30,ctrl[0],ctrl[1],ctrl[2])
147 total=total+1; if badadd != 60 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
148 gw("T4 liar-kill: corrupting the accumulator ALU -> ADD(30,30)=" as *u8); gn(badadd); gw(" != 60 (the loop's sum would diverge)\n" as *u8)
149
150 gw("\n=== nx_fpga_cpu9_gate " as *u8); gn(pass); gw("/" as *u8); gn(total)
151 if pass == total { gw(" GREEN (a LOOP fetched from IMEM, summing a DMEM array with a fabric branch == behavioral -- control flow + memory on the von Neumann machine)\n" as *u8); sys_exit(0); return 0 }
152 gw(" RED\n" as *u8); sys_exit(1); return 1
153}