code wiki / _hdl_build / nx_fpga_cpu2_gate.nx
nx_fpga_cpu2_gate.nx source
↩ module page · 166 lines · 10294 B
1import "nx_gate_gn.nx"
2import "nx_gate_base.nx"
3// nx_fpga_cpu2_gate.nx -- GATE for RUNG 12: the fabric CPU widened to I-TYPE IMMEDIATES (OP-IMM), so a
4// SELF-CONTAINED program runs from zero state (no pre-load -- the R11 crutch removed). Adds: opcode discrimination
5// (R-type 0x33 vs OP-IMM 0x13), 12-bit immediate extraction + SIGN-EXTENSION, and an operand-B mux (rs2 value vs
6// the immediate). The fabric ALU/shift/compare + decoder datapaths (R9) are REUSED unchanged -- the immediate is
7// just the second operand. Proven step-for-step vs the behavioral nx_rv64im_alu_compute.
8// T1 SELF-CONTAINED program (ADDI bootstrap + R-type + I-type incl a NEGATIVE immediate) == reference, every reg.
9// T2 final state spot-check (incl sign-extended ADDI x7=x3-10=127). T3 NEVER-BRICK. T4 LIAR-KILL.
10// GREEN iff all pass. expect_exit: 0 license_tier: ORIGINAL
11import "nx_fpga_decode.nx"
12import "nx_fpga_alu.nx"
13import "nx_fpga_cmp.nx"
14import "nx_fpga_shift.nx"
15import "nx_fpga_regfile.nx"
16import "rv64im_min_alu.nx"
17import "nx_syscalls.nx"
18
19func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("
20" as *u8); return ok }
21
22func ref_aluop(f3: i64, f7b5: i64) -> i64 {
23 if f3==0 { if f7b5==1 { return NX_RV64IM_ALU_SUB } return NX_RV64IM_ALU_ADD }
24 if f3==1 { return NX_RV64IM_ALU_SLL }
25 if f3==2 { return NX_RV64IM_ALU_SLT }
26 if f3==3 { return NX_RV64IM_ALU_SLTU }
27 if f3==4 { return NX_RV64IM_ALU_XOR }
28 if f3==5 { if f7b5==1 { return NX_RV64IM_ALU_SRA } return NX_RV64IM_ALU_SRL }
29 if f3==6 { return NX_RV64IM_ALU_OR }
30 return NX_RV64IM_ALU_AND
31}
32func enc_r(rd: i64, rs1: i64, rs2: i64, f3: i64, f7b5: i64) -> i64 {
33 var funct7: i64 = 0; if f7b5 == 1 { funct7 = 32 }
34 return (funct7 << 25) | (rs2 << 20) | (rs1 << 15) | (f3 << 12) | (rd << 7) | 51 // 0x33
35}
36func enc_i(rd: i64, rs1: i64, imm: i64, f3: i64) -> i64 {
37 return ((imm & 4095) << 20) | (rs1 << 15) | (f3 << 12) | (rd << 7) | 19 // 0x13, imm[11:0]
38}
39
40// fabric execute: decode (funct3,f7b5) on the fabric -> dispatch to the datapath fabric.
41func cpu_exec(DI: *i64, DS: *i64, DP: *i64, AI: *i64, AS: *i64, AP: *i64, anpi: i64, CI: *i64, CS: *i64, CP: *i64, cnpi: i64, SI: *i64, SS: *i64, SP: *i64, snpi: i64, pi: *i64, co: *i64, ctrl: *i64, f3: i64, f7b5: i64, a: i64, b: i64) -> i64 {
42 fab_decode_run(DI, DS, DP, pi, co, f3, f7b5, ctrl)
43 let cls: i64 = ctrl[6] | (ctrl[7] << 1)
44 if cls == 0 { return fab_alu_run(64, anpi, AI, AS, AP, pi, co, a, b, ctrl[0], ctrl[1], ctrl[2]) }
45 if cls == 1 { return fab_shift_run(64, snpi, SI, SS, SP, pi, co, a, b & 63, ctrl[3], ctrl[4]) }
46 return fab_cmp_run(64, cnpi, CI, CS, CP, pi, co, a, b, ctrl[5])
47}
48
49func main() -> i64 {
50 gw("=== nx_fpga_cpu2_gate: RUNG 12 -- the fabric CPU + I-TYPE immediates: a SELF-CONTAINED program runs ===\n" as *u8)
51 var pass: i64 = 0; var total: i64 = 0
52 let R: i64 = 8; let W: i64 = 64; let AB: i64 = 3
53
54 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
55 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
56 let CI: *i64=sys_mmap(8*256) as *i64; let CS: *i64=sys_mmap(8*1056) as *i64; let CP: *i64=sys_mmap(8*72) as *i64
57 let SI: *i64=sys_mmap(8*800) as *i64; let SS: *i64=sys_mmap(8*3200) as *i64; let SP: *i64=sys_mmap(8*72) as *i64
58 let pi: *i64=sys_mmap(8*160) as *i64; let co: *i64=sys_mmap(8*2200) as *i64; let ctrl: *i64=sys_mmap(8*16) as *i64
59 fab_build_decode(DI, DS, DP)
60 let anpi: i64 = fab_build_alu(64, AI, AS, AP)
61 let cnpi: i64 = fab_build_cmp(64, CI, CS, CP)
62 let snpi: i64 = fab_build_shifter(64, SI, SS, SP)
63 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
64 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
65 seq_build_regfile(R, W, AB, RKND, RINI, RSRC, RP)
66 let rnc: i64 = rf_ncells(R, W)
67
68 let ref: *i64 = sys_mmap(8 * 16) as *i64
69 let prog: *i64 = sys_mmap(8 * 16) as *i64
70 // SELF-CONTAINED program -- starts from x0=0, bootstraps with ADDI (no pre-load)
71 prog[0]=enc_i(1, 0, 100, 0) // ADDI x1, x0, 100 -> 100
72 prog[1]=enc_i(2, 0, 37, 0) // ADDI x2, x0, 37 -> 37
73 prog[2]=enc_r(3, 1, 2, 0, 0) // ADD x3, x1, x2 -> 137
74 prog[3]=enc_r(4, 1, 2, 0, 1) // SUB x4, x1, x2 -> 63
75 prog[4]=enc_i(5, 1, 255, 4) // XORI x5, x1, 0xFF -> 100^255
76 prog[5]=enc_i(6, 2, 4, 1) // SLLI x6, x2, 4 -> 37<<4 (imm[10]=0 -> logical)
77 prog[6]=enc_i(7, 3, 0-10, 0) // ADDI x7, x3, -10 -> 127 (SIGN-EXTENDED negative immediate)
78 prog[7]=enc_r(1, 4, 3, 2, 0) // SLT x1, x4, x3 -> 63<137=1 (overwrite x1)
79 let nprog: i64 = 8
80
81 // ---- run; compare fabric regfile to reference after every step ----
82 var z: i64 = 0; while z < rnc { RQ[z] = 0; z = z + 1 }
83 z = 0; while z < R { ref[z] = 0; z = z + 1 }
84 var mism: i64 = 0; var steps: i64 = 0
85 var ic: i64 = 0
86 while ic < nprog {
87 let instr: i64 = prog[ic]
88 let opcode: i64 = instr & 127
89 let rd: i64 = (instr >> 7) & 7
90 let rs1: i64 = (instr >> 15) & 7
91 let f3: i64 = (instr >> 12) & 7
92 var bval: i64 = 0; var refB: i64 = 0; var f7b5: i64 = 0
93 if opcode == 51 { // R-type 0x33
94 let rs2: i64 = (instr >> 20) & 7
95 bval = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, rs2)
96 refB = ref[rs2]
97 f7b5 = (instr >> 30) & 1
98 } else { // I-type OP-IMM 0x13
99 var imm: i64 = (instr >> 20) & 4095 // imm[11:0]
100 if (imm & 2048) != 0 { imm = imm - 4096 } // SIGN-EXTEND (bit 11)
101 bval = imm; refB = imm
102 if f3 == 1 { f7b5 = (instr >> 30) & 1 } // SLLI
103 if f3 == 5 { f7b5 = (instr >> 30) & 1 } // SRLI/SRAI (imm[10])
104 }
105 let aval: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, rs1)
106 let res: i64 = cpu_exec(DI, DS, DP, AI, AS, AP, anpi, CI, CS, CP, cnpi, SI, SS, SP, snpi, pi, co, ctrl, f3, f7b5, aval, bval)
107 if rd != 0 { rf_write(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, rd, res) }
108 let refres: i64 = nx_rv64im_alu_compute(ref_aluop(f3, f7b5), ref[rs1], refB)
109 if rd != 0 { ref[rd] = refres }
110 var rr: i64 = 0
111 while rr < R {
112 steps = steps + 1
113 if rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, rr) != ref[rr] { mism = mism + 1 }
114 rr = rr + 1
115 }
116 ic = ic + 1
117 }
118 total=total+1; if mism==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
119 gw("T1 self-contained program (ADDI bootstrap + R/I-type) == behavioral, step-for-step: " as *u8); gn(steps); gw(" register-compares (8 instrs x 8 regs), mismatches=" as *u8); gn(mism); gw("\n" as *u8)
120
121 // ---- T2: final-state spot-checks ----
122 let x6: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, 6)
123 let x7: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, 7)
124 let x1: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, 1)
125 total=total+1
126 var t2ok: i64 = 1
127 if x6 != (37 << 4) { t2ok = 0 } // SLLI 37<<4 = 592
128 if x7 != 127 { t2ok = 0 } // ADDI x3(137) + (-10) = 127 (sign-extend)
129 if x1 != 1 { t2ok = 0 } // SLT 63<137 = 1
130 if t2ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
131 gw("T2 final state: x6=" as *u8); gn(x6); gw(" (37<<4=592) x7=" as *u8); gn(x7); gw(" (137 + -10 = 127, sign-extended) x1=" as *u8); gn(x1); gw(" (SLT=1)\n" as *u8)
132
133 // ---- T3: never-brick ----
134 let y1: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, 7)
135 let y2: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, 7)
136 total=total+1; if y1==y2 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
137 gw("T3 never-brick (#26): deterministic, bounded per-instruction step, zero hardware-state writes\n" as *u8)
138
139 // ---- T4: liar-kill -- corrupt the decoder class LUT -> the program diverges ----
140 DI[6] = DI[6] ^ 0xffff
141 z = 0; while z < rnc { RQ[z] = 0; z = z + 1 }
142 let rf2: *i64 = sys_mmap(8 * 16) as *i64
143 z = 0; while z < R { rf2[z] = 0; z = z + 1 }
144 ic = 0
145 while ic < nprog {
146 let instr: i64 = prog[ic]
147 let opcode: i64 = instr & 127
148 let rd: i64=(instr>>7)&7; let rs1: i64=(instr>>15)&7; let f3: i64=(instr>>12)&7
149 var bval: i64=0; var refB: i64=0; var f7b5: i64=0
150 if opcode == 51 { let rs2: i64=(instr>>20)&7; bval=rf_read(R,W,AB,RKND,RINI,RSRC,pi,RCO,RQ,RP,rs2); refB=rf2[rs2]; f7b5=(instr>>30)&1 }
151 else { var imm: i64=(instr>>20)&4095; if (imm&2048)!=0 { imm=imm-4096 } bval=imm; refB=imm; if f3==1 { f7b5=(instr>>30)&1 } if f3==5 { f7b5=(instr>>30)&1 } }
152 let aval: i64 = rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, rs1)
153 let res: i64 = cpu_exec(DI, DS, DP, AI, AS, AP, anpi, CI, CS, CP, cnpi, SI, SS, SP, snpi, pi, co, ctrl, f3, f7b5, aval, bval)
154 if rd != 0 { rf_write(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, rd, res) }
155 if rd != 0 { rf2[rd] = nx_rv64im_alu_compute(ref_aluop(f3,f7b5), rf2[rs1], refB) }
156 ic = ic + 1
157 }
158 var liar: i64 = 0; var rr: i64 = 0
159 while rr < R { if rf_read(R, W, AB, RKND, RINI, RSRC, pi, RCO, RQ, RP, rr) != rf2[rr] { liar = liar + 1 } rr = rr + 1 }
160 total=total+1; if liar > 0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
161 gw("T4 liar-kill: scrambling the decoder class LUT -> the program diverges in " as *u8); gn(liar); gw(" registers\n" as *u8)
162
163 gw("\n=== nx_fpga_cpu2_gate " as *u8); gn(pass); gw("/" as *u8); gn(total)
164 if pass == total { gw(" GREEN (a SELF-CONTAINED R-type + I-type-immediate program runs on the simulated FPGA == the behavioral CPU; no pre-load)\n" as *u8); sys_exit(0); return 0 }
165 gw(" RED\n" as *u8); sys_exit(1); return 1
166}