code wiki / _hdl_build / nx_simtcore_gate.nx

nx_simtcore_gate.nx

buildroot/runtime/_hdl_build/nx_simtcore_gate.nx

63405 B1197 linesdepth 6pulls 17 transitivereach 0 importersview sourcekind gate/proof
docsdependenciesstructsconstsfunctions

about

nx_simtcore_gate.nx -- GATE: the sovereign SIMT GPGPU core executes real SIMT kernels and reproduces the ARCHITECTURAL RELATIONSHIPS published for Vortex (Georgia Tech). This is the measuring stick for nx_simtcore.nx. It closes the nx_sovgpu_census cell "open GPU core on OUR FPGA (Vortex/Nyuzi class)", previously graded GAP. ===== THE ORACLE ===== Vortex, MICRO'54 2021 (arXiv 2110.10857). The paper publishes NO per-benchmark absolute IPC in its text -- the IPC figures are plots, and their y-axes are labelled CPI while the captions say IPC, a contradiction the paper never resolves. So absolute IPC is NOT a usable oracle and we do not pretend it is. What the paper DOES state numerically, in prose, is two config relationships on sgemm -- and all three configs hold TOTAL THREADS CONSTANT at 16, so it is a fair comparison of how you PARTITION the same threads: "Moving from a 4W-4T configuration to a 2W-8T configuration, maximizing threads, introduces a 69% area cost increase in LUT and registers, as well as a speedup of 20% for sgemm." "changing the configuration to 8W-2T, maximizing wavefronts, generates cheaper hardware, about a 27% area reduction. This comes with a reduction in performance in terms of IPC, 36% for sgemm in the extreme case." sgemm is classified COMPUTE-BOUNDED by the same paper. So the falsifiable predictions our core must reproduce on a compute-bound kernel at equal total threads are: P1 2W-8T is FASTER than 4W-4T P2 8W-2T is SLOWER than 4W-4T HONEST SCOPE: we test DIRECTION, not magnitude. Our model has no FPU, no DRAM controller and no FPGA routing, so its idealised speedups are LARGER than Vortex's achieved ones (Vortex got +20%/-36% where a pure issue-width model predicts +100%/-50%). Claiming magnitude agreement would be dishonest; claiming direction agreement is exactly what the evidence supports. P3 is the counterpart the same paper implies and that every GPU exists for: on a MEMORY-BOUND kernel the ordering INVERTS, because more warps hide more latency. A core that reproduces P1/P2 but not P3 has modelled issue width and forgotten latency hiding. ===== TEETH ===== T1 CORRECTNESS -- 16 threads compute a per-thread result matching an independent

dependencies 6 imports · 0 importers

nx_syscalls.nx nishi_hdl_primitives.nx rv64im_min_decoder.nx rv64im_min_alu.nx rv64im_min_sim.nx nx_simtcore.nx nx_simtcore_gate.nx

imports: nx_syscalls.nxnishi_hdl_primitives.nxrv64im_min_decoder.nxrv64im_min_alu.nxrv64im_min_sim.nxnx_simtcore.nx

imported by: nobody (leaf or entry point)

call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown

main gw sys_write sys_mmap build_compute emit_prologue e_addi e_auipc e_simt e_rr e_slli e_addi ↻ e_rr ↻ e_branch e_sw run_config sys_mmap ↻ nx_simt_alloc sys_mmap ↻ nx_simt_init nx_simt_full_mask nx_simt_run nx_simt_any_active nx_simt_pick_warp nx_simt_srcs_ready nx_simt_in_range nx_rv64im_rs1 nx_rv64im_rs2 nx_simt_exec_warp nx_simt_load32 nx_simt_in_range ↻ nx_rv64im_rd nx_rv64im_rs1 ↻ nx_rv64im_rs2 ↻ nx_rv64im_funct3 nx_rv64im_funct7 nx_simt_popcount nx_simt_lowest_lane nx_simt_rf_read nx_simt_full_mask ↻

structs

none

consts

