FuNes is a Nintendo Entertainment System (NES) emulator, written in Haskell.
Warning
This emulator is for research purposes. Do not use as your daily emulator. You can easily find more mature NES emulators on GitHub!
⭐ Characteristics
- NTSC
- Audio (although not perfect)
- Mappers
- NROM
🔧 Installation
To build the emulator, you will need to have Stack and the SDL2 library installed.
# In the cloned repository stack build stack run -- ./my_rom.nes # The path to the rom to use
Note: stack install will install the emulator as funes-exe
🎮 Controls
| NES Controller | Physical Buttons |
|---|---|
| A | A |
| B | S or Z |
| Start | Enter |
| Select | Space |
| Directional Pad | Arrows |
Press Q or esc to quit.
✅ Testing and accuracy
We use the nestest ROM and trace to test the CPU's behaviour and instructions.
While accuracy is not the ultimate goal, we use the AccuracyCoin ROM to evaluate the correctness of the emulator.
Latest results
Do not be scared of the failing tests. Please check out this video to understand what this ROM checks for.
Score: 83 / 131
Results from Nov. 21 2025
🎥 Demo (w/ sound) 🔉
Click to expand
out.mp4
🔍 Why another NES emulator?
FuNes is an experiment before anything else. The goal was to see if the functional paradigm would apply well to writting virtual machines and emulator, thus being written in Haskell.
While the goal is to have a working emulator, it is in no way 100% compliant. Some features are not (yet) implemented (see here) and some behaviour may be invalid.
Results of this little experiment
- The different parts of the emulator (CPU, PPU, Bus) are isolated objects and computations on them were designed using Monads. This made testing a real pleasure. Moreover, I find the code overal quite elegant (e.g. for the opcodes).
- The typeafety prevented some bit-level mistakes (especially when handling 2-byte addresses and 1-byte data), which is always welcome.
- However, it feels like the functional paradigm didn't bring much else to the table, compared to a regular object-orented approach. Although, it should be noted that the functional paradigm never felt like an obstacle when designing and implementing the emulator.
⚙️ Technicalities
- Main stateful computations (operations on the CPU, APU, PPU, etc.) are modeled using continuation-passing style (CPS) monads
- Multi-threading for rendering and sound filtering
- Using SDL2
📚 Resources used
This project wouldn't exist without the following resources. Many thanks to their respective authors 🙏
- 6502 Reference
- 'Writing NES emulator in Rust' (GitHub Pages, Source Code)
- nesdev.org
- tetanes
- TriCNES
Why FuNes?
It's simple: Functional Programming + NES = FuNes
The fact that it shares the name with the late french actor Louis de Funes is accidental.
