code wiki / _hdl_build / nx_fpga_lui_gate.nx
nx_fpga_lui_gate.nx source
↩ module page · 85 lines · 5297 B
1import "nx_gate_gn.nx"
2import "nx_gate_base.nx"
3// nx_fpga_lui_gate.nx -- GATE for RUNG 21: LUI + AUIPC (the U-type upper-immediate op classes) on the fabric. With
4// these, the simulated core covers EVERY RV64I base-integer op class that writes a register {R, I-OP, LOAD, STORE,
5// BRANCH, JAL, JALR, LUI, AUIPC}. LUI: rd = sign_extend32(imm[31:12] << 12). AUIPC: rd = PC + sign_extend32(imm<<12).
6// The upper immediate is extracted by decode (bit slice) and the value is computed ON THE FABRIC ALU (LUI = 0 + uimm;
7// AUIPC = PC + uimm), so the same ALU datapath that does ADD does these. (PC is instruction-indexed in this sim, so
8// AUIPC adds the upper-immediate to the instruction index -- noted; the arithmetic is identical.)
9// T1 LUI over many imm20 (incl sign-extended/negative) == behavioral. T2 AUIPC over many (pc,imm20) == behavioral.
10// T3 NEVER-BRICK. T4 LIAR-KILL (corrupt the ALU -> the U-type result diverges). expect_exit: 0
11// license_tier: ORIGINAL
12import "nx_fpga_alu.nx"
13import "nx_fpga_decode.nx"
14import "rv64im_min_alu.nx"
15import "nx_syscalls.nx"
16
17func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("
18" as *u8); return ok }
19func enc_u(rd: i64, imm20: i64, opcode: i64) -> i64 { return ((imm20 & 1048575) << 12) | (rd << 7) | opcode } // imm20 in [31:12]
20func uimm(instr: i64) -> i64 { // U-immediate, sign-extended from bit 31
21 var raw: i64 = ((instr >> 12) & 1048575) << 12
22 if (raw & 2147483648) != 0 { raw = raw - 4294967296 }
23 return raw
24}
25
26func main() -> i64 {
27 gw("=== nx_fpga_lui_gate: RUNG 21 -- LUI + AUIPC (U-type upper-immediate) on the fabric ALU ===\n" as *u8)
28 var pass: i64 = 0; var total: i64 = 0
29 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
30 let pi: *i64=sys_mmap(8*200) as *i64; let co: *i64=sys_mmap(8*2200) as *i64
31 let anpi: i64 = fab_build_alu(64, AI, AS, AP)
32
33 // test imm20 values incl. sign bit (0x80000) set -> negative result
34 let imms: *i64 = sys_mmap(8*16) as *i64
35 imms[0]=0; imms[1]=1; imms[2]=0xfff; imms[3]=0x12345; imms[4]=0x7ffff; imms[5]=0x80000; imms[6]=0xabcde; imms[7]=0xfffff
36 let NIMM: i64 = 8
37
38 // T1: LUI rd = uimm (computed on the fabric as ADD(0, uimm))
39 var l1: i64=0; var lchk: i64=0; var ii: i64=0
40 while ii < NIMM {
41 let instr: i64 = enc_u(1, imms[ii], 55) // 0x37 = LUI
42 let u: i64 = uimm(instr)
43 let got: i64 = fab_alu_run(64, anpi, AI, AS, AP, pi, co, 0, u, 0, 1, 1) // 0 + uimm on the fabric
44 let want: i64 = u // LUI semantics: rd = sign_extend32(imm<<12)
45 lchk = lchk + 1; if got != want { l1 = l1 + 1 }
46 ii = ii + 1
47 }
48 total=total+1; if l1==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
49 gw("T1 LUI rd = imm<<12 (sign-extended) over " as *u8); gn(lchk); gw(" values incl negative, on the fabric ALU, mismatches=" as *u8); gn(l1); gw("\n" as *u8)
50
51 // T2: AUIPC rd = PC + uimm over several PCs
52 let pcs: *i64 = sys_mmap(8*8) as *i64; pcs[0]=0; pcs[1]=1; pcs[2]=5; pcs[3]=10; pcs[4]=100
53 var a1: i64=0; var achk: i64=0; var pj: i64=0
54 while pj < 5 {
55 ii = 0
56 while ii < NIMM {
57 let instr: i64 = enc_u(2, imms[ii], 23) // 0x17 = AUIPC
58 let u: i64 = uimm(instr)
59 let got: i64 = fab_alu_run(64, anpi, AI, AS, AP, pi, co, pcs[pj], u, 0, 1, 1) // PC + uimm on the fabric
60 let want: i64 = pcs[pj] + u
61 achk = achk + 1; if got != want { a1 = a1 + 1 }
62 ii = ii + 1
63 }
64 pj = pj + 1
65 }
66 total=total+1; if a1==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
67 gw("T2 AUIPC rd = PC + (imm<<12) over " as *u8); gn(achk); gw(" (pc,imm) cases, on the fabric ALU, mismatches=" as *u8); gn(a1); gw("\n" as *u8)
68
69 // T3: never-brick
70 let r1: i64 = fab_alu_run(64, anpi, AI, AS, AP, pi, co, 5, 0x12345000, 0, 1, 1)
71 let r2: i64 = fab_alu_run(64, anpi, AI, AS, AP, pi, co, 5, 0x12345000, 0, 1, 1)
72 total=total+1; if r1==r2 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
73 gw("T3 never-brick (#26): deterministic, bounded, pure-integer, zero hardware-state writes\n" as *u8)
74
75 // T4: liar-kill -- corrupt the ALU LUT config; LUI/AUIPC (which run ON the ALU) must diverge
76 var ci: i64=0; while ci < 640 { AI[ci] = AI[ci] ^ 0xffff; ci = ci + 1 }
77 let bad: i64 = fab_alu_run(64, anpi, AI, AS, AP, pi, co, 5, 0x10000, 0, 1, 1)
78 let good: i64 = 5 + 0x10000
79 total=total+1; if bad != good { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
80 gw("T4 liar-kill: corrupting the fabric ALU -> AUIPC(5,0x10000)=" as *u8); gn(bad); gw(" != " as *u8); gn(good); gw("\n" as *u8)
81
82 gw("\n=== nx_fpga_lui_gate " as *u8); gn(pass); gw("/" as *u8); gn(total)
83 if pass == total { gw(" GREEN (LUI + AUIPC on the fabric == behavioral -- the simulated core now covers EVERY RV64I register-writing op class)\n" as *u8); sys_exit(0); return 0 }
84 gw(" RED\n" as *u8); sys_exit(1); return 1
85}