code wiki / _hdl_build / nx_simtcore.nx

nx_simtcore.nx

buildroot/runtime/_hdl_build/nx_simtcore.nx

70217 B1615 linesdepth 5pulls 16 transitivereach 1 importersview sourcekind library
docsdependenciesstructsconstsfunctions

about

nx_simtcore.nx -- the SOVEREIGN SIMT GPGPU EXECUTION CORE. This is the missing organ named by our OWN ruler: nx_sovgpu_census grades the cell "open GPU core on OUR FPGA (Vortex/Nyuzi class)" as GAP. This file closes it. It is a SIMT (single-instruction multiple-thread) execution core built from the first bit in NishiLang on top of the sovereign RV64IM decoder + ALU already in nishi-silicon/hdl. WHAT SIMT ADDS OVER THE SCALAR CORE (rv64im_min_sim): scalar core : 1 PC, 1 register file, 1 instruction -> 1 result SIMT core : NW warps, each with 1 PC and a THREAD MASK; each warp owns NT threads; each thread owns its own 32-entry register file. One fetched instruction executes in lockstep across every ACTIVE thread of the selected warp. A masked-off thread commits NOTHING -- no register write, no memory write. That single rule is what makes control-flow divergence expressible on a machine with one PC. ===== BENCHMARK ORACLE (external, measured, never copied) ===== Vortex (Georgia Tech, MICRO'54 2021, arXiv 2110.10857) is the reference open-source RISC-V GPGPU. We use its PUBLISHED ARCHITECTURE AND MEASUREMENTS as a measuring stick. We copy no Vortex source, RTL, or asset. Verified facts driving this design: - Vortex extends RISC-V with SIX instructions: wspawn, tmc, split, join, bar, tex. "by adding only six new instructions to the standard RISC-V ISA" (MICRO'21 sec 1). - Divergence uses an IPDOM (immediate post-dominator) stack, TWO pushes per split. - Thread mask: "If the bit in the thread mask for a specific thread is zero, no modifications would be made to that thread's register file and no changes to the cache would be made based on that thread." (arXiv 2002.12151). - Scheduler picks ONE wavefront per cycle from a visible mask; stalled/barrier masks remove warps from contention (MICRO'21 sec 4.1.1). - Cache banks are kept equal to the threads-per-warp count (CARRV 2019). - Baseline config 4W-4T; configs evaluated 4W-4T, 2W-8T, 8W-2T, 4W-8T, 8W-4T. ===== SOVEREIGN ENCODING, NOT VORTEX'S ===== RISC-V reserves four opcodes for user extensions: 0x0B, 0x2B, 0x5B, 0x7B. Vortex documents 0x5B for its `tex`. We take custom-0 = 0x0B so there is ZERO encoding collision with Vortex: the CAPABILITY set is benchmarked, the BITS are our own. NEVER-BRICK (cardinal 26): this core is a pure behavioural model over caller-owned memory. It writes no firmware, no device, no persistent hardware state. It is deterministic and bounded by construction -- every run is replayable bit-for-bit. Status: SEED. 2026-07-31. license_tier: ORIGINAL expect_exit: 0

dependencies 5 imports · 1 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.nx

imported by: nx_simtcore_gate.nx

structs

228struct NxSimtCore
1468struct NxSimtCluster

consts

52const NX_SIMT_MAX_WARPS: i64 = 16
53const NX_SIMT_MAX_THREADS: i64 = 16
54const NX_SIMT_NREGS: i64 = 32 // RISC-V architectural GPRs, per thread
55const NX_SIMT_IPDOM_DEPTH: i64 = 32 // divergence nesting depth, per warp
56const NX_SIMT_NBARRIERS: i64 = 8 // hardware barrier slots
60const NX_SIMT_BAR_GLOBAL: i64 = 128
79const NX_SIMT_LAT_ALU: i64 = 1 // issue-to-issue for an ALU op
108const NX_SIMT_LAT_MULDIV: i64 = 8
109const NX_SIMT_LAT_MEM_SHORT: i64 = 24 // Vortex "sh" -- cache-resident / short latency
110const NX_SIMT_LAT_MEM_LONG: i64 = 200 // Vortex "lg" -- DRAM / long latency
111const NX_SIMT_CHAN_LOW: i64 = 2 // Vortex "2c" -- 2-channel memory
112const NX_SIMT_CHAN_HIGH: i64 = 8 // Vortex "8c" -- 8-channel memory
113const NX_SIMT_MAX_CHANNELS: i64 = 16
121const NX_SIMT_BURST_CYCLES: i64 = 4
136const NX_SIMT_CACHE_LINE_B: i64 = 64
137const NX_SIMT_CACHE_SETS: i64 = 128
138const NX_SIMT_CACHE_WAYS: i64 = 2
139const NX_SIMT_LAT_CACHE_HIT: i64 = 4 // cycles when every touched line is resident
145const NX_SIMT_OPCODE: i64 = 0x0B
147const NX_SIMT_F3_TMC: i64 = 0 // tmc rs1 -- thread mask control
148const NX_SIMT_F3_WSPAWN: i64 = 1 // wspawn rs1, rs2 -- activate rs1 warps at PC rs2
149const NX_SIMT_F3_SPLIT: i64 = 2 // split rs1 -- control-flow divergence
150const NX_SIMT_F3_JOIN: i64 = 3 // join -- control-flow reconvergence
151const NX_SIMT_F3_BAR: i64 = 4 // bar rs1, rs2 -- barrier id rs1, warp count rs2
152const NX_SIMT_F3_TID: i64 = 5 // tid rd -- rd = this thread's lane id
153const NX_SIMT_F3_WID: i64 = 6 // wid rd -- rd = this warp's id
154const NX_SIMT_F3_NTID: i64 = 7 // ntid rd -- rd = threads per warp
169const NX_SIMT_OPCODE_W: i64 = 0x2B
171const NX_SIMT_W_SHFL: i64 = 0 // shfl rd, rs1, rs2 -- rd[t] = rs1[ rs2[t] ]
172const NX_SIMT_W_SHFL_UP: i64 = 1 // shfl.up rd, rs1, rs2 -- rd[t] = rs1[t - rs2[t]]
173const NX_SIMT_W_SHFL_DOWN:i64 = 2 // shfl.down rd, rs1, rs2 -- rd[t] = rs1[t + rs2[t]]
174const NX_SIMT_W_SHFL_XOR: i64 = 3 // shfl.xor rd, rs1, rs2 -- rd[t] = rs1[t ^ rs2[t]]
175const NX_SIMT_W_BALLOT: i64 = 4 // ballot rd, rs1 -- rd = mask of lanes with rs1 != 0
176const NX_SIMT_W_ALL: i64 = 5 // all rd, rs1 -- rd = 1 if every active lane nonzero
177const NX_SIMT_W_ANY: i64 = 6 // any rd, rs1 -- rd = 1 if any active lane nonzero
178const NX_SIMT_W_ACTIVEMASK: i64 = 7 // activemask rd -- rd = the current thread mask
206const NX_SIMT_OPCODE_TEX: i64 = 0x7B
207const NX_SIMT_TEX_FRACBITS: i64 = 8 // 24.8 fixed point
208const NX_SIMT_TEX_FRACMASK: i64 = 255
209const NX_SIMT_LAT_TEX_FILTER: i64 = 2 // their sampler's two-cycle bilinear interpolation
213const NX_SIMT_OK: i64 = 0
214const NX_SIMT_E_ARG: i64 = 1 // bad argument / unconfigured core
215const NX_SIMT_E_IPDOM: i64 = 2 // IPDOM stack overflow or join-without-split
216const NX_SIMT_E_ILLEGAL: i64 = 3 // illegal instruction
217const NX_SIMT_E_BOUNDS: i64 = 4 // memory access out of the modelled aperture
1465const NX_SIMT_MAX_CORES: i64 = 16
1466const NX_SIMT_CORE_STRIDE: i64 = 1024 // bytes reserved per core; struct is well under this

functions

323func nx_simt_full_mask(nt: i64) -> i64
330func nx_simt_popcount(m: i64) -> i64
342func nx_simt_lowest_lane(tmask: i64) -> i64
called by 1: nx_simt_exec_warp
356func nx_simt_alloc(c: *NxSimtCore) -> i64
385func nx_simt_init(c: *NxSimtCore, nw: i64, nt: i64,
473func nx_simt_rf_read(c: *NxSimtCore, w: i64, t: i64, r: i64) -> i64
480func nx_simt_rf_write(c: *NxSimtCore, w: i64, t: i64, r: i64, v: i64) -> i64
called by 1: nx_simt_exec_warp
492func nx_simt_in_range(c: *NxSimtCore, addr: i64, width: i64) -> i64
499func nx_simt_load32(c: *NxSimtCore, addr: i64) -> i64
509func nx_simt_store32(c: *NxSimtCore, addr: i64, v: i64) -> i64
519func nx_simt_load64(c: *NxSimtCore, addr: i64) -> i64
called by 1: nx_simt_exec_warp calls 1: nx_simt_load32
525func nx_simt_store64(c: *NxSimtCore, addr: i64, v: i64) -> i64
called by 1: nx_simt_exec_warp calls 1: nx_simt_store32
545func nx_simt_bank_cost(c: *NxSimtCore, addrs: *i64, active: i64, bank_hits: *i64) -> i64
called by 1: nx_simt_mem_access
573func nx_simt_set_memory(c: *NxSimtCore, lat: i64, nchan: i64) -> i64
587func nx_simt_set_cache(c: *NxSimtCore, on: i64) -> i64
called by 1: run_config_full
601func nx_simt_cache_probe(c: *NxSimtCore, line: i64) -> i64
called by 1: nx_simt_mem_access
635func nx_simt_coalesce(c: *NxSimtCore, addrs: *i64, active: i64) -> i64
663func nx_simt_mem_issue(c: *NxSimtCore, w: i64, cost: i64, nmiss: i64) -> i64
called by 1: nx_simt_mem_access
686func nx_simt_mem_access(c: *NxSimtCore, w: i64, addrs: *i64, bank_hits: *i64) -> i64
709func nx_simt_set_texture(c: *NxSimtCore, base: i64, w: i64, h: i64) -> i64
called by 1: run_config_full
725func nx_simt_lerp_rgba(a: i64, b: i64, f: i64) -> i64
called by 1: nx_simt_tex_sample
739func nx_simt_texel(c: *NxSimtCore, ix: i64, iy: i64) -> i64
called by 1: nx_simt_tex_sample calls 1: nx_simt_load32
752func nx_simt_tex_sample(c: *NxSimtCore, u: i64, v: i64) -> i64
784func nx_simt_ipdom_push(c: *NxSimtCore, w: i64, mask: i64, pc: i64, ft: i64) -> i64
called by 1: nx_simt_do_split
795func nx_simt_do_split(c: *NxSimtCore, w: i64, rs1: i64) -> i64
828func nx_simt_do_join(c: *NxSimtCore, w: i64) -> i64
called by 1: nx_simt_exec_warp
848func nx_simt_do_bar(c: *NxSimtCore, w: i64, bar_id: i64, expect: i64) -> i64
called by 1: nx_simt_exec_warp
892func nx_simt_mark_dest(c: *NxSimtCore, w: i64, rd: i64, lat: i64) -> i64
called by 1: nx_simt_exec_warp
903func nx_simt_srcs_ready(c: *NxSimtCore, w: i64) -> i64
940func nx_simt_pick_warp(c: *NxSimtCore) -> i64
967func nx_simt_any_active(c: *NxSimtCore) -> i64
981func nx_simt_exec_warp(c: *NxSimtCore, w: i64, addrs: *i64, bank_hits: *i64) -> i64
1428func nx_simt_run(c: *NxSimtCore, max_cycles: i64, addrs: *i64, bank_hits: *i64) -> i64
1486func nx_simt_cluster_core(cl: *NxSimtCluster, i: i64) -> *NxSimtCore
1490func nx_simt_cluster_init(cl: *NxSimtCluster, ncores: i64, nw: i64, nt: i64,
1532func nx_simt_cluster_run(cl: *NxSimtCluster, max_cycles: i64,
1594func nx_simt_cluster_ipc_permille(cl: *NxSimtCluster) -> i64
called by 1: run_cluster
1603func nx_simt_ipc_permille(c: *NxSimtCore) -> i64
1612func nx_simt_lane_ipc_permille(c: *NxSimtCore) -> i64