Philpax icon

Philpax

Notes · Other Peoples' Talks · FOSDEM 2026 · The joys and horrors of NES dynamic recompilation

https://fosdem.org/2026/schedule/event/ETLVUA-the_joys_and_horrors_of_nes_dynamic_recompilation/

  • Emulator vs recompiler
    • Pros:
      • Simple and flexible
      • Can avoid pitfalls
      • Very easy to debug
    • Cons: Very slow to interpret
  • JIT/Dynamic recompiler: the "easy" way
    • When you want to run an instruction, you recompile a block of instructions
    • Pros
      • Usually faster than interpreters
      • Can perform hot-path optimisations
      • Can reuse code blocks
    • Cons
      • Hard to debug
      • Overhead from new code
  • AoT/Static Recompilation
    • Recompile all of the code before running it
    • Pros
      • Fastest of all methods
      • Can be recompiled just once, and then reused as required
      • Can be easier to debug
    • Cons
      • Very, very difficul to implement correctly
      • Cannot perform hot-path optimisations
  • The project:
    • NES dynamic recompiler
    • C++20, LLVM ORC JIT, SDL
  • Small hobby project, so:
    • no self-modifying code
    • doesn't handle all instructions
    • can only rnu a subset of NES games
    • uses an existing interpreter for PPU
    • no audio
  • It can run Pac-Man!
  • How does it work?
    • For every code block, recompile every instruction into a LLVM function
    • Can restrict the amount to recompile
    • Pass CPU state around as a struct to each code block function
    • Regular instructions are transliterated into LLVM IR
    • For conditional branching instructions, write an early return if possible to avoid recompiling the rest
    • Jump/call writes address of recompiled target
  • Horrors:
    • Need to check for CPU interrupts in cycles, which can require cache invalidation