code wiki / _hdl_build / nx_fpga_cpu8_gate.nx
nx_fpga_cpu8_gate.nx source
↩ module page · 138 lines · 11154 B
1import "nx_gate_gn.nx"
2import "nx_gate_base.nx"
3// nx_fpga_cpu8_gate.nx -- GATE for RUNG 19: the UNIFIED von Neumann CPU. ONE machine that FETCHES instructions from
4// an IMEM RAM fabric (R18) AND keeps its DATA in a DMEM RAM fabric (R17, a true RAM -- so data ADDRESS 0 works, the
5// end-to-end fix for R16's data-memory-can't-use-address-0 finding). Each step: instr = ram_read(IMEM, PC); decode;
6// dispatch (R/I -> ALU+regfile; SW -> ram_write(DMEM); LW -> ram_read(DMEM)); PC++. Both code and data live in
7// simulated memory fabrics; the machine reads code out of one and reads/writes data in the other.
8// Program: store a 2-element array to DMEM STARTING AT ADDRESS 0, load both back, sum them.
9// T1 the program (fetched from IMEM, data in DMEM) == behavioral (regfile + DMEM), every step.
10// T2 result x5 = DMEM[0]+DMEM[1] = 10+20 = 30, AND DMEM[0] (address 0) holds 10.
11// T3 NEVER-BRICK. T4 LIAR-KILL: corrupt IMEM word 2 (the SW to address 0) -> the store never happens -> diverges.
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 }
27
28func main() -> i64 {
29 gw("=== nx_fpga_cpu8_gate: RUNG 19 -- the UNIFIED von Neumann CPU (fetch from IMEM RAM + data in DMEM RAM) ===\n" as *u8)
30 var pass: i64 = 0; var total: i64 = 0
31 let R: i64=8; let W: i64=64; let AB: i64=3
32 let MR: i64=8; let MAB: i64=3 // DMEM: 8 words x 64-bit
33 let IR: i64=8; let IW: i64=32; let IAB: i64=3 // IMEM: 8 words x 32-bit
34
35 // IMEM (true RAM)
36 let IK: *i64=sys_mmap(8*1100) as *i64; let II: *i64=sys_mmap(8*1100) as *i64; let IS: *i64=sys_mmap(8*4400) as *i64
37 let IPO: *i64=sys_mmap(8*40) as *i64; let IQ: *i64=sys_mmap(8*1100) as *i64
38 seq_build_ram(IR, IW, IAB, IK, II, IS, IPO); let inc: i64=ram_ncells(IR, IW)
39 // DMEM (true RAM)
40 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
41 let MPO: *i64=sys_mmap(8*72) as *i64; let MQ: *i64=sys_mmap(8*2100) as *i64
42 seq_build_ram(MR, W, MAB, MK, MI, MS, MPO); let mnc: i64=ram_ncells(MR, W)
43 // datapath
44 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
45 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
46 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
47 fab_build_decode(DI, DS, DP); let anpi: i64=fab_build_alu(64, AI, AS, AP)
48 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
49 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
50 seq_build_regfile(R, W, AB, RKND, RINI, RSRC, RP); let rnc: i64=rf_ncells(R, W)
51 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
52 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
53 seq_build_pc(W, PKND, PINI, PSRC, PPO); let pcnc: i64=pc_ncells(W)
54
55 let prog: *i64=sys_mmap(8*16) as *i64
56 prog[0]=enc_i(1,0,10,0) // ADDI x1,x0,10
57 prog[1]=enc_i(2,0,20,0) // ADDI x2,x0,20
58 prog[2]=enc_sw(0,1,0) // SW x1,0(x0) DMEM[0]=10 <- DATA ADDRESS 0 (the R17 fix)
59 prog[3]=enc_sw(0,2,1) // SW x2,1(x0) DMEM[1]=20
60 prog[4]=enc_lw(3,0,0) // LW x3,0(x0) x3=DMEM[0]=10
61 prog[5]=enc_lw(4,0,1) // LW x4,1(x0) x4=DMEM[1]=20
62 prog[6]=enc_r(5,3,4,0) // ADD x5,x3,x4 = 30
63 prog[7]=enc_i(0,0,0,0) // NOP (halt-ish)
64 let NSTEP: i64=7
65
66 var z: i64=0; while z<inc { IQ[z]=0; z=z+1 }
67 var a: i64=0; while a < 8 { ram_write(IR,IW,IAB,IK,II,IS,pi,co,IQ,a,prog[a]); a=a+1 }
68
69 let ref: *i64=sys_mmap(8*16) as *i64; let refm: *i64=sys_mmap(8*16) as *i64
70 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 }
71 z=0; while z<R { ref[z]=0; z=z+1 } z=0; while z<MR { refm[z]=0; z=z+1 }
72 var mism: i64=0; var cmps: i64=0; var s: i64=0
73 while s < NSTEP {
74 let pc: i64=pc_read(W, PQ)
75 let instr: i64=ram_read(IR,IW,IAB,IK,II,IS,pi,co,IQ,IPO,pc) // FETCH from IMEM
76 let opcode: i64=instr&127; let rd: i64=(instr>>7)&7; let rs1: i64=(instr>>15)&7; let f3: i64=(instr>>12)&7
77 if opcode==3 { // LW
78 var imm: i64=(instr>>20)&4095; if (imm&2048)!=0 {imm=imm-4096}
79 let base: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1)
80 let addr: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,base,imm,0,1,1)
81 let ld: i64=ram_read(MR,W,MAB,MK,MI,MS,pi,co,MQ,MPO,addr) // LOAD from DMEM
82 if rd!=0 { rf_write(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,rd,ld); ref[rd]=refm[(ref[rs1]+imm)&7] }
83 } else { if opcode==35 { // SW
84 var imm: i64=(((instr>>25)&127)<<5)|((instr>>7)&31); if (imm&2048)!=0 {imm=imm-4096}
85 let rs2: i64=(instr>>20)&7
86 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)
87 let addr: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,base,imm,0,1,1)
88 ram_write(MR,W,MAB,MK,MI,MS,pi,co,MQ,addr,v); refm[(ref[rs1]+imm)&7]=ref[rs2] // STORE to DMEM
89 } else { // R/I ALU
90 var bval: i64=0; var refB: i64=0; var f7b5: i64=0
91 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 }
92 else { var imm: i64=(instr>>20)&4095; if (imm&2048)!=0 {imm=imm-4096} bval=imm; refB=imm }
93 let av: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1)
94 fab_decode_run(DI,DS,DP,pi,co,f3,f7b5,ctrl)
95 let res: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,av,bval,ctrl[0],ctrl[1],ctrl[2])
96 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) }
97 } }
98 pc_tick(W,PKND,PINI,PSRC,pi,PCO,PQ,0,0)
99 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 }
100 var mm: i64=0; while mm<MR { cmps=cmps+1; if ram_read(MR,W,MAB,MK,MI,MS,pi,co,MQ,MPO,mm)!=refm[mm] {mism=mism+1} mm=mm+1 }
101 s=s+1
102 }
103 total=total+1; if mism==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
104 gw("T1 program FETCHED from IMEM + data in DMEM == behavioral (regfile + DMEM): " as *u8); gn(cmps); gw(" compares, mismatches=" as *u8); gn(mism); gw("\n" as *u8)
105
106 // T2: result + data address 0
107 let x5: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,5); let d0: i64=ram_read(MR,W,MAB,MK,MI,MS,pi,co,MQ,MPO,0)
108 total=total+1; var t2ok: i64=1; if x5!=30 {t2ok=0} if d0!=10 {t2ok=0}
109 if t2ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
110 gw("T2 x5 = DMEM[0]+DMEM[1] = " as *u8); gn(x5); gw(" (=30); DMEM address 0 holds " as *u8); gn(d0); gw(" (=10, stored+loaded at addr 0 via the RAM fabric)\n" as *u8)
111
112 // T3: never-brick
113 let q1: i64=pc_read(W,PQ); let q2: i64=pc_read(W,PQ)
114 total=total+1; if q1==q2 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
115 gw("T3 never-brick (#26): deterministic fetch+execute+memory, bounded step, zero hardware-state writes\n" as *u8)
116
117 // T4: liar-kill -- corrupt IMEM word 2 (the SW to address 0) into a NOP; the store never happens -> x5 wrong
118 z=0; while z<inc { IQ[z]=0; z=z+1 } a=0; while a<8 { ram_write(IR,IW,IAB,IK,II,IS,pi,co,IQ,a,prog[a]); a=a+1 }
119 ram_write(IR,IW,IAB,IK,II,IS,pi,co,IQ,2,enc_i(0,0,0,0)) // mem[2]: SW -> NOP (the store vanishes)
120 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 }
121 var s2: i64=0
122 while s2 < NSTEP {
123 let pc: i64=pc_read(W,PQ); let instr: i64=ram_read(IR,IW,IAB,IK,II,IS,pi,co,IQ,IPO,pc)
124 let opcode: i64=instr&127; let rd: i64=(instr>>7)&7; let rs1: i64=(instr>>15)&7; let f3: i64=(instr>>12)&7
125 if opcode==3 { var imm: i64=(instr>>20)&4095; if (imm&2048)!=0 {imm=imm-4096} let base: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1); let addr: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,base,imm,0,1,1); let ld: i64=ram_read(MR,W,MAB,MK,MI,MS,pi,co,MQ,MPO,addr); if rd!=0 {rf_write(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,rd,ld)} }
126 else { if opcode==35 { var imm: i64=(((instr>>25)&127)<<5)|((instr>>7)&31); if (imm&2048)!=0 {imm=imm-4096} let rs2: i64=(instr>>20)&7; 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); let addr: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,base,imm,0,1,1); ram_write(MR,W,MAB,MK,MI,MS,pi,co,MQ,addr,v) }
127 else { var bval: i64=0; var f7b5: i64=0; 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} else {var imm: i64=(instr>>20)&4095; if (imm&2048)!=0 {imm=imm-4096} bval=imm} let av: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1); fab_decode_run(DI,DS,DP,pi,co,f3,f7b5,ctrl); let res: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,av,bval,ctrl[0],ctrl[1],ctrl[2]); if rd!=0 {rf_write(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,rd,res)} } }
128 pc_tick(W,PKND,PINI,PSRC,pi,PCO,PQ,0,0)
129 s2=s2+1
130 }
131 let bx5: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,5)
132 total=total+1; if bx5 != 30 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
133 gw("T4 liar-kill: corrupting IMEM word 2 (the store to addr 0) -> x5=" as *u8); gn(bx5); gw(" != 30 (the machine's result depends on what is in memory)\n" as *u8)
134
135 gw("\n=== nx_fpga_cpu8_gate " as *u8); gn(pass); gw("/" as *u8); gn(total)
136 if pass == total { gw(" GREEN (a UNIFIED von Neumann CPU: fetches code from an IMEM RAM fabric + stores/loads data in a DMEM RAM fabric incl ADDRESS 0 == behavioral)\n" as *u8); sys_exit(0); return 0 }
137 gw(" RED\n" as *u8); sys_exit(1); return 1
138}