code wiki / _hdl_build / nx_fpga_cpu5_gate.nx

nx_fpga_cpu5_gate.nx source

↩ module page · 131 lines · 9412 B

1import "nx_gate_gn.nx" 2import "nx_gate_base.nx" 3// nx_fpga_cpu5_gate.nx -- GATE for RUNG 15: JUMPS (JAL/JALR) -- function calls on the fabric CPU. JAL: rd <- PC+1 4// (the link/return address), PC <- PC+offset (jump). JALR: rd <- PC+1, PC <- rs1+imm (computed on the fabric ALU). 5// Both write the regfile + LOAD the fabric PC. Runs a CALL -> compute -> RETURN program and proves the PC AND 6// register file == the behavioral reference step-for-step. (Light gate: decode+ALU+regfile+PC; the program is 7// ALU-class R/I + jumps. J-immediate simplified to instruction units; instruction-indexed PC.) 8// T1 CALL/RETURN == reference (PC + regfile every step). T2 final (x5=link=2, x4=func result=10, x3=99 post-return). 9// T3 NEVER-BRICK. T4 LIAR-KILL (corrupt the PC load path -> the jump diverges). 10// expect_exit: 0 license_tier: ORIGINAL 11import "nx_fpga_decode.nx" 12import "nx_fpga_alu.nx" 13import "nx_fpga_regfile.nx" 14import "nx_fpga_pc.nx" 15import "rv64im_min_alu.nx" 16import "nx_syscalls.nx" 17 18func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw(" 19" as *u8); return ok } 20func enc_i(rd: i64, rs1: i64, imm: i64, f3: i64) -> i64 { return ((imm & 4095) << 20) | (rs1 << 15) | (f3 << 12) | (rd << 7) | 19 } 21func enc_r(rd: i64, rs1: i64, rs2: i64, f3: i64) -> i64 { return (rs2<<20)|(rs1<<15)|(f3<<12)|(rd<<7)|51 } 22func enc_jal(rd: i64, off: i64) -> i64 { return ((off & 4095) << 20) | (rd << 7) | 111 } // 0x6F 23func enc_jalr(rd: i64, rs1: i64, imm: i64) -> i64 { return ((imm & 4095) << 20) | (rs1 << 15) | (rd << 7) | 103 } // 0x67 24 25func main() -> i64 { 26 gw("=== nx_fpga_cpu5_gate: RUNG 15 -- JUMPS (JAL/JALR): function calls on the fabric CPU ===\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 30 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 31 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 32 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 33 fab_build_decode(DI, DS, DP) 34 let anpi: i64 = fab_build_alu(64, AI, AS, AP) 35 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 36 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 37 seq_build_regfile(R, W, AB, RKND, RINI, RSRC, RP) 38 let rnc: i64 = rf_ncells(R, W) 39 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 40 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 41 seq_build_pc(W, PKND, PINI, PSRC, PPO) 42 let pcnc: i64 = pc_ncells(W) 43 44 let ref: *i64 = sys_mmap(8*16) as *i64 45 let prog: *i64 = sys_mmap(8*16) as *i64 46 prog[0]=enc_i(1,0,5,0) // ADDI x1,x0,5 47 prog[1]=enc_jal(5,3) // JAL x5,+3 (x5=link=2; PC=1+3=4) 48 prog[2]=enc_i(3,0,99,0) // ADDI x3,x0,99 (after return) 49 prog[3]=enc_jal(0,0) // JAL x0,0 (halt: self-loop) 50 prog[4]=enc_r(4,1,1,0) // ADD x4,x1,x1 (function body: x4=10) 51 prog[5]=enc_jalr(0,5,0) // JALR x0,x5,0 (return: PC=x5=2) 52 let NSTEP: i64 = 8 53 54 var z: i64 = 0; while z < rnc { RQ[z]=0; z=z+1 } 55 z = 0; while z < pcnc { PQ[z]=0; z=z+1 } 56 z = 0; while z < R { ref[z]=0; z=z+1 } 57 var refpc: i64 = 0 58 var mism: i64 = 0; var cmps: i64 = 0 59 var s: i64 = 0 60 while s < NSTEP { 61 let pc: i64 = pc_read(W, PQ) 62 let instr: i64 = prog[pc] 63 let opcode: i64 = instr & 127 64 let rd: i64=(instr>>7)&7; let rs1: i64=(instr>>15)&7; let f3: i64=(instr>>12)&7 65 var pcload: i64 = 0; var pcval: i64 = 0 66 if opcode == 111 { // JAL 67 var off: i64=(instr>>20)&4095; if (off&2048)!=0 {off=off-4096} 68 if rd != 0 { rf_write(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,rd,pc+1) } 69 if rd != 0 { ref[rd]=refpc+1 } 70 pcload=1; pcval=pc+off; refpc=refpc+off 71 } else { if opcode == 103 { // JALR 72 var imm: i64=(instr>>20)&4095; if (imm&2048)!=0 {imm=imm-4096} 73 let rs1v: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1) 74 let tgt: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,rs1v,imm,0,1,1) // rs1+imm on the fabric ALU 75 if rd != 0 { rf_write(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,rd,pc+1) } 76 if rd != 0 { ref[rd]=refpc+1 } 77 pcload=1; pcval=tgt; refpc=ref[rs1]+imm 78 } else { // R/I-type (ALU-class) 79 var bval: i64=0; var refB: i64=0; var f7b5: i64=0 80 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 } 81 else { var imm: i64=(instr>>20)&4095; if (imm&2048)!=0 {imm=imm-4096} bval=imm; refB=imm } 82 let av: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1) 83 fab_decode_run(DI,DS,DP,pi,co,f3,f7b5,ctrl) 84 let res: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,av,bval,ctrl[0],ctrl[1],ctrl[2]) 85 if rd != 0 { rf_write(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,rd,res) } 86 if rd != 0 { ref[rd]=nx_rv64im_alu_compute(NX_RV64IM_ALU_ADD, ref[rs1], refB) } 87 refpc=refpc+1 88 } } 89 pc_tick(W, PKND, PINI, PSRC, pi, PCO, PQ, pcload, pcval) 90 cmps=cmps+1; if pc_read(W,PQ) != refpc { mism=mism+1 } 91 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 } 92 s=s+1 93 } 94 total=total+1; if mism==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 95 gw("T1 CALL/RETURN runs on the fabric == behavioral (PC + regfile), step-for-step: " as *u8); gn(cmps); gw(" compares, mismatches=" as *u8); gn(mism); gw("\n" as *u8) 96 97 // T2: final state 98 let x5: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,5); let x4: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,4); let x3: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,3) 99 total=total+1; var t2ok: i64=1; if x5!=2 {t2ok=0} if x4!=10 {t2ok=0} if x3!=99 {t2ok=0} 100 if t2ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 101 gw("T2 final: x5=" as *u8); gn(x5); gw(" (JAL link=2), x4=" as *u8); gn(x4); gw(" (function x1+x1=10), x3=" as *u8); gn(x3); gw(" (99, ran after JALR return)\n" as *u8) 102 103 // T3: never-brick 104 let p1: i64=pc_read(W,PQ); let p2: i64=pc_read(W,PQ) 105 total=total+1; if p1==p2 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 106 gw("T3 never-brick (#26): deterministic PC, bounded step, zero hardware-state writes\n" as *u8) 107 108 // T4: liar-kill -- corrupt the PC load-mux of bit 1 -> jumps land on the wrong target 109 PINI[3*W + 1 + 1] = PINI[3*W + 1 + 1] ^ 0xffff // ldmux of PC bit 1 (cell 3W+1+1) 110 z = 0; while z < rnc { RQ[z]=0; z=z+1 } 111 z = 0; while z < pcnc { PQ[z]=0; z=z+1 } 112 let ref2: *i64=sys_mmap(8*16) as *i64; z=0; while z<R {ref2[z]=0; z=z+1} 113 var rpc2: i64=0; var liar: i64=0; var s2: i64=0 114 while s2 < NSTEP { 115 let pc: i64=pc_read(W,PQ); var fpc: i64=pc; if fpc<0 {fpc=0} if fpc>15 {fpc=15} 116 let instr: i64=prog[fpc]; let opcode: i64=instr&127; let rd: i64=(instr>>7)&7; let rs1: i64=(instr>>15)&7; let f3: i64=(instr>>12)&7 117 var pcload: i64=0; var pcval: i64=0 118 if opcode==111 { var off: i64=(instr>>20)&4095; if (off&2048)!=0 {off=off-4096} if rd!=0 {rf_write(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,rd,pc+1); ref2[rd]=rpc2+1} pcload=1; pcval=pc+off; rpc2=rpc2+off } 119 else { if opcode==103 { var imm: i64=(instr>>20)&4095; if (imm&2048)!=0 {imm=imm-4096} let rv: i64=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs1); let tgt: i64=fab_alu_run(64,anpi,AI,AS,AP,pi,co,rv,imm,0,1,1); if rd!=0 {rf_write(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,rd,pc+1); ref2[rd]=rpc2+1} pcload=1; pcval=tgt; rpc2=ref2[rs1]+imm } 120 else { var bval: i64=0; var refB: 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); refB=ref2[rs2]} else {var imm: i64=(instr>>20)&4095; if (imm&2048)!=0 {imm=imm-4096} bval=imm; refB=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,0,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); ref2[rd]=nx_rv64im_alu_compute(NX_RV64IM_ALU_ADD,ref2[rs1],refB)} rpc2=rpc2+1 } } 121 pc_tick(W, PKND, PINI, PSRC, pi, PCO, PQ, pcload, pcval) 122 if pc_read(W,PQ) != rpc2 { liar=liar+1 } 123 s2=s2+1 124 } 125 total=total+1; if liar > 0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 126 gw("T4 liar-kill: corrupting the PC load-mux -> jumps land wrong, PC diverges in " as *u8); gn(liar); gw(" steps\n" as *u8) 127 128 gw("\n=== nx_fpga_cpu5_gate " as *u8); gn(pass); gw("/" as *u8); gn(total) 129 if pass == total { gw(" GREEN (JAL/JALR function calls run on the simulated FPGA == the behavioral CPU; call -> compute -> return)\n" as *u8); sys_exit(0); return 0 } 130 gw(" RED\n" as *u8); sys_exit(1); return 1 131}