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}