80const R_ZERO: i64 = 0
81const R_T0: i64 = 5
82const R_T1: i64 = 6
83const R_T2: i64 = 7
84const R_S0: i64 = 8
85const R_S1: i64 = 9
86const R_A0: i64 = 10
87const R_A1: i64 = 11
88const R_A2: i64 = 12
89const R_A3: i64 = 13
90const R_A4: i64 = 14
91const R_A5: i64 = 15
92const R_A6: i64 = 16
93const R_A7: i64 = 17
94const R_S2: i64 = 18
95const R_T3: i64 = 28
96const R_T4: i64 = 29
97const R_T5: i64 = 30
98const R_T6: i64 = 31
116const VTX_SGEMM_4W4T: i64 = 2000 // IPC x1000
117const VTX_SGEMM_2W8T: i64 = 2400
118const VTX_SGEMM_8W2T: i64 = 1470
125const VTX_RATIO_2W8T_PERMILLE: i64 = 1200
126const VTX_RATIO_8W2T_PERMILLE: i64 = 735
129const G_MEM_BASE: i64 = 0x80000000
130const G_MEM_SIZE: i64 = 0x8000
133const G_OUT_OFF: i64 = 0x1010
134const G_NTHREADS: i64 = 16 // total threads held CONSTANT across all three configs
135const G_LOOP_K: i64 = 64 // loop trip count; large enough that the loop dominates
351const G_TEX_OFF: i64 = 0x1800
352const G_TEX_W: i64 = 16
353const G_TEX_H: i64 = 16
354const G_TEX_REL: i64 = 2032 // G_TEX_OFF - G_OUT_OFF, fits a 12-bit signed immediate

functions

64func gw(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
called by 2: report_configmain calls 1: sys_write
65func gn(v: i64) -> i64
called by 2: report_configmain calls 2: sys_mmapsys_write
138func e_addi(rd: i64, rs1: i64, imm: i64) -> i64 { return ((imm & 0xFFF) << 20) | (rs1 << 15) | (rd << 7) | 0x13 }
139func e_andi(rd: i64, rs1: i64, imm: i64) -> i64 { return ((imm & 0xFFF) << 20) | (rs1 << 15) | (7 << 12) | (rd << 7) | 0x13 }
140func e_slli(rd: i64, rs1: i64, sh: i64) -> i64 { return ((sh & 0x3F) << 20) | (rs1 << 15) | (1 << 12) | (rd << 7) | 0x13 }
141func e_auipc(rd: i64, imm20: i64) -> i64 { return ((imm20 & 0xFFFFF) << 12) | (rd << 7) | 0x17 }
called by 1: emit_prologue
142func e_rr(rd: i64, rs1: i64, rs2: i64, f3: i64, f7: i64) -> i64
145func e_sw(rs1: i64, rs2: i64, imm: i64) -> i64
148func e_lw(rd: i64, rs1: i64, imm: i64) -> i64 { return ((imm & 0xFFF) << 20) | (rs1 << 15) | (2 << 12) | (rd << 7) | 0x03 }
149func e_branch(rs1: i64, rs2: i64, off: i64, f3: i64) -> i64
156func e_jal(rd: i64, off: i64) -> i64
called by 1: build_divergent
164func e_simt(f3: i64, rd: i64, rs1: i64, rs2: i64) -> i64
168func e_simtw(f3: i64, rd: i64, rs1: i64, rs2: i64) -> i64
171func e_srli(rd: i64, rs1: i64, sh: i64) -> i64 { return ((sh & 0x3F) << 20) | (rs1 << 15) | (5 << 12) | (rd << 7) | 0x13 }
called by 1: build_tex_sw
173func e_tex(rd: i64, rs1: i64, rs2: i64, rs3: i64) -> i64
called by 1: build_tex_hw
176func e_nop() -> i64 { return e_addi(R_ZERO, R_ZERO, 0) }
called by 1: build_divergent calls 1: e_addi
181func emit_prologue(prog: *i64, nw: i64) -> i64
209func build_compute(prog: *i64, nw: i64, k: i64) -> i64
224func ref_compute(gid: i64, k: i64) -> i64
called by 1: main
237func build_membound(prog: *i64, nw: i64, k: i64) -> i64
253func build_divergent(prog: *i64, nw: i64, nop_out: i64) -> i64
285func build_sgemm_like(prog: *i64, nw: i64, k: i64) -> i64
305func build_reduce_hw(prog: *i64, nw: i64) -> i64
327func build_reduce_sw(prog: *i64, nw: i64) -> i64
357func build_tex_hw(prog: *i64, nw: i64, k: i64) -> i64
376func build_tex_sw(prog: *i64, nw: i64, k: i64) -> i64
421func build_ballot(prog: *i64, nw: i64) -> i64
called by 1: main calls 4: emit_prologuee_andie_simtwe_sw
430func gabs(v: i64) -> i64
called by 1: main
440func build_gbar(prog: *i64, nw: i64, expect: i64) -> i64
called by 1: main calls 4: emit_prologuee_addie_simte_sw
454func run_cluster(prog: *i64, nprog: i64, ncores: i64, nw: i64, nt: i64,
486func run_config_full(prog: *i64, nprog: i64, nw: i64, nt: i64,
552func run_config_mem(prog: *i64, nprog: i64, nw: i64, nt: i64,
592func run_config(prog: *i64, nprog: i64, nw: i64, nt: i64,
631func report_config(name: *u8, nw: i64, nt: i64, cycles: i64, stats: *i64) -> i64
called by 1: main calls 2: gwgn
642func main() -> i64