Dendy is a NES/Famicom emulator written in Go and named after the soviet Famicom
clone, that I used to have back in my childhood. It’s nothing serious, so do not
expect it to beat any of the existing emulators in terms of performance or accuracy.
Yet, it is capable of running most of the games I tried, so it’s not completely useless.
Download
You can download the latest pre-built binaries for Windows, macOS, and Linux
from the releases page: (not tested).
Alternatively, if you have Go installed, you can build it from source:
$ go install github.com/maxpoletaev/dendy/cmd/dendy@latest
For this, you may need to install additional dependencies required by raylib. See
https://github.com/gen2brain/raylib-go#requirements for more details.
Play
There is no GUI, so you will have to run the emulator from the command line.
Just point it to the ROM file you want to play (only .nes
, .zip
won’t work
for now):
$ dendy romfile.nes
There’s a bunch of command line flags that you can know about by running
dendy -help
. Here are some of the most useful ones:
-scale=<n>
- Scale the window by n
times (default: 2)
-nospritelimit
- Disable original sprite per scanline limit (eliminates flickering)
-listen
and -connect
- For network multiplayer (see below)
-nosave
- Do not load and save the game state on exit
Controls
Controller
Player 1 controller is emulated using the keyboard. The default mapping is as
follows. Multiplayer on a single keyboard is not supported.
┆┆
┌───────────────────────────────────────┐
│ │
│ [W] │
│ [A] [D] │
│ [S] [J] [K] │
│ [Enter] [RShift] │
│ │
└───────────────────────────────────────┘
Zapper (Light Gun)
Zapper is emulated using the mouse and can be used in games like Duck Hunt. Point
the mouse cursor at the right position on the screen and click to shoot.
Hotkeys
CTRL+R
or ⌘+R
- Reset the game
CTRL+Q
or ⌘+Q
- Quit the emulator
CTRL+X
or ⌘+X
- Resync the emulators (netplay)
F12
- Take a screenshot
M
- Mute/unmute
Network Multiplayer
Run the emulator with the -listen=<host>:<port>
flag to start a netplay server
that will be waiting for the second player to connect via the -connect=<host>:<port>
flag. Once the connection is established, the game will start for both sides.
The player who started the server will be controlling the first joystick. Ensure
that both sides are using the same ROM file and the same version of the emulator.
The multiplayer feature is based on rollback networking, similar to how it is done in
RetroArch and Fightcade. The emulation always runs at the full speed on both sides,
and the player inputs for each frame are exchanged over the network.
It compensates for slight drifts in the clock speed and network latency by predicting
input events for the other player when the real input has not yet been received. When
the input from the remote player arrives, it corrects itself by "rolling back" to the
last known synchronized state and replaying the inputs from that point. Theoretically,
this should keep the game playable for both sides without any local input delay, even
if the network connection is not very stable (e.g., over the Internet). When tested,
latencies of up to 150ms felt pretty playable.
Tested Games
Game |
Status |
Issues |
Bad Apple |
Playable |
|
Balloon Fight |
Playable |
|
Batman |
Playable |
|
Battle City |
Playable |
|
Battletoads |
Playable |
|
Battletoads & Double Dragon |
Not Playable |
Freezes |
Bomberman |
Playable |
|
Captain America |
Playable |
|
Castlevania |
Playable |
|
Chip 'n Dale |
Playable |
|
Chip 'n Dale 2 |
Playable |
|
Contra Force |
Playable |
|
Contra |
Playable |
|
Darkwing Duck |
Playable |
|
Donkey Kong |
Playable |
|
Double Dragon 2 |
Playable |
|
Double Dragon 3 |
Playable |
|
Duck Hunt |
Playable |
|
Duck Tales |
Playable |
|
Ice Climber |
Playable |
|
Jackal |
Not Playable |
Black screen |
Kirby's Adventure |
Playable |
|
Legend of Zelda |
Playable |
|
Mario Bros. |
Playable |
|
Megaman |
Playable |
|
Megaman 4 |
Playable |
|
Metal Gear |
Playable |
|
Mighty Final Fight |
Playable |
|
Ninja Cat |
Playable |
|
Prince of Persia |
Playable |
Incorrect sprite/background priority |
Super Contra |
Playable |
|
Super Mario Bros. 3 |
Crash |
|
Super Mario Bros. |
Playable |
|
Teenage Mutant Ninja Turtles |
Playable |
|
Teenage Mutant Ninja Turtles 2 |
Playable |
|
Teenage Mutant Ninja Turtles 3 |
Playable |
|
Teenage Mutant Ninja Turtles: Tournament Fighters |
Not Playable |
Graphical artifacts |
Tiny Toon Adventures |
Playable |
|
Status
CPU
- Official opcodes
- Unofficial opcodes
- Runtime disassembly
- Cycle-accurate emulation
- Accurate clock speed
- Interrupts
Graphics
- Background rendering
- Sprite rendering
- 8×16 sprites
- Palettes
- Scrolling
- Color emphasis
- Graphics output
- Controllers
- Zapper
Sound
The sound chip emulation is still work in progress and is not very reliable yet.
It may occasionally produce some pops and crackles, but it should be good enough
for most games.
- Square channels
- Triangle channel
- Noise channel
- Length counter
- Envelope
- Sweep
- DMC
Mappers
The goal is to support top 7 mappers covering the majority of games. The
percentage indicates the number of games that use the mapper according to
nescartdb.com.
- MMC1 (Mapper 1) - 28%
- MMC3 (Mapper 4) - 24%
- UxROM (Mapper 2) - 11%
- NROM (Mapper 0) - 10%
- CNROM (Mapper 3) - 6%
- AxROM (Mapper 7) - 3%
- MMC5 (Mapper 5) - 1%
Resources
Although NES emulation is a pretty well-covered topic, It is still a very
interesting and challenging project to work on. Here are some of the resources
that I found particularly useful while writing this emulator. Big thanks to
everyone who made them!
Documentation
Videos
- The NES Emulator from Scratch series covers most of the topics from
the CPU to the sound, but I found the two videos about the PPU to be the most
useful for understanding the obscure details of the NES rendering pipeline:
[1], [2].
Code
During bad times, it’s always nice to look at other people’s code to see how
they solved the same problems. Here are some of the emulators written by other
people that I often referred to when I was stuck: