r/EmuDev 15h ago

NES I put the NES inside a CUDA kernel, one console per thread, and ran 65k of them at once

Built this for a reinforcement learning project (PPO on Super Mario Bros), but the emulator side turned out to be the interesting part, so I figured this sub would care more about that.

One CUDA thread runs one entire console. 6502, PPU, bus, OAM DMA. State is structure-of-arrays indexed by env id, and CPU registers stay in hardware registers for the life of the kernel. 65,536 independent consoles at about 3.3M steps/s on an A100.

- CPU passes the Klaus functional test suite, cycle counts included

- PPU is not cycle accurate. SMB's title screen never advances past the menu because of a timing bug I haven't fixed. I sidestep it by resetting from a save state

- No APU. The registers exist as a byte array, nothing generates sound

- Mapper 0 only

Two results that surprised me:

Opcode-binned dispatch (sorting a warp's threads by opcode before executing) came out 3.2x slower than just letting them diverge. I tested it on instruction streams sampled from 535M profiled SMB executions. A decorrelated warp holds about 20.6 distinct opcodes, and hardware SIMT reconvergence was already sharing fetch and addressing acrossthem. Explicit binning serializes what it was already sharing.

Putting the zero page in shared memory was a 1.9x regression. 256 bytes across 128 threads is 32KB per block, which drops occupancy from 32 warps to 6.

https://github.com/hbofz/NeSLE

Would love help with mappers. MMC1 and MMC3 would open up most of the library.

87 Upvotes

11 comments sorted by

20

u/Far_Outlandishness92 14h ago

Wow, didn't even think this was possible. I am impressed!! A lot!

14

u/joamag Game Boy 14h ago

12M frames per second… wooow

5

u/ShinyHappyREM 5h ago

ca. 55 emulated hours per second

14

u/Aliryth 8h ago

The rare non-slop post and it's absolutely magnificent.
Well done! What kind of usages do you anticipate for outcomes, or just a cool project for the PPO thing?
I'm interested in learning more!

Also I should put a disclaimer that I'm by far not an anti-AI person, but good lord the "I paid $20 for Claude to make a GameBoy emulator in a single commit" posts are getting rough, extending to other niche programming circles like OS/Kernel dev.

1

u/hurricane_news 4h ago

The rare non-slop post and it's absolutely magnificent.
Well done! What kind of usages do you anticipate for outcomes, or just a cool project for the PPO thing?
I'm interested in learning more!

the post itself has a ton of telltale signs of being AI generated

If the project itself is done by OP and not done by an LLM, all good I suppose

4

u/starquakegamma GBC NES C64 Z80 14h ago

I love how extreme this is, excellent!

5

u/StereoRocker 13h ago

I can't help the code, but I can say this is pretty damn cool.

Is the 3.3M steps/sec per instance, or cumulative across all of them? Are you able to translate roughly what FPS you're achieving on each instance?

4

u/Imaginary_Heat_2235 12h ago

Cumulative. Per instance at 65,536 envs it’s ~50 env-steps/s each, frameskip 4, so ~199 NES fps per console (3.3x real time), times 65,536.

Scales down as you go up: 4,096 envs = 304 fps each, 65,536 = 199, 131,072 = 93. And at 1 env the GPU loses to a CPU emulator (0.4x, launch overhead). Overtakes by 8 envs.
Terrible way to run one NES, good way to run 65,536.

-26

u/Even-Serve-3095 13h ago

ew nv*dia-only software, gross

3

u/Imaginary_Heat_2235 12h ago

Believe me, I’m not doing this out of brand loyalty. ROCm PR welcome.

-3

u/Even-Serve-3095 10h ago

why not use opencl? it works on both lol