code wiki / _hdl_build / nx_fpga_cpu7_gate.nx
nx_fpga_cpu7_gate.nx source
↩ module page · 121 lines · 8251 B
1import "nx_gate_gn.nx"
2import "nx_gate_base.nx"
3// nx_fpga_cpu7_gate.nx -- GATE for RUNG 18: INSTRUCTION FETCH FROM A MEMORY FABRIC (the von Neumann step). The CPU
4// no longer indexes a software prog[] array -- each step it FETCHES the instruction by reading the RAM fabric
5// (nx_fpga_ram, R17) at the PC: instr = ram_read(IMEM, PC). Then it decodes + executes on the fabric datapath
6// (regfile + decode + ALU + PC, as in R16). The program lives in the simulated memory; the machine reads it out.
7// T1 a program loaded into IMEM runs (fetch->decode->execute) and the registers == the behavioral reference.
8// T2 fetch integrity: ram_read(IMEM,addr) == each loaded instruction (the fetch reads real memory, not a shortcut).
9// T3 NEVER-BRICK. T4 LIAR-KILL: corrupt the MEMORY WORD holding instruction 2 -> the CPU fetches a different
10// instruction -> the result diverges (proof the CPU truly executes what is in memory). expect_exit: 0
11// license_tier: ORIGINAL
12import "nx_fpga_ram.nx"
13import "nx_fpga_decode.nx"
14import "nx_fpga_alu.nx"
15import "nx_fpga_regfile.nx"
16import "nx_fpga_pc.nx"
17import "rv64im_min_alu.nx"
18import "nx_syscalls.nx"
19
20func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("
21" as *u8); return ok }
22func enc_i(rd: i64, rs1: i64, imm: i64, f3: i64) -> i64 { return ((imm & 4095) << 20) | (rs1 << 15) | (f3 << 12) | (rd << 7) | 19 }
23func enc_r(rd: i64, rs1: i64, rs2: i64, f3: i64) -> i64 { return (rs2<<20)|(rs1<<15)|(f3<<12)|(rd<<7)|51 }
24
25func main() -> i64 {
26 gw("=== nx_fpga_cpu7_gate: RUNG 18 -- INSTRUCTION FETCH FROM A MEMORY FABRIC (von Neumann) ===\n" as *u8)
27 var pass: i64 = 0; var total: i64 = 0
28 let R: i64 = 8; let W: i64 = 64; let AB: i64 = 3
29 let IR: i64 = 4; let IW: i64 = 32; let IAB: i64 = 2 // IMEM: 4 words x 32-bit, 2 addr bits
30
31 // IMEM (the true RAM fabric)
32 let IK: *i64=sys_mmap(8*600) as *i64; let II: *i64=sys_mmap(8*600) as *i64; let IS: *i64=sys_mmap(8*2400) as *i64
33 let IPO: *i64=sys_mmap(8*40) as *i64; let IQ: *i64=sys_mmap(8*600) as *i64
34 seq_build_ram(IR, IW, IAB, IK, II, IS, IPO)
35 let inc: i64 = ram_ncells(IR, IW)
36 // datapath fabrics
37 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
38 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
39 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
40 fab_build_decode(DI, DS, DP)
41 let anpi: i64 = fab_build_alu(64, AI, AS, AP)
42 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
43 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
44 seq_build_regfile(R, W, AB, RKND, RINI, RSRC, RP)
45 let rnc: i64 = rf_ncells(R, W)
46 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
47 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
48 seq_build_pc(W, PKND, PINI, PSRC, PPO)
49 let pcnc: i64 = pc_ncells(W)
50
51 // the program -- loaded INTO the IMEM fabric
52 let prog: *i64 = sys_mmap(8*8) as *i64
53 prog[0]=enc_i(1,0,5,0) // ADDI x1,x0,5
54 prog[1]=enc_i(2,0,7,0) // ADDI x2,x0,7
55 prog[2]=enc_r(3,1,2,0) // ADD x3,x1,x2 (=12)
56 prog[3]=enc_r(4,3,3,0) // ADD x4,x3,x3 (=24)
57 let NSTEP: i64 = 4
58 var z: i64=0; while z<inc { IQ[z]=0; z=z+1 }
59 var a: i64=0; while a < NSTEP { ram_write(IR,IW,IAB,IK,II,IS,pi,co,IQ,a,prog[a]); a=a+1 }
60
61 // run -- FETCH each instruction from IMEM
62 let ref: *i64=sys_mmap(8*16) as *i64
63 z=0; while z<rnc { RQ[z]=0; z=z+1 } z=0; while z<pcnc { PQ[z]=0; z=z+1 } z=0; while z<R { ref[z]=0; z=z+1 }
64 var mism: i64=0; var cmps: i64=0; var s: i64=0
65 while s < NSTEP {
66 let pc: i64 = pc_read(W, PQ)
67 let instr: i64 = ram_read(IR,IW,IAB,IK,II,IS,pi,co,IQ,IPO,pc) // <-- FETCH FROM THE MEMORY FABRIC
68 let opcode: i64=instr&127; let rd: i64=(instr>>7)&7; let rs1: i64=(instr>>15)&7; let f3: i64=(instr>>12)&7
69 var bval: i64=0; var refB: i64=0; var f7b5: i64=0
70 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 }
71 else { var imm: i64=(instr>>20)&4095; if (imm&2048)!=0 {imm=imm-4096} bval=imm; refB=imm }
72 let av: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1)
73 fab_decode_run(DI,DS,DP,pi,co,f3,f7b5,ctrl)
74 let res: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,av,bval,ctrl[0],ctrl[1],ctrl[2])
75 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) }
76 pc_tick(W,PKND,PINI,PSRC,pi,PCO,PQ,0,0)
77 var rr: i64=0; 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 }
78 s=s+1
79 }
80 total=total+1; if mism==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
81 gw("T1 program FETCHED from the IMEM fabric runs == behavioral; x3=" as *u8); gn(rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,3)); gw(" (=12) x4=" as *u8); gn(rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,4)); gw(" (=24), regfile mismatches=" as *u8); gn(mism); gw("\n" as *u8)
82
83 // T2: fetch integrity -- the memory really holds the program
84 var fmis: i64=0; a=0
85 while a < NSTEP { if ram_read(IR,IW,IAB,IK,II,IS,pi,co,IQ,IPO,a) != prog[a] { fmis=fmis+1 } a=a+1 }
86 total=total+1; if fmis==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
87 gw("T2 fetch integrity: all " as *u8); gn(NSTEP); gw(" instructions read back from IMEM == the loaded program, mismatches=" as *u8); gn(fmis); gw("\n" as *u8)
88
89 // T3: never-brick
90 let q1: i64=pc_read(W,PQ); let q2: i64=pc_read(W,PQ)
91 total=total+1; if q1==q2 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
92 gw("T3 never-brick (#26): deterministic fetch+execute, bounded step, zero hardware-state writes\n" as *u8)
93
94 // T4: liar-kill -- corrupt the MEMORY WORD holding instruction 2 (ADD x3), re-run; the result must diverge
95 z=0; while z<inc { IQ[z]=0; z=z+1 }
96 a=0; while a < NSTEP { ram_write(IR,IW,IAB,IK,II,IS,pi,co,IQ,a,prog[a]); a=a+1 }
97 ram_write(IR,IW,IAB,IK,II,IS,pi,co,IQ,2,enc_i(3,0,1,0)) // overwrite mem[2]: ADD x3 -> ADDI x3,x0,1
98 z=0; while z<rnc { RQ[z]=0; z=z+1 } z=0; while z<pcnc { PQ[z]=0; z=z+1 }
99 var s2: i64=0
100 while s2 < NSTEP {
101 let pc: i64=pc_read(W,PQ)
102 let instr: i64=ram_read(IR,IW,IAB,IK,II,IS,pi,co,IQ,IPO,pc)
103 let opcode: i64=instr&127; let rd: i64=(instr>>7)&7; let rs1: i64=(instr>>15)&7; let f3: i64=(instr>>12)&7
104 var bval: i64=0; var f7b5: i64=0
105 if opcode==51 { let rs2: i64=(instr>>20)&7; bval=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs2); f7b5=(instr>>30)&1 }
106 else { var imm: i64=(instr>>20)&4095; if (imm&2048)!=0 {imm=imm-4096} bval=imm }
107 let av: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1)
108 fab_decode_run(DI,DS,DP,pi,co,f3,f7b5,ctrl)
109 let res: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,av,bval,ctrl[0],ctrl[1],ctrl[2])
110 if rd!=0 { rf_write(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,rd,res) }
111 pc_tick(W,PKND,PINI,PSRC,pi,PCO,PQ,0,0)
112 s2=s2+1
113 }
114 let bx3: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,3)
115 total=total+1; if bx3 != 12 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
116 gw("T4 liar-kill: corrupting IMEM word 2 -> the CPU fetched a different instruction -> x3=" as *u8); gn(bx3); gw(" != 12 (the machine executes what is in memory)\n" as *u8)
117
118 gw("\n=== nx_fpga_cpu7_gate " as *u8); gn(pass); gw("/" as *u8); gn(total)
119 if pass == total { gw(" GREEN (the CPU FETCHES its instructions from a memory fabric and runs them == behavioral -- the von Neumann step)\n" as *u8); sys_exit(0); return 0 }
120 gw(" RED\n" as *u8); sys_exit(1); return 1
121}