A NES emulator written in Odin: Comments
Developer Lucy Pero created lucyNES in Odin over seven months, running Battletoads and supporting seven cartridge mappers before pausing work in January 2025.
By Dillip Chowdary • Nov 15, 2026 • Source: lucypero.com
In this post
Independent developer Lucy Pero developed lucyNES, an open-source Nintendo Entertainment System emulator written in the Odin programming language, according to lucypero.com's report. Built over a seven-month span beginning in late June 2024, the software reached sufficient execution fidelity to emulate complex commercial titles including Battletoads alongside hundreds of standard games before work paused in January 2025. The project serves as an implementation study demonstrating low-level systems programming without relying on automated memory runtimes.
This technical breakdown analyzes the emulator design choices, runtime memory architecture, hardware synchronization obstacles, and Odin language ergonomics uncovered during the build. The analysis is structured for systems engineers, language enthusiasts, and retro gaming preservationists evaluating non-garbage-collected languages for cycle-sensitive simulation workloads. It details practical implementation barriers, mapper circuit emulation, test automation pipelines, and unresolved audio generation subsystems.
01Seven cartridge mappers and core features
The emulator bundles an interactive menu interface, a specialized debugger view, configurable controller inputs, instant save states, and an optional cathode-ray tube shader toggle. Core compatibility spans seven distinct cartridge board mappers: NROM, MMC1, UXROM, CNROM, MMC3, GxROM, and AxROM. This mapper coverage provides electrical and address routing support across a broad catalog of release eras.
Physical Nintendo Entertainment System cartridges contained dedicated printed circuit boards housing custom circuitry rather than inert read-only storage media. These board configurations provided supplemental read-only memory banks, internal writable memory buffers, and occasional expansion audio hardware that effectively acted as modular hardware extensions. Implementing these discrete circuit topologies proved mandatory to boot commercial software correctly across various board revisions.
While the primary mapper implementations unlock execution for hundreds of classic titles, several edge cases remain partially supported. Complex cartridge boards with sparse or difficult documentation caused sporadic behavioral faults in certain test scenarios. The graphics processing routines, however, maintain sufficient accuracy to render titles like Battletoads without graphical collapse across raster splits.
02Parallel processor synchronization and timing accuracy
Reaching basic boot capabilities on simple early titles such as Donkey Kong required minimal development time, achieving initial functionality within early milestones. Getting the final ten percent of edge cases functional, however, consumed seven months of intermittent debugging labor. Commercial game software frequently relied on undocumented hardware behaviors and exact cycle latencies across physical silicon components.

The central processing unit and the picture processing unit run concurrently inside the console, exchanging register data and interrupt signals continuously. Because both processors execute in parallel, minor synchronization drift causes immediate sprite corruption, displaced scanlines, or fatal game lockups. Emulating this bidirectional communication pipeline requires strict cycle accounting across both execution loops rather than loose frame-step intervals.
Certain games tolerate minor timing deviations, but complex software like Battletoads breaks immediately if bus communications desynchronize. Developers must resolve subtle bus contention, register latch behavior, and interrupt timing to satisfy demanding assembly routines. Achieving this level of precision turned the latter stage of development into an arduous debugging endeavor.
Advertisement
Tech Pulse Daily
Get tomorrow's pulse first
Join engineers who read Tech Pulse before stand-up. Free, weekday mornings.
03Test suites and community hardware documentation
Development relied heavily on community-authored technical references, including comprehensive hardware wikis, specialized forum discussions, and dedicated Discord chat channels. Video lecture series by creator Javidx provided initial structural outlines, despite containing minor logic errors in early demonstration code. Detailed technical documentation explaining internal register updates across the picture processing unit helped clarify scanline generation logic.
Automated test read-only memory images served as primary verification harnesses to accelerate accuracy improvements across the virtual microprocessor. These specialized diagnostic programs systematically exercise isolated instruction combinations, status register bit updates, and cycle-exact interrupt assertions. Running test suites eliminated guesswork by exposing hidden regression errors before testing real game cartridges.
Direct technical guidance from experienced emulator creators inside the Nesdev community resolved ambiguous circuit specifications and conflicting behavioral descriptions. Without these external validation suites and community debugging insights, identifying edge-case processor bugs would have proved intractable. The open repository of test programs established reliable benchmarks for instruction execution correctness.
04Custom memory arenas and strict typing
The Odin programming language provided low-level memory freedom and strong typing without background runtime overhead, making it appropriate for real-time systems emulation. Odin enforces strict numeric handling by omitting automatic integer promotion, which prevented unintended widening casts but initially caused subtle calculation bugs. Adapting to explicit integer casts resolved these calculation discrepancies throughout internal arithmetic logic.
Memory management avoids complex garbage collection overhead through a three-tiered allocation strategy. A per-frame temporary allocator automatically resets on every rendered frame to collect transient computational buffers. Persistent platform resources use a global heap allocator, while cartridge session data resides in a dedicated arena allocator that clears whenever a play session terminates.
Object serialization for save states utilized the CBOR format library, which initially struggled with custom language constructs. Serializing a raw union holding eight-bit register bit fields, such as the PpuCtrl structure tracking pattern table addresses and vertical blanking flags, required custom type serialization handlers. Once developers established explicit serialization pathways, save states functioned reliably across game sessions.
05Audio synthesis limitations and unmapped hardware
Audio reproduction remains incomplete in the current build, producing acceptable output on a limited selection of titles while faltering on others. The audio processing unit still lacks an implementation of the delta modulation channel, which handles digitized sample playback in sophisticated soundtracks. Incomplete voice synthesis creates perceptible distortion and missing audio effects across sound-heavy game catalogs.
Cartridge compatibility also remains bounded by unmapped board configurations and lingering defects inside supported mapper logic. While baseline Nintendo boards operate smoothly, esoteric commercial titles with uncommon memory-banking hardware fail to boot or experience runtime crashes. Expanding mapper definitions and refining existing memory banking logic represent necessary prerequisites for comprehensive catalog coverage.
Active engineering paused in January 2025 to accommodate other development priorities, leaving the project in a functional but incomplete state. Future milestones would require finishing the delta modulation channel, resolving mapper bugs, and polishing general sound synthesis. The current source code remains available for developers studying low-level systems emulation in Odin.
A NES emulator written in Odin FAQ
What is lucyNES?
lucyNES is an open-source Nintendo Entertainment System emulator written in the Odin programming language. It includes a debugger view, save states, CRT shader toggles, and controller support.
Which cartridge mappers are supported by the emulator?
The emulator supports seven mappers: NROM, MMC1, UXROM, CNROM, MMC3, GxROM, and AxROM. These mappers provide the circuitry and memory banking required to run hundreds of NES games, including Battletoads.
How does the emulator manage memory in Odin?
The project uses a per-frame temporary allocator that resets every frame, a global heap allocator for persistent structures, and a NES Arena allocator that lives for the duration of a gaming session.
What features remain incomplete in lucyNES?
Audio generation remains partially implemented because the delta modulation channel is still missing. Additionally, some mapper implementations contain bugs and need further work to support more games.
Sources
Author
Dillip Chowdary
Writes Tech Bytes coverage of AI, engineering, and the tools that actually ship. Editor of Tech Pulse Daily.
Related on Tech Bytes
Advertisement