Cupid is an NES and Famicom emulator with NTSC, PAL, and Dendy timing. It runs cartridge games, UNIF images, NSF and NSFe music, Famicom Disk System disks, StudyBox media, and supported VS System arcade images. Disk System and StudyBox images need their respective BIOS files.
You can open and switch games, save your settings and input profiles, and use save states, rewind, cheats, netplay, and HD packs. Music playback, screenshots, and audio and video recording are built in. Settings and tools have separate, resizable windows, so you can keep the debugger open while a game runs. Visual PPU tools show pattern tables, nametables, sprites, palettes, registers, and VRAM. You can paint writable tiles and edit RAM while the game is paused.
The menu bar and toolbar give you access to the main actions, with submenus keeping longer lists on screen. Settings use checkboxes, dropdowns, editable numbers, and native file pickers. The audio output dropdown lists detected devices. SDL2 handles video, audio, and controllers; Clay handles desktop layouts, with cached TrueType text. The CPU and PPU core is written in C11. Cartridge board modules and the EPSM YMF288 sound engine use C++17.
The tested implementation passes all 144 AccuracyCoin tests with none skipped or unfinished, all 91 ROMs in the diagnostic collection, and the 8,991-state canonical CPU trace in both normal and sanitizer builds. Separate mapper, input, storage, and expansion audio tests cover hardware outside AccuracyCoin's scope. See the accuracy notes for the test setup and coverage.
| Area | Implemented behavior |
|---|---|
| CPU and PPU | Official and undocumented instructions, shared OAM/DMC DMA timing, register delays, selectable PPU readback and sprite-evaluation behavior, regional frame timing, startup alignment and RAM contents, and optional PPU reset suppression |
| Cartridges | Board-specific PRG/CHR banking, mixed CHR RAM/NVRAM with separate persistence, nametable routing, bus conflicts, RAM permissions, IRQs, EEPROM, and flash; the mapper table lists supported families and variants |
| Sound | Five base APU channels, optional oldest-Famicom noise and clone pulse duty behavior, CPU-cycle band-limited reconstruction, cartridge and disk expansion audio, and EPSM stereo output with timer IRQs |
| Music and other media | NSF/NSFe initialization and play scheduling, track transport, timed fades, silence-based progression, repeat and shuffle, bank switching and expansion sound; StudyBox tape transport and audio; Famicom Network System RAM, character-ROM, and controller interfaces |
| Controllers and storage | NES, SNES, and Virtual Boy gamepads; SNES and Subor mice; NTT Data keypads; multiplayer adapters, light guns, paddles, mats, keyboards, trackballs, tablets, specialty expansion controllers, Turbo File, and BattleBox |
| VS System | Header-selected RGB PPU and controller behavior, hardware-palette light sensing, cabinet controls and protection, and dual machines with shared RAM, two screens, and mixed audio |
Cartridge loading supports iNES, NES 2.0, named UNIF boards, and an optional CRC
database for legacy corrections and recognized headerless images. Cupid looks
for NesDB.txt in its application data folder; --data-dir changes that folder
and --game-db selects a specific database. Database records also select the
Zapper connector: Famicom and Dendy games use the
expansion port, and NES games use controller port two. Explicit controller
options take precedence. Small and
irregular images use the board's implemented page mapping, including open bus
where a complete page cannot be mapped. CHR ROM and RAM follow each board's
source selectors, startup mappings, and write permissions. Declared memory can
remain allocated even when the board cannot address every byte. Work RAM and
save RAM retain separate ownership; UNROM 512 and GTROM also keep ordinary RAM
saves independent of their writable flash images. The
cartridge checkpoints
record the tested memory and banking fixes.
For NSF and NSFe files that use MMC5, multiplier operands survive soft reset
and track changes. Loading a music image initializes both operands to zero.
Music INIT receives the PAL flag only in PAL mode; Dendy keeps its own clock
while using X=0 for initialization.
VRC7 cartridges reset their FM synthesizer on console reset and retain their bank and IRQ registers. CPU reset preserves NMI edges raised during its bus cycles, including vblank edges when PPU reset suppression keeps the raster running. Disk-adapter work RAM and CHR RAM use the selected power-on profile when a disk is loaded and retain their contents across soft reset.
Device selection and timing follow the ROM header and
command-line options. --region auto uses image metadata
and applicable database corrections;
--region ntsc, --region pal, and --region dendy select an explicit timing
profile for supported hardware. Console wiring remains a separate choice.
Supported mapper families can still
reject unsupported submappers or memory layouts. The
hardware guide records remaining
limits, including optional Jaleco speech, a distinct RP2C03G palette, and MMC5
auxiliary I/O/timers. VS images requesting RP2C03G use the documented 2C03 fallback.
Clone the repository and run the build commands from its root:
git clone https://github.com/cupidthecat/cupid-nes.git
cd cupid-nesInstall C11 and C++17 compilers, Make, and the SDL2 development libraries. On Ubuntu:
sudo apt install build-essential libsdl2-dev
make
./cupid-nes path/to/game.nesUse make CC=clang CXX=clang++ for Clang. Both language compilers are required
even when the loaded game does not use EPSM. Run make clean before changing
compilers or flags.
Install Clang and the Windows SDK/MSVC build tools, and extract the SDL2 VC development package. In PowerShell:
.\scripts\test-windows.ps1 -SdlRoot 'C:\path\to\SDL2-2.32.10'
.\build\windows\cupid-nes.exe 'C:\path\to\game.nes'The script builds the application and hardware tests, copies SDL2.dll beside
the executables, and runs the hardware suite. See
getting started for prerequisites, output paths, and
sanitizer builds.
Run the application without an image to open the desktop, then use Open or File > Open Game. The recent list remembers successfully opened images, including the selected member of a ZIP or 7z archive and any applied patch. Open another image in the same window to switch games. A failed load or save keeps the current session available.
An image argument still opens a game directly. Explicit command-line choices
take precedence over saved settings for that launch. The application data
folder contains settings.ini, recent.ini, and the optional NesDB.txt;
--data-dir selects another folder. See configuration
for the options and getting started for file dialogs,
archives, and platform details.
For example, an Oeka Kids cartridge needs its tablet selected explicitly:
./cupid-nes --console famicom --expansion oeka-kids-tablet path/to/oeka-kids.nesEPSM is selected by NES 2.0 console metadata. A separately supplied 8 KiB
percussion ROM can be loaded with --epsm-adpcm; that option alone does not
enable EPSM. Configuration covers these choices and
other peripheral combinations.
| Key | Action |
|---|---|
| Z / X | A / B |
| Right Shift / Enter | Select / Start |
| Arrow keys | D-pad |
| Ctrl+O | Open a game |
| Ctrl+P / Ctrl+. | Pause or resume / advance one frame while paused |
| Ctrl+R / Ctrl+Shift+R | Soft reset / power cycle |
| Ctrl+Alt+R | Reload the current image |
| Ctrl+F / Ctrl+Shift+F | Hold fast-forward / toggle fast-forward |
| Ctrl+1 / Ctrl+2 / Ctrl+3 | Half speed / normal speed / double speed |
| F5 / F7 | Quick save / quick load the selected state slot |
| Ctrl+F5 / Ctrl+F7 | Save / load a state file |
| F6 | Restore the default palette |
| Page Up / Page Down | Next / previous NSF or NSFe track |
| Ctrl+Space / Ctrl+End / Ctrl+Home | Music play-pause / stop / restart |
| Ctrl+V | Paste palette text |
| F12 / Ctrl+F12 / Shift+F12 | Screenshot / audio recording / video recording |
| Ctrl+Shift+F12 | Stop and finalize a recording |
These are the default bindings. Settings can select another input profile and change keyboard or gamepad assignments. The keyboard and first SDL game controller both drive player 1 by default. More controllers fill the remaining player slots; the selected multiplayer adapter or VS image determines which players a game can read. See controls and peripherals for controller assignment, light guns, paddles, floor mats, keyboards, mouse and tablet input, and the Famicom expansion devices. Peripheral key handlers can take precedence over the shortcuts above; Family BASIC, Subor keyboards, and active mats consume R as device input.
The hardware reference lists supported mapper families, expansion audio, console revisions, ROM-header requirements, and remaining limits. Mapper support describes implemented hardware; it is not a per-game compatibility guarantee.
To open a disk image with its 8 KiB BIOS:
./cupid-nes --fds-bios disksys.rom --fds-write-protect game.fdsF8 inserts or ejects the selected side, F9 changes sides, and F10 toggles write protection. The desktop defaults to overlay saving: disk writes go into a separate IPS file and leave the original image unchanged. In-place saving is also available. Archived or patched disks use their own overlay identity.
Cartridge save files live beside their ROM. The saves and media guide covers PRG/CHR save memory, EEPROM, flash, disk images, BASIC tapes, and Turbo File/BattleBox storage. Cartridge RAM can remain readable at addresses where writes select banks. Its layout and persistence follow the selected board and header.
Normal quit and image replacement finalize pending recordings and persistent data before discarding the running session. Failed writes keep the session available for retry. Save states restore the machine as well as its memory; input movies and network sessions use isolated timelines so their writes cannot silently replace ordinary progress. See states and replay and the save guide for those ownership rules.
| Task | Guide |
|---|---|
| Build Cupid and start a game | Getting started |
| Look up options and defaults | Configuration |
| Set up controllers and peripherals | Controls |
| Check supported hardware and ROM formats | Hardware |
| Look up hardware and test terminology | Hardware terminology |
| Locate saves and use writable media | Saves and media |
| Use states, rewind, run-ahead, or input movies | States and replay |
| Play NSF and NSFe tracks | Music player |
| Save screenshots, audio, or video | Screenshots and recordings |
| Inspect execution and hardware | Debugger and Lua |
| Manage per-game cheat codes | Cheats |
| Diagnose a build or runtime problem | Troubleshooting |
| Understand the core and source layout | Architecture |
| Run tests or investigate an accuracy failure | Development and testing |
| Submit a change | Contributing |
The documentation index also links test evidence and component credits. For questions and bug reports, see support.
On Linux, make test builds and runs the hardware regressions against the
production core. The Windows build script runs the same suite. External test
ROMs are separate checkouts; the development guide gives
their pinned revisions and the commands for the CPU trace, diagnostics, and
AccuracyCoin.
The accuracy workflow builds with strict GCC and Clang sanitizer settings on pushes and pull requests. Both jobs run the hardware suite, eleven region launch cases, CPU trace, all 91 diagnostic ROMs, and AccuracyCoin. The Clang job enables AddressSanitizer, UndefinedBehaviorSanitizer, and Linux leak detection.
Test results apply to the checked commit and configuration. The baseline uses the default startup alignment. Explicit phases, seeded startup choices, and optional hardware profiles have separate focused checks; the baseline does not establish every possible DMA/register alignment or analog output effect.
Cupid is GPL-3.0-or-later; see LICENSE. The bundled emu2413 component retains its MIT license, and ymfm retains its BSD 3-Clause license. See credits and references for component attribution, test sources, and hardware documentation.
The desktop guide covers menus, settings, feature panels, and storage locations.

